Browse Source

fcl-passrc: useanalyzer: store and use initialization/finalization references

git-svn-id: trunk@38394 -
Mattias Gaertner 7 years ago
parent
commit
23cf3dceb4

+ 259 - 166
packages/fcl-passrc/src/pasresolver.pp

@@ -486,8 +486,51 @@ type
     Element: TPasType; // TPasClassOfType or TPasPointerType
   end;
 
+  TPSRefAccess = (
+    psraNone,
+    psraRead,
+    psraWrite,
+    psraReadWrite,
+    psraWriteRead,
+    psraTypeInfo
+    );
+
+  { TPasScopeReference }
+
+  TPasScopeReference = class
+  private
+    FElement: TPasElement;
+    procedure SetElement(const AValue: TPasElement);
+  public
+    {$IFDEF VerbosePasResolver}
+    Owner: TObject;
+    {$ENDIF}
+    Access: TPSRefAccess;
+    NextSameName: TPasScopeReference;
+    destructor Destroy; override;
+    property Element: TPasElement read FElement write SetElement;
+  end;
+
   TPasScope = class;
 
+  { TPasScopeReferences - used by TPasAnalyzer to store references of a proc or initialization section }
+
+  TPasScopeReferences = class
+  private
+    FScope: TPasScope;
+    procedure OnClearItem(Item, Dummy: pointer);
+    procedure OnCollectItem(Item, aList: pointer);
+  public
+    References: TFPHashList; // hash list of TPasScopeReference
+    constructor Create(aScope: TPasScope);
+    destructor Destroy; override;
+    procedure Clear;
+    function Add(El: TPasElement; Access: TPSRefAccess): TPasScopeReference;
+    function Find(const aName: string): TPasScopeReference;
+    function GetList: TFPList;
+    property Scope: TPasScope read FScope;
+  end;
+
   TIterateScopeElement = procedure(El: TPasElement; ElScope, StartScope: TPasScope;
     Data: Pointer; var Abort: boolean) of object;
 
@@ -548,6 +591,7 @@ type
     property RangeErrorClass: TPasClassType read FRangeErrorClass write SetRangeErrorClass;
     property RangeErrorConstructor: TPasConstructor read FRangeErrorConstructor write SetRangeErrorConstructor;
   end;
