Bläddra i källkod

fcl-passrc: useanalyzer: for in class do

git-svn-id: trunk@37802 -
Mattias Gaertner 7 år sedan
förälder
incheckning
7d0942a774

+ 18 - 0
packages/fcl-passrc/src/pasresolver.pp

@@ -701,6 +701,15 @@ type
     destructor Destroy; override;
   end;
 
+  { TPasForLoopScope }
+
+  TPasForLoopScope = Class(TPasScope)
+  public
+    GetEnumerator: TPasFunction;
+    MoveNext: TPasFunction;
+    Current: TPasProperty;
+  end;
+
   { TPasSubScope - base class for sub scopes aka dotted scopes }
 
   TPasSubScope = Class(TPasIdentifierScope)
@@ -5258,6 +5267,8 @@ var
   TypeEl: TPasType;
   C: TClass;
 begin
+  CreateScope(Loop,TPasForLoopScope);
+
   // loop var
   ResolveExpr(Loop.VariableName,rraReadAndAssign);
   ComputeElement(Loop.VariableName,VarResolved,[rcNoImplicitProc,rcSetReferenceFlags]);
@@ -8201,6 +8212,7 @@ var
   ptm: TProcTypeModifier;
   ResultResolved, MoveNextResolved, CurrentResolved: TPasResolverResult;
   CurrentProp: TPasProperty;
+  ForScope: TPasForLoopScope;
 begin
   Result:=false;
   TypeEl:=ResolveAliasType(InResolved.TypeEl);
@@ -8290,6 +8302,12 @@ begin
       RaiseIncompatibleTypeRes(20171221200018,nIncompatibleTypesGotExpected,[],VarResolved,CurrentResolved,Loop.VariableName);
 
     PopScope;
+
+    ForScope:=Loop.CustomData as TPasForLoopScope;
+    ForScope.GetEnumerator:=GetterFunc;
+    ForScope.MoveNext:=MoveNextFunc;
+    ForScope.Current:=CurrentProp;
+
     exit(true);
     end;
 

+ 7 - 0
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -854,6 +854,7 @@ var
   CaseSt: TPasImplCaseStatement;
   WithDo: TPasImplWithDo;
   SubEl, ParentEl: TPasElement;
+  ForScope: TPasForLoopScope;
 begin
   // do not mark
   if El=nil then exit;
@@ -903,6 +904,10 @@ begin
     UseExpr(ForLoop.VariableName);
     UseExpr(ForLoop.StartExpr);
     UseExpr(ForLoop.EndExpr);
+    ForScope:=ForLoop.CustomData as TPasForLoopScope;
+    UseProcedure(ForScope.GetEnumerator);
+    UseProcedure(ForScope.MoveNext);
+    UseVariable(ForScope.Current,rraRead,false);
     UseImplElement(ForLoop.Body);
     end
   else if C=TPasImplIfElse then
@@ -1190,6 +1195,7 @@ var
   ProcScope: TPasProcedureScope;
   ImplProc: TPasProcedure;
 begin
+  if Proc=nil then exit;
   // use declaration, not implementation
   ProcScope:=Proc.CustomData as TPasProcedureScope;
   if ProcScope.DeclarationProc<>nil then
@@ -1442,6 +1448,7 @@ var
   i: Integer;
   IsRead, IsWrite, CanRead, CanWrite: Boolean;
 begin
+  if El=nil then exit;
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
   {$ENDIF}

+ 34 - 0
packages/fcl-passrc/tests/tcuseanalyzer.pas

@@ -129,6 +129,7 @@ type
     procedure TestWP_PublishedProperty;
     procedure TestWP_BuiltInFunctions;
     procedure TestWP_TypeInfo;
+    procedure TestWP_ForInClass;
   end;
 
 implementation
@@ -1924,6 +1925,39 @@ begin
   AnalyzeWholeProgram;
 end;
 
+procedure TTestUseAnalyzer.TestWP_ForInClass;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '  end;',
+  '  {#tenumerator_used}TEnumerator = class',
+  '  strict private',
+  '    {#fcurrent_used}FCurrent: longint;',
+  '  public',
+  '    {#v_notused}v: string;',
+  '    function {#movenext_used}MoveNext: boolean;',
+  '    property {#current_used}Current: longint read FCurrent;',
+  '  end;',
+  '  {#tbird_used}TBird = class',
+  '    function {#getenumerator_used}GetEnumerator: TEnumerator;',
+  '  end;',
+  'function TEnumerator.MoveNext: boolean;',
+  'begin',
+  'end;',
+  'function TBird.GetEnumerator: TEnumerator;',
+  'begin',
+  'end;',
+  'var',
+  '  {#b_used}b: TBird;',
+  '  {#i_used}i: longint;',
+  'begin',
+  '  for i in b do ;',
+  '']);
+  AnalyzeWholeProgram;
+end;
+
 initialization
   RegisterTests([TTestUseAnalyzer]);