fpc/utils/fpdoc/fpdocclasstree.pp
marco 35109f800d # revisions: 40925
git-svn-id: branches/fixes_3_2@41999 -
2019-05-05 15:36:41 +00:00

190 lines
4.8 KiB
ObjectPascal

unit fpdocclasstree;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, DOM, pastree;
Type
TClassTreeBuilder = Class
Private
FClassTree : TXMLDocument;
FTreeStart : TDomElement;
FObjectKind : TPasObjKind;
FPackage: TPasPackage;
FParentObject : TPasClassType;
Protected
function LookForElement(PE: TDomElement; AElement: TPasElement; NoPath : Boolean): TDomNode;
function NodeMatch(N: TDomNode; AElement: TPasElement; NoPath : Boolean): Boolean;
Function AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
Public
Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
Destructor Destroy; override;
Function BuildTree(AObjects : TStringList) : Integer;
Property ClassTree : TXMLDocument Read FClassTree;
end;
implementation
constructor TClassTreeBuilder.Create(APackage : TPasPackage;
AObjectKind: TPasObjKind);
begin
FCLassTree:=TXMLDocument.Create;
FPackage:=APAckage;
FObjectKind:=AObjectKind;
Case FObjectkind of
okObject : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
okClass : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
end;
FParentObject.ObjKind:=FObjectKind;
FTreeStart:=FClassTree.CreateElement('TObject');
FTreeStart['unit']:='System';
ClassTree.AppendChild(FTreeStart);
end;
destructor TClassTreeBuilder.Destroy;
begin
FreeAndNil(FParentObject);
FreeAndNil(FClassTree);
Inherited;
end;
Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
Var
I : Integer;
PC : TPasClassType;
begin
Result:=0;
AObjects.Sorted:=True;
For I:=0 to AObjects.Count-1 do
begin
PC:=AObjects.Objects[i] as TPasClassType;
If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
AddToClassTree(PC,Result);
end;
end;
Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
Var
PN,S,EN : String;
begin
EN:=AELement.Name;
Result:=(N.NodeType=ELEMENT_NODE);
if Result then
begin
S:=UTF8Encode(N.NodeName);
if NoPath then
Begin
Result:=CompareText(S,EN)=0;
end
else
begin
IF Assigned(Aelement.GetModule) then
PN:=Aelement.GetModule.PackageName
else
PN:=FPackage.Name;
S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S;
Result:=(CompareText(S,AElement.PathName)=0);
end;
end;
end;
Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
Var
N : TDomNode;
begin
// Writeln('Enter TClassTreeBuilderLookForElement');
Result:=PE;
While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
Result:=Result.NextSibling;
If (Result=Nil) then
if Assigned(PE) then
begin
N:=PE.FirstChild;
While (Result=Nil) and (N<>Nil) do
begin
if (N.NodeType=ELEMENT_NODE) then
begin
Result:=LookForElement(N as TDomElement,AElement,NoPath);
end;
N:=N.NextSibling;
end;
end;
// Writeln('Exit TClassTreeBuilderLookForElement');
end;
Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
// there are several codepaths that use uninitialized variables. (N,PE)
// I initialized them to nil to at least make failures deterministic.
Var
PC : TPasClassType;
PE : TDomElement;
M : TPasModule;
N : TDomNode;
begin
// Writeln('Enter TClassTreeBuilder.AddToClassTree');
//if Assigned(AElement) then
//Writeln('Addtoclasstree : ',aElement.Name);
Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
If (AElement=Nil) then
begin
Result:=FTreeStart;
Exit;
end
else If (AElement is TPasUnresolvedTypeRef) then
begin
N:=LookForElement(FTreeStart,AElement,True);
If (N=Nil) then
PE:=FTreeStart;
end
else If (AElement is TPasClassType) then
begin
if (AElement=FParentObject) then
Result:=FTreeStart
else
begin
PC:=AElement as TPasClassType;
PE:=AddToClassTree(PC.AncestorType,ACount);
if PE=Nil then
PE:=FTreeStart;
N:=LookForElement(PE,PC,False);
end
end;
If (N<>Nil) then
begin
Result:=N as TDomElement
end
else if AElement.Name<>'' then
begin // N=NIL, PE might be nil.
Inc(ACount);
Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name));
If Not (AElement is TPasUnresolvedTypeRef) then
begin
M:=AElement.GetModule;
if Assigned(M) then
Result['unit']:=UTF8Decode(M.Name);
end;
if PE=Nil then
begin
PE:=FTreeStart
end;
// if not assigned, probably needs to be assigned to something else.
if assigned(PE) then
PE.AppendChild(Result);
end;
end;
end.