+  TPasModuleScopeClass = class of TPasModuleScope;
 
   TPasIdentifierKind = (
     pikNone, // not yet initialized
@@ -631,6 +675,16 @@ type
     procedure WriteIdentifiers(Prefix: string); override;
   end;
 
+  { TPasInitialFinalizationScope - e.g. TInitializationSection, TFinalizationSection }
+
+  TPasInitialFinalizationScope = Class(TPasScope)
+  public
+    References: TPasScopeReferences; // created by TPasAnalyzer
+    function AddReference(El: TPasElement; Access: TPSRefAccess): TPasScopeReference;
+    destructor Destroy; override;
+  end;
+  TPasInitialFinalizationScopeClass = class of TPasInitialFinalizationScope;
+
   { TPasEnumTypeScope }
 
   TPasEnumTypeScope = Class(TPasIdentifierScope)
@@ -670,31 +724,6 @@ type
   end;
   TPasClassScopeClass = class of TPasClassScope;
 
-  TPSRefAccess = (
-    psraNone,
-    psraRead,
-    psraWrite,
-    psraReadWrite,
-    psraWriteRead,
-    psraTypeInfo
-    );
-
-  { TPasProcScopeReference }
-
-  TPasProcScopeReference = class
-  private
-    FElement: TPasElement;
-    procedure SetElement(const AValue: TPasElement);
-  public
-    {$IFDEF VerbosePasResolver}
-    Owner: TObject;
-    {$ENDIF}
-    Access: TPSRefAccess;
-    NextSameName: TPasProcScopeReference;
-    destructor Destroy; override;
-    property Element: TPasElement read FElement write SetElement;
-  end;
-
   TPasProcedureScopeFlag = (
     ppsfIsGroupOverload // mode objfpc: one overload is enough for all procs in same scope
     );
@@ -703,9 +732,6 @@ type
   { TPasProcedureScope }
 
   TPasProcedureScope = Class(TPasIdentifierScope)
-  private
-    procedure OnClearReferenceItem(Item, Dummy: pointer);
-    procedure OnCollectReferenceItem(Item, aList: pointer);
   public
     DeclarationProc: TPasProcedure; // the corresponding forward declaration
     ImplProc: TPasProcedure; // the corresponding proc with Body
@@ -715,7 +741,6 @@ type
     Mode: TModeSwitch;
     Flags: TPasProcedureScopeFlags;
     BoolSwitches: TBoolSwitches;
-    References: TFPHashList; // list of TPasProcScopeReference, created by TPasAnalyzer
     function FindIdentifier(const Identifier: String): TPasIdentifier; override;
     procedure IterateElements(const aName: string; StartScope: TPasScope;
       const OnIterateElement: TIterateScopeElement; Data: Pointer;
@@ -723,9 +748,9 @@ type
     function GetSelfScope: TPasProcedureScope; // get the next parent procscope with a classcope
     procedure WriteIdentifiers(Prefix: string); override;
     destructor Destroy; override;
-    procedure ClearReferences;
-    function AddReference(El: TPasElement; Access: TPSRefAccess): TPasProcScopeReference;
-    function FindReference(const aName: string): TPasProcScopeReference;
+  public
+    References: TPasScopeReferences; // created by TPasAnalyzer in DeclrationProc
+    function AddReference(El: TPasElement; Access: TPSRefAccess): TPasScopeReference;
     function GetReferences: TFPList;
   end;
   TPasProcedureScopeClass = class of TPasProcedureScope;
@@ -1066,6 +1091,8 @@ type
     FPendingForwardProcs: TFPList; // list of TPasElement needed to check for forward procs
     FRootElement: TPasModule;
     FScopeClass_Class: TPasClassScopeClass;
+    FScopeClass_InitialFinalization: TPasInitialFinalizationScopeClass;
+    FScopeClass_Module: TPasModuleScopeClass;
     FScopeClass_Proc: TPasProcedureScopeClass;
     FScopeClass_WithExpr: TPasWithExprScopeClass;
     FScopeCount: integer;
@@ -1136,6 +1163,7 @@ type
       const Kind: TPasIdentifierKind): TPasIdentifier; virtual;
     procedure AddModule(El: TPasModule); virtual;
     procedure AddSection(El: TPasSection); virtual;
+    procedure AddInitialFinalizationSection(El: TPasImplBlock); virtual;
     procedure AddType(El: TPasType); virtual;
     procedure AddRecordType(El: TPasRecordType); virtual;
     procedure AddClassType(El: TPasClassType); virtual;
@@ -1210,6 +1238,7 @@ type
     procedure FinishPropertyParamAccess(Params: TParamsExpr;
       Prop: TPasProperty);
     procedure FinishCallArgAccess(Expr: TPasExpr; Access: TResolvedRefAccess);
+    procedure FinishInitialFinalization(El: TPasImplBlock);
     procedure EmitTypeHints(PosEl: TPasElement; aType: TPasType); virtual;
     function EmitElementHints(PosEl, El: TPasElement): boolean; virtual;
     procedure StoreScannerFlagsInProc(ProcScope: TPasProcedureScope);
@@ -1623,6 +1652,8 @@ type
     property TopScope: TPasScope read FTopScope;
     property DefaultScope: TPasDefaultScope read FDefaultScope write FDefaultScope;
     property ScopeClass_Class: TPasClassScopeClass read FScopeClass_Class write FScopeClass_Class;
+    property ScopeClass_InitialFinalization: TPasInitialFinalizationScopeClass read FScopeClass_InitialFinalization write FScopeClass_InitialFinalization;
+    property ScopeClass_Module: TPasModuleScopeClass read FScopeClass_Module write FScopeClass_Module;
     property ScopeClass_Procedure: TPasProcedureScopeClass read FScopeClass_Proc write FScopeClass_Proc;
     property ScopeClass_WithExpr: TPasWithExprScopeClass read FScopeClass_WithExpr write FScopeClass_WithExpr;
     // last element
@@ -2159,9 +2190,25 @@ begin
   str(a,Result);
 end;
 
-{ TPasProcScopeReference }
+{ TPasInitialFinalizationScope }
 
-procedure TPasProcScopeReference.SetElement(const AValue: TPasElement);
+function TPasInitialFinalizationScope.AddReference(El: TPasElement;
+  Access: TPSRefAccess): TPasScopeReference;
+begin
+  if References=nil then
+    References:=TPasScopeReferences.Create(Self);
+  Result:=References.Add(El,Access);
+end;
+
+destructor TPasInitialFinalizationScope.Destroy;
+begin
+  FreeAndNil(References);
+  inherited Destroy;
+end;
+
+{ TPasScopeReference }
+
+procedure TPasScopeReference.SetElement(const AValue: TPasElement);
 begin
   if FElement=AValue then Exit;
   if FElement<>nil then
@@ -2171,7 +2218,7 @@ begin
     FElement.AddRef;
 end;
 
-destructor TPasProcScopeReference.Destroy;
+destructor TPasScopeReference.Destroy;
 begin
   {$IFDEF VerbosePasResolverMem}
   writeln('TPasProcScopeReference.Destroy START ',ClassName,' "',GetObjName(Element),'"');
@@ -2183,6 +2230,154 @@ begin
   {$ENDIF}
 end;
 
+{ TPasScopeReferences }
+
+procedure TPasScopeReferences.OnClearItem(Item, Dummy: pointer);
+var
+  Ref: TPasScopeReference absolute Item;
+  Ref2: TPasScopeReference;
+begin
+  if Dummy=nil then ;
+  //writeln('TPasProcedureScope.OnClearReferenceItem ',GetObjName(Ref.Element));
+  while Ref<>nil do
+    begin
+    Ref2:=Ref;
+    Ref:=Ref.NextSameName;
+    Ref2.Free;
+    end;
+end;
+
+procedure TPasScopeReferences.OnCollectItem(Item, aList: pointer);
+var
+  Ref: TPasScopeReference absolute Item;
+  List: TFPList absolute aList;
+begin
+  List.Add(Ref);
+end;
+
+constructor TPasScopeReferences.Create(aScope: TPasScope);
+begin
+  References:=TFPHashList.Create;
+  FScope:=aScope;
+end;
+
+destructor TPasScopeReferences.Destroy;
+begin
+  Clear;
+  FreeAndNil(References);
+  inherited Destroy;
+end;
+
+procedure TPasScopeReferences.Clear;
+begin
+  if References=nil then exit;
+  References.ForEachCall(@OnClearItem,nil);
+  References.Clear;
+end;
+
+function TPasScopeReferences.Add(El: TPasElement; Access: TPSRefAccess
+  ): TPasScopeReference;
+var
+  LoName: String;
+  OldItem, Item: TPasScopeReference;
+  Index: Integer;
+begin
+  LoName:=lowercase(El.Name);
+  OldItem:=TPasScopeReference(References.Find(LoName));
+  Item:=OldItem;
+  while Item<>nil do
+    begin
+    if Item.Element=El then
+      begin
+      // already marked as used -> combine access
+      case Access of
+      psraNone: ;
+      psraRead:
+        case Item.Access of
+          psraNone: Item.Access:=Access;
+          //psraRead: ;
+          psraWrite: Item.Access:=psraWriteRead;
+          //psraReadWrite: ;
+          //psraWriteRead: ;
+          //psraTypeInfo: ;
+        end;
+      psraWrite:
+        case Item.Access of
+          psraNone: Item.Access:=Access;
+          psraRead: Item.Access:=psraReadWrite;
+          //psraWrite: ;
+          //psraReadWrite: ;
+          //psraWriteRead: ;
+          //psraTypeInfo: ;
+        end;
+      psraReadWrite:
+        case Item.Access of
+          psraNone: Item.Access:=Access;
+          psraRead: Item.Access:=psraReadWrite;
+          psraWrite: Item.Access:=psraWriteRead;
+          //psraReadWrite: ;
+          //psraWriteRead: ;
+          //psraTypeInfo: ;
+        end;
+      psraWriteRead:
+        case Item.Access of
+          psraNone: Item.Access:=Access;
+          psraRead: Item.Access:=psraReadWrite;
+          psraWrite: Item.Access:=psraWriteRead;
+          //psraReadWrite: ;
+          //psraWriteRead: ;
+          //psraTypeInfo: ;
+        end;
+      psraTypeInfo: Item.Access:=psraTypeInfo;
+      else
+        raise EPasResolve.Create(GetObjName(El)+' unknown Access');
+      end;
+      exit(Item);
+      end;
+    Item:=Item.NextSameName;
+    end;
+  // new reference
+  Item:=TPasScopeReference.Create;
+  Item.Element:=El;
+  Item.Access:=Access;
+  Index:=References.FindIndexOf(LoName);
+  if Index<0 then
+    begin
+    References.Add(LoName,Item);
+    {$IFDEF VerbosePJUFiler}
+    if TPasScopeReference(References.Find(LoName))<>Item then
+      raise EPasResolve.Create('20180219230028');
+    {$ENDIF}
+    end
+  else
+    begin
+    OldItem:=TPasScopeReference(References.List^[Index].Data);
+    {$IFDEF VerbosePJUFiler}
+    if lowercase(OldItem.Element.Name)<>LoName then
+      raise EPasResolve.Create('20180219230055');
+    {$ENDIF}
+    Item.NextSameName:=OldItem;
+    References.List^[Index].Data:=Item;
+    end;
+  Result:=Item;
+end;
+
+function TPasScopeReferences.Find(const aName: string): TPasScopeReference;
+var
+  LoName: String;
+begin
+  if References=nil then exit(nil);
+  LoName:=lowercase(aName);
+  Result:=TPasScopeReference(References.Find(LoName));
+end;
+
+function TPasScopeReferences.GetList: TFPList;
+begin
+  Result:=TFPList.Create;
+  if References=nil then exit;
+  References.ForEachCall(@OnCollectItem,Result);
+end;
+
 { TPasPropertyScope }
 
 destructor TPasPropertyScope.Destroy;
@@ -2280,29 +2475,6 @@ end;
 
 { TPasProcedureScope }
 
-procedure TPasProcedureScope.OnClearReferenceItem(Item, Dummy: pointer);
-var
-  Ref: TPasProcScopeReference absolute Item;
-  Ref2: TPasProcScopeReference;
-begin
-  if Dummy=nil then ;
-  //writeln('TPasProcedureScope.OnClearReferenceItem ',GetObjName(Ref.Element));
-  while Ref<>nil do
-    begin
-    Ref2:=Ref;
-    Ref:=Ref.NextSameName;
-    Ref2.Free;
-    end;
-end;
-
-procedure TPasProcedureScope.OnCollectReferenceItem(Item, aList: pointer);
-var
-  Ref: TPasProcScopeReference absolute Item;
-  List: TFPList absolute aList;
-begin
-  List.Add(Ref);
-end;
-
 function TPasProcedureScope.FindIdentifier(const Identifier: String
   ): TPasIdentifier;
 begin
@@ -2345,7 +2517,7 @@ end;
 
 destructor TPasProcedureScope.Destroy;
 begin
-  ClearReferences;
+  FreeAndNil(References);
   {$IFDEF VerbosePasResolverMem}
   writeln('TPasProcedureScope.Destroy START ',ClassName);
   {$ENDIF}
@@ -2356,118 +2528,20 @@ begin
   {$ENDIF}
 end;
 
-procedure TPasProcedureScope.ClearReferences;
-begin
-  if References=nil then exit;
-  References.ForEachCall(@OnClearReferenceItem,nil);
-  References.Clear;
-  FreeAndNil(References);
-end;
-
 function TPasProcedureScope.AddReference(El: TPasElement; Access: TPSRefAccess
-  ): TPasProcScopeReference;
-var
-  LoName: String;
-  OldItem, Item: TPasProcScopeReference;
-  Index: Integer;
+  ): TPasScopeReference;
 begin
   if References=nil then
