Browse Source

fcl-passrc: fixed searching overload in mode delphi

mattias 3 years ago
parent
commit
309d8a90fd
2 changed files with 75 additions and 27 deletions
  1. 35 27
      packages/fcl-passrc/src/pasresolver.pp
  2. 40 0
      packages/fcl-passrc/tests/tcresolver.pas

+ 35 - 27
packages/fcl-passrc/src/pasresolver.pp

@@ -1556,8 +1556,8 @@ type
       TFindCallElData = record
       TFindCallElData = record
         Params: TParamsExpr;
         Params: TParamsExpr;
         TemplCnt: integer;
         TemplCnt: integer;
-        Found: TPasElement; // TPasProcedure or TPasUnresolvedSymbolRef(built in proc) or TPasType (typecast)
-        LastProc: TPasProcedure;
+        Found: TPasElement; // TPasProcedure or TPasUnresolvedSymbolRef(built in proc) or TPasType (typecast), best candidate so far
+        LastProc: TPasProcedure; // last checked TPasProcedure
         ElScope, StartScope: TPasScope;
         ElScope, StartScope: TPasScope;
         Distance: integer; // compatibility distance
         Distance: integer; // compatibility distance
         Count: integer;
         Count: integer;
@@ -1595,7 +1595,7 @@ type
     procedure OnFindProcDeclaration(El: TPasElement; ElScope, StartScope: TPasScope;
     procedure OnFindProcDeclaration(El: TPasElement; ElScope, StartScope: TPasScope;
       FindProcData: Pointer; var Abort: boolean); virtual;
       FindProcData: Pointer; var Abort: boolean); virtual;
     function IsSameProcContext(ProcParentA, ProcParentB: TPasElement): boolean;
     function IsSameProcContext(ProcParentA, ProcParentB: TPasElement): boolean;
-    function IsProcOverload(LastProc, LastExactProc, CurProc: TPasProcedure): boolean;
+    function IsProcOverloading(LastProc, CurProc: TPasProcedure): boolean;
     function FindProcSameSignature(const ProcName: string; Proc: TPasProcedure;
     function FindProcSameSignature(const ProcName: string; Proc: TPasProcedure;
       Scope: TPasIdentifierScope; OnlyLocal: boolean): TPasProcedure;
       Scope: TPasIdentifierScope; OnlyLocal: boolean): TPasProcedure;
   protected
   protected
