Browse Source

fcl-passrc: resolver: system.builtin, check hidden proc overloads

git-svn-id: trunk@37602 -
Mattias Gaertner 7 years ago
parent
commit
107439bf37

+ 6 - 0
packages/fcl-passrc/src/pasresolveeval.pas

@@ -145,6 +145,9 @@ const
   nAddingIndexSpecifierRequiresNewX = 3072;
   nCantFindUnitX = 3073;
   nCannotFindEnumeratorForType = 3074;
+  nPreviousDeclMissesOverload = 3075;
+  nOverloadedProcMissesOverload = 3076;
+  nMethodHidesMethodOfBaseType = 3077;
 
 // resourcestring patterns of messages
 resourcestring
@@ -222,6 +225,9 @@ resourcestring
   sAddingIndexSpecifierRequiresNewX = 'adding index specifier requires new "%s" specifier';
   sCantFindUnitX = 'can''t find unit "%s"';
   sCannotFindEnumeratorForType = 'Cannot find an enumerator for the type "%s"';
+  sPreviousDeclMissesOverload = 'Previous declaration of "%s" at %s was not marked with "overload" directive';
+  sOverloadedProcMissesOverload = 'Overloaded procedure misses "overload" directive. Previous declaration is at %s';
+  sMethodHidesMethodOfBaseType = 'Method "%s" hides method of base type "%s" at %s';
 
 type
   { TResolveData - base class for data stored in TPasElement.CustomData }

+ 231 - 96
packages/fcl-passrc/src/pasresolver.pp

@@ -137,7 +137,10 @@ Works:
 - built-in procedure str(const boolean|integer|enumvalue|classinstance,var s: string)
 - pointer TPasPointerType
   - nil, assigned(), typecast, class, classref, dynarray, procvar
-- emit hints platform, deprecated, experimental, library, unimplemented
+- emit hints
+  - platform, deprecated, experimental, library, unimplemented
+  - hiding ancestor method
+  - hiding other unit identifier
 - dotted unitnames
 - eval:
   - nil, true, false
@@ -165,9 +168,6 @@ Works:
   - array var
 
 ToDo:
-- Warning: An inherited method is hidden by "constructor Create(TComponent);
-- mode delphi: Error: Not all declarations of "Create" are declared with OVERLOAD
--
 - for..in..do
    - function: enumerator
    - class
@@ -714,8 +714,9 @@ type
       Data: Pointer; var Abort: boolean);
     procedure SetModule(AValue: TPasModule);
   public
-    InterfaceScope: TPasSectionScope;
     ImplementationScope: TPasSectionScope;
+    InterfaceScope: TPasSectionScope;
+    SystemScope: TPasDefaultScope;
     destructor Destroy; override;
     function FindIdentifier(const Identifier: String): TPasIdentifier; override;
     procedure IterateElements(const aName: string; StartScope: TPasScope;
@@ -973,10 +974,18 @@ type
       end;
       PFindCallElData = ^TFindCallElData;
 
+      TFindOverloadProcKind = (
+        fopkFinishMethodBody, // search method declaration for a body
+        fopkProc,   // check overloads for a proc
+        fopkMethod  // check overloads for a method
+        );
       TFindOverloadProcData = record
         Proc: TPasProcedure;
         Args: TFPList;        // List of TPasArgument objects
+        Kind: TFindOverloadProcKind;
         OnlyScope: TPasScope;
+        FoundOverloadModifier: boolean;
+        FoundInSameScope: integer;
         Found: TPasProcedure;
         ElScope, StartScope: TPasScope;
         FoundNonProc: TPasElement;
@@ -989,6 +998,7 @@ type
       FindProcsData: Pointer; var Abort: boolean); virtual;
     procedure OnFindOverloadProc(El: TPasElement; ElScope, StartScope: TPasScope;
       FindOverloadData: Pointer; var Abort: boolean); virtual;
+    function IsSameProcContext(ProcParentA, ProcParentB: TPasElement): boolean;
   protected
     procedure SetCurrentParser(AValue: TPasParser); override;
     procedure CheckTopScope(ExpectedClass: TPasScopeClass; AllowDescendants: boolean = false);
@@ -2173,17 +2183,22 @@ end;
 
 function TPasModuleDotScope.FindIdentifier(const Identifier: String
   ): TPasIdentifier;