-    References:=TFPHashList.Create;
-  LoName:=lowercase(El.Name);
-  OldItem:=TPasProcScopeReference(References.Find(LoName));
-  Item:=OldItem;
-  while Item<>nil do
-    begin
-    if Item.Element=El then
-      begin
-      // already marked as used -> combine access
-      case Access of
-      psraNone: ;
-      psraRead:
-        case Item.Access of
-          psraNone: Item.Access:=Access;
-          //psraRead: ;
-          psraWrite: Item.Access:=psraWriteRead;
-          //psraReadWrite: ;
-          //psraWriteRead: ;
-          //psraTypeInfo: ;
-        end;
-      psraWrite:
-        case Item.Access of
-          psraNone: Item.Access:=Access;
-          psraRead: Item.Access:=psraReadWrite;
-          //psraWrite: ;
-          //psraReadWrite: ;
-          //psraWriteRead: ;
-          //psraTypeInfo: ;
-        end;
-      psraReadWrite:
-        case Item.Access of
-          psraNone: Item.Access:=Access;
-          psraRead: Item.Access:=psraReadWrite;
-          psraWrite: Item.Access:=psraWriteRead;
-          //psraReadWrite: ;
-          //psraWriteRead: ;
-          //psraTypeInfo: ;
-        end;
-      psraWriteRead:
-        case Item.Access of
-          psraNone: Item.Access:=Access;
-          psraRead: Item.Access:=psraReadWrite;
-          psraWrite: Item.Access:=psraWriteRead;
-          //psraReadWrite: ;
-          //psraWriteRead: ;
-          //psraTypeInfo: ;
-        end;
-      psraTypeInfo: Item.Access:=psraTypeInfo;
-      else
-        raise EPasResolve.Create(GetObjName(El)+' unknown Access');
-      end;
-      exit(Item);
-      end;
-    Item:=Item.NextSameName;
-    end;
-  // new reference
-  Item:=TPasProcScopeReference.Create;
-  Item.Element:=El;
-  Item.Access:=Access;
-  Index:=References.FindIndexOf(LoName);
-  if Index<0 then
-    begin
-    References.Add(LoName,Item);
-    {$IFDEF VerbosePJUFiler}
-    if TPasProcScopeReference(References.Find(LoName))<>Item then
-      raise EPasResolve.Create('20180219230028');
-    {$ENDIF}
-    end
-  else
-    begin
-    OldItem:=TPasProcScopeReference(References.List^[Index].Data);
-    {$IFDEF VerbosePJUFiler}
-    if lowercase(OldItem.Element.Name)<>LoName then
-      raise EPasResolve.Create('20180219230055');
-    {$ENDIF}
-    Item.NextSameName:=OldItem;
-    References.List^[Index].Data:=Item;
-    end;
-  Result:=Item;
-end;
-
-function TPasProcedureScope.FindReference(const aName: string
-  ): TPasProcScopeReference;
-var
-  LoName: String;
-begin
-  if References=nil then exit(nil);
-  LoName:=lowercase(aName);
-  Result:=TPasProcScopeReference(References.Find(LoName));
+    References:=TPasScopeReferences.Create(Self);
+  Result:=References.Add(El,Access);
 end;
 
 function TPasProcedureScope.GetReferences: TFPList;
 begin
-  Result:=TFPList.Create;
-  if References=nil then exit;
-  References.ForEachCall(@OnCollectReferenceItem,Result);
+  if References=nil then
+    Result:=TFPList.Create
+  else
+    Result:=References.GetList;
 end;
 
 { TPasClassScope }
