|
@@ -218,12 +218,16 @@ const
|
|
|
);
|
|
|
|
|
|
type
|
|
|
+ TPAOtherCheckedEl = (
|
|
|
+ pocClassConstructor
|
|
|
+ );
|
|
|
|
|
|
{ TPasAnalyzer }
|
|
|
|
|
|
TPasAnalyzer = class
|
|
|
private
|
|
|
- FChecked: array[TPAUseMode] of TPasAnalyzerKeySet; // tree of TElement
|
|
|
+ FModeChecked: array[TPAUseMode] of TPasAnalyzerKeySet; // tree of TElement
|
|
|
+ FOtherChecked: array[TPAOtherCheckedEl] of TPasAnalyzerKeySet; // tree of TElement
|
|
|
FOnMessage: TPAMessageEvent;
|
|
|
FOptions: TPasAnalyzerOptions;
|
|
|
FOverrideLists: TPasAnalyzerKeySet; // tree of TPAOverrideList sorted for Element
|
|
@@ -245,7 +249,8 @@ type
|
|
|
function PAElementExists(El: TPasElement): boolean; inline;
|
|
|
procedure CreateTree; virtual;
|
|
|
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; overload;
|
|
|
+ function ElementVisited(El: TPasElement; OtherCheck: TPAOtherCheckedEl): boolean; overload;
|
|
|
procedure MarkImplScopeRef(El, RefEl: TPasElement; Access: TPSRefAccess);
|
|
|
procedure UseElement(El: TPasElement; Access: TResolvedRefAccess;
|
|
|
UseFull: boolean); virtual;
|
|
@@ -263,6 +268,7 @@ type
|
|
|
procedure UseProcedureType(ProcType: TPasProcedureType); virtual;
|
|
|
procedure UseType(El: TPasType; Mode: TPAUseMode); virtual;
|
|
|
procedure UseClassOrRecType(El: TPasMembersType; Mode: TPAUseMode); virtual;
|
|
|
+ procedure UseClassConstructor(El: TPasMembersType); virtual;
|
|
|
procedure UseVariable(El: TPasVariable; Access: TResolvedRefAccess;
|
|
|
UseFull: boolean); virtual;
|
|
|
procedure UseResourcestring(El: TPasResString); virtual;
|
|
@@ -952,9 +958,19 @@ function TPasAnalyzer.ElementVisited(El: TPasElement; Mode: TPAUseMode
|
|
|
begin
|
|
|
if El=nil then
|
|
|
exit(true);
|
|
|
- if FChecked[Mode].ContainsItem(El) then exit(true);
|
|
|
+ if FModeChecked[Mode].ContainsItem(El) then exit(true);
|
|
|
+ Result:=false;
|
|
|
+ FModeChecked[Mode].Add(El,false);
|
|
|
+end;
|
|
|
+
|
|
|
+function TPasAnalyzer.ElementVisited(El: TPasElement;
|
|
|
+ OtherCheck: TPAOtherCheckedEl): boolean;
|
|
|
+begin
|
|
|
+ if El=nil then
|
|
|
+ exit(true);
|
|
|
+ if FOtherChecked[OtherCheck].ContainsItem(El) then exit(true);
|
|
|
Result:=false;
|
|
|
- FChecked[Mode].Add(El,false);
|
|
|
+ FOtherChecked[OtherCheck].Add(El,false);
|
|
|
end;
|
|
|
|
|
|
procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement;
|
|
@@ -1441,6 +1457,7 @@ var
|
|
|
ModScope: TPasModuleScope;
|
|
|
Access: TResolvedRefAccess;
|
|
|
SubEl: TPasElement;
|
|
|
+ ParamsExpr: TParamsExpr;
|
|
|
begin
|
|
|
if El=nil then exit;
|
|
|
// Note: expression itself is not marked, but it can reference identifiers
|
|
@@ -1455,6 +1472,10 @@ begin
|
|
|
MarkImplScopeRef(El,Decl,ResolvedToPSRefAccess[Access]);
|
|
|
UseElement(Decl,Access,false);
|
|
|
|
|
|
+ if Ref.Context<>nil then
|
|
|
+ begin
|
|
|
+ end;
|
|
|
+
|
|
|
if Resolver.IsNameExpr(El) then
|
|
|
begin
|
|
|
if Ref.WithExprScope<>nil then
|
|
@@ -1487,7 +1508,8 @@ begin
|
|
|
case BuiltInProc.BuiltIn of
|
|
|
bfExit:
|
|
|
begin
|
|
|
- if El.Parent is TParamsExpr then
|
|
|
+ ParamsExpr:=Resolver.GetParamsOfNameExpr(El);
|
|
|
+ if ParamsExpr<>nil then
|
|
|
begin
|
|
|
Params:=(El.Parent as TParamsExpr).Params;
|
|
|
if length(Params)=1 then
|
|
@@ -1506,7 +1528,10 @@ begin
|
|
|
end;
|
|
|
bfTypeInfo:
|
|
|
begin
|
|
|
- Params:=(El.Parent as TParamsExpr).Params;
|
|
|
+ ParamsExpr:=Resolver.GetParamsOfNameExpr(El);
|
|
|
+ if ParamsExpr=nil then
|
|
|
+ RaiseNotSupported(20190225150136,El);
|
|
|
+ Params:=ParamsExpr.Params;
|
|
|
if length(Params)<>1 then
|
|
|
RaiseNotSupported(20180226144217,El.Parent);
|
|
|
Resolver.ComputeElement(Params[0],ParamResolved,[rcNoImplicitProc]);
|
|
@@ -1547,7 +1572,6 @@ begin
|
|
|
UseExpr(El.format2);
|
|
|
C:=El.ClassType;
|
|
|
if (C=TPrimitiveExpr)
|
|
|
- or (C=TSelfExpr)
|
|
|
or (C=TBoolConstExpr)
|
|
|
or (C=TNilExpr) then
|
|
|
// ok
|
|
@@ -1621,7 +1645,7 @@ begin
|
|
|
RaiseNotSupported(20170403173817,Params);
|
|
|
end;
|
|
|
end
|
|
|
- else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
|
|
|
+ else if (C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent) then
|
|
|
begin
|
|
|
if (Expr.CustomData is TResolvedReference) then
|
|
|
begin
|
|
@@ -1734,6 +1758,9 @@ begin
|
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
|
writeln('TPasAnalyzer.UseProcedure ',GetElModName(Proc));
|
|
|
{$ENDIF}
|
|
|
+ if Proc.Parent is TPasMembersType then
|
|
|
+ UseClassOrRecType(TPasMembersType(Proc.Parent),paumElement);
|
|
|
+
|
|
|
UseScopeReferences(ProcScope.References);
|
|
|
|
|
|
UseProcedureType(Proc.ProcType);
|
|
@@ -1945,7 +1972,7 @@ var
|
|
|
List, ProcList: TFPList;
|
|
|
o: TObject;
|
|
|
Map: TPasClassIntfMap;
|
|
|
- ImplProc, IntfProc: TPasProcedure;
|
|
|
+ ImplProc, IntfProc, Proc: TPasProcedure;
|
|
|
aClass: TPasClassType;
|
|
|
begin
|
|
|
FirstTime:=true;
|
|
@@ -1970,13 +1997,13 @@ begin
|
|
|
RaiseInconsistency(20170414152143,IntToStr(ord(Mode)));
|
|
|
end;
|
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
|
- writeln('TPasAnalyzer.UseClassType ',GetElModName(El),' ',Mode,' First=',FirstTime);
|
|
|
+ writeln('TPasAnalyzer.UseClassOrRecType ',GetElModName(El),' ',Mode,' First=',FirstTime);
|
|
|
{$ENDIF}
|
|
|
aClass:=nil;
|
|
|
ClassScope:=nil;
|
|
|
IsCOMInterfaceRoot:=false;
|
|
|
|
|
|
- if El is TPasClassType then
|
|
|
+ if El.ClassType=TPasClassType then
|
|
|
begin
|
|
|
aClass:=TPasClassType(El);
|
|
|
if aClass.IsForward then
|
|
@@ -2026,43 +2053,51 @@ begin
|
|
|
Member:=TPasElement(El.Members[i]);
|
|
|
if FirstTime and (Member is TPasProcedure) then
|
|
|
begin
|
|
|
+ Proc:=TPasProcedure(Member);
|
|
|
ProcScope:=Member.CustomData as TPasProcedureScope;
|
|
|
- if TPasProcedure(Member).IsOverride and (ProcScope.OverriddenProc<>nil) then
|
|
|
+ if Proc.IsOverride and (ProcScope.OverriddenProc<>nil) then
|
|
|
begin
|
|
|
// this is an override
|
|
|
AddOverride(ProcScope.OverriddenProc,Member);
|
|
|
if ScopeModule<>nil then
|
|
|
begin
|
|
|
// when analyzing a single module, all overrides are assumed to be called
|
|
|
- UseProcedure(TPasProcedure(Member));
|
|
|
+ UseProcedure(Proc);
|
|
|
continue;
|
|
|
end;
|
|
|
+ end
|
|
|
+ else if (Proc.ClassType=TPasClassConstructor)
|
|
|
+ or (Proc.ClassType=TPasClassDestructor) then
|
|
|
+ begin
|
|
|
+ UseProcedure(Proc);
|
|
|
+ continue;
|
|
|
end;
|
|
|
if IsCOMInterfaceRoot then
|
|
|
begin
|
|
|
case lowercase(Member.Name) of
|
|
|
'queryinterface':
|
|
|
- if (TPasProcedure(Member).ProcType.Args.Count=2) then
|
|
|
+ if (Proc.ProcType.Args.Count=2) then
|
|
|
begin
|
|
|
- UseProcedure(TPasProcedure(Member));
|
|
|
+ UseProcedure(Proc);
|
|
|
continue;
|
|
|
end;
|
|
|
'_addref':
|
|
|
- if TPasProcedure(Member).ProcType.Args.Count=0 then
|
|
|
+ if Proc.ProcType.Args.Count=0 then
|
|
|
begin
|
|
|
- UseProcedure(TPasProcedure(Member));
|
|
|
+ UseProcedure(Proc);
|
|
|
continue;
|
|
|
end;
|
|
|
'_release':
|
|
|
- if TPasProcedure(Member).ProcType.Args.Count=0 then
|
|
|
+ if Proc.ProcType.Args.Count=0 then
|
|
|
begin
|
|
|
- UseProcedure(TPasProcedure(Member));
|
|
|
+ UseProcedure(Proc);
|
|
|
continue;
|
|
|
end;
|
|
|
end;
|
|
|
//writeln('TPasAnalyzer.UseClassType ',El.FullName,' ',Mode,' ',Member.Name);
|
|
|
end;
|
|
|
end;
|
|
|
+
|
|
|
if AllPublished and (Member.Visibility=visPublished) then
|
|
|
begin
|
|
|
// include published
|
|
@@ -2123,6 +2158,20 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+procedure TPasAnalyzer.UseClassConstructor(El: TPasMembersType);
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+ Member: TPasElement;
|
|
|
+begin
|
|
|
+ if ElementVisited(El,pocClassConstructor) then exit;
|
|
|
+ for i:=0 to El.Members.Count-1 do
|
|
|
+ begin
|
|
|
+ Member:=TPasElement(El.Members[i]);
|
|
|
+ if (Member.ClassType=TPasClassConstructor) or (Member.ClassType=TPasClassDestructor) then
|
|
|
+ UseProcedure(TPasProcedure(Member));
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
procedure TPasAnalyzer.UseVariable(El: TPasVariable;
|
|
|
Access: TResolvedRefAccess; UseFull: boolean);
|
|
|
var
|
|
@@ -2427,6 +2476,7 @@ var
|
|
|
Usage: TPAElement;
|
|
|
i: Integer;
|
|
|
Member: TPasElement;
|
|
|
+ Members: TFPList;
|
|
|
begin
|
|
|
{$IFDEF VerbosePasAnalyzer}
|
|
|
writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
|
|
@@ -2449,21 +2499,21 @@ begin
|
|
|
exit;
|
|
|
end;
|
|
|
// emit hints for sub elements
|
|
|
+ Members:=nil;
|
|
|
C:=El.ClassType;
|
|
|
if C=TPasRecordType then
|
|
|
- begin
|
|
|
- for i:=0 to TPasRecordType(El).Members.Count-1 do
|
|
|
- EmitVariableHints(TObject(TPasRecordType(El).Members[i]) as TPasVariable);
|
|
|
- end
|
|
|
+ Members:=TPasRecordType(El).Members
|
|
|
else if C=TPasClassType then
|
|
|
begin
|
|
|
if TPasClassType(El).IsForward then exit;
|
|
|
- for i:=0 to TPasClassType(El).Members.Count-1 do
|
|
|
+ Members:=TPasClassType(El).Members;
|
|
|
+ end;
|
|
|
+ if Members<>nil then
|
|
|
+ for i:=0 to Members.Count-1 do
|
|
|
begin
|
|
|
- Member:=TPasElement(TPasClassType(El).Members[i]);
|
|
|
+ Member:=TPasElement(Members[i]);
|
|
|
EmitElementHints(Member);
|
|
|
end;
|
|
|
- end;
|
|
|
end;
|
|
|
|
|
|
procedure TPasAnalyzer.EmitVariableHints(El: TPasVariable);
|
|
@@ -2616,10 +2666,20 @@ end;
|
|
|
constructor TPasAnalyzer.Create;
|
|
|
var
|
|
|
m: TPAUseMode;
|
|
|
+ oc: TPAOtherCheckedEl;
|
|
|
begin
|
|
|
CreateTree;
|
|
|
for m in TPAUseMode do
|
|
|
- FChecked[m]:=TPasAnalyzerKeySet.Create(
|
|
|
+ FModeChecked[m]:=TPasAnalyzerKeySet.Create(
|
|
|
+ {$ifdef pas2js}
|
|
|
+ @PasElementToHashName
|
|
|
+ {$else}
|
|
|
+ @ComparePointer
|
|
|
+ {$endif}
|
|
|
+ ,nil
|
|
|
+ );
|
|
|
+ for oc in TPAOtherCheckedEl do
|
|
|
+ FOtherChecked[oc]:=TPasAnalyzerKeySet.Create(
|
|
|
{$ifdef pas2js}
|
|
|
@PasElementToHashName
|
|
|
{$else}
|
|
@@ -2638,23 +2698,29 @@ end;
|
|
|
destructor TPasAnalyzer.Destroy;
|
|
|
var
|
|
|
m: TPAUseMode;
|
|
|
+ oc: TPAOtherCheckedEl;
|
|
|
begin
|
|
|
Clear;
|
|
|
FreeAndNil(FOverrideLists);
|
|
|
FreeAndNil(FUsedElements);
|
|
|
for m in TPAUseMode do
|
|
|
- FreeAndNil(FChecked[m]);
|
|
|
+ FreeAndNil(FModeChecked[m]);
|
|
|
+ for oc in TPAOtherCheckedEl do
|
|
|
+ FreeAndNil(FOtherChecked[oc]);
|
|
|
inherited Destroy;
|
|
|
end;
|
|
|
|
|
|
procedure TPasAnalyzer.Clear;
|
|
|
var
|
|
|
m: TPAUseMode;
|
|
|
+ oc: TPAOtherCheckedEl;
|
|
|
begin
|
|
|
FOverrideLists.FreeItems;
|
|
|
FUsedElements.FreeItems;
|
|
|
for m in TPAUseMode do
|
|
|
- FChecked[m].Clear;
|
|
|
+ FModeChecked[m].Clear;
|
|
|
+ for oc in TPAOtherCheckedEl do
|
|
|
+ FOtherChecked[oc].Clear;
|
|
|
end;
|
|
|
|
|
|
procedure TPasAnalyzer.AnalyzeModule(aModule: TPasModule);
|
|
@@ -2736,7 +2802,7 @@ end;
|
|
|
|
|
|
function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean;
|
|
|
begin
|
|
|
- Result:=FChecked[paumTypeInfo].ContainsItem(El);
|
|
|
+ Result:=FModeChecked[paumTypeInfo].ContainsItem(El);
|
|
|
end;
|
|
|
|
|
|
function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean;
|