fcl-passrc: adapt pasuseanalyzer for pas2js

git-svn-id: trunk@40013 -
This commit is contained in:
Mattias Gaertner 2018-10-22 10:39:43 +00:00
parent 9bd931e931
commit ce4ccfc0aa
2 changed files with 353 additions and 103 deletions

View File

@ -135,6 +135,10 @@ type
FParent: TPasElement; FParent: TPasElement;
FHints : TPasMemberHints; FHints : TPasMemberHints;
FHintMessage : String; FHintMessage : String;
{$ifdef pas2js}
FPasElementId: NativeInt;
class var FLastPasElementId: NativeInt;
{$endif}
{$ifdef EnablePasTreeGlobalRefCount} {$ifdef EnablePasTreeGlobalRefCount}
class var FGlobalRefCount: int64; class var FGlobalRefCount: int64;
{$endif} {$endif}
@ -175,9 +179,12 @@ type
property RefCount: LongWord read FRefCount; property RefCount: LongWord read FRefCount;
property Name: string read FName write FName; property Name: string read FName write FName;
property Parent: TPasElement read FParent Write SetParent; property Parent: TPasElement read FParent Write SetParent;
Property Hints : TPasMemberHints Read FHints Write FHints; property Hints : TPasMemberHints Read FHints Write FHints;
Property HintMessage : String Read FHintMessage Write FHintMessage; property HintMessage : String Read FHintMessage Write FHintMessage;
Property DocComment : String Read FDocComment Write FDocComment; property DocComment : String Read FDocComment Write FDocComment;
{$ifdef pas2js}
property PasElementId: NativeInt read FPasElementId; // global unique id
{$endif}
{$ifdef EnablePasTreeGlobalRefCount} {$ifdef EnablePasTreeGlobalRefCount}
class property GlobalRefCount: int64 read FGlobalRefCount write FGlobalRefCount; class property GlobalRefCount: int64 read FGlobalRefCount write FGlobalRefCount;
{$endif} {$endif}
@ -2308,6 +2315,10 @@ begin
inherited Create; inherited Create;
FName := AName; FName := AName;
FParent := AParent; FParent := AParent;
{$ifdef pas2js}
inc(FLastPasElementId);
FPasElementId:=FLastPasElementId;
{$endif}
{$ifdef EnablePasTreeGlobalRefCount} {$ifdef EnablePasTreeGlobalRefCount}
Inc(FGlobalRefCount); Inc(FGlobalRefCount);
{$endif} {$endif}

View File