@@ -3944,7 +4018,7 @@ begin
   // close all sections
   while (TopScope<>nil) and (TopScope.ClassType=TPasSectionScope) do
     PopScope;
-  CheckTopScope(TPasModuleScope);
+  CheckTopScope(FScopeClass_Module);
   PopScope;
 
   FStep:=prsFinishedModule;
@@ -5601,6 +5675,13 @@ begin
   ComputeElement(Expr,ResolvedEl,Flags);
 end;
 
+procedure TPasResolver.FinishInitialFinalization(El: TPasImplBlock);
+begin
+  if El=nil then ;
+  CheckTopScope(ScopeClass_InitialFinalization);
+  PopScope;
+end;
+
 procedure TPasResolver.EmitTypeHints(PosEl: TPasElement; aType: TPasType);
 begin
   while aType<>nil do
@@ -7311,7 +7392,7 @@ var
 begin
   if TopScope<>DefaultScope then
     RaiseInvalidScopeForElement(20160922163504,El);
-  ModScope:=TPasModuleScope(PushScope(El,TPasModuleScope));
+  ModScope:=TPasModuleScope(PushScope(El,FScopeClass_Module));
   ModScope.VisibilityContext:=El;
   ModScope.FirstName:=FirstDottedIdentifier(El.Name);
   C:=El.ClassType;
@@ -7331,6 +7412,11 @@ begin
   PushScope(El,TPasSectionScope);
 end;
 
+procedure TPasResolver.AddInitialFinalizationSection(El: TPasImplBlock);
+begin
+  PushScope(El,ScopeClass_InitialFinalization);
+end;
+
 procedure TPasResolver.AddType(El: TPasType);
 begin
   if (El.Name='') then exit; // sub type
@@ -11015,6 +11101,8 @@ begin
   FDynArrayMinIndex:=0;
   FDynArrayMaxIndex:=High(int64);
   FScopeClass_Class:=TPasClassScope;
+  FScopeClass_InitialFinalization:=TPasInitialFinalizationScope;
+  FScopeClass_Module:=TPasModuleScope;
   FScopeClass_Proc:=TPasProcedureScope;
   FScopeClass_WithExpr:=TPasWithExprScope;
   fExprEvaluator:=TResExprEvaluator.Create;
@@ -11145,6 +11233,10 @@ begin
   else if AClass=TPasUsesUnit then
   else if AClass.InheritsFrom(TPasExpr) then
     // resolved when finished
+  else if AClass=TInitializationSection then
+    AddInitialFinalizationSection(TInitializationSection(El))
+  else if AClass=TFinalizationSection then
+    AddInitialFinalizationSection(TFinalizationSection(El))
   else if AClass.InheritsFrom(TPasImplBlock) then
     // resolved when finished
   else if AClass=TPasUnresolvedUnitRef then
@@ -11727,6 +11819,7 @@ begin
   stExceptOnStatement: FinishExceptOnStatement;
   stDeclaration: FinishDeclaration(El);
   stAncestors: FinishAncestors(El as TPasClassType);
+  stInitialFinalization: FinishInitialFinalization(El as TPasImplBlock);
   else
     RaiseMsg(20170216152401,nNotYetImplemented,sNotYetImplemented+' FinishScope',[IntToStr(ord(ScopeType))],nil);
   end;

+ 1 - 0
packages/fcl-passrc/src/pastree.pp

@@ -1206,6 +1206,7 @@ Type
   public
     Elements: TFPList;    // list of TPasImplElement and maybe one TPasImplCaseElse
   end;
+  TPasImplBlockClass = class of TPasImplBlock;
 
   { TPasImplStatement }
 

+ 69 - 122
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -147,7 +147,7 @@ type
 
   TPasAnalyzerOption = (
     paoOnlyExports, // default: use all class members accessible from outside (protected, but not private)
-    paoProcImplReferences // collect TPasProcedureScope.References of top lvl proc implementations
+    paoImplReferences // collect references of top lvl proc implementations, initializationa dn finalization sections
     );
   TPasAnalyzerOptions = set of TPasAnalyzerOption;
 
@@ -179,19 +179,17 @@ type
     FResolver: TPasResolver;
     FScopeModule: TPasModule;
     FUsedElements: TAVLTree; // tree of TPAElement sorted for Element
-    FRefProcDecl: TPasProcedure; // if set, collect only what this proc references
-    FRefProcScope: TPasProcedureScope; // the ProcScope of FRefProcDecl
     procedure UseElType(El: TPasElement; aType: TPasType; Mode: TPAUseMode); inline;
     function AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
     function FindOverrideNode(El: TPasElement): TAVLTreeNode;
     function FindOverrideList(El: TPasElement): TPAOverrideList;
     procedure SetOptions(AValue: TPasAnalyzerOptions);
     procedure UpdateAccess(IsWrite: Boolean; IsRead: Boolean; Usage: TPAElement);
-    procedure OnUseProcScopeRef(data, DeclScope: pointer);
+    procedure OnUseScopeRef(data, DeclScope: pointer);
   protected
     procedure RaiseInconsistency(const Id: int64; Msg: string);
     procedure RaiseNotSupported(const Id: int64; El: TPasElement; const Msg: string = '');
-    function FindTopProcScope(El: TPasElement; Decl: boolean): TPasProcedureScope;
+    function FindTopImplScope(El: TPasElement): TPasScope;
     // mark used elements
     function Add(El: TPasElement; CheckDuplicate: boolean = true;
       aClass: TPAElementClass = nil): TPAElement;
@@ -200,8 +198,7 @@ type
     procedure CreateTree; virtual;
     function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
     function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
-    function MarkSingleProcRef(El: TPasElement; Access: TPSRefAccess): boolean; // true if outside FRefProcDecl
-    procedure MarkScopeRef(Parent, El: TPasElement; Access: TPSRefAccess);
+    procedure MarkImplScopeRef(El, RefEl: TPasElement; Access: TPSRefAccess);
     procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
       UseFull: boolean); virtual;
     procedure UsePublished(El: TPasElement); virtual;
@@ -213,6 +210,7 @@ type
     procedure UseExprRef(El: TPasElement; Expr: TPasExpr;
       Access: TResolvedRefAccess; UseFull: boolean); virtual;
     procedure UseInheritedExpr(El: TInheritedExpr); virtual;
+    procedure UseScopeReferences(Refs: TPasScopeReferences); virtual;
     procedure UseProcedure(Proc: TPasProcedure); virtual;
     procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
     procedure UseType(El: TPasType; Mode: TPAUseMode); virtual;
