Browse Source

* Patch from Mattias Gaertner to fix use of Forward defined Classes

git-svn-id: trunk@35697 -
michael 8 years ago
parent
commit
aade79cff4

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

@@ -1072,6 +1072,7 @@ var
   UsePublished, FirstTime: Boolean;
   UsePublished, FirstTime: Boolean;
   ProcScope: TPasProcedureScope;
   ProcScope: TPasProcedureScope;
   ClassScope: TPasClassScope;
   ClassScope: TPasClassScope;
+  Ref: TResolvedReference;
 begin
 begin
   FirstTime:=true;
   FirstTime:=true;
   case Mode of
   case Mode of
@@ -1092,6 +1093,13 @@ begin
   {$IFDEF VerbosePasAnalyzer}
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime);
   writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime);
   {$ENDIF}
   {$ENDIF}
+  if El.IsForward then
+    begin
+    Ref:=El.CustomData as TResolvedReference;
+    UseClassType(Ref.Declaration as TPasClassType,Mode);
+    exit;
+    end;
+
   ClassScope:=El.CustomData as TPasClassScope;
   ClassScope:=El.CustomData as TPasClassScope;
   if FirstTime then
   if FirstTime then
     begin
     begin
@@ -1426,6 +1434,7 @@ begin
     end
     end
   else if C=TPasClassType then
   else if C=TPasClassType then
     begin
     begin
+    if TPasClassType(El).IsForward then exit;
     for i:=0 to TPasClassType(El).Members.Count-1 do
     for i:=0 to TPasClassType(El).Members.Count-1 do
       begin
       begin
       Member:=TPasElement(TPasClassType(El).Members[i]);
       Member:=TPasElement(TPasClassType(El).Members[i]);

+ 18 - 10
packages/fcl-passrc/tests/tcresolver.pas

@@ -315,6 +315,7 @@ type
     Procedure TestClassDefaultInheritance;
     Procedure TestClassDefaultInheritance;
     Procedure TestClassTripleInheritance;
     Procedure TestClassTripleInheritance;
     Procedure TestClassForward;
     Procedure TestClassForward;
+    Procedure TestClassForwardAsAncestorFail;
     Procedure TestClassForwardNotResolved;
     Procedure TestClassForwardNotResolved;
     Procedure TestClass_Method;
     Procedure TestClass_Method;
     Procedure TestClass_MethodWithoutClassFail;
     Procedure TestClass_MethodWithoutClassFail;
@@ -4223,9 +4224,22 @@ begin
   ParseProgram;
   ParseProgram;
 end;
 end;
 
 
+procedure TTestResolver.TestClassForwardAsAncestorFail;
+begin
+  StartProgram(false);
+  Add('type');
+  Add('  TObject = class;');
+  Add('  TBird = class end;');
+  Add('  TObject = class');
+  Add('  end;');
+  Add('var');
+  Add('  v: TBird;');
+  Add('begin');
+  CheckResolverException('Can''t use forward declaration "TObject" as ancestor',
+    nCantUseForwardDeclarationAsAncestor);
+end;
+
 procedure TTestResolver.TestClassForwardNotResolved;
 procedure TTestResolver.TestClassForwardNotResolved;
-var
-  ErrorNo: Integer;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
   Add('type');
   Add('type');
@@ -4235,14 +4249,8 @@ begin
   Add('var');
   Add('var');
   Add('  v: TClassB;');
   Add('  v: TClassB;');
   Add('begin');
   Add('begin');
-  ErrorNo:=0;
-  try
-    ParseModule;
-  except
-    on E: EPasResolve do
-      ErrorNo:=E.MsgNumber;
-  end;
-  AssertEquals('Forward class not resolved raises correct error',nForwardTypeNotResolved,ErrorNo);
+  CheckResolverException('Forward class not resolved raises correct error',
+    nForwardTypeNotResolved);
 end;
 end;
 
 
 procedure TTestResolver.TestClass_Method;
 procedure TTestResolver.TestClass_Method;

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

@@ -65,6 +65,7 @@ type
     procedure TestM_ProcedureType;
     procedure TestM_ProcedureType;
     procedure TestM_Params;
     procedure TestM_Params;
     procedure TestM_Class;
     procedure TestM_Class;
+    procedure TestM_ClassForward;
     procedure TestM_Class_Property;
     procedure TestM_Class_Property;
     procedure TestM_Class_PropertyOverride;
     procedure TestM_Class_PropertyOverride;
     procedure TestM_Class_MethodOverride;
     procedure TestM_Class_MethodOverride;
@@ -653,6 +654,26 @@ begin
   AnalyzeProgram;
   AnalyzeProgram;
 end;
 end;
 
 
+procedure TTestUseAnalyzer.TestM_ClassForward;
+begin
+  StartProgram(false);
+  Add('type');
+  Add('  {#integer_notused}integer = longint;');
+  Add('  {#TObject_used}TObject = class end;');
+  Add('  TFelidae = class;');
+  Add('  {#TCheetah_used}TCheetah = class');
+  Add('  public');
+  Add('    {#i_notused}i: integer;');
+  Add('    {#f_used}f: TFelidae;');
+  Add('  end;');
+  Add('  {TFelidae_used}TFelidae = class');
+  Add('  end;');
+  Add('var {#c_used}c: TCheetah;');
+  Add('begin');
+  Add('  c.f:=nil;');
+  AnalyzeProgram;
+end;
+
 procedure TTestUseAnalyzer.TestM_Class_Property;
 procedure TTestUseAnalyzer.TestM_Class_Property;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 21 - 2