@ -39,12 +39,23 @@ Working:
} }
unit PasUseAnalyzer; unit PasUseAnalyzer;
{$mode objfpc}{$H+}{$inline on} {$mode objfpc}{$H+}
{$inline on}
{$ifdef fpc}
{$define UsePChar}
{$define HasInt64}
{$endif}
interface interface
uses uses
Classes, SysUtils, Types, AVL_Tree, {$ifdef pas2js}
js,
{$else}
AVL_Tree,
{$endif}
Classes, SysUtils, Types,
PasTree, PScanner, PasResolveEval, PasResolver; PasTree, PScanner, PasResolveEval, PasResolver;
const const
@ -88,7 +99,7 @@ type
private private
FRefCount: integer; FRefCount: integer;
public public
Id: int64; Id: TMaxPrecInt;
MsgType: TMessageType; MsgType: TMessageType;
MsgNumber: integer; MsgNumber: integer;
MsgText: string; MsgText: string;
@ -148,6 +159,43 @@ type
property Overrides[Index: integer]: TPasElement read GetOverrides; default; property Overrides[Index: integer]: TPasElement read GetOverrides; default;
end; end;
{$ifdef pas2js}
TPASItemToNameProc = function(Item: Pointer): String;
{$endif}
{ TPasAnalyzerKeySet - set of items, each item has a key, no duplicate keys }
TPasAnalyzerKeySet = class
private
{$ifdef pas2js}
FItems: TJSObject;
FCount: integer;
FItemToName: TPASItemToNameProc;
FKeyToName: TPASItemToNameProc;
{$else}
FTree: TAVLTree; // tree of pointers, sorted for keys given by OnItemToKey, no duplicate keys
FCompareKeyWithData: TListSortCompare;
{$endif}
public
{$ifdef pas2js}
constructor Create(const OnItemToName, OnKeyToName: TPASItemToNameProc); reintroduce;
{$else}
constructor Create(const OnCompareMethod: TListSortCompare;
const OnCompareKeyWithData: TListSortCompare);
{$endif}
destructor Destroy; override;
procedure Clear;
procedure FreeItems;
procedure Add(Item: Pointer; CheckDuplicates: boolean = true);
procedure Remove(Item: Pointer);
function ContainsItem(Item: Pointer): boolean;
function ContainsKey(Key: Pointer): boolean;
function FindItem(Item: Pointer): Pointer;
function FindKey(Key: Pointer): Pointer;
function Count: integer;
function GetList: TFPList; // list of items
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)
paoImplReferences // collect references of top lvl proc implementations, initializationa dn finalization sections paoImplReferences // collect references of top lvl proc implementations, initializationa dn finalization sections
@ -175,29 +223,26 @@ type
TPasAnalyzer = class TPasAnalyzer = class
private private
FChecked: array[TPAUseMode] of TAVLTree; // tree of TElement FChecked: array[TPAUseMode] of TPasAnalyzerKeySet; // tree of TElement
FOnMessage: TPAMessageEvent; FOnMessage: TPAMessageEvent;
FOptions: TPasAnalyzerOptions; FOptions: TPasAnalyzerOptions;
FOverrideLists: TAVLTree; // tree of TPAOverrideList sorted for Element FOverrideLists: TPasAnalyzerKeySet; // tree of TPAOverrideList sorted for Element
FResolver: TPasResolver; FResolver: TPasResolver;
FScopeModule: TPasModule; FScopeModule: TPasModule;
FUsedElements: TAVLTree; // tree of TPAElement sorted for Element FUsedElements: TPasAnalyzerKeySet; // tree of TPAElement sorted for Element
procedure UseElType(El: TPasElement; aType: TPasType; Mode: TPAUseMode); inline; 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 FindOverrideList(El: TPasElement): TPAOverrideList;
procedure SetOptions(AValue: TPasAnalyzerOptions); procedure SetOptions(AValue: TPasAnalyzerOptions);
procedure UpdateAccess(IsWrite: Boolean; IsRead: Boolean; Usage: TPAElement); procedure UpdateAccess(IsWrite: Boolean; IsRead: Boolean; Usage: TPAElement);
procedure OnUseScopeRef(Data, DeclScope: pointer); procedure OnUseScopeRef(Data, DeclScope: pointer);
protected protected
procedure RaiseInconsistency(const Id: int64; Msg: string); procedure RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
procedure RaiseNotSupported(const Id: int64; El: TPasElement; const Msg: string = ''); procedure RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement; const Msg: string = '');
function FindTopImplScope(El: TPasElement): TPasScope; function FindTopImplScope(El: TPasElement): TPasScope;
// 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;
function FindNode(El: TPasElement): TAVLTreeNode; inline; function PAElementExists(El: TPasElement): boolean; inline;
function FindPAElement(El: TPasElement): TPAElement; inline;
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;
@ -238,7 +283,7 @@ type
procedure AnalyzeModule(aModule: TPasModule); procedure AnalyzeModule(aModule: TPasModule);
procedure AnalyzeWholeProgram(aStartModule: TPasProgram); procedure AnalyzeWholeProgram(aStartModule: TPasProgram);
procedure EmitModuleHints(aModule: TPasModule); virtual; procedure EmitModuleHints(aModule: TPasModule); virtual;
function FindElement(El: TPasElement): TPAElement; function FindElement(El: TPasElement): TPAElement; inline;
function FindUsedElement(El: TPasElement): TPAElement; function FindUsedElement(El: TPasElement): TPAElement;
// utility // utility
function IsUsed(El: TPasElement): boolean; // valid after calling Analyze* function IsUsed(El: TPasElement): boolean; // valid after calling Analyze*
@ -247,8 +292,10 @@ type
function IsExport(El: TPasElement): boolean; function IsExport(El: TPasElement): boolean;
function IsIdentifier(El: TPasElement): boolean; function IsIdentifier(El: TPasElement): boolean;
function IsImplBlockEmpty(El: TPasImplBlock): boolean; function IsImplBlockEmpty(El: TPasImplBlock): boolean;
procedure EmitMessage(Id: int64; MsgType: TMessageType; procedure EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
MsgNumber: integer; Fmt: String; const Args: array of const; PosEl: TPasElement); MsgNumber: integer; Fmt: String;
const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
PosEl: TPasElement);
procedure EmitMessage(Msg: TPAMessage); procedure EmitMessage(Msg: TPAMessage);
class function GetWarnIdentifierNumbers(Identifier: string; class function GetWarnIdentifierNumbers(Identifier: string;
out MsgNumbers: TIntegerDynArray): boolean; virtual; out MsgNumbers: TIntegerDynArray): boolean; virtual;
@ -259,15 +306,43 @@ type
property ScopeModule: TPasModule read FScopeModule write FScopeModule; property ScopeModule: TPasModule read FScopeModule write FScopeModule;
end; end;
{$ifdef pas2js}
function PasElementToHashName(Item: Pointer): String;
function PAElement_ElToHashName(Item: Pointer): String;
function PAOverrideList_ElToHashName(Item: Pointer): String;
{$else}
function ComparePAElements(Identifier1, Identifier2: Pointer): integer; function ComparePAElements(Identifier1, Identifier2: Pointer): integer;
function CompareElementWithPAElement(El, Id: Pointer): integer; function CompareElementWithPAElement(El, Id: Pointer): integer;
function ComparePAOverrideLists(List1, List2: Pointer): integer; function ComparePAOverrideLists(List1, List2: Pointer): integer;
function CompareElementWithPAOverrideList(El, List: Pointer): integer; function CompareElementWithPAOverrideList(El, List: Pointer): integer;
{$endif}
function GetElModName(El: TPasElement): string; function GetElModName(El: TPasElement): string;
function dbgs(a: TPAIdentifierAccess): string; overload; function dbgs(a: TPAIdentifierAccess): string; overload;
implementation implementation
{$ifdef pas2js}
function PasElementToHashName(Item: Pointer): String;
var
El: TPasElement absolute Item;
begin
Result:=string(jsvalue(El.PasElementId));
end;
function PAElement_ElToHashName(Item: Pointer): String;
var
El: TPAElement absolute Item;
begin
Result:=string(jsvalue(El.Element.PasElementId));
end;
function PAOverrideList_ElToHashName(Item: Pointer): String;
var
List: TPAOverrideList absolute Item;
begin
Result:=string(jsvalue(List.Element.PasElementId));
end;
{$else}
function ComparePointer(Data1, Data2: Pointer): integer; function ComparePointer(Data1, Data2: Pointer): integer;
begin begin
if Data1>Data2 then Result:=-1 if Data1>Data2 then Result:=-1
@ -304,6 +379,7 @@ var
begin begin
Result:=ComparePointer(El,OvList.Element); Result:=ComparePointer(El,OvList.Element);
end; end;
{$endif}
function GetElModName(El: TPasElement): string; function GetElModName(El: TPasElement): string;
var var
@ -324,6 +400,190 @@ begin
str(a,Result); str(a,Result);
end; end;
{ TPasAnalyzerKeySet }
{$ifdef pas2js}
constructor TPasAnalyzerKeySet.Create(const OnItemToName,
OnKeyToName: TPASItemToNameProc);
begin
FItemToName:=OnItemToName;
FKeyToName:=OnKeyToName;
FItems:=TJSObject.new;
end;
{$else}
constructor TPasAnalyzerKeySet.Create(const OnCompareMethod: TListSortCompare;
const OnCompareKeyWithData: TListSortCompare);
begin
FTree:=TAVLTree.Create(OnCompareMethod);
FCompareKeyWithData:=OnCompareKeyWithData;
end;
{$endif}
destructor TPasAnalyzerKeySet.Destroy;
begin
{$ifdef pas2js}
FItems:=nil;
{$else}
FreeAndNil(FTree);
{$endif}
inherited Destroy;
end;
procedure TPasAnalyzerKeySet.Clear;
begin
{$ifdef pas2js}
FItems:=TJSObject.new;
FCount:=0;
{$else}
FTree.Clear;
{$endif}
end;
procedure TPasAnalyzerKeySet.FreeItems;
{$ifdef pas2js}
var
List: TStringDynArray;
i: Integer;
begin
List:=TJSObject.getOwnPropertyNames(FItems);
for i:=0 to length(List)-1 do
TObject(FItems[List[i]]).Destroy;
FItems:=TJSObject.new;
FCount:=0;
end;
{$else}
begin
FTree.FreeAndClear;
end;
{$endif}
procedure TPasAnalyzerKeySet.Add(Item: Pointer; CheckDuplicates: boolean);
begin
if CheckDuplicates then
if ContainsItem(Item) then
raise Exception.Create('TPasAnalyzerSet.Add duplicate');
{$ifdef pas2js}
FItems[FItemToName(Item)]:=Item;
inc(FCount);
{$else}
FTree.Add(Item);
{$endif}
end;
procedure TPasAnalyzerKeySet.Remove(Item: Pointer);
{$ifdef pas2js}
var
aName: string;
begin
aName:=FItemToName(Item);
if not FItems.hasOwnProperty(aName) then exit;
JSDelete(FItems,aName);
dec(FCount);
end;
{$else}
begin
FTree.Remove(Item);
end;
{$endif}
function TPasAnalyzerKeySet.ContainsItem(Item: Pointer): boolean;
begin
{$ifdef pas2js}
Result:=FItems.hasOwnProperty(FItemToName(Item));
{$else}
Result:=FTree.Find(Item)<>nil;
{$endif}
end;
function TPasAnalyzerKeySet.ContainsKey(Key: Pointer): boolean;
begin
{$ifdef pas2js}
Result:=FItems.hasOwnProperty(FKeyToName(Key));
{$else}
Result:=FTree.FindKey(Key,FCompareKeyWithData)<>nil;
{$endif}
end;
function TPasAnalyzerKeySet.FindItem(Item: Pointer): Pointer;
{$ifdef pas2js}
var
aName: string;
begin
aName:=FItemToName(Item);
if not FItems.hasOwnProperty(aName) then
exit(nil)
else
Result:=Pointer(FItems[aName]);
end;
{$else}
var
Node: TAVLTreeNode;
begin
Node:=FTree.Find(Item);
if Node<>nil then
Result:=Node.Data
else
Result:=nil;
end;
{$endif}
function TPasAnalyzerKeySet.FindKey(Key: Pointer): Pointer;
{$ifdef pas2js}
var
aName: string;
begin
aName:=FKeyToName(Key);
if not FItems.hasOwnProperty(aName) then
exit(nil)
else
Result:=Pointer(FItems[aName]);
end;
{$else}
var
Node: TAVLTreeNode;
begin
Node:=FTree.FindKey(Key,FCompareKeyWithData);
if Node<>nil then
Result:=Node.Data
else
Result:=nil;
end;
{$endif}
function TPasAnalyzerKeySet.Count: integer;
begin
{$ifdef pas2js}
Result:=FCount;
{$else}
Result:=FTree.Count;
{$endif}
end;
function TPasAnalyzerKeySet.GetList: TFPList;
{$ifdef pas2js}
var
List: TStringDynArray;
i: Integer;
begin
List:=TJSObject.getOwnPropertyNames(FItems);
Result:=TFPList.Create;
for i:=0 to length(List)-1 do
Result.Add(FItems[List[i]]);
end;
{$else}
var
Node: TAVLTreeNode;
begin
Result:=TFPList.Create;
Node:=FTree.FindLowest;
while Node<>nil do
begin
Result.Add(Node.Data);
Node:=FTree.FindSuccessor(Node);
end;
end;
{$endif}
{ TPAMessage } { TPAMessage }
constructor TPAMessage.Create; constructor TPAMessage.Create;
@ -342,7 +602,11 @@ begin
raise Exception.Create(''); raise Exception.Create('');
dec(FRefCount); dec(FRefCount);
if FRefCount=0 then if FRefCount=0 then
{$ifdef pas2js}
Destroy;
{$else}
Free; Free;
{$endif}
end; end;
{ TPAOverrideList } { TPAOverrideList }
@ -417,21 +681,9 @@ end;
{ TPasAnalyzer } { TPasAnalyzer }
// inline // inline
function TPasAnalyzer.FindNode(El: TPasElement): TAVLTreeNode; function TPasAnalyzer.PAElementExists(El: TPasElement): boolean;
begin begin
Result:=FUsedElements.FindKey(El,@CompareElementWithPAElement); Result:=FUsedElements.ContainsKey(El);
end;
// inline
function TPasAnalyzer.FindPAElement(El: TPasElement): TPAElement;
var
Node: TAVLTreeNode;
begin
Node:=FindNode(El);
if Node=nil then
Result:=nil
else
Result:=TPAElement(Node.Data);
end; end;
// inline // inline
@ -443,33 +695,22 @@ begin
UseType(aType,Mode); UseType(aType,Mode);
end; end;
// inline
function TPasAnalyzer.FindElement(El: TPasElement): TPAElement;
begin
Result:=TPAElement(FUsedElements.FindKey(El));
end;
procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions); procedure TPasAnalyzer.SetOptions(AValue: TPasAnalyzerOptions);
begin begin
if FOptions=AValue then Exit; if FOptions=AValue then Exit;
FOptions:=AValue; FOptions:=AValue;
end; end;
function TPasAnalyzer.FindOverrideNode(El: TPasElement): TAVLTreeNode;
begin
Result:=FOverrideLists.FindKey(El,@CompareElementWithPAOverrideList);
end;
function TPasAnalyzer.FindOverrideList(El: TPasElement): TPAOverrideList;
var
Node: TAVLTreeNode;
begin
Node:=FindOverrideNode(El);
if Node=nil then
Result:=nil
else
Result:=TPAOverrideList(Node.Data);
end;
function TPasAnalyzer.AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean; function TPasAnalyzer.AddOverride(OverriddenEl, OverrideEl: TPasElement): boolean;
// OverrideEl overrides OverriddenEl // OverrideEl overrides OverriddenEl
// returns true if new override // returns true if new override
var var
Node: TAVLTreeNode;
Item: TPAOverrideList; Item: TPAOverrideList;
OverriddenPAEl: TPAElement; OverriddenPAEl: TPAElement;
TypeEl: TPasType; TypeEl: TPasType;
@ -477,16 +718,15 @@ begin
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.AddOverride OverriddenEl=',GetElModName(OverriddenEl),' OverrideEl=',GetElModName(OverrideEl)); writeln('TPasAnalyzer.AddOverride OverriddenEl=',GetElModName(OverriddenEl),' OverrideEl=',GetElModName(OverrideEl));
{$ENDIF} {$ENDIF}
Node:=FindOverrideNode(OverriddenEl); Item:=TPAOverrideList(FOverrideLists.FindKey(OverriddenEl));
if Node=nil then if Item=nil then
begin begin
Item:=TPAOverrideList.Create; Item:=TPAOverrideList.Create;
Item.Element:=OverriddenEl; Item.Element:=OverriddenEl;
FOverrideLists.Add(Item); FOverrideLists.Add(Item,false);
end end
else else
begin begin
Item:=TPAOverrideList(Node.Data);
if Item.IndexOf(OverrideEl)>=0 then if Item.IndexOf(OverrideEl)>=0 then
exit(false); exit(false);
end; end;
@ -494,7 +734,7 @@ begin
Item.Add(OverrideEl); Item.Add(OverrideEl);
Result:=true; Result:=true;
OverriddenPAEl:=FindPAElement(OverriddenEl); OverriddenPAEl:=FindElement(OverriddenEl);
if OverriddenPAEl<>nil then if OverriddenPAEl<>nil then
begin begin
// OverriddenEl was already used -> use OverrideEl // OverriddenEl was already used -> use OverrideEl
@ -567,7 +807,7 @@ begin
end; end;
end; end;
procedure TPasAnalyzer.RaiseInconsistency(const Id: int64; Msg: string); procedure TPasAnalyzer.RaiseInconsistency(const Id: TMaxPrecInt; Msg: string);
begin begin
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.RaiseInconsistency ['+IntToStr(Id)+']: '+Msg); writeln('TPasAnalyzer.RaiseInconsistency ['+IntToStr(Id)+']: '+Msg);
@ -575,7 +815,7 @@ begin
raise EPasAnalyzer.Create('['+IntToStr(Id)+']: '+Msg); raise EPasAnalyzer.Create('['+IntToStr(Id)+']: '+Msg);
end; end;
procedure TPasAnalyzer.RaiseNotSupported(const Id: int64; El: TPasElement; procedure TPasAnalyzer.RaiseNotSupported(const Id: TMaxPrecInt; El: TPasElement;
const Msg: string); const Msg: string);
var var
s: String; s: String;
@ -626,9 +866,9 @@ begin
if El=nil then if El=nil then
RaiseInconsistency(20170308093407,''); RaiseInconsistency(20170308093407,'');
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.Add ',GetElModName(El),' New=',FindNode(El)=nil); writeln('TPasAnalyzer.Add ',GetElModName(El),' New=',not PAElementExists(El));
{$ENDIF} {$ENDIF}
if CheckDuplicate and (FindNode(El)<>nil) then if CheckDuplicate and PAElementExists(El) then
RaiseInconsistency(20170304201318,''); RaiseInconsistency(20170304201318,'');
if aClass=nil then if aClass=nil then
aClass:=TPAElement; aClass:=TPAElement;
@ -636,13 +876,18 @@ begin
Result.Element:=El; Result.Element:=El;
FUsedElements.Add(Result); FUsedElements.Add(Result);
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
//writeln('TPasAnalyzer.Add END ',GetElModName(El),' Success=',FindNode(El)<>nil,' ',ptruint(pointer(El))); //writeln('TPasAnalyzer.Add END ',GetElModName(El),' Success=',PAElementExists(El),' ',ptruint(pointer(El)));
{$ENDIF} {$ENDIF}
end; end;
procedure TPasAnalyzer.CreateTree; procedure TPasAnalyzer.CreateTree;
begin begin
FUsedElements:=TAVLTree.Create(@ComparePAElements); FUsedElements:=TPasAnalyzerKeySet.Create(
{$ifdef pas2js}
@PAElement_ElToHashName,@PasElementToHashName
{$else}
@ComparePAElements,@CompareElementWithPAElement
{$endif});
end; end;
function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass
@ -650,7 +895,7 @@ function TPasAnalyzer.MarkElementAsUsed(El: TPasElement; aClass: TPAElementClass
function MarkModule(CurModule: TPasModule): boolean; function MarkModule(CurModule: TPasModule): boolean;
begin begin
if FindNode(CurModule)<>nil then if PAElementExists(CurModule) then
exit(false); exit(false);
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.MarkElement.MarkModule mark "',GetElModName(CurModule),'"'); writeln('TPasAnalyzer.MarkElement.MarkModule mark "',GetElModName(CurModule),'"');
@ -686,7 +931,7 @@ begin
end; end;
// mark element // mark element
if FindNode(El)<>nil then exit(false); if PAElementExists(El) then exit(false);
Add(El,false,aClass); Add(El,false,aClass);
Result:=true; Result:=true;
@ -705,9 +950,9 @@ function TPasAnalyzer.ElementVisited(El: TPasElement; Mode: TPAUseMode
begin begin
if El=nil then if El=nil then
exit(true); exit(true);
if FChecked[Mode].Find(El)<>nil then exit(true); if FChecked[Mode].ContainsItem(El) then exit(true);
Result:=false; Result:=false;
FChecked[Mode].Add(El); FChecked[Mode].Add(El,false);
end; end;
procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement; procedure TPasAnalyzer.MarkImplScopeRef(El, RefEl: TPasElement;
@ -900,7 +1145,7 @@ procedure TPasAnalyzer.UseModule(aModule: TPasModule; Mode: TPAUseMode);
UseScopeReferences(Scope.References); UseScopeReferences(Scope.References);
if (Scope.References=nil) and IsImplBlockEmpty(ImplBlock) then exit; if (Scope.References=nil) and 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 not PAElementExists(aModule) then
Add(aModule); Add(aModule);
UseImplBlock(ImplBlock,true); UseImplBlock(ImplBlock,true);
end; end;
@ -936,7 +1181,7 @@ begin
if Mode=paumElement then if Mode=paumElement then
// e.g. a reference: unitname.identifier // e.g. a reference: unitname.identifier
if FindNode(aModule)=nil then if not PAElementExists(aModule) then
Add(aModule); Add(aModule);
end; end;
@ -979,7 +1224,7 @@ begin
if IsImplBlockEmpty(UsedModule.InitializationSection) if IsImplBlockEmpty(UsedModule.InitializationSection)
and IsImplBlockEmpty(UsedModule.FinalizationSection) then and IsImplBlockEmpty(UsedModule.FinalizationSection) then
continue; continue;
if FindNode(UsedModule)=nil then if not PAElementExists(UsedModule) then
Add(UsedModule); Add(UsedModule);
UseImplBlock(UsedModule.InitializationSection,true); UseImplBlock(UsedModule.InitializationSection,true);
UseImplBlock(UsedModule.FinalizationSection,true); UseImplBlock(UsedModule.FinalizationSection,true);
@ -1427,7 +1672,7 @@ procedure TPasAnalyzer.UseProcedure(Proc: TPasProcedure);
i: Integer; i: Integer;
OverrideProc: TPasProcedure; OverrideProc: TPasProcedure;
begin begin
OverrideList:=FindOverrideList(CurProc); OverrideList:=TPAOverrideList(FOverrideLists.FindKey(CurProc));
if OverrideList=nil then exit; if OverrideList=nil then exit;
// Note: while traversing the OverrideList it may grow // Note: while traversing the OverrideList it may grow
i:=0; i:=0;
@ -1637,7 +1882,7 @@ procedure TPasAnalyzer.UseClassType(El: TPasClassType; Mode: TPAUseMode);
i: Integer; i: Integer;
Prop: TPasProperty; Prop: TPasProperty;
begin begin
OverrideList:=FindOverrideList(El); OverrideList:=TPAOverrideList(FOverrideLists.FindKey(El));
if OverrideList=nil then exit; if OverrideList=nil then exit;
// Note: while traversing the OverrideList it may grow // Note: while traversing the OverrideList it may grow
i:=0; i:=0;
@ -2099,7 +2344,7 @@ begin
begin begin
UsedModule:=TPasModule(Use.Module); UsedModule:=TPasModule(Use.Module);
if CompareText(UsedModule.Name,'system')=0 then continue; if CompareText(UsedModule.Name,'system')=0 then continue;
if FindNode(UsedModule)=nil then if not PAElementExists(UsedModule) then
EmitMessage(20170311191725,mtHint,nPAUnitNotUsed,sPAUnitNotUsed, EmitMessage(20170311191725,mtHint,nPAUnitNotUsed,sPAUnitNotUsed,
[UsedModule.Name,aModule.Name],Use.Expr); [UsedModule.Name,aModule.Name],Use.Expr);
end; end;
@ -2128,7 +2373,7 @@ begin
EmitProcedureHints(TPasProcedure(Decl)) EmitProcedureHints(TPasProcedure(Decl))
else else
begin begin
Usage:=FindPAElement(Decl); Usage:=FindElement(Decl);
if Usage=nil then if Usage=nil then
begin begin
// declaration was never used // declaration was never used
@ -2149,7 +2394,7 @@ begin
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El)); writeln('TPasAnalyzer.EmitTypeHints ',GetElModName(El));
{$ENDIF} {$ENDIF}
Usage:=FindPAElement(El); Usage:=FindElement(El);
if Usage=nil then if Usage=nil then
begin begin
// the whole type was never used // the whole type was never used
@ -2191,7 +2436,7 @@ begin
{$IFDEF VerbosePasAnalyzer} {$IFDEF VerbosePasAnalyzer}
writeln('TPasAnalyzer.EmitVariableHints ',GetElModName(El)); writeln('TPasAnalyzer.EmitVariableHints ',GetElModName(El));
{$ENDIF} {$ENDIF}
Usage:=FindPAElement(El); Usage:=FindElement(El);
if Usage=nil then if Usage=nil then
begin begin
// not used // not used
@ -2251,7 +2496,7 @@ begin
ImplProc:=El ImplProc:=El
else else
ImplProc:=ProcScope.ImplProc; ImplProc:=ProcScope.ImplProc;
if FindNode(DeclProc)=nil then if not PAElementExists(DeclProc) then
begin begin
// procedure never used // procedure never used
if ProcScope.DeclarationProc=nil then if ProcScope.DeclarationProc=nil then
@ -2282,7 +2527,7 @@ begin
for i:=0 to Args.Count-1 do for i:=0 to Args.Count-1 do
begin begin
Arg:=TPasArgument(Args[i]); Arg:=TPasArgument(Args[i]);
Usage:=FindPAElement(Arg); Usage:=FindElement(Arg);
if (Usage=nil) or (Usage.Access=paiaNone) then if (Usage=nil) or (Usage.Access=paiaNone) then
begin begin
// parameter was never used // parameter was never used
@ -2308,7 +2553,7 @@ begin
PosEl:=TPasFunction(El).FuncType.ResultEl; PosEl:=TPasFunction(El).FuncType.ResultEl;
if (ProcScope.ImplProc<>nil) and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then if (ProcScope.ImplProc<>nil) and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then
PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl; PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl;
Usage:=FindPAElement(TPasFunction(El).FuncType.ResultEl); Usage:=FindElement(TPasFunction(El).FuncType.ResultEl);
if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then
// result was never used // result was never used
EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet, EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet,
@ -2334,8 +2579,20 @@ var
begin begin
CreateTree; CreateTree;
for m in TPAUseMode do for m in TPAUseMode do
FChecked[m]:=TAVLTree.Create; FChecked[m]:=TPasAnalyzerKeySet.Create(
FOverrideLists:=TAVLTree.Create(@ComparePAOverrideLists); {$ifdef pas2js}
@PasElementToHashName
{$else}
@ComparePointer
{$endif}
,nil
);
FOverrideLists:=TPasAnalyzerKeySet.Create(
{$ifdef pas2js}
@PAOverrideList_ElToHashName,@PasElementToHashName
{$else}
@ComparePAOverrideLists,@CompareElementWithPAOverrideList
{$endif});
end; end;
destructor TPasAnalyzer.Destroy; destructor TPasAnalyzer.Destroy;
@ -2354,8 +2611,8 @@ procedure TPasAnalyzer.Clear;
var var
m: TPAUseMode; m: TPAUseMode;
begin begin
FOverrideLists.FreeAndClear; FOverrideLists.FreeItems;
FUsedElements.FreeAndClear; FUsedElements.FreeItems;
for m in TPAUseMode do for m in TPAUseMode do
FChecked[m].Clear; FChecked[m].Clear;
end; end;
@ -2418,17 +2675,6 @@ begin
//EmitBlockHints(aModule.FinalizationSection); //EmitBlockHints(aModule.FinalizationSection);
end; end;
function TPasAnalyzer.FindElement(El: TPasElement): TPAElement;
var
Node: TAVLTreeNode;
begin
Node:=FindNode(El);
if Node=nil then
Result:=nil
else
Result:=TPAElement(Node.Data);
end;
function TPasAnalyzer.FindUsedElement(El: TPasElement): TPAElement; function TPasAnalyzer.FindUsedElement(El: TPasElement): TPAElement;
var var
ProcScope: TPasProcedureScope; ProcScope: TPasProcedureScope;
@ -2450,7 +2696,7 @@ end;
function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean; function TPasAnalyzer.IsTypeInfoUsed(El: TPasElement): boolean;
begin begin
Result:=FChecked[paumTypeInfo].Find(El)<>nil; Result:=FChecked[paumTypeInfo].ContainsItem(El);
end; end;
function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean; function TPasAnalyzer.IsModuleInternal(El: TPasElement): boolean;
@ -2497,8 +2743,9 @@ begin
Result:=false; Result:=false;
end; end;
procedure TPasAnalyzer.EmitMessage(Id: int64; MsgType: TMessageType; procedure TPasAnalyzer.EmitMessage(Id: TMaxPrecInt; MsgType: TMessageType;
MsgNumber: integer; Fmt: String; const Args: array of const; MsgNumber: integer; Fmt: String;
const Args: array of {$ifdef pas2js}jsvalue{$else}const{$endif};
PosEl: TPasElement); PosEl: TPasElement);
var var
Msg: TPAMessage; Msg: TPAMessage;
@ -2617,16 +2864,8 @@ begin
end; end;
function TPasAnalyzer.GetUsedElements: TFPList; function TPasAnalyzer.GetUsedElements: TFPList;
var
Node: TAVLTreeNode;
begin begin
Result:=TFPList.Create; Result:=FUsedElements.GetList;
Node:=FUsedElements.FindLowest;
while Node<>nil do
begin
Result.Add(Node.Data);
Node:=FUsedElements.FindSuccessor(Node);
end;
end; end;
end. end.