@@ -236,7 +234,6 @@ type
     procedure Clear;
     procedure AnalyzeModule(aModule: TPasModule);
     procedure AnalyzeWholeProgram(aStartModule: TPasProgram);
-    procedure AnalyzeProcRefs(Proc: TPasProcedure);
     procedure EmitModuleHints(aModule: TPasModule); virtual;
     function FindElement(El: TPasElement): TPAElement;
     function FindUsedElement(El: TPasElement): TPAElement;
@@ -436,7 +433,7 @@ procedure TPasAnalyzer.UseElType(El: TPasElement; aType: TPasType;
   Mode: TPAUseMode);
 begin
   if aType=nil then exit;
-  MarkScopeRef(El,aType,PAUseModeToPSRefAccess[Mode]);
+  MarkImplScopeRef(El,aType,PAUseModeToPSRefAccess[Mode]);
   UseType(aType,Mode);
 end;
 
@@ -518,10 +515,10 @@ begin
     end;
 end;
 
-procedure TPasAnalyzer.OnUseProcScopeRef(data, DeclScope: pointer);
+procedure TPasAnalyzer.OnUseScopeRef(data, DeclScope: pointer);
 var
-  Ref: TPasProcScopeReference absolute data;
-  Scope: TPasProcedureScope absolute DeclScope;
+  Ref: TPasScopeReference absolute data;
+  Scope: TPasScope absolute DeclScope;
 begin
   if Scope=nil then ;
   case Ref.Access of
@@ -564,22 +561,33 @@ begin
   raise E;
 end;
 
-function TPasAnalyzer.FindTopProcScope(El: TPasElement; Decl: boolean
-  ): TPasProcedureScope;
+function TPasAnalyzer.FindTopImplScope(El: TPasElement): TPasScope;
+var
+  ProcScope: TPasProcedureScope;
+  C: TClass;
+  ImplProc: TPasProcedure;
 begin
   Result:=nil;
   while El<>nil do
     begin
-    if El is TPasProcedure then
-      Result:=El.CustomData as TPasProcedureScope;
+    C:=El.ClassType;
+    if C.InheritsFrom(TPasProcedure) then
+      begin
+      ProcScope:=TPasProcedureScope(El.CustomData);
+      if ProcScope.DeclarationProc<>nil then
+        ProcScope:=TPasProcedureScope(ProcScope.DeclarationProc.CustomData);
+      ImplProc:=ProcScope.ImplProc;
+      if ImplProc=nil then
+        ImplProc:=TPasProcedure(ProcScope.Element);
+      if ImplProc.Body<>nil then
+        // has implementation, not an external proc
+        Result:=ProcScope;
+      end
+    else if (C=TInitializationSection)
+        or (C=TFinalizationSection) then
+      Result:=TPasInitialFinalizationScope(El.CustomData);
     El:=El.Parent;
     end;
-  if Result=nil then exit;
-  if Decl then
-    begin
-    if Result.DeclarationProc<>nil then
-      Result:=Result.DeclarationProc.CustomData as TPasProcedureScope;
-    end;
 end;
 
 function TPasAnalyzer.Add(El: TPasElement; CheckDuplicate: boolean;
@@ -669,47 +677,31 @@ begin
   FChecked[Mode].Add(El);
 end;
 
-function TPasAnalyzer.MarkSingleProcRef(El: TPasElement; Access: TPSRefAccess
-  ): boolean;
-var
-  Parent: TPasElement;
-begin
-  Parent:=El;
-  while Parent<>nil do
-    begin
-    if (Parent=FRefProcDecl) or (Parent=FRefProcScope.ImplProc) then
-      exit(false); // inside proc
-    Parent:=Parent.Parent;
-    end;
-  FRefProcScope.AddReference(El,Access);
-  Result:=true;
-end;
-
-procedure TPasAnalyzer.MarkScopeRef(Parent, El: TPasElement;
+procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement;
   Access: TPSRefAccess);
 
   procedure CheckImplRef;
+  // check if El inside a proc, initialization or finalization
+  // and if RefEl is outside
   var
-    ParentProcScope, ElProcScope: TPasProcedureScope;
-    ImplProc: TPasProcedure;
+    ElImplScope, RefElImplScope: TPasScope;
   begin
-    ParentProcScope:=FindTopProcScope(Parent,true);
-    if ParentProcScope=nil then exit;
-    ImplProc:=ParentProcScope.ImplProc;
-    if ImplProc=nil then
-      ImplProc:=TPasProcedure(ParentProcScope.Element);
-    if ImplProc.Body=nil then
-      exit; // has no implementation, e.g. external proc
-
-    ElProcScope:=FindTopProcScope(El,true);
-    if ElProcScope=ParentProcScope then exit;
-    ParentProcScope.AddReference(El,Access);
+    ElImplScope:=FindTopImplScope(El);
+    if ElImplScope=nil then exit;
+    RefElImplScope:=FindTopImplScope(RefEl);
+    if RefElImplScope=ElImplScope then exit;
+    if ElImplScope is TPasProcedureScope then
+      TPasProcedureScope(ElImplScope).AddReference(RefEl,Access)
+    else if ElImplScope is TPasInitialFinalizationScope then
+      TPasInitialFinalizationScope(ElImplScope).AddReference(RefEl,Access)
+    else
+      RaiseInconsistency(20180302142933,GetObjName(ElImplScope));
   end;
 
 begin
-  if El=nil then exit;
-  if El.Parent=Parent then exit; // same scope
-  if paoProcImplReferences in Options then
+  if RefEl=nil then exit;
+  if RefEl.Parent=El then exit; // same scope
+  if paoImplReferences in Options then
     CheckImplRef;
 end;
 
@@ -754,7 +746,7 @@ procedure TPasAnalyzer.UsePublished(El: TPasElement);
   procedure UseSubEl(SubEl: TPasElement); inline;
   begin
     if SubEl=nil then exit;
-    MarkScopeRef(El,SubEl,psraTypeInfo);
+    MarkImplScopeRef(El,SubEl,psraTypeInfo);
     UsePublished(SubEl);
   end;
 
@@ -771,7 +763,6 @@ begin
   writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
   {$ENDIF}
   if ElementVisited(El,paumPublished) then exit;
-  if (FRefProcDecl<>nil) and MarkSingleProcRef(El,psraTypeInfo) then exit;
 
   C:=El.ClassType;
   if C=TPasUnresolvedSymbolRef then
@@ -845,8 +836,13 @@ end;
 procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
 
   procedure UseInitFinal(ImplBlock: TPasImplBlock);
+  var
+    Scope: TPasInitialFinalizationScope;
   begin
-    if IsImplBlockEmpty(ImplBlock) then exit;
+    if ImplBlock=nil then exit;
+    Scope:=TPasInitialFinalizationScope(ImplBlock.CustomData);
+    UseScopeReferences(Scope.References);
+    if (Scope.References=nil) and IsImplBlockEmpty(ImplBlock) then exit;
     // this module has an initialization section -> mark module
     if FindNode(aModule)=nil then
       Add(aModule);
@@ -857,7 +853,6 @@ var
   ModScope: TPasModuleScope;
 begin
   if ElementVisited(aModule,Mode) then exit;
-  if (FRefProcDecl<>nil) and MarkSingleProcRef(aModule,psraRead) then exit;
 
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode);
@@ -944,7 +939,7 @@ begin
     writeln('TPasAnalyzer.UseSection ',Section.ClassName,' Decl=',GetElModName(Decl),' Mode=',Mode);
     {$ENDIF}
     C:=Decl.ClassType;
