|
@@ -34,11 +34,11 @@ Working:
|
|
- Hint: 'Private const "%s" never used'
|
|
- Hint: 'Private const "%s" never used'
|
|
- Hint: 'Private property "%s" never used'
|
|
- Hint: 'Private property "%s" never used'
|
|
- Hint: 'Function result does not seem to be set'
|
|
- Hint: 'Function result does not seem to be set'
|
|
|
|
+- TPasArgument: compute the effective Access
|
|
|
|
+- calls: use the effective Access of arguments
|
|
|
|
|
|
ToDo:
|
|
ToDo:
|
|
- Add test: Call Override: e.g. A.Proc, mark only overrides of descendants of A
|
|
- Add test: Call Override: e.g. A.Proc, mark only overrides of descendants of A
|
|
-- TPasArgument: compute the effective Access
|
|
|
|
-- calls: use the effective Access of arguments
|
|
|
|
}
|
|
}
|
|
unit PasUseAnalyzer;
|
|
unit PasUseAnalyzer;
|
|
|
|
|
|
@@ -146,7 +146,8 @@ type
|
|
end;
|
|
end;
|
|
|
|
|
|
TPasAnalyzerOption = (
|
|
TPasAnalyzerOption = (
|
|
- paoOnlyExports // default: use all class members accessible from outside (protected, but not private)
|
|
|
|
|
|
+ paoOnlyExports, // default: use all class members accessible from outside (protected, but not private)
|
|
|
|
+ paoProcReferences // collect TPasProcedureScope.References of top lvl proc implementations
|
|
);
|
|
);
|
|
TPasAnalyzerOptions = set of TPasAnalyzerOption;
|
|
TPasAnalyzerOptions = set of TPasAnalyzerOption;
|
|
|
|
|
|
@@ -180,6 +181,7 @@ type
|
|
FUsedElements: TAVLTree; // tree of TPAElement sorted for Element
|
|
FUsedElements: TAVLTree; // tree of TPAElement sorted for Element
|
|
FRefProcDecl: TPasProcedure; // if set, collect only what this proc references
|
|
FRefProcDecl: TPasProcedure; // if set, collect only what this proc references
|
|
FRefProcScope: TPasProcedureScope; // the ProcScope of FRefProcDecl
|
|
FRefProcScope: TPasProcedureScope; // the ProcScope of FRefProcDecl
|
|
|
|
+ procedure UseElType(El: TPasElement; aType: TPasType; Mode: TPAUseMode); inline;
|
|
function AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
|
|
function AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
|
|
function FindOverrideNode(El: TPasElement): TAVLTreeNode;
|
|
function FindOverrideNode(El: TPasElement): TAVLTreeNode;
|
|
function FindOverrideList(El: TPasElement): TPAOverrideList;
|
|
function FindOverrideList(El: TPasElement): TPAOverrideList;
|
|
@@ -188,6 +190,7 @@ type
|
|
protected
|
|
protected
|
|
procedure RaiseInconsistency(const Id: int64; Msg: string);
|
|
procedure RaiseInconsistency(const Id: int64; Msg: string);
|
|
procedure RaiseNotSupported(const Id: int64; El: TPasElement; const Msg: string = '');
|
|
procedure RaiseNotSupported(const Id: int64; El: TPasElement; const Msg: string = '');
|
|
|
|
+ function FindTopProcScope(El: TPasElement; Decl: boolean): TPasProcedureScope;
|
|
// mark used elements
|
|
// mark used elements
|
|
function Add(El: TPasElement; CheckDuplicate: boolean = true;
|
|
function Add(El: TPasElement; CheckDuplicate: boolean = true;
|
|
aClass: TPAElementClass = nil): TPAElement;
|
|
aClass: TPAElementClass = nil): TPAElement;
|
|
@@ -196,7 +199,8 @@ type
|
|
procedure CreateTree; virtual;
|
|
procedure CreateTree; virtual;
|
|
function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
|
|
function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
|
|
function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
|
|
function ElementVisited(El: TPasElement; Mode: TPAUseMode): boolean;
|
|
- function MarkProcRef(El: TPasElement; Access: TPSRefAccess): boolean; // true if outside FRefProcDecl
|
|
|
|
|
|
+ function MarkSingleProcRef(El: TPasElement; Access: TPSRefAccess): boolean; // true if outside FRefProcDecl
|
|
|
|
+ procedure MarkScopeRef(Parent, El: TPasElement; Access: TPSRefAccess);
|
|
procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
|
|
procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
|
|
UseFull: boolean); virtual;
|
|
UseFull: boolean); virtual;
|
|
procedure UsePublished(El: TPasElement); virtual;
|
|
procedure UsePublished(El: TPasElement); virtual;
|
|
@@ -205,8 +209,8 @@ type
|
|
procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
|
|
procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
|
|
procedure UseImplElement(El: TPasImplElement); virtual;
|
|
procedure UseImplElement(El: TPasImplElement); virtual;
|
|
procedure UseExpr(El: TPasExpr); virtual;
|
|
procedure UseExpr(El: TPasExpr); virtual;
|
|
- procedure UseExprRef(Expr: TPasExpr; Access: TResolvedRefAccess;
|
|
|
|
- UseFull: boolean); virtual;
|
|
|
|
|
|
+ procedure UseExprRef(El: TPasElement; Expr: TPasExpr;
|
|
|
|
+ Access: TResolvedRefAccess; UseFull: boolean); virtual;
|
|
procedure UseInheritedExpr(El: TInheritedExpr); virtual;
|
|
procedure UseInheritedExpr(El: TInheritedExpr); virtual;
|
|
procedure UseProcedure(Proc: TPasProcedure); virtual;
|
|
procedure UseProcedure(Proc: TPasProcedure); virtual;
|
|
procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
|
|
procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
|
|
@@ -418,6 +422,15 @@ begin
|
|
Result:=TPAElement(Node.Data);
|
|
Result:=TPAElement(Node.Data);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+// inline
|
|
|
|
+procedure TPasAnalyzer.UseElType(El: TPasElement; aType: TPasType;
|
|
|
|
+ Mode: TPAUseMode);
|
|
|
|
+begin
|
|
|
|
+ if aType=nil then exit;
|
|
|
|
+ MarkScopeRef(El,aType,PAUseModeToPSRefAccess[Mode]);
|
|
|
|
+ UseType(aType,Mode);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions);
|
|
procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions);
|
|
begin
|
|
begin
|
|
if FOptions=AValue then Exit;
|
|
if FOptions=AValue then Exit;
|
|
@@ -520,6 +533,24 @@ begin
|
|
raise E;
|
|
raise E;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TPasAnalyzer.FindTopProcScope(El: TPasElement; Decl: boolean
|
|
|
|
+ ): TPasProcedureScope;
|
|
|
|
+begin
|
|
|
|
+ Result:=nil;
|
|
|
|
+ while El<>nil do
|
|
|
|
+ begin
|
|
|
|
+ if El is TPasProcedure then
|
|
|
|
+ Result:=El.CustomData as TPasProcedureScope;
|
|
|
|
+ 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;
|
|
function TPasAnalyzer.Add(El: TPasElement; CheckDuplicate: boolean;
|
|
aClass: TPAElementClass): TPAElement;
|
|
aClass: TPAElementClass): TPAElement;
|
|
begin
|
|
begin
|
|
@@ -607,7 +638,7 @@ begin
|
|
FChecked[Mode].Add(El);
|
|
FChecked[Mode].Add(El);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TPasAnalyzer.MarkProcRef(El: TPasElement; Access: TPSRefAccess
|
|
|
|
|
|
+function TPasAnalyzer.MarkSingleProcRef(El: TPasElement; Access: TPSRefAccess
|
|
): boolean;
|
|
): boolean;
|
|
var
|
|
var
|
|
Parent: TPasElement;
|
|
Parent: TPasElement;
|
|
@@ -623,6 +654,27 @@ begin
|
|
Result:=true;
|
|
Result:=true;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TPasAnalyzer.MarkScopeRef(Parent, El: TPasElement;
|
|
|
|
+ Access: TPSRefAccess);
|
|
|
|
+var
|
|
|
|
+ ParentProcScope, ElProcScope: TPasProcedureScope;
|
|
|
|
+begin
|
|
|
|
+ if El=nil then exit;
|
|
|
|
+ if El.Parent=Parent then exit; // same scope
|
|
|
|
+ if paoProcReferences in Options then
|
|
|
|
+ begin
|
|
|
|
+ ParentProcScope:=FindTopProcScope(Parent,true);
|
|
|
|
+ if ParentProcScope<>nil then
|
|
|
|
+ begin
|
|
|
|
+ ElProcScope:=FindTopProcScope(El,true);
|
|
|
|
+ if ElProcScope<>ParentProcScope then
|
|
|
|
+ begin
|
|
|
|
+ ParentProcScope.AddReference(El,Access);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TPasAnalyzer.UseElement(El: TPasElement; Access: TResolvedRefAccess;
|
|
procedure TPasAnalyzer.UseElement(El: TPasElement; Access: TResolvedRefAccess;
|
|
UseFull: boolean);
|
|
UseFull: boolean);
|
|
var
|
|
var
|
|
@@ -660,6 +712,14 @@ end;
|
|
|
|
|
|
procedure TPasAnalyzer.UsePublished(El: TPasElement);
|
|
procedure TPasAnalyzer.UsePublished(El: TPasElement);
|
|
// mark typeinfo, do not mark code
|
|
// mark typeinfo, do not mark code
|
|
|
|
+
|
|
|
|
+ procedure UseSubEl(SubEl: TPasElement); inline;
|
|
|
|
+ begin
|
|
|
|
+ if SubEl=nil then exit;
|
|
|
|
+ MarkScopeRef(El,SubEl,psraTypeInfo);
|
|
|
|
+ UsePublished(SubEl);
|
|
|
|
+ end;
|
|
|
|
+
|
|
var
|
|
var
|
|
C: TClass;
|
|
C: TClass;
|
|
Members: TFPList;
|
|
Members: TFPList;
|
|
@@ -673,21 +733,21 @@ begin
|
|
writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
|
|
writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
if ElementVisited(El,paumPublished) then exit;
|
|
if ElementVisited(El,paumPublished) then exit;
|
|
- if (FRefProcDecl<>nil) and MarkProcRef(El,psraTypeInfo) then exit;
|
|
|
|
|
|
+ if (FRefProcDecl<>nil) and MarkSingleProcRef(El,psraTypeInfo) then exit;
|
|
|
|
|
|
C:=El.ClassType;
|
|
C:=El.ClassType;
|
|
if C=TPasUnresolvedSymbolRef then
|
|
if C=TPasUnresolvedSymbolRef then
|
|
else if (C=TPasVariable) or (C=TPasConst) then
|
|
else if (C=TPasVariable) or (C=TPasConst) then
|
|
- UsePublished(TPasVariable(El).VarType)
|
|
|
|
|
|
+ UseSubEl(TPasVariable(El).VarType)
|
|
else if (C=TPasArgument) then
|
|
else if (C=TPasArgument) then
|
|
- UsePublished(TPasArgument(El).ArgType)
|
|
|
|
|
|
+ UseSubEl(TPasArgument(El).ArgType)
|
|
else if C=TPasProperty then
|
|
else if C=TPasProperty then
|
|
begin
|
|
begin
|
|
// published property
|
|
// published property
|
|
Prop:=TPasProperty(El);
|
|
Prop:=TPasProperty(El);
|
|
for i:=0 to Prop.Args.Count-1 do
|
|
for i:=0 to Prop.Args.Count-1 do
|
|
- UsePublished(TPasArgument(Prop.Args[i]).ArgType);
|
|
|
|
- UsePublished(Prop.VarType);
|
|
|
|
|
|
+ UseSubEl(TPasArgument(Prop.Args[i]).ArgType);
|
|
|
|
+ UseSubEl(Prop.VarType);
|
|
// Note: read, write and index don't need extra typeinfo
|
|
// Note: read, write and index don't need extra typeinfo
|
|
|
|
|
|
// stored and defaultvalue are only used when published -> mark as used
|
|
// stored and defaultvalue are only used when published -> mark as used
|
|
@@ -695,23 +755,23 @@ begin
|
|
UseElement(Prop.DefaultExpr,rraRead,false);
|
|
UseElement(Prop.DefaultExpr,rraRead,false);
|
|
end
|
|
end
|
|
else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
|
|
else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
|
|
- UsePublished(TPasAliasType(El).DestType)
|
|
|
|
|
|
+ UseSubEl(TPasAliasType(El).DestType)
|
|
else if C=TPasEnumType then
|
|
else if C=TPasEnumType then
|
|
else if C=TPasSetType then
|
|
else if C=TPasSetType then
|
|
- UsePublished(TPasSetType(El).EnumType)
|
|
|
|
|
|
+ UseSubEl(TPasSetType(El).EnumType)
|
|
else if C=TPasRangeType then
|
|
else if C=TPasRangeType then
|
|
else if C=TPasArrayType then
|
|
else if C=TPasArrayType then
|
|
begin
|
|
begin
|
|
- UsePublished(TPasArrayType(El).ElType);
|
|
|
|
|
|
+ UseSubEl(TPasArrayType(El).ElType);
|
|
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
|
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
|
begin
|
|
begin
|
|
Member:=TPasArrayType(El).Ranges[i];
|
|
Member:=TPasArrayType(El).Ranges[i];
|
|
Resolver.ComputeElement(Member,MemberResolved,[rcConstant]);
|
|
Resolver.ComputeElement(Member,MemberResolved,[rcConstant]);
|
|
- UsePublished(MemberResolved.TypeEl);
|
|
|
|
|
|
+ UseSubEl(MemberResolved.TypeEl);
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else if C=TPasPointerType then
|
|
else if C=TPasPointerType then
|
|
- UsePublished(TPasPointerType(El).DestType)
|
|
|
|
|
|
+ UseSubEl(TPasPointerType(El).DestType)
|
|
else if C=TPasClassType then
|
|
else if C=TPasClassType then
|
|
else if C=TPasClassOfType then
|
|
else if C=TPasClassOfType then
|
|
else if C=TPasRecordType then
|
|
else if C=TPasRecordType then
|
|
@@ -721,19 +781,19 @@ begin
|
|
for i:=0 to Members.Count-1 do
|
|
for i:=0 to Members.Count-1 do
|
|
begin
|
|
begin
|
|
Member:=TPasElement(Members[i]);
|
|
Member:=TPasElement(Members[i]);
|
|
- UsePublished(Member);
|
|
|
|
|
|
+ UseSubEl(Member);
|
|
UseElement(Member,rraNone,true);
|
|
UseElement(Member,rraNone,true);
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else if C.InheritsFrom(TPasProcedure) then
|
|
else if C.InheritsFrom(TPasProcedure) then
|
|
- UsePublished(TPasProcedure(El).ProcType)
|
|
|
|
|
|
+ UseSubEl(TPasProcedure(El).ProcType)
|
|
else if C.InheritsFrom(TPasProcedureType) then
|
|
else if C.InheritsFrom(TPasProcedureType) then
|
|
begin
|
|
begin
|
|
ProcType:=TPasProcedureType(El);
|
|
ProcType:=TPasProcedureType(El);
|
|
for i:=0 to ProcType.Args.Count-1 do
|
|
for i:=0 to ProcType.Args.Count-1 do
|
|
- UsePublished(TPasArgument(ProcType.Args[i]).ArgType);
|
|
|
|
|
|
+ UseSubEl(TPasArgument(ProcType.Args[i]).ArgType);
|
|
if El is TPasFunctionType then
|
|
if El is TPasFunctionType then
|
|
- UsePublished(TPasFunctionType(El).ResultEl.ResultType);
|
|
|
|
|
|
+ UseSubEl(TPasFunctionType(El).ResultEl.ResultType);
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
@@ -746,20 +806,20 @@ end;
|
|
|
|
|
|
procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
|
|
procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
|
|
|
|
|
|
- procedure UseInitFinal(aSection: TPasImplBlock);
|
|
|
|
|
|
+ procedure UseInitFinal(ImplBlock: TPasImplBlock);
|
|
begin
|
|
begin
|
|
- if IsImplBlockEmpty(aSection) then exit;
|
|
|
|
|
|
+ if IsImplBlockEmpty(ImplBlock) then exit;
|
|
// this module has an initialization section -> mark module
|
|
// this module has an initialization section -> mark module
|
|
if FindNode(aModule)=nil then
|
|
if FindNode(aModule)=nil then
|
|
Add(aModule);
|
|
Add(aModule);
|
|
- UseImplBlock(aSection,true);
|
|
|
|
|
|
+ UseImplBlock(ImplBlock,true);
|
|
end;
|
|
end;
|
|
|
|
|
|
var
|
|
var
|
|
ModScope: TPasModuleScope;
|
|
ModScope: TPasModuleScope;
|
|
begin
|
|
begin
|
|
if ElementVisited(aModule,Mode) then exit;
|
|
if ElementVisited(aModule,Mode) then exit;
|
|
- if (FRefProcDecl<>nil) and MarkProcRef(aModule,psraRead) then exit;
|
|
|
|
|
|
+ if (FRefProcDecl<>nil) and MarkSingleProcRef(aModule,psraRead) then exit;
|
|
|
|
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode);
|
|
writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode);
|
|
@@ -774,6 +834,7 @@ begin
|
|
begin
|
|
begin
|
|
// unit
|
|
// unit
|
|
UseSection(aModule.InterfaceSection,Mode);
|
|
UseSection(aModule.InterfaceSection,Mode);
|
|
|
|
+ // Note: implementation can not be used directly from outside
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
UseInitFinal(aModule.InitializationSection);
|
|
UseInitFinal(aModule.InitializationSection);
|
|
@@ -845,6 +906,7 @@ begin
|
|
writeln('TPasAnalyzer.UseSection ',Section.ClassName,' Decl=',GetElModName(Decl),' Mode=',Mode);
|
|
writeln('TPasAnalyzer.UseSection ',Section.ClassName,' Decl=',GetElModName(Decl),' Mode=',Mode);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
C:=Decl.ClassType;
|
|
C:=Decl.ClassType;
|
|
|
|
+ // Note: no MarkScopeRef needed, because all Decl are in the same scope
|
|
if C.InheritsFrom(TPasProcedure) then
|
|
if C.InheritsFrom(TPasProcedure) then
|
|
begin
|
|
begin
|
|
if OnlyExports and ([pmExport,pmPublic]*TPasProcedure(Decl).Modifiers=[]) then
|
|
if OnlyExports and ([pmExport,pmPublic]*TPasProcedure(Decl).Modifiers=[]) then
|
|
@@ -946,8 +1008,11 @@ begin
|
|
UseExpr(ForLoop.StartExpr);
|
|
UseExpr(ForLoop.StartExpr);
|
|
UseExpr(ForLoop.EndExpr);
|
|
UseExpr(ForLoop.EndExpr);
|
|
ForScope:=ForLoop.CustomData as TPasForLoopScope;
|
|
ForScope:=ForLoop.CustomData as TPasForLoopScope;
|
|
|
|
+ MarkScopeRef(ForLoop,ForScope.GetEnumerator,psraRead);
|
|
UseProcedure(ForScope.GetEnumerator);
|
|
UseProcedure(ForScope.GetEnumerator);
|
|
|
|
+ MarkScopeRef(ForLoop,ForScope.MoveNext,psraRead);
|
|
UseProcedure(ForScope.MoveNext);
|
|
UseProcedure(ForScope.MoveNext);
|
|
|
|
+ MarkScopeRef(ForLoop,ForScope.Current,psraRead);
|
|
UseVariable(ForScope.Current,rraRead,false);
|
|
UseVariable(ForScope.Current,rraRead,false);
|
|
UseImplElement(ForLoop.Body);
|
|
UseImplElement(ForLoop.Body);
|
|
end
|
|
end
|
|
@@ -983,7 +1048,8 @@ begin
|
|
else if C=TPasImplExceptOn then
|
|
else if C=TPasImplExceptOn then
|
|
begin
|
|
begin
|
|
// except-on
|
|
// except-on
|
|
- UseType(TPasImplExceptOn(El).TypeEl,paumElement);
|
|
|
|
|
|
+ // Note: VarEl is marked when actually used
|
|
|
|
+ UseElType(El,TPasImplExceptOn(El).TypeEl,paumElement);
|
|
UseImplElement(TPasImplExceptOn(El).Body);
|
|
UseImplElement(TPasImplExceptOn(El).Body);
|
|
end
|
|
end
|
|
else if C=TPasImplRaise then
|
|
else if C=TPasImplRaise then
|
|
@@ -1028,6 +1094,8 @@ var
|
|
ParamResolved: TPasResolverResult;
|
|
ParamResolved: TPasResolverResult;
|
|
Decl: TPasElement;
|
|
Decl: TPasElement;
|
|
ModScope: TPasModuleScope;
|
|
ModScope: TPasModuleScope;
|
|
|
|
+ Access: TResolvedRefAccess;
|
|
|
|
+ SubEl: TPasElement;
|
|
begin
|
|
begin
|
|
if El=nil then exit;
|
|
if El=nil then exit;
|
|
// Note: expression itself is not marked, but it can reference identifiers
|
|
// Note: expression itself is not marked, but it can reference identifiers
|
|
@@ -1038,7 +1106,9 @@ begin
|
|
// this is a reference -> mark target
|
|
// this is a reference -> mark target
|
|
Ref:=TResolvedReference(El.CustomData);
|
|
Ref:=TResolvedReference(El.CustomData);
|
|
Decl:=Ref.Declaration;
|
|
Decl:=Ref.Declaration;
|
|
- UseElement(Decl,Ref.Access,false);
|
|
|
|
|
|
+ Access:=Ref.Access;
|
|
|
|
+ MarkScopeRef(El,Decl,ResolvedToPSRefAccess[Access]);
|
|
|
|
+ UseElement(Decl,Access,false);
|
|
|
|
|
|
if Resolver.IsNameExpr(El) then
|
|
if Resolver.IsNameExpr(El) then
|
|
begin
|
|
begin
|
|
@@ -1047,7 +1117,7 @@ begin
|
|
if Ref.WithExprScope.Scope is TPasRecordScope then
|
|
if Ref.WithExprScope.Scope is TPasRecordScope then
|
|
begin
|
|
begin
|
|
// a record member was accessed -> access the record too
|
|
// a record member was accessed -> access the record too
|
|
- UseExprRef(Ref.WithExprScope.Expr,Ref.Access,false);
|
|
|
|
|
|
+ UseExprRef(El,Ref.WithExprScope.Expr,Access,false);
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -1058,8 +1128,8 @@ begin
|
|
if ((Decl.Parent is TPasRecordType)
|
|
if ((Decl.Parent is TPasRecordType)
|
|
or (Decl.Parent is TPasVariant)) then
|
|
or (Decl.Parent is TPasVariant)) then
|
|
begin
|
|
begin
|
|
- // a record member was accessed -> access the record too
|
|
|
|
- UseExprRef(TBinaryExpr(El.Parent).left,Ref.Access,false);
|
|
|
|
|
|
+ // a record member was accessed -> access the record with same Access
|
|
|
|
+ UseExprRef(El.Parent,TBinaryExpr(El.Parent).left,Access,false);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -1073,20 +1143,32 @@ begin
|
|
bfTypeInfo:
|
|
bfTypeInfo:
|
|
begin
|
|
begin
|
|
Params:=(El.Parent as TParamsExpr).Params;
|
|
Params:=(El.Parent as TParamsExpr).Params;
|
|
|
|
+ if length(Params)<>1 then
|
|
|
|
+ RaiseNotSupported(20180226144217,El.Parent);
|
|
Resolver.ComputeElement(Params[0],ParamResolved,[rcNoImplicitProc]);
|
|
Resolver.ComputeElement(Params[0],ParamResolved,[rcNoImplicitProc]);
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
writeln('TPasAnalyzer.UseExpr typeinfo ',GetResolverResultDbg(ParamResolved));
|
|
writeln('TPasAnalyzer.UseExpr typeinfo ',GetResolverResultDbg(ParamResolved));
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
if ParamResolved.IdentEl is TPasFunction then
|
|
if ParamResolved.IdentEl is TPasFunction then
|
|
- UsePublished(TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType)
|
|
|
|
|
|
+ begin
|
|
|
|
+ SubEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType;
|
|
|
|
+ MarkScopeRef(El,SubEl,psraTypeInfo);
|
|
|
|
+ UsePublished(SubEl);
|
|
|
|
+ end
|
|
else
|
|
else
|
|
- UsePublished(ParamResolved.IdentEl);
|
|
|
|
|
|
+ begin
|
|
|
|
+ SubEl:=ParamResolved.IdentEl;
|
|
|
|
+ MarkScopeRef(El,SubEl,psraTypeInfo);
|
|
|
|
+ UsePublished(SubEl);
|
|
|
|
+ end;
|
|
|
|
+ // the parameter is not used otherwise
|
|
|
|
+ exit;
|
|
end;
|
|
end;
|
|
bfAssert:
|
|
bfAssert:
|
|
begin
|
|
begin
|
|
ModScope:=Resolver.RootElement.CustomData as TPasModuleScope;
|
|
ModScope:=Resolver.RootElement.CustomData as TPasModuleScope;
|
|
if ModScope.AssertClass<>nil then
|
|
if ModScope.AssertClass<>nil then
|
|
- UseType(ModScope.AssertClass,paumElement);
|
|
|
|
|
|
+ UseElType(El,ModScope.AssertClass,paumElement);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -1128,8 +1210,8 @@ begin
|
|
RaiseNotSupported(20170307085444,El);
|
|
RaiseNotSupported(20170307085444,El);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TPasAnalyzer.UseExprRef(Expr: TPasExpr; Access: TResolvedRefAccess;
|
|
|
|
- UseFull: boolean);
|
|
|
|
|
|
+procedure TPasAnalyzer.UseExprRef(El: TPasElement; Expr: TPasExpr;
|
|
|
|
+ Access: TResolvedRefAccess; UseFull: boolean);
|
|
var
|
|
var
|
|
Ref: TResolvedReference;
|
|
Ref: TResolvedReference;
|
|
C: TClass;
|
|
C: TClass;
|
|
@@ -1137,18 +1219,12 @@ var
|
|
Params: TParamsExpr;
|
|
Params: TParamsExpr;
|
|
ValueResolved: TPasResolverResult;
|
|
ValueResolved: TPasResolverResult;
|
|
begin
|
|
begin
|
|
- if (Expr.CustomData is TResolvedReference) then
|
|
|
|
- begin
|
|
|
|
- Ref:=TResolvedReference(Expr.CustomData);
|
|
|
|
- UseElement(Ref.Declaration,Access,UseFull);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
C:=Expr.ClassType;
|
|
C:=Expr.ClassType;
|
|
if C=TBinaryExpr then
|
|
if C=TBinaryExpr then
|
|
begin
|
|
begin
|
|
Bin:=TBinaryExpr(Expr);
|
|
Bin:=TBinaryExpr(Expr);
|
|
if Bin.OpCode in [eopSubIdent,eopNone] then
|
|
if Bin.OpCode in [eopSubIdent,eopNone] then
|
|
- UseExprRef(Bin.right,Access,UseFull);
|
|
|
|
|
|
+ UseExprRef(El,Bin.right,Access,UseFull);
|
|
end
|
|
end
|
|
else if C=TParamsExpr then
|
|
else if C=TParamsExpr then
|
|
begin
|
|
begin
|
|
@@ -1156,14 +1232,14 @@ begin
|
|
case Params.Kind of
|
|
case Params.Kind of
|
|
pekFuncParams:
|
|
pekFuncParams:
|
|
if Resolver.IsTypeCast(Params) then
|
|
if Resolver.IsTypeCast(Params) then
|
|
- UseExprRef(Params.Params[0],Access,UseFull)
|
|
|
|
|
|
+ UseExprRef(El,Params.Params[0],Access,UseFull)
|
|
else
|
|
else
|
|
- UseExprRef(Params.Value,Access,UseFull);
|
|
|
|
|
|
+ UseExprRef(El,Params.Value,Access,UseFull);
|
|
pekArrayParams:
|
|
pekArrayParams:
|
|
begin
|
|
begin
|
|
Resolver.ComputeElement(Params.Value,ValueResolved,[]);
|
|
Resolver.ComputeElement(Params.Value,ValueResolved,[]);
|
|
if not Resolver.IsDynArray(ValueResolved.TypeEl) then
|
|
if not Resolver.IsDynArray(ValueResolved.TypeEl) then
|
|
- UseExprRef(Params.Value,Access,UseFull);
|
|
|
|
|
|
+ UseExprRef(El,Params.Value,Access,UseFull);
|
|
end;
|
|
end;
|
|
pekSet: ;
|
|
pekSet: ;
|
|
else
|
|
else
|
|
@@ -1171,9 +1247,16 @@ begin
|
|
end;
|
|
end;
|
|
end
|
|
end
|
|
else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
|
|
else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
|
|
- // ok
|
|
|
|
|
|
+ begin
|
|
|
|
+ if (Expr.CustomData is TResolvedReference) then
|
|
|
|
+ begin
|
|
|
|
+ Ref:=TResolvedReference(Expr.CustomData);
|
|
|
|
+ MarkScopeRef(El,Ref.Declaration,ResolvedToPSRefAccess[Access]);
|
|
|
|
+ UseElement(Ref.Declaration,Access,UseFull);
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
else if (Access=rraRead)
|
|
else if (Access=rraRead)
|
|
- and ((C=TPrimitiveExpr)
|
|
|
|
|
|
+ and ((C=TPrimitiveExpr) // Kind<>pekIdent
|
|
or (C=TNilExpr)
|
|
or (C=TNilExpr)
|
|
or (C=TBoolConstExpr)
|
|
or (C=TBoolConstExpr)
|
|
or (C=TUnaryExpr)) then
|
|
or (C=TUnaryExpr)) then
|
|
@@ -1254,7 +1337,7 @@ begin
|
|
exit; // skip implementation, Note:PasResolver always refers the declaration
|
|
exit; // skip implementation, Note:PasResolver always refers the declaration
|
|
|
|
|
|
if not MarkElementAsUsed(Proc) then exit;
|
|
if not MarkElementAsUsed(Proc) then exit;
|
|
- if (FRefProcDecl<>nil) and MarkProcRef(Proc,psraRead) then exit;
|
|
|
|
|
|
+ if (FRefProcDecl<>nil) and MarkSingleProcRef(Proc,psraRead) then exit;
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
|
|
writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
@@ -1270,7 +1353,10 @@ begin
|
|
if FRefProcDecl=nil then
|
|
if FRefProcDecl=nil then
|
|
begin
|
|
begin
|
|
if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
|
|
if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
|
|
|
|
+ begin
|
|
|
|
+ MarkScopeRef(Proc,ProcScope.OverriddenProc,psraRead);
|
|
AddOverride(ProcScope.OverriddenProc,Proc);
|
|
AddOverride(ProcScope.OverriddenProc,Proc);
|
|
|
|
+ end;
|
|
|
|
|
|
// mark overrides
|
|
// mark overrides
|
|
if [pmOverride,pmVirtual]*Proc.Modifiers<>[] then
|
|
if [pmOverride,pmVirtual]*Proc.Modifiers<>[] then
|
|
@@ -1294,11 +1380,11 @@ begin
|
|
Arg:=TPasArgument(ProcType.Args[i]);
|
|
Arg:=TPasArgument(ProcType.Args[i]);
|
|
// Note: the arguments themselves are marked when used in code
|
|
// Note: the arguments themselves are marked when used in code
|
|
// mark argument type and default value
|
|
// mark argument type and default value
|
|
- UseType(Arg.ArgType,paumElement);
|
|
|
|
|
|
+ UseElType(ProcType,Arg.ArgType,paumElement);
|
|
UseExpr(Arg.ValueExpr);
|
|
UseExpr(Arg.ValueExpr);
|
|
end;
|
|
end;
|
|
if ProcType is TPasFunctionType then
|
|
if ProcType is TPasFunctionType then
|
|
- UseType(TPasFunctionType(ProcType).ResultEl.ResultType,paumElement);
|
|
|
|
|
|
+ UseElType(ProcType,TPasFunctionType(ProcType).ResultEl.ResultType,paumElement);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TPasAnalyzer.UseType(El: TPasType; Mode: TPAUseMode);
|
|
procedure TPasAnalyzer.UseType(El: TPasType; Mode: TPAUseMode);
|
|
@@ -1307,7 +1393,7 @@ var
|
|
i: Integer;
|
|
i: Integer;
|
|
begin
|
|
begin
|
|
if El=nil then exit;
|
|
if El=nil then exit;
|
|
- if (FRefProcDecl<>nil) and MarkProcRef(El,PAUseModeToPSRefAccess[Mode]) then exit;
|
|
|
|
|
|
+ if (FRefProcDecl<>nil) and MarkSingleProcRef(El,PAUseModeToPSRefAccess[Mode]) then exit;
|
|
|
|
|
|
C:=El.ClassType;
|
|
C:=El.ClassType;
|
|
if Mode=paumAllExports then
|
|
if Mode=paumAllExports then
|
|
@@ -1337,14 +1423,14 @@ begin
|
|
or (C=TPasClassOfType) then
|
|
or (C=TPasClassOfType) then
|
|
begin
|
|
begin
|
|
if not MarkElementAsUsed(El) then exit;
|
|
if not MarkElementAsUsed(El) then exit;
|
|
- UseType(TPasAliasType(El).DestType,Mode);
|
|
|
|
|
|
+ UseElType(El,TPasAliasType(El).DestType,Mode);
|
|
end
|
|
end
|
|
else if C=TPasArrayType then
|
|
else if C=TPasArrayType then
|
|
begin
|
|
begin
|
|
if not MarkElementAsUsed(El) then exit;
|
|
if not MarkElementAsUsed(El) then exit;
|
|
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
|
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
|
UseExpr(TPasArrayType(El).Ranges[i]);
|
|
UseExpr(TPasArrayType(El).Ranges[i]);
|
|
- UseType(TPasArrayType(El).ElType,Mode);
|
|
|
|
|
|
+ UseElType(El,TPasArrayType(El).ElType,Mode);
|
|
end
|
|
end
|
|
else if C=TPasRecordType then
|
|
else if C=TPasRecordType then
|
|
UseRecordType(TPasRecordType(El),Mode)
|
|
UseRecordType(TPasRecordType(El),Mode)
|
|
@@ -1359,7 +1445,7 @@ begin
|
|
else if C=TPasPointerType then
|
|
else if C=TPasPointerType then
|
|
begin
|
|
begin
|
|
if not MarkElementAsUsed(El) then exit;
|
|
if not MarkElementAsUsed(El) then exit;
|
|
- UseType(TPasPointerType(El).DestType,Mode);
|
|
|
|
|
|
+ UseElType(El,TPasPointerType(El).DestType,Mode);
|
|
end
|
|
end
|
|
else if C=TPasRangeType then
|
|
else if C=TPasRangeType then
|
|
begin
|
|
begin
|
|
@@ -1369,7 +1455,7 @@ begin
|
|
else if C=TPasSetType then
|
|
else if C=TPasSetType then
|
|
begin
|
|
begin
|
|
if not MarkElementAsUsed(El) then exit;
|
|
if not MarkElementAsUsed(El) then exit;
|
|
- UseType(TPasSetType(El).EnumType,Mode);
|
|
|
|
|
|
+ UseElType(El,TPasSetType(El).EnumType,Mode);
|
|
end
|
|
end
|
|
else if C.InheritsFrom(TPasProcedureType) then
|
|
else if C.InheritsFrom(TPasProcedureType) then
|
|
UseProcedureType(TPasProcedureType(El),true)
|
|
UseProcedureType(TPasProcedureType(El),true)
|
|
@@ -1434,11 +1520,11 @@ begin
|
|
ClassScope:=El.CustomData as TPasClassScope;
|
|
ClassScope:=El.CustomData as TPasClassScope;
|
|
if FirstTime then
|
|
if FirstTime then
|
|
begin
|
|
begin
|
|
- UseType(ClassScope.DirectAncestor,paumElement);
|
|
|
|
- UseType(El.HelperForType,paumElement);
|
|
|
|
|
|
+ UseElType(El,ClassScope.DirectAncestor,paumElement);
|
|
|
|
+ UseElType(El,El.HelperForType,paumElement);
|
|
UseExpr(El.GUIDExpr);
|
|
UseExpr(El.GUIDExpr);
|
|
for i:=0 to El.Interfaces.Count-1 do
|
|
for i:=0 to El.Interfaces.Count-1 do
|
|
- UseType(TPasType(El.Interfaces[i]),paumElement);
|
|
|
|
|
|
+ UseElType(El,TPasType(El.Interfaces[i]),paumElement);
|
|
end;
|
|
end;
|
|
// members
|
|
// members
|
|
AllPublished:=(Mode<>paumAllExports);
|
|
AllPublished:=(Mode<>paumAllExports);
|
|
@@ -1454,7 +1540,7 @@ begin
|
|
AddOverride(ProcScope.OverriddenProc,Member);
|
|
AddOverride(ProcScope.OverriddenProc,Member);
|
|
if ScopeModule<>nil then
|
|
if ScopeModule<>nil then
|
|
begin
|
|
begin
|
|
- // when analyzingf a single module, all overrides are assumed to be called
|
|
|
|
|
|
+ // when analyzing a single module, all overrides are assumed to be called
|
|
UseElement(Member,rraNone,true);
|
|
UseElement(Member,rraNone,true);
|
|
continue;
|
|
continue;
|
|
end;
|
|
end;
|
|
@@ -1514,7 +1600,7 @@ begin
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
|
|
writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
- if (FRefProcDecl<>nil) and MarkProcRef(El,ResolvedToPSRefAccess[Access]) then exit;
|
|
|
|
|
|
+ if (FRefProcDecl<>nil) and MarkSingleProcRef(El,ResolvedToPSRefAccess[Access]) then exit;
|
|
|
|
|
|
if El.ClassType=TPasProperty then
|
|
if El.ClassType=TPasProperty then
|
|
Prop:=TPasProperty(El)
|
|
Prop:=TPasProperty(El)
|
|
@@ -1566,7 +1652,7 @@ begin
|
|
Usage.Access:=paiaWrite;
|
|
Usage.Access:=paiaWrite;
|
|
UpdateVarAccess(IsRead,IsWrite);
|
|
UpdateVarAccess(IsRead,IsWrite);
|
|
// then use recursively
|
|
// then use recursively
|
|
- UseType(El.VarType,paumElement);
|
|
|
|
|
|
+ UseElType(El,El.VarType,paumElement);
|
|
UseExpr(El.Expr);
|
|
UseExpr(El.Expr);
|
|
UseExpr(El.LibraryName);
|
|
UseExpr(El.LibraryName);
|
|
UseExpr(El.ExportName);
|
|
UseExpr(El.ExportName);
|
|
@@ -1574,7 +1660,7 @@ begin
|
|
if Prop<>nil then
|
|
if Prop<>nil then
|
|
begin
|
|
begin
|
|
for i:=0 to Prop.Args.Count-1 do
|
|
for i:=0 to Prop.Args.Count-1 do
|
|
- UseType(TPasArgument(Prop.Args[i]).ArgType,paumElement);
|
|
|
|
|
|
+ UseElType(Prop,TPasArgument(Prop.Args[i]).ArgType,paumElement);
|
|
UseExpr(Prop.IndexExpr);
|
|
UseExpr(Prop.IndexExpr);
|
|
UseExpr(Prop.ImplementsFunc);
|
|
UseExpr(Prop.ImplementsFunc);
|
|
// ToDo: UseExpr(Prop.DispIDExpr);
|
|
// ToDo: UseExpr(Prop.DispIDExpr);
|
|
@@ -2186,6 +2272,11 @@ end;
|
|
procedure TPasAnalyzer.EmitMessage(Msg: TPAMessage);
|
|
procedure TPasAnalyzer.EmitMessage(Msg: TPAMessage);
|
|
begin
|
|
begin
|
|
if FRefProcDecl<>nil then exit;
|
|
if FRefProcDecl<>nil then exit;
|
|
|
|
+ if not Assigned(OnMessage) then
|
|
|
|
+ begin
|
|
|
|
+ Msg.Release;
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
writeln('TPasAnalyzer.EmitMessage [',Msg.Id,'] ',Msg.MsgType,': (',Msg.MsgNumber,') ',Msg.MsgText);
|
|
writeln('TPasAnalyzer.EmitMessage [',Msg.Id,'] ',Msg.MsgType,': (',Msg.MsgNumber,') ',Msg.MsgText);
|
|
{$ENDIF}
|
|
{$ENDIF}
|