+
+  function Find(Scope: TPasIdentifierScope): boolean;
+  var
+    Found: TPasIdentifier;
+  begin
+    if Scope=nil then exit(false);
+    Found:=Scope.FindLocalIdentifier(Identifier);
+    FindIdentifier:=Found;
+    Result:=(Found<>nil) and (Found.Element.ClassType<>TPasModule);
+  end;
+
 begin
-  if ImplementationScope<>nil then
-    begin
-    Result:=ImplementationScope.FindLocalIdentifier(Identifier);
-    if (Result<>nil) and (Result.Element.ClassType<>TPasModule) then
-      exit;
-    end;
-  if InterfaceScope<>nil then
-    Result:=InterfaceScope.FindLocalIdentifier(Identifier)
-  else
-    Result:=nil;
+  Result:=nil;
+  if Find(ImplementationScope) then exit;
+  if Find(InterfaceScope) then exit;
+  Find(SystemScope);
 end;
 
 procedure TPasModuleDotScope.IterateElements(const aName: string;
@@ -2191,16 +2206,20 @@ procedure TPasModuleDotScope.IterateElements(const aName: string;
   Data: Pointer; var Abort: boolean);
 var
   FilterData: TPasIterateFilterData;
+
+  function Iterate(Scope: TPasIdentifierScope): boolean;
+  begin
+    if Scope=nil then exit(false);
+    Scope.IterateLocalElements(aName,StartScope,@OnInternalIterate,@FilterData,Abort);
+    Result:=Abort;
+  end;
+
 begin
   FilterData.OnIterate:=OnIterateElement;
   FilterData.Data:=Data;
-  if ImplementationScope<>nil then
-    begin
-    ImplementationScope.IterateLocalElements(aName,StartScope,@OnInternalIterate,@FilterData,Abort);
-    if Abort then exit;
-    end;
-  if InterfaceScope<>nil then
-    InterfaceScope.IterateLocalElements(aName,StartScope,@OnInternalIterate,@FilterData,Abort);
+  if Iterate(ImplementationScope) then exit;
+  if Iterate(InterfaceScope) then exit;
+  Iterate(SystemScope);
 end;
 
 procedure TPasModuleDotScope.WriteIdentifiers(Prefix: string);
@@ -2209,6 +2228,8 @@ begin
     ImplementationScope.WriteIdentifiers(Prefix+'  ');
   if InterfaceScope<>nil then
     InterfaceScope.WriteIdentifiers(Prefix+'  ');
+  if SystemScope<>nil then
+    SystemScope.WriteIdentifiers(Prefix+'  ');
 end;
 
 { TPasSectionScope }
@@ -2753,6 +2774,7 @@ begin
     begin
     // identifier is a proc
     Proc:=TPasProcedure(El);
+    PrevProc:=nil;
 
     if Data^.Found=Proc then
       begin
@@ -2793,13 +2815,30 @@ begin
         end;
       end;
 
+    CandidateFound:=true;
     Distance:=CheckCallProcCompatibility(Proc.ProcType,Data^.Params,false);
+    if msDelphi in CurrentParser.CurrentModeswitches then
+      begin
+      if (not Proc.IsOverload) then
+        Abort:=true; // mode delphi: without 'overload' stop search
+      end
+    else
+      begin
+      if (PrevProc<>nil) and (not PrevProc.IsOverload)
+          and not IsSameProcContext(PrevProc.Parent,Proc.Parent) then
+        begin
+        // mode ObjFPC: last proc had no 'overload' and was in another scope
+        //  -> abort and ignore this proc
+        Abort:=true;
+        exit;
+        end;
+      end;
+
     {$IFDEF VerbosePasResolver}
     writeln('TPasResolver.OnFindCallElements Proc Distance=',Distance,
       ' Data^.Found=',Data^.Found<>nil,' Data^.Distance=',ord(Data^.Distance),
       ' Signature={',GetProcTypeDescription(Proc.ProcType,true,true),'}');
     {$ENDIF}
-    CandidateFound:=true;
     end
   else if El is TPasType then
     begin
@@ -2981,6 +3020,15 @@ procedure TPasResolver.OnFindOverloadProc(El: TPasElement; ElScope,
 var
   Data: PFindOverloadProcData absolute FindOverloadData;
   Proc: TPasProcedure;
+  Store, SameScope: Boolean;
+
+  procedure CountProcInSameModule;
+  begin
+    inc(Data^.FoundInSameScope);
+    if Proc.IsOverload then
+      Data^.FoundOverloadModifier:=true;
+  end;
+
 begin
   //writeln('TPasResolver.OnFindOverloadProc START ',El.Name,':',El.ElementTypeName,' itself=',El=Data^.Proc);
   if not (El is TPasProcedure) then
@@ -2989,18 +3037,45 @@ begin
     if (El is TPasVariable) then
       begin
       if TPasVariable(El).Visibility=visStrictPrivate then
-        exit;
+        exit; // not visible
       if (TPasVariable(El).Visibility=visPrivate)
           and (El.GetModule<>StartScope.Element.GetModule) then
-        exit;
+        exit; // not visible
       end;
+
     Data^.FoundNonProc:=El;
     Abort:=true;
+    if (El.CustomData is TResElDataBuiltInProc) then
+      begin
+      if Data^.Proc.IsOverload then
+        exit; // no hint
+      end;
+    case Data^.Kind of
+      fopkProc:
+        // proc hides a non proc
+        if (Data^.Proc.GetModule=El.GetModule) then
+          // forbidden within same module
+          RaiseMsg(20170216151649,nDuplicateIdentifier,sDuplicateIdentifier,
+            [El.Name,GetElementSourcePosStr(El)],Data^.Proc.ProcType)
+        else
+          // give a hint
+          LogMsg(20171118205344,mtHint,nFunctionHidesIdentifier,sFunctionHidesIdentifier,
+            [El.Name,GetElementSourcePosStr(El)],Data^.Proc.ProcType);
+      fopkMethod:
+        // method hides a non proc
+        RaiseMsg(20171118232543,nDuplicateIdentifier,sDuplicateIdentifier,
+          [El.Name,GetElementSourcePosStr(El)],Data^.Proc.ProcType);
+    end;
     exit;
     end;
   // identifier is a proc
+  Proc:=TPasProcedure(El);
   if El=Data^.Proc then
-    exit; // found itself -> normal when searching for overloads
+    begin
+    // found itself -> this is normal when searching for overloads
+    CountProcInSameModule;
+    exit;
+    end;
 
   //writeln('TPasResolver.OnFindOverloadProc Data^.OnlyScope=',GetObjName(Data^.OnlyScope),' ElScope=',GetObjName(ElScope),' ',Data^.OnlyScope=ElScope);
   if (Data^.OnlyScope<>nil) and (Data^.OnlyScope<>ElScope) then
@@ -3014,8 +3089,82 @@ begin
   {$IFDEF VerbosePasResolver}
   writeln('TPasResolver.OnFindOverloadProc ',GetTreeDbg(El,2));
   {$ENDIF}
-  Proc:=TPasProcedure(El);
-  if CheckOverloadProcCompatibility(Data^.Proc,Proc) then
+  Store:=CheckOverloadProcCompatibility(Data^.Proc,Proc);
+  if Data^.Kind=fopkFinishMethodBody then
+    // finding a proc with same signature is enough, see above Data^.OnlyScope
+  else
+    begin
+    if Data^.Kind=fopkProc then
+      SameScope:=Data^.Proc.GetModule=Proc.GetModule
+    else
+      SameScope:=Data^.Proc.Parent=Proc.Parent;
+    if SameScope then
+      begin
+      // same scope
+      Store:=CheckOverloadProcCompatibility(Data^.Proc,Proc);
+      if Store then
+        begin
+        // same scope, same signature
+        if (Data^.Kind=fopkProc)
+            and IsSameProcContext(Data^.Proc.Parent,Proc.Parent)
+            and ProcNeedsImplProc(Proc)
+            and (not ProcNeedsImplProc(Data^.Proc)) then
+          begin
+          // Proc is the forward declaration of Data^.Proc
+          end
+        else
+          RaiseMsg(20171118221821,nDuplicateIdentifier,sDuplicateIdentifier,
+                   [Proc.Name,GetElementSourcePosStr(Proc)],Data^.Proc.ProcType);
+        end
+      else
+        begin
+        // same scope, different signature
+        if (msDelphi in CurrentParser.CurrentModeswitches) then
+          begin
+          // Delphi does not allow different procs without 'overload' in a scope
+          if not Proc.IsOverload then
+            RaiseMsg(20171118222112,nPreviousDeclMissesOverload,sPreviousDeclMissesOverload,
+              [Proc.Name,GetElementSourcePosStr(Proc)],Data^.Proc.ProcType)
+          else if not Proc.IsOverload then
+            RaiseMsg(20171118222147,nOverloadedProcMissesOverload,sOverloadedProcMissesOverload,
+              [GetElementSourcePosStr(Proc)],Data^.Proc.ProcType);
+          end
+        else
+          begin
+          // ObjFPC allows different procs without 'overload' modifier
+          end;
+        CountProcInSameModule;
+        end;
+      end
+    else
+      begin
+      // different scopes
+      if Data^.Proc.IsOverride then
+        begin
+        Store:=CheckOverloadProcCompatibility(Data^.Proc,Proc);
+        end
+      else if not Data^.Proc.IsReintroduced then
+        begin
+        if Store
+            or ((Data^.FoundInSameScope=1) // missing 'overload' hints only for the first proc in a scope
+               and ((not Data^.FoundOverloadModifier)
+                or (not Proc.IsOverload))) then
+          begin
+          // give a hint, that proc is hiding a proc in other scope
+          if Data^.Kind=fopkMethod then
+            LogMsg(20170216151712,mtWarning,nMethodHidesMethodOfBaseType,
+              sMethodHidesMethodOfBaseType,
+              [Data^.Proc.Name,Proc.Parent.Name,GetElementSourcePosStr(Proc)],Data^.Proc.ProcType)
+          else
+            LogMsg(20171118214523,mtHint,nFunctionHidesIdentifier,sFunctionHidesIdentifier,
+              [Proc.Name,GetElementSourcePosStr(Proc)],Data^.Proc.ProcType);
+          Abort:=true;
+          end;
+        end;
+      end;
+    end;
+
+  if Store then
     begin
     Data^.Found:=Proc;
     Data^.ElScope:=ElScope;
@@ -3024,6 +3173,25 @@ begin
     end;
 end;
 
+function TPasResolver.IsSameProcContext(ProcParentA, ProcParentB: TPasElement
+  ): boolean;
+begin
+  if ProcParentA=ProcParentB then exit(true);
+  if (ProcParentA.ClassType=TInterfaceSection) then
+    begin
+    if (ProcParentB.ClassType=TImplementationSection)
+        and (ProcParentB.Parent=ProcParentA.Parent) then
+      exit(true);
+    end
+  else if (ProcParentB.ClassType=TInterfaceSection) then
+    begin
+    if (ProcParentA.ClassType=TImplementationSection)
+        and (ProcParentA.Parent=ProcParentB.Parent) then
+      exit(true);
+    end;
+  Result:=false;
+end;
+
 procedure TPasResolver.SetCurrentParser(AValue: TPasParser);
 begin
   //writeln('TPasResolver.SetCurrentParser ',AValue<>nil);
@@ -3646,17 +3814,15 @@ begin
 
     if Proc.IsExternal then
       begin
-      for pm in TProcedureModifier do
-        if (pm in Proc.Modifiers)
-            and not (pm in [pmVirtual, pmDynamic, pmOverride,
-                        pmOverload, pmMessage, pmReintroduce,
-                        pmExternal, pmDispId,
-                        pmfar]) then
+      for pm in Proc.Modifiers do
+        if not (pm in [pmVirtual, pmDynamic, pmOverride,
+                       pmOverload, pmMessage, pmReintroduce,
+                       pmExternal, pmDispId,
+                       pmfar]) then
           RaiseMsg(20170216151616,nInvalidXModifierY,
             sInvalidXModifierY,[Proc.ElementTypeName,'external, '+ModifierNames[pm]],Proc);
-      for ptm in TProcTypeModifier do
-        if (ptm in Proc.ProcType.Modifiers)
-            and not (ptm in [ptmOfObject,ptmIsNested,ptmStatic,ptmVarargs,ptmReferenceTo]) then
+      for ptm in Proc.ProcType.Modifiers do
+        if not (ptm in [ptmOfObject,ptmIsNested,ptmStatic,ptmVarargs,ptmReferenceTo]) then
           RaiseMsg(20170411171224,nInvalidXModifierY,
             sInvalidXModifierY,[Proc.ElementTypeName,'external, '+ProcTypeModifiers[ptm]],Proc);
       end;
@@ -3675,6 +3841,8 @@ begin
         end;
       if Proc.IsVirtual and Proc.IsOverride then
         RaiseMsg(20170216151627,nInvalidXModifierY,sInvalidXModifierY,[Proc.ElementTypeName,'virtual, override'],Proc);
+      if Proc.IsReintroduced and Proc.IsOverride then
+        RaiseMsg(20171119111845,nInvalidXModifierY,sInvalidXModifierY,[Proc.ElementTypeName,'reintroduce, override'],Proc);
       if Proc.IsForward then
         RaiseMsg(20170216151629,nInvalidXModifierY,sInvalidXModifierY,[Proc.ElementTypeName,'forward'],Proc);
       if Proc.IsStatic then
@@ -3730,50 +3898,26 @@ begin
     FindData:=Default(TFindOverloadProcData);
     FindData.Proc:=Proc;
     FindData.Args:=Proc.ProcType.Args;
+    FindData.Kind:=fopkProc;
     Abort:=false;
     IterateElements(ProcName,@OnFindOverloadProc,@FindData,Abort);
-    if FindData.FoundNonProc<>nil then
-      begin
-      // proc hides a non proc -> forbidden within module
-      if (Proc.GetModule=FindData.FoundNonProc.GetModule) then
-        RaiseMsg(20170216151649,nDuplicateIdentifier,sDuplicateIdentifier,
-          [FindData.FoundNonProc.Name,GetElementSourcePosStr(FindData.FoundNonProc)],Proc.ProcType);
-      end;
     if FindData.Found=nil then
-      exit; // no overload -> ok
+      exit; // no forward definition found -> ok
 
-    // overload found with same signature
     DeclProc:=FindData.Found;
     {$IFDEF VerbosePasResolver}
-    writeln('TPasResolver.FinishProcedureHeader overload found: Proc2=',GetTreeDbg(DeclProc),' ',GetElementSourcePosStr(DeclProc),' IsForward=',DeclProc.IsForward,' Parent=',GetObjName(DeclProc.Parent));
+    writeln('TPasResolver.FinishProcedureHeader forward found: Proc2=',GetTreeDbg(DeclProc),' ',GetElementSourcePosStr(DeclProc),' IsForward=',DeclProc.IsForward,' Parent=',GetObjName(DeclProc.Parent));
     {$ENDIF}
-    if (Proc.Parent=DeclProc.Parent)
-        or ((Proc.Parent is TImplementationSection)
-           and (DeclProc.Parent is TInterfaceSection)
-           and (Proc.Parent.Parent=DeclProc.Parent.Parent))
-    then
-      begin
-      // both procs are defined in the same scope
-      if ProcNeedsImplProc(Proc) or (not ProcNeedsImplProc(DeclProc)) then
-        RaiseMsg(20170216151652,nDuplicateIdentifier,sDuplicateIdentifier,
-                 [ProcName,GetElementSourcePosStr(DeclProc)],Proc.ProcType);
-      CheckProcSignatureMatch(DeclProc,Proc,true);
-      DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
-      DeclProcScope.ImplProc:=Proc;
-      ProcScope:=Proc.CustomData as TPasProcedureScope;
-      ProcScope.DeclarationProc:=DeclProc;
-      // remove ImplProc from scope
-      ParentScope:=Scopes[ScopeCount-2];
-      (ParentScope as TPasIdentifierScope).RemoveLocalIdentifier(Proc);
-      // replace arguments with declaration arguments
-      ReplaceProcScopeImplArgsWithDeclArgs(ProcScope);
-      end
-    else
-      begin
-      // give a hint, that proc is hiding DeclProc
-      LogMsg(20170216151656,mtHint,nFunctionHidesIdentifier,sFunctionHidesIdentifier,
-        [DeclProc.Name,GetElementSourcePosStr(DeclProc)],Proc.ProcType);
-      end;
+    CheckProcSignatureMatch(DeclProc,Proc,true);
+    DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
+    DeclProcScope.ImplProc:=Proc;
+    ProcScope:=Proc.CustomData as TPasProcedureScope;
+    ProcScope.DeclarationProc:=DeclProc;
+    // remove ImplProc from scope
+    ParentScope:=Scopes[ScopeCount-2];
+    (ParentScope as TPasIdentifierScope).RemoveLocalIdentifier(Proc);
+    // replace arguments with declaration arguments
+    ReplaceProcScopeImplArgsWithDeclArgs(ProcScope);
     end
   else if El.Name<>'' then
     begin
@@ -3808,12 +3952,10 @@ begin
   FindData:=Default(TFindOverloadProcData);
   FindData.Proc:=Proc;
   FindData.Args:=Proc.ProcType.Args;
+  FindData.Kind:=fopkMethod;
   Abort:=false;
   ClassScope.IterateElements(Proc.Name,ClassScope,@OnFindOverloadProc,@FindData,Abort);
-  if FindData.FoundNonProc<>nil then
-    // proc hides a non proc -> duplicate
-    RaiseMsg(20170216151659,nDuplicateIdentifier,sDuplicateIdentifier,
-      [FindData.FoundNonProc.Name,GetElementSourcePosStr(FindData.FoundNonProc)],Proc.ProcType);
+
   if FindData.Found=nil then
     begin
     // no overload
@@ -3825,11 +3967,10 @@ begin
     begin
     // overload found
     OverloadProc:=FindData.Found;
-    if Proc.Parent=OverloadProc.Parent then
-      // overload in same scope -> duplicate
-      RaiseMsg(20170216151705,nDuplicateIdentifier,sDuplicateIdentifier,
-        [OverloadProc.Name,GetElementSourcePosStr(OverloadProc)],Proc.ProcType);
+
+    // Note: 'inherited;' needs the OverriddenProc, even without 'override' modifier
     ProcScope.OverriddenProc:=OverloadProc;
+
     if Proc.IsOverride then
       begin
       if (not OverloadProc.IsVirtual) and (not OverloadProc.IsOverride) then
@@ -3857,12 +3998,6 @@ begin
       // check name case
       if proFixCaseOfOverrides in Options then
         Proc.Name:=OverloadProc.Name;
-      end
-    else if not Proc.IsReintroduced then
-      begin
-        // give a hint, that proc is hiding OverloadProc
-        LogMsg(20170216151712,mtHint,nFunctionHidesIdentifier,sFunctionHidesIdentifier,
-          [OverloadProc.Name,GetElementSourcePosStr(OverloadProc)],Proc.ProcType);
       end;
     end;
 end;
@@ -3910,6 +4045,7 @@ begin
   FindData.Proc:=ImplProc;
   FindData.Args:=ImplProc.ProcType.Args;
   FindData.OnlyScope:=CurClassScope;
+  FindData.Kind:=fopkFinishMethodBody;
   Abort:=false;
   CurClassScope.IterateElements(ProcName,CurClassScope,@OnFindOverloadProc,@FindData,Abort);
   if FindData.Found=nil then
@@ -5532,18 +5668,15 @@ begin
   DeclProc:=SelfScope.DeclarationProc;
   DeclProcScope:=DeclProc.CustomData as TPasProcedureScope;
   AncestorProc:=DeclProcScope.OverriddenProc;
-  if AncestorProc<>nil then
-    begin
-    CreateReference(AncestorProc,El,Access);
-    if AncestorProc.IsAbstract then
-      RaiseMsg(20170216152144,nAbstractMethodsCannotBeCalledDirectly,
-        sAbstractMethodsCannotBeCalledDirectly,[],El);
-    end
-  else
+  if AncestorProc=nil then
     begin
     // 'inherited;' without ancestor method is silently ignored
     exit;
     end;
+  CreateReference(AncestorProc,El,Access);
+  if AncestorProc.IsAbstract then
+    RaiseMsg(20170216152144,nAbstractMethodsCannotBeCalledDirectly,
+      sAbstractMethodsCannotBeCalledDirectly,[],El);
 end;
 
 procedure TPasResolver.ResolveInheritedCall(El: TBinaryExpr;
@@ -10629,6 +10762,8 @@ begin
         and (aModule.ImplementationSection.CustomData<>nil)
     then
       Result.ImplementationScope:=NoNil(aModule.ImplementationSection.CustomData) as TPasSectionScope;
+    if CompareText(aModule.Name,'system')=0 then
+      Result.SystemScope:=DefaultScope;
     end;
 
   PushScope(Result);

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

@@ -340,6 +340,7 @@ type
     Procedure TestProcOverloadWithInhClassTypes;
     Procedure TestProcOverloadWithInhAliasClassTypes;
     Procedure TestProcOverloadBaseTypeOtherUnit;
+    Procedure TestProcOverloadBaseProcNoHint;
     Procedure TestProcDuplicate;
     Procedure TestNestedProc;
     Procedure TestFuncAssignFail;
@@ -411,9 +412,14 @@ type
     Procedure TestClass_MethodOverrideSameResultType;
     Procedure TestClass_MethodOverrideDiffResultTypeFail;
     Procedure TestClass_MethodOverrideDiffVarName;
+    Procedure TestClass_MethodOverloadMissingInDelphi;
     Procedure TestClass_MethodOverloadAncestor;
+    Procedure TestClass_MethodOverloadUnit;
+    Procedure TestClass_MethodReintroduce;
     Procedure TestClass_MethodOverloadArrayOfTClass;
+    Procedure TestClass_ConstructorHidesAncestorWarning;
     Procedure TestClass_ConstructorOverride;
+    Procedure TestClass_ConstructorAccessHiddenAncestorFail;
     Procedure TestClass_MethodScope;
     Procedure TestClass_IdentifierSelf;
     Procedure TestClassCallInherited;
@@ -5043,6 +5049,22 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestProcOverloadBaseProcNoHint;
+begin
+  StartProgram(false);
+  Add([
+  'function Copy(s: string): string; overload;',
+  'begin end;',
+  'var',
+  '  A: array of longint;',
+  '  s: string;',
+  'begin',
+  '  A:=Copy(A,1);',
+  '  s:=copy(s)']);
+  ParseProgram;
+  CheckResolverUnexpectedHints;
+end;
+
 procedure TTestResolver.TestProcDuplicate;
 begin
   StartProgram(false);
@@ -6292,6 +6314,21 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestClass_MethodOverloadMissingInDelphi;
+begin
+  StartProgram(false);
+  Add([
+  '{$mode delphi}',
+  'type',
+  '  TObject = class',
+  '    procedure DoIt(i: longint); virtual; abstract;',
+  '    procedure DoIt(s: string); virtual; abstract;',
+  '  end;',
+  'begin'
+  ]);
+  CheckResolverException(sPreviousDeclMissesOverload,nPreviousDeclMissesOverload);
+end;
+
 procedure TTestResolver.TestClass_MethodOverloadAncestor;
 begin
   StartProgram(false);
@@ -6318,6 +6355,41 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestClass_MethodOverloadUnit;
+begin
+  StartProgram(true);
+  Add([
+  'type',
+  '  TObject = class',
+  '    procedure Copy(s: string);',
+  '  end;',
+  'procedure TObject.Copy(s: string);',
+  'var a: array of longint;',
+  'begin',
+  '  a:=system.Copy(a,1,3);',
+  'end;',
+  'begin']);
+  ParseProgram;
+  CheckResolverUnexpectedHints;
+end;
+
+procedure TTestResolver.TestClass_MethodReintroduce;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    procedure DoIt(p: pointer); virtual; abstract;',
+  '  end;',
+  '  TBird = class',
+  '    procedure DoIt(i: longint); virtual; abstract; reintroduce;',
+  '    procedure DoIt(s: string); virtual; abstract;',
+  '  end;',
+  'begin']);
+  ParseProgram;
+  CheckResolverUnexpectedHints;
+end;
+
 procedure TTestResolver.TestClass_MethodOverloadArrayOfTClass;
 begin
   StartProgram(false);
@@ -6371,6 +6443,25 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestClass_ConstructorHidesAncestorWarning;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    constructor Create(o: tobject); virtual; abstract;',
+  '  end;',
+  '  TBird = class',
+  '    constructor Create(s: string); virtual; abstract;',
+  '  end;',
+  'begin',
+  '']);
+  ParseProgram;
+  CheckResolverHint(mtWarning,nMethodHidesMethodOfBaseType,
+    'Method "Create" hides method of base type "TObject" at afile.pp(4,23)');
+  CheckResolverUnexpectedHints;
+end;
+
 procedure TTestResolver.TestClass_ConstructorOverride;
 begin
   StartProgram(false);
@@ -6396,6 +6487,27 @@ begin
   ParseProgram;
 end;
 
+procedure TTestResolver.TestClass_ConstructorAccessHiddenAncestorFail;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class',
+  '    constructor Create(o: tobject);',
+  '  end;',
+  '  TBird = class',
+  '    constructor Create(i: longint); reintroduce;',
+  '  end;',
+  'constructor tobject.Create(o: tobject); begin end;',
+  'constructor tbird.Create(i: longint); begin end;',
+  'var o: TBird;',
+  'begin',
+  '  o:=TBird.Create(nil);',
+  '']);
+  CheckResolverException('Incompatible type arg no. 1: Got "Nil", expected "Longint"',
+    nIncompatibleTypeArgNo);
+end;
+
 procedure TTestResolver.TestClass_MethodScope;
 begin
   StartProgram(false);