-    // Note: no MarkScopeRef needed, because all Decl are in the same scope
+    // Note: no MarkImplScopeRef needed, because all Decl are in the same scope
     if C.InheritsFrom(TPasProcedure) then
       begin
       if OnlyExports and ([pmExport,pmPublic]*TPasProcedure(Decl).Modifiers=[]) then
@@ -1046,11 +1041,11 @@ begin
     UseExpr(ForLoop.StartExpr);
     UseExpr(ForLoop.EndExpr);
     ForScope:=ForLoop.CustomData as TPasForLoopScope;
-    MarkScopeRef(ForLoop,ForScope.GetEnumerator,psraRead);
+    MarkImplScopeRef(ForLoop,ForScope.GetEnumerator,psraRead);
     UseProcedure(ForScope.GetEnumerator);
-    MarkScopeRef(ForLoop,ForScope.MoveNext,psraRead);
+    MarkImplScopeRef(ForLoop,ForScope.MoveNext,psraRead);
     UseProcedure(ForScope.MoveNext);
-    MarkScopeRef(ForLoop,ForScope.Current,psraRead);
+    MarkImplScopeRef(ForLoop,ForScope.Current,psraRead);
     UseVariable(ForScope.Current,rraRead,false);
     UseImplElement(ForLoop.Body);
     end
@@ -1145,7 +1140,7 @@ begin
     Ref:=TResolvedReference(El.CustomData);
     Decl:=Ref.Declaration;
     Access:=Ref.Access;
-    MarkScopeRef(El,Decl,ResolvedToPSRefAccess[Access]);
+    MarkImplScopeRef(El,Decl,ResolvedToPSRefAccess[Access]);
     UseElement(Decl,Access,false);
 
     if Resolver.IsNameExpr(El) then
@@ -1190,13 +1185,13 @@ begin
           if ParamResolved.IdentEl is TPasFunction then
             begin
             SubEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType;
-            MarkScopeRef(El,SubEl,psraTypeInfo);
+            MarkImplScopeRef(El,SubEl,psraTypeInfo);
             UsePublished(SubEl);
             end
           else
             begin
             SubEl:=ParamResolved.IdentEl;
-            MarkScopeRef(El,SubEl,psraTypeInfo);
+            MarkImplScopeRef(El,SubEl,psraTypeInfo);
             UsePublished(SubEl);
             end;
           // the parameter is not used otherwise
@@ -1289,7 +1284,7 @@ begin
     if (Expr.CustomData is TResolvedReference) then
       begin
       Ref:=TResolvedReference(Expr.CustomData);
-      MarkScopeRef(El,Ref.Declaration,ResolvedToPSRefAccess[Access]);
+      MarkImplScopeRef(El,Ref.Declaration,ResolvedToPSRefAccess[Access]);
       UseElement(Ref.Declaration,Access,UseFull);
       end;
     end
@@ -1344,6 +1339,12 @@ begin
     end;
 end;
 
+procedure TPasAnalyzer.UseScopeReferences(Refs: TPasScopeReferences);
+begin
+  if Refs=nil then exit;
+  Refs.References.ForEachCall(@OnUseScopeRef,Refs.Scope);
+end;
+
 procedure TPasAnalyzer.UseProcedure(Proc: TPasProcedure);
 
   procedure UseOverrides(CurProc: TPasProcedure);
@@ -1375,13 +1376,10 @@ begin
     exit; // skip implementation, Note:PasResolver always refers the declaration
 
   if not MarkElementAsUsed(Proc) then exit;
-  if (FRefProcDecl<>nil) and MarkSingleProcRef(Proc,psraRead) then exit;
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
   {$ENDIF}
-
-  if ProcScope.References<>nil then
-    ProcScope.References.ForEachCall(@OnUseProcScopeRef,ProcScope);
+  UseScopeReferences(ProcScope.References);
 
   UseProcedureType(Proc.ProcType,false);
 
@@ -1390,19 +1388,6 @@ begin
     ImplProc:=ProcScope.ImplProc;
   if ImplProc.Body<>nil then
     UseImplBlock(ImplProc.Body.Body,false);
