mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-02 15:52:05 +02:00
fcl-passrc: useanalyzer: option to generate references of all used procs
git-svn-id: trunk@38355 -
This commit is contained in:
parent
f623038da6
commit
02e57c36c2
@ -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;
|
procedure UseExprRef(El: TPasElement; Expr: TPasExpr;
|
||||||
UseFull: boolean); virtual;
|
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);
|
UseSubEl(TPasArgument(Prop.Args[i]).ArgType);
|
||||||
UsePublished(Prop.VarType);
|
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
|
// a record member was accessed -> access the record with same Access
|
||||||
UseExprRef(TBinaryExpr(El.Parent).left,Ref.Access,false);
|
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;
|
procedure TPasAnalyzer.UseExprRef(El: TPasElement; Expr: TPasExpr;
|
||||||
UseFull: boolean);
|
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);
|
UseElType(El,ClassScope.DirectAncestor,paumElement);
|
||||||
UseType(El.HelperForType,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}
|
||||||
|
@ -21,6 +21,7 @@ type
|
|||||||
FAnalyzer: TPasAnalyzer;
|
FAnalyzer: TPasAnalyzer;
|
||||||
FPAMessages: TFPList; // list of TPAMessage
|
FPAMessages: TFPList; // list of TPAMessage
|
||||||
FPAGoodMessages: TFPList;
|
FPAGoodMessages: TFPList;
|
||||||
|
FProcAnalyzer: TPasAnalyzer;
|
||||||
function GetPAMessages(Index: integer): TPAMessage;
|
function GetPAMessages(Index: integer): TPAMessage;
|
||||||
procedure OnAnalyzerMessage(Sender: TObject; Msg: TPAMessage);
|
procedure OnAnalyzerMessage(Sender: TObject; Msg: TPAMessage);
|
||||||
protected
|
protected
|
||||||
@ -39,6 +40,7 @@ type
|
|||||||
const RefNames: array of string);
|
const RefNames: array of string);
|
||||||
public
|
public
|
||||||
property Analyzer: TPasAnalyzer read FAnalyzer;
|
property Analyzer: TPasAnalyzer read FAnalyzer;
|
||||||
|
property ProcAnalyzer: TPasAnalyzer read FProcAnalyzer;
|
||||||
function PAMessageCount: integer;
|
function PAMessageCount: integer;
|
||||||
property PAMessages[Index: integer]: TPAMessage read GetPAMessages;
|
property PAMessages[Index: integer]: TPAMessage read GetPAMessages;
|
||||||
end;
|
end;
|
||||||
@ -185,6 +187,7 @@ begin
|
|||||||
TPAMessage(FPAMessages[i]).Release;
|
TPAMessage(FPAMessages[i]).Release;
|
||||||
FreeAndNil(FPAMessages);
|
FreeAndNil(FPAMessages);
|
||||||
FreeAndNil(FAnalyzer);
|
FreeAndNil(FAnalyzer);
|
||||||
|
FreeAndNil(FProcAnalyzer);
|
||||||
inherited TearDown;
|
inherited TearDown;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -353,7 +356,7 @@ type
|
|||||||
var
|
var
|
||||||
Entries: array of TEntry;
|
Entries: array of TEntry;
|
||||||
|
|
||||||
procedure CheckRefs(Scope: TPasProcedureScope);
|
procedure CheckRefs(Scope: TPasProcedureScope; const Prefix: string);
|
||||||
|
|
||||||
procedure DumpRefsAndFail(Refs: TFPList; const Msg: string);
|
procedure DumpRefsAndFail(Refs: TFPList; const Msg: string);
|
||||||
var
|
var
|
||||||
@ -365,10 +368,10 @@ var
|
|||||||
Ref:=TPasProcScopeReference(Refs[i]);
|
Ref:=TPasProcScopeReference(Refs[i]);
|
||||||
if Ref=nil then break;
|
if Ref=nil then break;
|
||||||
{$IFDEF VerbosePasAnalyzer}
|
{$IFDEF VerbosePasAnalyzer}
|
||||||
writeln('DumpRefsAndFail ',i,' ',GetObjName(Ref.Element),' ',Ref.Access);
|
writeln('DumpRefsAndFail ',Prefix,' ',i,' ',GetObjName(Ref.Element),' ',Ref.Access);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
Fail(Msg);
|
Fail(Prefix+': '+Msg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -384,7 +387,7 @@ var
|
|||||||
begin
|
begin
|
||||||
o:=TObject(Refs[i]);
|
o:=TObject(Refs[i]);
|
||||||
if not (o is TPasProcScopeReference) then
|
if not (o is TPasProcScopeReference) then
|
||||||
Fail('Refs['+IntToStr(i)+'] '+GetObjName(o));
|
Fail(Prefix+': Refs['+IntToStr(i)+'] '+GetObjName(o));
|
||||||
end;
|
end;
|
||||||
// check that all Entries are referenced
|
// check that all Entries are referenced
|
||||||
for i:=0 to length(Entries)-1 do
|
for i:=0 to length(Entries)-1 do
|
||||||
@ -422,6 +425,7 @@ var
|
|||||||
El: TPasElement;
|
El: TPasElement;
|
||||||
Proc: TPasProcedure;
|
Proc: TPasProcedure;
|
||||||
Scope: TPasProcedureScope;
|
Scope: TPasProcedureScope;
|
||||||
|
ProcAnalyzer: TPasAnalyzer;
|
||||||
begin
|
begin
|
||||||
for i:=0 to Section.Declarations.Count-1 do
|
for i:=0 to Section.Declarations.Count-1 do
|
||||||
begin
|
begin
|
||||||
@ -432,9 +436,21 @@ var
|
|||||||
Proc:=TPasProcedure(El);
|
Proc:=TPasProcedure(El);
|
||||||
Scope:=Proc.CustomData as TPasProcedureScope;
|
Scope:=Proc.CustomData as TPasProcedureScope;
|
||||||
if Scope.DeclarationProc<>nil then continue;
|
if Scope.DeclarationProc<>nil then continue;
|
||||||
Analyzer.Clear;
|
|
||||||
Analyzer.AnalyzeProcRefs(Proc);
|
// check references created by AnalyzeModule
|
||||||
CheckRefs(Scope);
|
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');
|
||||||
|
|
||||||
exit(true);
|
exit(true);
|
||||||
end;
|
end;
|
||||||
Result:=false;
|
Result:=false;
|
||||||
@ -443,8 +459,6 @@ var
|
|||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
ParseUnit;
|
|
||||||
|
|
||||||
SetLength(Entries,High(RefNames)-low(RefNames)+1);
|
SetLength(Entries,High(RefNames)-low(RefNames)+1);
|
||||||
for i:=low(RefNames) to high(RefNames) do
|
for i:=low(RefNames) to high(RefNames) do
|
||||||
begin
|
begin
|
||||||
@ -1750,6 +1764,7 @@ begin
|
|||||||
'end;',
|
'end;',
|
||||||
'begin',
|
'begin',
|
||||||
' DoIt(nil);']);
|
' DoIt(nil);']);
|
||||||
|
AnalyzeProgram;
|
||||||
CheckUseAnalyzerUnexpectedHints;
|
CheckUseAnalyzerUnexpectedHints;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2252,6 +2267,8 @@ begin
|
|||||||
' b:=i;',
|
' b:=i;',
|
||||||
'end;',
|
'end;',
|
||||||
'']);
|
'']);
|
||||||
|
Analyzer.Options:=Analyzer.Options+[paoProcReferences];
|
||||||
|
AnalyzeUnit;
|
||||||
CheckUnitProcedureReferences('DoIt',['i','tintcolor']);
|
CheckUnitProcedureReferences('DoIt',['i','tintcolor']);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, fpcunit, testregistry,
|
Classes, SysUtils, fpcunit, testregistry,
|
||||||
PasTree, PScanner, PasResolver, PasResolveEval, PParser,
|
PasTree, PScanner, PasResolver, PasResolveEval, PParser, PasUseAnalyzer,
|
||||||
FPPas2Js, Pas2JsFiler,
|
FPPas2Js, Pas2JsFiler,
|
||||||
tcmodules;
|
tcmodules;
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ type
|
|||||||
|
|
||||||
TCustomTestPrecompile = Class(TCustomTestModule)
|
TCustomTestPrecompile = Class(TCustomTestModule)
|
||||||
private
|
private
|
||||||
|
FAnalyzer: TPasAnalyzer;
|
||||||
FInitialFlags: TPJUInitialFlags;
|
FInitialFlags: TPJUInitialFlags;
|
||||||
FPJUReader: TPJUReader;
|
FPJUReader: TPJUReader;
|
||||||
FPJUWriter: TPJUWriter;
|
FPJUWriter: TPJUWriter;
|
||||||
@ -42,6 +43,7 @@ type
|
|||||||
protected
|
protected
|
||||||
procedure SetUp; override;
|
procedure SetUp; override;
|
||||||
procedure TearDown; override;
|
procedure TearDown; override;
|
||||||
|
procedure ConvertModule; override;
|
||||||
procedure WriteReadUnit; virtual;
|
procedure WriteReadUnit; virtual;
|
||||||
procedure StartParsing; override;
|
procedure StartParsing; override;
|
||||||
function CheckRestoredObject(const Path: string; Orig, Rest: TObject): boolean; virtual;
|
function CheckRestoredObject(const Path: string; Orig, Rest: TObject): boolean; virtual;
|
||||||
@ -106,6 +108,7 @@ type
|
|||||||
procedure CheckRestoredProcedure(const Path: string; Orig, Rest: TPasProcedure); virtual;
|
procedure CheckRestoredProcedure(const Path: string; Orig, Rest: TPasProcedure); virtual;
|
||||||
procedure CheckRestoredOperator(const Path: string; Orig, Rest: TPasOperator); virtual;
|
procedure CheckRestoredOperator(const Path: string; Orig, Rest: TPasOperator); virtual;
|
||||||
public
|
public
|
||||||
|
property Analyzer: TPasAnalyzer read FAnalyzer;
|
||||||
property PJUWriter: TPJUWriter read FPJUWriter write FPJUWriter;
|
property PJUWriter: TPJUWriter read FPJUWriter write FPJUWriter;
|
||||||
property PJUReader: TPJUReader read FPJUReader write FPJUReader;
|
property PJUReader: TPJUReader read FPJUReader write FPJUReader;
|
||||||
property InitialFlags: TPJUInitialFlags read FInitialFlags;
|
property InitialFlags: TPJUInitialFlags read FInitialFlags;
|
||||||
@ -165,16 +168,25 @@ procedure TCustomTestPrecompile.SetUp;
|
|||||||
begin
|
begin
|
||||||
inherited SetUp;
|
inherited SetUp;
|
||||||
FInitialFlags:=TPJUInitialFlags.Create;
|
FInitialFlags:=TPJUInitialFlags.Create;
|
||||||
|
FAnalyzer:=TPasAnalyzer.Create;
|
||||||
|
Analyzer.Resolver:=Engine;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomTestPrecompile.TearDown;
|
procedure TCustomTestPrecompile.TearDown;
|
||||||
begin
|
begin
|
||||||
|
FreeAndNil(FAnalyzer);
|
||||||
FreeAndNil(FPJUWriter);
|
FreeAndNil(FPJUWriter);
|
||||||
FreeAndNil(FPJUReader);
|
FreeAndNil(FPJUReader);
|
||||||
FreeAndNil(FInitialFlags);
|
FreeAndNil(FInitialFlags);
|
||||||
inherited TearDown;
|
inherited TearDown;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomTestPrecompile.ConvertModule;
|
||||||
|
begin
|
||||||
|
Analyzer.AnalyzeModule(Module);
|
||||||
|
inherited ConvertModule;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomTestPrecompile.WriteReadUnit;
|
procedure TCustomTestPrecompile.WriteReadUnit;
|
||||||
var
|
var
|
||||||
ms: TMemoryStream;
|
ms: TMemoryStream;
|
||||||
|
Loading…
Reference in New Issue
Block a user