packages/pastojs/src/fppas2js.pp

@@ -1139,6 +1139,7 @@ function TPas2JSResolver.GetOverloadIndex(Identifier: TPasIdentifier;
 var
 var
   El: TPasElement;
   El: TPasElement;
   ProcScope: TPasProcedureScope;
   ProcScope: TPasProcedureScope;
+  C: TClass;
 begin
 begin
   Result:=0;
   Result:=0;
   // iterate from last added to first added
   // iterate from last added to first added
@@ -1151,7 +1152,13 @@ begin
       Result:=0;
       Result:=0;
       continue;
       continue;
       end;
       end;
-    if El is TPasProcedure then
+    C:=El.ClassType;
+    if C=TPasClassType then
+      begin
+      if TPasClassType(El).IsForward then
+        continue;
+      end
+    else if C.InheritsFrom(TPasProcedure) then
       begin
       begin
       if TPasProcedure(El).IsOverride then
       if TPasProcedure(El).IsOverride then
         continue;
         continue;
@@ -1239,6 +1246,9 @@ begin
     RenameSubOverloads(aSection.Declarations);
     RenameSubOverloads(aSection.Declarations);
     end;
     end;
   PopOverloadScope;
   PopOverloadScope;
+  {$IFDEF VerbosePas2JS}
+  writeln('TPas2JSResolver.RenameOverloadsInSection END ',GetObjName(aSection));
+  {$ENDIF}
 end;
 end;
 
 
 procedure TPas2JSResolver.RenameOverloads(DeclEl: TPasElement;
 procedure TPas2JSResolver.RenameOverloads(DeclEl: TPasElement;
@@ -1275,6 +1285,9 @@ begin
           ProcScope.ImplProc.Name:=Proc.Name;
           ProcScope.ImplProc.Name:=Proc.Name;
       end;
       end;
     end;
     end;
+  {$IFDEF VerbosePas2JS}
+  writeln('TPas2JSResolver.RenameOverloads END ',GetObjName(DeclEl));
+  {$ENDIF}
 end;
 end;
 
 
 procedure TPas2JSResolver.RenameSubOverloads(Declarations: TFPList);
 procedure TPas2JSResolver.RenameSubOverloads(Declarations: TFPList);
@@ -1296,7 +1309,9 @@ begin
       Proc:=TPasProcedure(El);
       Proc:=TPasProcedure(El);
       if Proc.IsAbstract or Proc.IsExternal then continue;
       if Proc.IsAbstract or Proc.IsExternal then continue;
       ProcScope:=Proc.CustomData as TPasProcedureScope;
       ProcScope:=Proc.CustomData as TPasProcedureScope;
-      //writeln('TPas2JSResolver.RenameSubOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
+      {$IFDEF VerbosePas2JS}
+      writeln('TPas2JSResolver.RenameSubOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
+      {$ENDIF}
       if ProcScope.DeclarationProc<>nil then
       if ProcScope.DeclarationProc<>nil then
         // proc implementation (not forward) -> skip
         // proc implementation (not forward) -> skip
         continue;
         continue;
@@ -1318,6 +1333,7 @@ begin
     else if C=TPasClassType then
     else if C=TPasClassType then
       begin
       begin
       ClassEl:=TPasClassType(El);
       ClassEl:=TPasClassType(El);
+      if ClassEl.IsForward then continue;
       ClassScope:=El.CustomData as TPas2JSClassScope;
       ClassScope:=El.CustomData as TPas2JSClassScope;
       OldScopeCount:=FOverloadScopes.Count;
       OldScopeCount:=FOverloadScopes.Count;
 
 
@@ -1341,6 +1357,9 @@ begin
     else if C.InheritsFrom(TPasVariable) and (El.Parent.ClassType=TPasClassType) then
     else if C.InheritsFrom(TPasVariable) and (El.Parent.ClassType=TPasClassType) then
       RenameOverload(El);
       RenameOverload(El);
     end;
     end;
+  {$IFDEF VerbosePas2JS}
+  writeln('TPas2JSResolver.RenameSubOverloads END');
+  {$ENDIF}
 end;
 end;
 
 
 procedure TPas2JSResolver.PushOverloadScope(Scope: TPasIdentifierScope);
 procedure TPas2JSResolver.PushOverloadScope(Scope: TPasIdentifierScope);

+ 2 - 0
packages/pastojs/tests/tcmodules.pas

@@ -6544,10 +6544,12 @@ procedure TTestModule.TestClass_OverloadsAncestor;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
   Add('type');
   Add('type');
+  Add('  TObject = class;');
   Add('  TObject = class');
   Add('  TObject = class');
   Add('    procedure DoIt(vA: longint);');
   Add('    procedure DoIt(vA: longint);');
   Add('    procedure DoIt(vA, vB: longint);');
   Add('    procedure DoIt(vA, vB: longint);');
   Add('  end;');
   Add('  end;');
+  Add('  TCar = class;');
   Add('  TCar = class');
   Add('  TCar = class');
   Add('    procedure DoIt(vA: longint);');
   Add('    procedure DoIt(vA: longint);');
   Add('    procedure DoIt(vA, vB: longint);');
   Add('    procedure DoIt(vA, vB: longint);');