-
-  if FRefProcDecl=nil then
-    begin
-    if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
-      begin
-      MarkScopeRef(Proc,ProcScope.OverriddenProc,psraRead);
-      AddOverride(ProcScope.OverriddenProc,Proc);
-      end;
-
-    // mark overrides
-    if [pmOverride,pmVirtual]*Proc.Modifiers<>[] then
-      UseOverrides(Proc);
-    end;
 end;
 
 procedure TPasAnalyzer.UseProcedureType(ProcType: TPasProcedureType;
@@ -1434,7 +1419,6 @@ var
   i: Integer;
 begin
   if El=nil then exit;
-  if (FRefProcDecl<>nil) and MarkSingleProcRef(El,PAUseModeToPSRefAccess[Mode]) then exit;
 
   C:=El.ClassType;
   if Mode=paumAllExports then
@@ -1641,7 +1625,6 @@ begin
   {$IFDEF VerbosePasAnalyzer}
   writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
   {$ENDIF}
-  if (FRefProcDecl<>nil) and MarkSingleProcRef(El,ResolvedToPSRefAccess[Access]) then exit;
 
   if El.ClassType=TPasProperty then
     Prop:=TPasProperty(El)
@@ -1747,8 +1730,6 @@ var
   Usage: TPAElement;
   IsRead, IsWrite: Boolean;
 begin
-  if FRefProcDecl<>nil then exit;
-
   IsRead:=false;
   IsWrite:=false;
   case Access of
@@ -1783,8 +1764,6 @@ var
   IsRead, IsWrite: Boolean;
   Usage: TPAElement;
 begin
-  if FRefProcDecl<>nil then exit;
-
   IsRead:=false;
   IsWrite:=false;
   case Access of
@@ -1816,7 +1795,6 @@ end;
 procedure TPasAnalyzer.EmitElementHints(El: TPasElement);
 begin
   if El=nil then exit;
-  if FRefProcDecl<>nil then exit;
 
   if El is TPasVariable then
     EmitVariableHints(TPasVariable(El))
@@ -2133,36 +2111,6 @@ begin
   {$ENDIF}
 end;
 
-procedure TPasAnalyzer.AnalyzeProcRefs(Proc: TPasProcedure);
-var
-  ProcScope: TPasProcedureScope;
-begin
-  {$IFDEF VerbosePasAnalyzer}
-  writeln('TPasAnalyzer.AnalyzeProcRefs START ',GetObjName(Proc));
-  {$ENDIF}
-  if Resolver=nil then
-    RaiseInconsistency(20180221110035,'TPasAnalyzer.AnalyzeProcRefs missing Resolver '+GetObjName(Proc));
-  if FUsedElements.Count>0 then
-    RaiseInconsistency(20180221110035,GetObjName(Proc));
-  ScopeModule:=Proc.GetModule;
-  ProcScope:=NoNil(Proc.CustomData) as TPasProcedureScope;
-  if ProcScope.References<>nil then
-    RaiseInconsistency(20180221161728,GetObjName(Proc));
-  if ProcScope.DeclarationProc<>nil then
-    RaiseInconsistency(20180221110215,GetObjName(Proc));
-  FRefProcDecl:=Proc;
-  FRefProcScope:=ProcScope;
-  try
-    UseProcedure(Proc);
-  finally
-    FRefProcDecl:=nil;
-    FRefProcScope:=nil;
-  end;
-  {$IFDEF VerbosePasAnalyzer}
-  writeln('TPasAnalyzer.AnalyzeProcRefs END ',GetObjName(Proc));
-  {$ENDIF}
-end;
-
 procedure TPasAnalyzer.EmitModuleHints(aModule: TPasModule);
 begin
   {$IFDEF VerbosePasAnalyzer}
@@ -2317,7 +2265,6 @@ end;
 
 procedure TPasAnalyzer.EmitMessage(Msg: TPAMessage);
 begin
-  if FRefProcDecl<>nil then exit;
   if not Assigned(OnMessage) then
     begin
     Msg.Release;

+ 5 - 1
packages/fcl-passrc/src/pparser.pp

@@ -151,7 +151,8 @@ type
     stExceptOnExpr,
     stExceptOnStatement,
     stDeclaration, // e.g. a TPasProperty, TPasVariable, TPasArgument
-    stAncestors // the list of ancestors and interfaces of a class
+    stAncestors, // the list of ancestors and interfaces of a class
+    stInitialFinalization
     );
   TPasScopeTypes = set of TPasScopeType;
 
@@ -2904,10 +2905,12 @@ begin
     if (CurToken=tkend) then
     begin
       ExpectToken(tkDot);
+      Engine.FinishScope(stInitialFinalization,Section);
       exit;
     end
     else if (CurToken=tkfinalization) then
     begin
+      Engine.FinishScope(stInitialFinalization,Section);
       ParseFinalization;
       exit;
     end
@@ -2933,6 +2936,7 @@ begin
     if (CurToken=tkend) then
     begin
       ExpectToken(tkDot);
+      Engine.FinishScope(stInitialFinalization,Section);
       exit;
     end
     else if CurToken<>tkSemiColon then

+ 96 - 36
packages/fcl-passrc/tests/tcuseanalyzer.pas

@@ -36,7 +36,7 @@ type
       const MsgText: string); virtual;
     procedure CheckUseAnalyzerUnexpectedHints; virtual;
     procedure CheckUnitUsed(const aFilename: string; Used: boolean); virtual;