@@ -5018,7 +5018,7 @@ procedure TPasResolver.OnFindFirst_GenericEl(El: TPasElement; ElScope,
 var
 var
   Data: PPRFindGenericData absolute FindFirstGenericData;
   Data: PPRFindGenericData absolute FindFirstGenericData;
   GenericTemplateTypes: TFPList;
   GenericTemplateTypes: TFPList;
-  Proc, LastExactProc: TPasProcedure;
+  Proc: TPasProcedure;
   ProcScope: TPasProcedureScope;
   ProcScope: TPasProcedureScope;
 begin
 begin
   Proc:=nil;
   Proc:=nil;
@@ -5037,11 +5037,7 @@ begin
 
 
     if (Data^.LastProc<>nil) then
     if (Data^.LastProc<>nil) then
       begin
       begin
-      if Data^.Find.Found is TPasProcedure then
-        LastExactProc:=TPasProcedure(Data^.Find.Found)
-      else
-        LastExactProc:=nil;
-      if not IsProcOverload(Data^.LastProc,LastExactProc,Proc) then
+      if not IsProcOverloading(Data^.LastProc,Proc) then
         begin
         begin
         Abort:=true;
         Abort:=true;
         exit;
         exit;
@@ -5126,30 +5122,49 @@ begin
       El:=Proc;
       El:=Proc;
       end;
       end;
 
 
+    if (msDelphi in ProcScope.ModeSwitches) and not IsProcOverload(Proc) then
+      begin
+      Abort:=true; // stop searching after this proc
+      if Data^.LastProc<>nil then
+        exit;
+      end;
+
+    if (Data^.LastProc<>nil) then
+      begin
+      if (TPasProcedureScope(Data^.LastProc.CustomData).OverriddenProc=Proc) then
+        begin
+        // already checked the override -> skip
+        Data^.LastProc:=Proc;
+        exit;
+        end;
+      if not IsProcOverloading(Data^.LastProc,Proc) then
+        begin
+        Abort:=true;
+        exit;
+        end;
+      end;
+
     if Data^.Found is TPasProcedure then
     if Data^.Found is TPasProcedure then
       begin
       begin
       // there is already a previous proc
       // there is already a previous proc
       PrevProc:=TPasProcedure(Data^.Found);
       PrevProc:=TPasProcedure(Data^.Found);
 
 
-      if (Data^.Distance=cExact) and (PrevProc.Parent<>Proc.Parent)
-          and (PrevProc.Parent.ClassType=TPasClassType) then
+      if (TPasProcedureScope(PrevProc.CustomData).OverriddenProc=Proc) then
         begin
         begin
-        // there was already a perfect proc in a descendant
-        Abort:=true;
+        // already checked the override -> skip
+        Data^.LastProc:=Proc;
         exit;
         exit;
         end;
         end;
 
 
-      if not IsProcOverload(Data^.LastProc,PrevProc,Proc) then
+      if (Data^.Distance=cExact) and (PrevProc.Parent<>Proc.Parent)
+          and (PrevProc.Parent.ClassType=TPasClassType) then
         begin
         begin
+        // there was already a perfect proc in a descendant
         Abort:=true;
         Abort:=true;
         exit;
         exit;
         end;
         end;
-
       end;
       end;
 
 
-    if (msDelphi in ProcScope.ModeSwitches) and not IsProcOverload(Proc) then
-      Abort:=true; // stop searching after this proc
-
     CandidateFound:=true;
     CandidateFound:=true;
     if Data^.TemplCnt>0 then
     if Data^.TemplCnt>0 then
       begin
       begin
@@ -5639,8 +5654,8 @@ begin
   Result:=false;
   Result:=false;
 end;
 end;
 
 
-function TPasResolver.IsProcOverload(LastProc, LastExactProc,
-  CurProc: TPasProcedure): boolean;
+function TPasResolver.IsProcOverloading(LastProc, CurProc: TPasProcedure
+  ): boolean;
 begin
 begin
   if msDelphi in TPasProcedureScope(LastProc.CustomData).ModeSwitches then
   if msDelphi in TPasProcedureScope(LastProc.CustomData).ModeSwitches then
     begin
     begin
@@ -5660,13 +5675,6 @@ begin
       end;
       end;
     end;
     end;
 
 
-  // check if previous found proc is override of found proc
-  if (LastExactProc<>nil) and IsProcOverride(CurProc,LastExactProc) then
-    begin
-    // previous found proc is override of found proc -> skip
-    exit(false);
-    end;
-
   Result:=true;
   Result:=true;
 end;
 end;
 
 

+ 40 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -431,6 +431,7 @@ type
     Procedure TestProcOverloadObjFPCUnitWithoutOverloadMod;
     Procedure TestProcOverloadObjFPCUnitWithoutOverloadMod;
     Procedure TestProcOverloadDelphiWithObjFPC;
     Procedure TestProcOverloadDelphiWithObjFPC;
     Procedure TestProcOverloadDelphiOverride;
     Procedure TestProcOverloadDelphiOverride;
+    Procedure TestProcOverloadDelphiOverrideOne;
     Procedure TestProcDuplicate;
     Procedure TestProcDuplicate;
     Procedure TestNestedProc;
     Procedure TestNestedProc;
     Procedure TestNestedProc_ResultString;
     Procedure TestNestedProc_ResultString;
@@ -7085,6 +7086,45 @@ begin
   ParseProgram;
   ParseProgram;
 end;
 end;
 
 
+procedure TTestResolver.TestProcOverloadDelphiOverrideOne;
+begin
+  StartProgram(false);
+  Add([
+  '{$mode delphi}',
+  'type',
+  '  TObject = class',
+  '    constructor Create(b: boolean); virtual;',
+  '  end;',
+  '  TBird = class',
+  '    // add first an overload',
+  '    constructor Create(w: word); overload;',
+  '    // and then override the previous',
+  '    constructor Create(b: boolean); override; overload;',
+  '  end;',
+  '  TEagle = class(TBird)',
+  '    constructor Create(b: boolean); override; overload;',
+  '  end;',
+  'constructor TObject.Create(b: boolean);',
+  'begin',
+  'end;',
+  'constructor TBird.Create(w: word);',
+  'begin',
+  'end;',
+  'constructor TBird.Create(b: boolean);',
+  'begin',
+  'end;',
+  'constructor TEagle.Create(b: boolean);',
+  'begin',
+  'end;',
+  'begin',
+  '  TBird.Create(false);',
+  '  TBird.Create(2);',
+  '  TEagle.Create(true);',
+  '  TEagle.Create(3);',
+  '']);
+  ParseProgram;
+end;
+
 procedure TTestResolver.TestProcDuplicate;
 procedure TTestResolver.TestProcDuplicate;
 begin
 begin
   StartProgram(false);
   StartProgram(false);