mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-30 02:41:57 +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 property "%s" never used'
|
||||
- Hint: 'Function result does not seem to be set'
|
||||
- TPasArgument: compute the effective Access
|
||||
- calls: use the effective Access of arguments
|
||||
|
||||
ToDo:
|
||||
- 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;
|
||||
|
||||
@ -146,7 +146,8 @@ type
|
||||
end;
|
||||
|
||||
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;
|
||||
|
||||
@ -180,6 +181,7 @@ type
|
||||
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;
|
||||
@ -188,6 +190,7 @@ type
|
||||
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;
|
||||
// mark used elements
|
||||
function Add(El: TPasElement; CheckDuplicate: boolean = true;
|
||||
aClass: TPAElementClass = nil): TPAElement;
|
||||
@ -196,7 +199,8 @@ type
|
||||
procedure CreateTree; virtual;
|
||||
function MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass = nil): boolean; // true if new
|
||||
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;
|
||||
UseFull: boolean); virtual;
|
||||
procedure UsePublished(El: TPasElement); virtual;
|
||||
@ -205,8 +209,8 @@ type
|
||||
procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
|
||||
procedure UseImplElement(El: TPasImplElement); 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 UseProcedure(Proc: TPasProcedure); virtual;
|
||||
procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
|
||||
@ -418,6 +422,15 @@ begin
|
||||
Result:=TPAElement(Node.Data);
|
||||
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);
|
||||
begin
|
||||
if FOptions=AValue then Exit;
|
||||
@ -520,6 +533,24 @@ begin
|
||||
raise E;
|
||||
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;
|
||||
aClass: TPAElementClass): TPAElement;
|
||||
begin
|
||||
@ -607,7 +638,7 @@ begin
|
||||
FChecked[Mode].Add(El);
|
||||
end;
|
||||
|
||||
function TPasAnalyzer.MarkProcRef(El: TPasElement; Access: TPSRefAccess
|
||||
function TPasAnalyzer.MarkSingleProcRef(El: TPasElement; Access: TPSRefAccess
|
||||
): boolean;
|
||||
var
|
||||
Parent: TPasElement;
|
||||
@ -623,6 +654,27 @@ begin
|
||||
Result:=true;
|
||||
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;
|
||||
UseFull: boolean);
|
||||
var
|
||||
@ -660,6 +712,14 @@ end;
|
||||
|
||||
procedure TPasAnalyzer.UsePublished(El: TPasElement);
|
||||
// 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
|
||||
C: TClass;
|
||||
Members: TFPList;
|
||||
@ -673,21 +733,21 @@ begin
|
||||
writeln('TPasAnalyzer.UsePublished START ',GetObjName(El));
|
||||
{$ENDIF}
|
||||
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;
|
||||
if C=TPasUnresolvedSymbolRef then
|
||||
else if (C=TPasVariable) or (C=TPasConst) then
|
||||
UsePublished(TPasVariable(El).VarType)
|
||||
UseSubEl(TPasVariable(El).VarType)
|
||||
else if (C=TPasArgument) then
|
||||
UsePublished(TPasArgument(El).ArgType)
|
||||
UseSubEl(TPasArgument(El).ArgType)
|
||||
else if C=TPasProperty then
|
||||
begin
|
||||
// published property
|
||||
Prop:=TPasProperty(El);
|
||||
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
|
||||
|
||||
// stored and defaultvalue are only used when published -> mark as used
|
||||
@ -695,23 +755,23 @@ begin
|
||||
UseElement(Prop.DefaultExpr,rraRead,false);
|
||||
end
|
||||
else if (C=TPasAliasType) or (C=TPasTypeAliasType) then
|
||||
UsePublished(TPasAliasType(El).DestType)
|
||||
UseSubEl(TPasAliasType(El).DestType)
|
||||
else if C=TPasEnumType then
|
||||
else if C=TPasSetType then
|
||||
UsePublished(TPasSetType(El).EnumType)
|
||||
UseSubEl(TPasSetType(El).EnumType)
|
||||
else if C=TPasRangeType then
|
||||
else if C=TPasArrayType then
|
||||
begin
|
||||
UsePublished(TPasArrayType(El).ElType);
|
||||
UseSubEl(TPasArrayType(El).ElType);
|
||||
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
||||
begin
|
||||
Member:=TPasArrayType(El).Ranges[i];
|
||||
Resolver.ComputeElement(Member,MemberResolved,[rcConstant]);
|
||||
UsePublished(MemberResolved.TypeEl);
|
||||
UseSubEl(MemberResolved.TypeEl);
|
||||
end;
|
||||
end
|
||||
else if C=TPasPointerType then
|
||||
UsePublished(TPasPointerType(El).DestType)
|
||||
UseSubEl(TPasPointerType(El).DestType)
|
||||
else if C=TPasClassType then
|
||||
else if C=TPasClassOfType then
|
||||
else if C=TPasRecordType then
|
||||
@ -721,19 +781,19 @@ begin
|
||||
for i:=0 to Members.Count-1 do
|
||||
begin
|
||||
Member:=TPasElement(Members[i]);
|
||||
UsePublished(Member);
|
||||
UseSubEl(Member);
|
||||
UseElement(Member,rraNone,true);
|
||||
end;
|
||||
end
|
||||
else if C.InheritsFrom(TPasProcedure) then
|
||||
UsePublished(TPasProcedure(El).ProcType)
|
||||
UseSubEl(TPasProcedure(El).ProcType)
|
||||
else if C.InheritsFrom(TPasProcedureType) then
|
||||
begin
|
||||
ProcType:=TPasProcedureType(El);
|
||||
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
|
||||
UsePublished(TPasFunctionType(El).ResultEl.ResultType);
|
||||
UseSubEl(TPasFunctionType(El).ResultEl.ResultType);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -746,20 +806,20 @@ end;
|
||||
|
||||
procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
|
||||
|
||||
procedure UseInitFinal(aSection: TPasImplBlock);
|
||||
procedure UseInitFinal(ImplBlock: TPasImplBlock);
|
||||
begin
|
||||
if IsImplBlockEmpty(aSection) then exit;
|
||||
if IsImplBlockEmpty(ImplBlock) then exit;
|
||||
// this module has an initialization section -> mark module
|
||||
if FindNode(aModule)=nil then
|
||||
Add(aModule);
|
||||
UseImplBlock(aSection,true);
|
||||
UseImplBlock(ImplBlock,true);
|
||||
end;
|
||||
|
||||
var
|
||||
ModScope: TPasModuleScope;
|
||||
begin
|
||||
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}
|
||||
writeln('TPasAnalyzer.UseModule ',GetElModName(aModule),' Mode=',Mode);
|
||||
@ -774,6 +834,7 @@ begin
|
||||
begin
|
||||
// unit
|
||||
UseSection(aModule.InterfaceSection,Mode);
|
||||
// Note: implementation can not be used directly from outside
|
||||
end;
|
||||
end;
|
||||
UseInitFinal(aModule.InitializationSection);
|
||||
@ -845,6 +906,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
|
||||
if C.InheritsFrom(TPasProcedure) then
|
||||
begin
|
||||
if OnlyExports and ([pmExport,pmPublic]*TPasProcedure(Decl).Modifiers=[]) then
|
||||
@ -946,8 +1008,11 @@ begin
|
||||
UseExpr(ForLoop.StartExpr);
|
||||
UseExpr(ForLoop.EndExpr);
|
||||
ForScope:=ForLoop.CustomData as TPasForLoopScope;
|
||||
MarkScopeRef(ForLoop,ForScope.GetEnumerator,psraRead);
|
||||
UseProcedure(ForScope.GetEnumerator);
|
||||
MarkScopeRef(ForLoop,ForScope.MoveNext,psraRead);
|
||||
UseProcedure(ForScope.MoveNext);
|
||||
MarkScopeRef(ForLoop,ForScope.Current,psraRead);
|
||||
UseVariable(ForScope.Current,rraRead,false);
|
||||
UseImplElement(ForLoop.Body);
|
||||
end
|
||||
@ -983,7 +1048,8 @@ begin
|
||||
else if C=TPasImplExceptOn then
|
||||
begin
|
||||
// except-on
|
||||
UseType(TPasImplExceptOn(El).TypeEl,paumElement);
|
||||
// Note: VarEl is marked when actually used
|
||||
UseElType(El,TPasImplExceptOn(El).TypeEl,paumElement);
|
||||
UseImplElement(TPasImplExceptOn(El).Body);
|
||||
end
|
||||
else if C=TPasImplRaise then
|
||||
@ -1028,6 +1094,8 @@ var
|
||||
ParamResolved: TPasResolverResult;
|
||||
Decl: TPasElement;
|
||||
ModScope: TPasModuleScope;
|
||||
Access: TResolvedRefAccess;
|
||||
SubEl: TPasElement;
|
||||
begin
|
||||
if El=nil then exit;
|
||||
// Note: expression itself is not marked, but it can reference identifiers
|
||||
@ -1038,7 +1106,9 @@ begin
|
||||
// this is a reference -> mark target
|
||||
Ref:=TResolvedReference(El.CustomData);
|
||||
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
|
||||
begin
|
||||
@ -1047,7 +1117,7 @@ begin
|
||||
if Ref.WithExprScope.Scope is TPasRecordScope then
|
||||
begin
|
||||
// a record member was accessed -> access the record too
|
||||
UseExprRef(Ref.WithExprScope.Expr,Ref.Access,false);
|
||||
UseExprRef(El,Ref.WithExprScope.Expr,Access,false);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
@ -1058,8 +1128,8 @@ begin
|
||||
if ((Decl.Parent is TPasRecordType)
|
||||
or (Decl.Parent is TPasVariant)) then
|
||||
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;
|
||||
@ -1073,20 +1143,32 @@ begin
|
||||
bfTypeInfo:
|
||||
begin
|
||||
Params:=(El.Parent as TParamsExpr).Params;
|
||||
if length(Params)<>1 then
|
||||
RaiseNotSupported(20180226144217,El.Parent);
|
||||
Resolver.ComputeElement(Params[0],ParamResolved,[rcNoImplicitProc]);
|
||||
{$IFDEF VerbosePasAnalyzer}
|
||||
writeln('TPasAnalyzer.UseExpr typeinfo ',GetResolverResultDbg(ParamResolved));
|
||||
{$ENDIF}
|
||||
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
|
||||
UsePublished(ParamResolved.IdentEl);
|
||||
begin
|
||||
SubEl:=ParamResolved.IdentEl;
|
||||
MarkScopeRef(El,SubEl,psraTypeInfo);
|
||||
UsePublished(SubEl);
|
||||
end;
|
||||
// the parameter is not used otherwise
|
||||
exit;
|
||||
end;
|
||||
bfAssert:
|
||||
begin
|
||||
ModScope:=Resolver.RootElement.CustomData as TPasModuleScope;
|
||||
if ModScope.AssertClass<>nil then
|
||||
UseType(ModScope.AssertClass,paumElement);
|
||||
UseElType(El,ModScope.AssertClass,paumElement);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1128,8 +1210,8 @@ begin
|
||||
RaiseNotSupported(20170307085444,El);
|
||||
end;
|
||||
|
||||
procedure TPasAnalyzer.UseExprRef(Expr: TPasExpr; Access: TResolvedRefAccess;
|
||||
UseFull: boolean);
|
||||
procedure TPasAnalyzer.UseExprRef(El: TPasElement; Expr: TPasExpr;
|
||||
Access: TResolvedRefAccess; UseFull: boolean);
|
||||
var
|
||||
Ref: TResolvedReference;
|
||||
C: TClass;
|
||||
@ -1137,18 +1219,12 @@ var
|
||||
Params: TParamsExpr;
|
||||
ValueResolved: TPasResolverResult;
|
||||
begin
|
||||
if (Expr.CustomData is TResolvedReference) then
|
||||
begin
|
||||
Ref:=TResolvedReference(Expr.CustomData);
|
||||
UseElement(Ref.Declaration,Access,UseFull);
|
||||
end;
|
||||
|
||||
C:=Expr.ClassType;
|
||||
if C=TBinaryExpr then
|
||||
begin
|
||||
Bin:=TBinaryExpr(Expr);
|
||||
if Bin.OpCode in [eopSubIdent,eopNone] then
|
||||
UseExprRef(Bin.right,Access,UseFull);
|
||||
UseExprRef(El,Bin.right,Access,UseFull);
|
||||
end
|
||||
else if C=TParamsExpr then
|
||||
begin
|
||||
@ -1156,14 +1232,14 @@ begin
|
||||
case Params.Kind of
|
||||
pekFuncParams:
|
||||
if Resolver.IsTypeCast(Params) then
|
||||
UseExprRef(Params.Params[0],Access,UseFull)
|
||||
UseExprRef(El,Params.Params[0],Access,UseFull)
|
||||
else
|
||||
UseExprRef(Params.Value,Access,UseFull);
|
||||
UseExprRef(El,Params.Value,Access,UseFull);
|
||||
pekArrayParams:
|
||||
begin
|
||||
Resolver.ComputeElement(Params.Value,ValueResolved,[]);
|
||||
if not Resolver.IsDynArray(ValueResolved.TypeEl) then
|
||||
UseExprRef(Params.Value,Access,UseFull);
|
||||
UseExprRef(El,Params.Value,Access,UseFull);
|
||||
end;
|
||||
pekSet: ;
|
||||
else
|
||||
@ -1171,9 +1247,16 @@ begin
|
||||
end;
|
||||
end
|
||||
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)
|
||||
and ((C=TPrimitiveExpr)
|
||||
and ((C=TPrimitiveExpr) // Kind<>pekIdent
|
||||
or (C=TNilExpr)
|
||||
or (C=TBoolConstExpr)
|
||||
or (C=TUnaryExpr)) then
|
||||
@ -1254,7 +1337,7 @@ begin
|
||||
exit; // skip implementation, Note:PasResolver always refers the declaration
|
||||
|
||||
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}
|
||||
writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
|
||||
{$ENDIF}
|
||||
@ -1270,7 +1353,10 @@ begin
|
||||
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
|
||||
@ -1294,11 +1380,11 @@ begin
|
||||
Arg:=TPasArgument(ProcType.Args[i]);
|
||||
// Note: the arguments themselves are marked when used in code
|
||||
// mark argument type and default value
|
||||
UseType(Arg.ArgType,paumElement);
|
||||
UseElType(ProcType,Arg.ArgType,paumElement);
|
||||
UseExpr(Arg.ValueExpr);
|
||||
end;
|
||||
if ProcType is TPasFunctionType then
|
||||
UseType(TPasFunctionType(ProcType).ResultEl.ResultType,paumElement);
|
||||
UseElType(ProcType,TPasFunctionType(ProcType).ResultEl.ResultType,paumElement);
|
||||
end;
|
||||
|
||||
procedure TPasAnalyzer.UseType(El: TPasType; Mode: TPAUseMode);
|
||||
@ -1307,7 +1393,7 @@ var
|
||||
i: Integer;
|
||||
begin
|
||||
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;
|
||||
if Mode=paumAllExports then
|
||||
@ -1337,14 +1423,14 @@ begin
|
||||
or (C=TPasClassOfType) then
|
||||
begin
|
||||
if not MarkElementAsUsed(El) then exit;
|
||||
UseType(TPasAliasType(El).DestType,Mode);
|
||||
UseElType(El,TPasAliasType(El).DestType,Mode);
|
||||
end
|
||||
else if C=TPasArrayType then
|
||||
begin
|
||||
if not MarkElementAsUsed(El) then exit;
|
||||
for i:=0 to length(TPasArrayType(El).Ranges)-1 do
|
||||
UseExpr(TPasArrayType(El).Ranges[i]);
|
||||
UseType(TPasArrayType(El).ElType,Mode);
|
||||
UseElType(El,TPasArrayType(El).ElType,Mode);
|
||||
end
|
||||
else if C=TPasRecordType then
|
||||
UseRecordType(TPasRecordType(El),Mode)
|
||||
@ -1359,7 +1445,7 @@ begin
|
||||
else if C=TPasPointerType then
|
||||
begin
|
||||
if not MarkElementAsUsed(El) then exit;
|
||||
UseType(TPasPointerType(El).DestType,Mode);
|
||||
UseElType(El,TPasPointerType(El).DestType,Mode);
|
||||
end
|
||||
else if C=TPasRangeType then
|
||||
begin
|
||||
@ -1369,7 +1455,7 @@ begin
|
||||
else if C=TPasSetType then
|
||||
begin
|
||||
if not MarkElementAsUsed(El) then exit;
|
||||
UseType(TPasSetType(El).EnumType,Mode);
|
||||
UseElType(El,TPasSetType(El).EnumType,Mode);
|
||||
end
|
||||
else if C.InheritsFrom(TPasProcedureType) then
|
||||
UseProcedureType(TPasProcedureType(El),true)
|
||||
@ -1434,11 +1520,11 @@ begin
|
||||
ClassScope:=El.CustomData as TPasClassScope;
|
||||
if FirstTime then
|
||||
begin
|
||||
UseType(ClassScope.DirectAncestor,paumElement);
|
||||
UseType(El.HelperForType,paumElement);
|
||||
UseElType(El,ClassScope.DirectAncestor,paumElement);
|
||||
UseElType(El,El.HelperForType,paumElement);
|
||||
UseExpr(El.GUIDExpr);
|
||||
for i:=0 to El.Interfaces.Count-1 do
|
||||
UseType(TPasType(El.Interfaces[i]),paumElement);
|
||||
UseElType(El,TPasType(El.Interfaces[i]),paumElement);
|
||||
end;
|
||||
// members
|
||||
AllPublished:=(Mode<>paumAllExports);
|
||||
@ -1454,7 +1540,7 @@ begin
|
||||
AddOverride(ProcScope.OverriddenProc,Member);
|
||||
if ScopeModule<>nil then
|
||||
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);
|
||||
continue;
|
||||
end;
|
||||
@ -1514,7 +1600,7 @@ begin
|
||||
{$IFDEF VerbosePasAnalyzer}
|
||||
writeln('TPasAnalyzer.UseVariable ',GetElModName(El),' ',Access,' Full=',UseFull);
|
||||
{$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
|
||||
Prop:=TPasProperty(El)
|
||||
@ -1566,7 +1652,7 @@ begin
|
||||
Usage.Access:=paiaWrite;
|
||||
UpdateVarAccess(IsRead,IsWrite);
|
||||
// then use recursively
|
||||
UseType(El.VarType,paumElement);
|
||||
UseElType(El,El.VarType,paumElement);
|
||||
UseExpr(El.Expr);
|
||||
UseExpr(El.LibraryName);
|
||||
UseExpr(El.ExportName);
|
||||
@ -1574,7 +1660,7 @@ begin
|
||||
if Prop<>nil then
|
||||
begin
|
||||
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.ImplementsFunc);
|
||||
// ToDo: UseExpr(Prop.DispIDExpr);
|
||||
@ -2186,6 +2272,11 @@ end;
|
||||
procedure TPasAnalyzer.EmitMessage(Msg: TPAMessage);
|
||||
begin
|
||||
if FRefProcDecl<>nil then exit;
|
||||
if not Assigned(OnMessage) then
|
||||
begin
|
||||
Msg.Release;
|
||||
exit;
|
||||
end;
|
||||
{$IFDEF VerbosePasAnalyzer}
|
||||
writeln('TPasAnalyzer.EmitMessage [',Msg.Id,'] ',Msg.MsgType,': (',Msg.MsgNumber,') ',Msg.MsgText);
|
||||
{$ENDIF}
|
||||
|
@ -21,6 +21,7 @@ type
|
||||
FAnalyzer: TPasAnalyzer;
|
||||
FPAMessages: TFPList; // list of TPAMessage
|
||||
FPAGoodMessages: TFPList;
|
||||
FProcAnalyzer: TPasAnalyzer;
|
||||
function GetPAMessages(Index: integer): TPAMessage;
|
||||
procedure OnAnalyzerMessage(Sender: TObject; Msg: TPAMessage);
|
||||
protected
|
||||
@ -39,6 +40,7 @@ type
|
||||
const RefNames: array of string);
|
||||
public
|
||||
property Analyzer: TPasAnalyzer read FAnalyzer;
|
||||
property ProcAnalyzer: TPasAnalyzer read FProcAnalyzer;
|
||||
function PAMessageCount: integer;
|
||||
property PAMessages[Index: integer]: TPAMessage read GetPAMessages;
|
||||
end;
|
||||
@ -185,6 +187,7 @@ begin
|
||||
TPAMessage(FPAMessages[i]).Release;
|
||||
FreeAndNil(FPAMessages);
|
||||
FreeAndNil(FAnalyzer);
|
||||
FreeAndNil(FProcAnalyzer);
|
||||
inherited TearDown;
|
||||
end;
|
||||
|
||||
@ -353,7 +356,7 @@ type
|
||||
var
|
||||
Entries: array of TEntry;
|
||||
|
||||
procedure CheckRefs(Scope: TPasProcedureScope);
|
||||
procedure CheckRefs(Scope: TPasProcedureScope; const Prefix: string);
|
||||
|
||||
procedure DumpRefsAndFail(Refs: TFPList; const Msg: string);
|
||||
var
|
||||
@ -365,10 +368,10 @@ var
|
||||
Ref:=TPasProcScopeReference(Refs[i]);
|
||||
if Ref=nil then break;
|
||||
{$IFDEF VerbosePasAnalyzer}
|
||||
writeln('DumpRefsAndFail ',i,' ',GetObjName(Ref.Element),' ',Ref.Access);
|
||||
writeln('DumpRefsAndFail ',Prefix,' ',i,' ',GetObjName(Ref.Element),' ',Ref.Access);
|
||||
{$ENDIF}
|
||||
end;
|
||||
Fail(Msg);
|
||||
Fail(Prefix+': '+Msg);
|
||||
end;
|
||||
|
||||
var
|
||||
@ -384,7 +387,7 @@ var
|
||||
begin
|
||||
o:=TObject(Refs[i]);
|
||||
if not (o is TPasProcScopeReference) then
|
||||
Fail('Refs['+IntToStr(i)+'] '+GetObjName(o));
|
||||
Fail(Prefix+': Refs['+IntToStr(i)+'] '+GetObjName(o));
|
||||
end;
|
||||
// check that all Entries are referenced
|
||||
for i:=0 to length(Entries)-1 do
|
||||
@ -422,6 +425,7 @@ var
|
||||
El: TPasElement;
|
||||
Proc: TPasProcedure;
|
||||
Scope: TPasProcedureScope;
|
||||
ProcAnalyzer: TPasAnalyzer;
|
||||
begin
|
||||
for i:=0 to Section.Declarations.Count-1 do
|
||||
begin
|
||||
@ -432,9 +436,21 @@ var
|
||||
Proc:=TPasProcedure(El);
|
||||
Scope:=Proc.CustomData as TPasProcedureScope;
|
||||
if Scope.DeclarationProc<>nil then continue;
|
||||
Analyzer.Clear;
|
||||
Analyzer.AnalyzeProcRefs(Proc);
|
||||
CheckRefs(Scope);
|
||||
|
||||
// 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');
|
||||
|
||||
exit(true);
|
||||
end;
|
||||
Result:=false;
|
||||
@ -443,8 +459,6 @@ var
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
ParseUnit;
|
||||
|
||||
SetLength(Entries,High(RefNames)-low(RefNames)+1);
|
||||
for i:=low(RefNames) to high(RefNames) do
|
||||
begin
|
||||
@ -1750,6 +1764,7 @@ begin
|
||||
'end;',
|
||||
'begin',
|
||||
' DoIt(nil);']);
|
||||
AnalyzeProgram;
|
||||
CheckUseAnalyzerUnexpectedHints;
|
||||
end;
|
||||
|
||||
@ -2252,6 +2267,8 @@ begin
|
||||
' b:=i;',
|
||||
'end;',
|
||||
'']);
|
||||
Analyzer.Options:=Analyzer.Options+[paoProcReferences];
|
||||
AnalyzeUnit;
|
||||
CheckUnitProcedureReferences('DoIt',['i','tintcolor']);
|
||||
end;
|
||||
|
||||
|
@ -24,7 +24,7 @@ interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fpcunit, testregistry,
|
||||
PasTree, PScanner, PasResolver, PasResolveEval, PParser,
|
||||
PasTree, PScanner, PasResolver, PasResolveEval, PParser, PasUseAnalyzer,
|
||||
FPPas2Js, Pas2JsFiler,
|
||||
tcmodules;
|
||||
|
||||
@ -34,6 +34,7 @@ type
|
||||
|
||||
TCustomTestPrecompile = Class(TCustomTestModule)
|
||||
private
|
||||
FAnalyzer: TPasAnalyzer;
|
||||
FInitialFlags: TPJUInitialFlags;
|
||||
FPJUReader: TPJUReader;
|
||||
FPJUWriter: TPJUWriter;
|
||||
@ -42,6 +43,7 @@ type
|
||||
protected
|
||||
procedure SetUp; override;
|
||||
procedure TearDown; override;
|
||||
procedure ConvertModule; override;
|
||||
procedure WriteReadUnit; virtual;
|
||||
procedure StartParsing; override;
|
||||
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 CheckRestoredOperator(const Path: string; Orig, Rest: TPasOperator); virtual;
|
||||
public
|
||||
property Analyzer: TPasAnalyzer read FAnalyzer;
|
||||
property PJUWriter: TPJUWriter read FPJUWriter write FPJUWriter;
|
||||
property PJUReader: TPJUReader read FPJUReader write FPJUReader;
|
||||
property InitialFlags: TPJUInitialFlags read FInitialFlags;
|
||||
@ -165,16 +168,25 @@ procedure TCustomTestPrecompile.SetUp;
|
||||
begin
|
||||
inherited SetUp;
|
||||
FInitialFlags:=TPJUInitialFlags.Create;
|
||||
FAnalyzer:=TPasAnalyzer.Create;
|
||||
Analyzer.Resolver:=Engine;
|
||||
end;
|
||||
|
||||
procedure TCustomTestPrecompile.TearDown;
|
||||
begin
|
||||
FreeAndNil(FAnalyzer);
|
||||
FreeAndNil(FPJUWriter);
|
||||
FreeAndNil(FPJUReader);
|
||||
FreeAndNil(FInitialFlags);
|
||||
inherited TearDown;
|
||||
end;
|
||||
|
||||
procedure TCustomTestPrecompile.ConvertModule;
|
||||
begin
|
||||
Analyzer.AnalyzeModule(Module);
|
||||
inherited ConvertModule;
|
||||
end;
|
||||
|
||||
procedure TCustomTestPrecompile.WriteReadUnit;
|
||||
var
|
||||
ms: TMemoryStream;
|
||||
|
Loading…
Reference in New Issue
Block a user