-    procedure CheckUnitProcedureReferences(const ProcName: string;
+    procedure CheckScopeReferences(const ScopeName: string;
       const RefNames: array of string);
   public
     property Analyzer: TPasAnalyzer read FAnalyzer;
@@ -141,8 +141,9 @@ type
     procedure TestWP_AssertSysUtils;
     procedure TestWP_RangeErrorSysUtils;
 
-    // procedure references
-    procedure TestPR_UnitVar;
+    // scope references
+    procedure TestSR_Proc_UnitVar;
+    procedure TestSR_Init_UnitVar;
   end;
 
 function dbgs(a: TPSRefAccess) : string;
@@ -345,8 +346,8 @@ begin
     end;
 end;
 
-procedure TCustomTestUseAnalyzer.CheckUnitProcedureReferences(
-  const ProcName: string; const RefNames: array of string);
+procedure TCustomTestUseAnalyzer.CheckScopeReferences(
+  const ScopeName: string; const RefNames: array of string);
 type
   TEntry = record
     Name: string;
@@ -356,16 +357,20 @@ type
 var
   Entries: array of TEntry;
 
-  procedure CheckRefs(Scope: TPasProcedureScope; const Prefix: string);
+  procedure CheckRefs(ScopeRefs: TPasScopeReferences; const Prefix: string);
 
     procedure DumpRefsAndFail(Refs: TFPList; const Msg: string);
     var
       i: Integer;
-      Ref: TPasProcScopeReference;
+      Ref: TPasScopeReference;
     begin
+      {$IFDEF VerbosePasAnalyzer}
+      if Refs.Count=0 then
+        writeln('DumpRefsAndFail ',Prefix,' NO REFS');
+      {$ENDIF}
       for i:=0 to Refs.Count-1 do
         begin
-        Ref:=TPasProcScopeReference(Refs[i]);
+        Ref:=TPasScopeReference(Refs[i]);
         if Ref=nil then break;
         {$IFDEF VerbosePasAnalyzer}
         writeln('DumpRefsAndFail ',Prefix,' ',i,' ',GetObjName(Ref.Element),' ',Ref.Access);
@@ -378,15 +383,18 @@ var
     Refs: TFPList;
     j, i: Integer;
     o: TObject;
-    Ref: TPasProcScopeReference;
+    Ref: TPasScopeReference;
   begin
-    Refs:=Scope.GetReferences;
+    if ScopeRefs=nil then
+      Refs:=TFPList.Create
+    else
+      Refs:=ScopeRefs.GetList;
     try
       // check that Refs only contains TPasProcScopeReference
       for i:=0 to Refs.Count-1 do
         begin
         o:=TObject(Refs[i]);
-        if not (o is TPasProcScopeReference) then
+        if not (o is TPasScopeReference) then
           Fail(Prefix+': Refs['+IntToStr(i)+'] '+GetObjName(o));
         end;
       // check that all Entries are referenced
@@ -394,11 +402,11 @@ var
         begin
         j:=Refs.Count-1;
         while (j>=0)
-            and (CompareText(Entries[i].Name,TPasProcScopeReference(Refs[j]).Element.Name)<>0) do
+            and (CompareText(Entries[i].Name,TPasScopeReference(Refs[j]).Element.Name)<>0) do
           dec(j);
         if j<0 then
           DumpRefsAndFail(Refs,'Missing reference "'+Entries[i].Name+'"');
-        Ref:=TPasProcScopeReference(Refs[j]);
+        Ref:=TPasScopeReference(Refs[j]);
         if (Entries[i].Access<>psraNone) and (Ref.Access<>Entries[i].Access) then
           DumpRefsAndFail(Refs,'Wrong reference access "'+Entries[i].Name+'",'
             +' expected '+dbgs(Entries[i].Access)+', but got '+dbgs(Ref.Access));
@@ -406,7 +414,7 @@ var
       // check that no other references are in Refs
       for i:=0 to Refs.Count-1 do
         begin
-        Ref:=TPasProcScopeReference(Refs[i]);
+        Ref:=TPasScopeReference(Refs[i]);
         j:=length(Entries)-1;
         while (j>=0)
             and (CompareText(Ref.Element.Name,Entries[j].Name)<>0) do
@@ -425,12 +433,11 @@ var
     El: TPasElement;
     Proc: TPasProcedure;
     Scope: TPasProcedureScope;
-    ProcAnalyzer: TPasAnalyzer;
   begin
     for i:=0 to Section.Declarations.Count-1 do
       begin
       El:=TPasElement(Section.Declarations[i]);
-      if CompareText(El.Name,ProcName)<>0 then continue;
+      if CompareText(El.Name,ScopeName)<>0 then continue;
       if not (El is TPasProcedure) then
         Fail('El is not proc '+GetObjName(El));
       Proc:=TPasProcedure(El);
@@ -438,24 +445,21 @@ var
       if Scope.DeclarationProc<>nil then continue;
 
       // check references created by AnalyzeModule
-      CheckRefs(Scope,'AnalyzeModule');
-
-      // check references created by AnalyzeProcRefs
-      Scope.ClearReferences;
-      if FProcAnalyzer=nil then
-        begin
-        ProcAnalyzer:=TPasAnalyzer.Create;
-        ProcAnalyzer.Resolver:=ResolverEngine;
-        end;
-      ProcAnalyzer.Clear;
-      ProcAnalyzer.AnalyzeProcRefs(Proc);
-      CheckRefs(Scope,'AnalyzeProcRefs');
+      CheckRefs(Scope.References,'AnalyzeModule');
 
       exit(true);
       end;
     Result:=false;
   end;
 
+  procedure CheckInitialFinalization(El: TPasImplBlock);
+  var
+    Scope: TPasInitialFinalizationScope;
+  begin
+    Scope:=El.CustomData as TPasInitialFinalizationScope;
+    CheckRefs(Scope.References,'AnalyzeModule');
+  end;
+
 var
   i: Integer;
 begin
@@ -468,18 +472,46 @@ begin
 
   if Module is TPasProgram then
     begin
-    if FindProc(TPasProgram(Module).ProgramSection) then exit;
+    if CompareText(ScopeName,'begin')=0 then
+      begin
+      // check begin-block references created by AnalyzeModule
+      CheckInitialFinalization(Module.InitializationSection);
+      exit;
+      end
+    else if FindProc(TPasProgram(Module).ProgramSection) then
+      exit;
     end
   else if Module is TPasLibrary then
     begin
-    if FindProc(TPasLibrary(Module).LibrarySection) then exit;
+    if CompareText(ScopeName,'begin')=0 then
+      begin
+      // check begin-block references created by AnalyzeModule
+      CheckInitialFinalization(Module.InitializationSection);
+      exit;
+      end
+    else if FindProc(TPasLibrary(Module).LibrarySection) then
+      exit;
     end
   else if Module.ClassType=TPasModule then
     begin
-    if FindProc(Module.InterfaceSection) then exit;
-    if FindProc(Module.ImplementationSection) then exit;
+    if CompareText(ScopeName,'initialization')=0 then
+      begin
+      // check initialization references created by AnalyzeModule
+      CheckInitialFinalization(Module.InitializationSection);
+      exit;
+      end
+    else if CompareText(ScopeName,'finalization')=0 then
+      begin
+      // check finalization references created by AnalyzeModule
+      CheckInitialFinalization(Module.FinalizationSection);
+      exit;
+      end
+    else if FindProc(Module.InterfaceSection) then
+      exit
+    else if FindProc(Module.ImplementationSection) then
+      exit;
     end;
-  Fail('missing proc '+ProcName);
+  Fail('missing proc '+ScopeName);
 end;
 
 function TCustomTestUseAnalyzer.PAMessageCount: integer;
@@ -2245,7 +2277,7 @@ begin
   AnalyzeWholeProgram;
 end;
 
-procedure TTestUseAnalyzer.TestPR_UnitVar;
+procedure TTestUseAnalyzer.TestSR_Proc_UnitVar;
 begin
   StartUnit(false);
   Add([
@@ -2267,9 +2299,37 @@ begin
   '  b:=i;',
   'end;',
   '']);
-  Analyzer.Options:=Analyzer.Options+[paoProcImplReferences];
+  Analyzer.Options:=Analyzer.Options+[paoImplReferences];
+  AnalyzeUnit;
+  CheckScopeReferences('DoIt',['i','tintcolor']);
+end;
+
+procedure TTestUseAnalyzer.TestSR_Init_UnitVar;
+begin
+  StartUnit(false);
+  Add([
+  'interface',
+  'type',
+  '  TColor = longint;',
+  '  TIntColor = TColor;',
+  'var',
+  '  i: longint;',
+  '  j: longint;',
+  'implementation',
+  'type',
+  '  TSubColor = TIntColor;',
+  'var',
+  '  b: TSubColor;',
+  'initialization',
+  '  b:=i;',
+  'finalization',
+  '  b:=j;',
+  'end.',
+  '']);
+  Analyzer.Options:=Analyzer.Options+[paoImplReferences];
   AnalyzeUnit;
-  CheckUnitProcedureReferences('DoIt',['i','tintcolor']);
+  CheckScopeReferences('initialization',['b','i']);
+  CheckScopeReferences('finalization',['b','j']);
 end;
 
 initialization