fpdocclasstree.pp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. unit fpdocclasstree;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, DOM, pastree;
  6. Type
  7. TClassTreeBuilder = Class
  8. Private
  9. FClassTree : TXMLDocument;
  10. FTreeStart : TDomElement;
  11. FObjectKind : TPasObjKind;
  12. FPackage: TPasPackage;
  13. FParentObject : TPasClassType;
  14. Protected
  15. function LookForElement(PE: TDomElement; AElement: TPasElement; NoPath : Boolean): TDomNode;
  16. function NodeMatch(N: TDomNode; AElement: TPasElement; NoPath : Boolean): Boolean;
  17. Function AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
  18. Public
  19. Constructor Create(APackage : TPasPackage; AObjectKind : TPasObjKind = okClass);
  20. Destructor Destroy; override;
  21. Function BuildTree(AObjects : TStringList) : Integer;
  22. Property ClassTree : TXMLDocument Read FClassTree;
  23. end;
  24. implementation
  25. constructor TClassTreeBuilder.Create(APackage : TPasPackage;
  26. AObjectKind: TPasObjKind);
  27. begin
  28. FCLassTree:=TXMLDocument.Create;
  29. FPackage:=APAckage;
  30. FObjectKind:=AObjectKind;
  31. Case FObjectkind of
  32. okObject : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
  33. okClass : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
  34. okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
  35. end;
  36. FParentObject.ObjKind:=FObjectKind;
  37. FTreeStart:=FClassTree.CreateElement('TObject');
  38. FTreeStart['unit']:='System';
  39. ClassTree.AppendChild(FTreeStart);
  40. end;
  41. destructor TClassTreeBuilder.Destroy;
  42. begin
  43. FreeAndNil(FParentObject);
  44. FreeAndNil(FClassTree);
  45. Inherited;
  46. end;
  47. Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
  48. Var
  49. I : Integer;
  50. PC : TPasClassType;
  51. begin
  52. Result:=0;
  53. AObjects.Sorted:=True;
  54. For I:=0 to AObjects.Count-1 do
  55. begin
  56. PC:=AObjects.Objects[i] as TPasClassType;
  57. If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
  58. AddToClassTree(PC,Result);
  59. end;
  60. end;
  61. Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
  62. Var
  63. PN,S,EN : String;
  64. begin
  65. EN:=AELement.Name;
  66. Result:=(N.NodeType=ELEMENT_NODE);
  67. if Result then
  68. begin
  69. S:=UTF8Encode(N.NodeName);
  70. if NoPath then
  71. Begin
  72. Result:=CompareText(S,EN)=0;
  73. end
  74. else
  75. begin
  76. IF Assigned(Aelement.GetModule) then
  77. PN:=Aelement.GetModule.PackageName
  78. else
  79. PN:=FPackage.Name;
  80. S:=PN+'.'+UTF8Encode(TDomElement(N)['unit'])+'.'+S;
  81. Result:=(CompareText(S,AElement.PathName)=0);
  82. end;
  83. end;
  84. end;
  85. Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
  86. Var
  87. N : TDomNode;
  88. begin
  89. // Writeln('Enter TClassTreeBuilderLookForElement');
  90. Result:=PE;
  91. While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
  92. Result:=Result.NextSibling;
  93. If (Result=Nil) then
  94. if Assigned(PE) then
  95. begin
  96. N:=PE.FirstChild;
  97. While (Result=Nil) and (N<>Nil) do
  98. begin
  99. if (N.NodeType=ELEMENT_NODE) then
  100. begin
  101. Result:=LookForElement(N as TDomElement,AElement,NoPath);
  102. end;
  103. N:=N.NextSibling;
  104. end;
  105. end;
  106. // Writeln('Exit TClassTreeBuilderLookForElement');
  107. end;
  108. Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
  109. // there are several codepaths that use uninitialized variables. (N,PE)
  110. // I initialized them to nil to at least make failures deterministic.
  111. Var
  112. PC : TPasClassType;
  113. PE : TDomElement;
  114. M : TPasModule;
  115. N : TDomNode;
  116. begin
  117. // Writeln('Enter TClassTreeBuilder.AddToClassTree');
  118. //if Assigned(AElement) then
  119. //Writeln('Addtoclasstree : ',aElement.Name);
  120. Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
  121. If (AElement=Nil) then
  122. begin
  123. Result:=FTreeStart;
  124. Exit;
  125. end
  126. else If (AElement is TPasUnresolvedTypeRef) then
  127. begin
  128. N:=LookForElement(FTreeStart,AElement,True);
  129. If (N=Nil) then
  130. PE:=FTreeStart;
  131. end
  132. else If (AElement is TPasClassType) then
  133. begin
  134. if (AElement=FParentObject) then
  135. Result:=FTreeStart
  136. else
  137. begin
  138. PC:=AElement as TPasClassType;
  139. PE:=AddToClassTree(PC.AncestorType,ACount);
  140. if PE=Nil then
  141. PE:=FTreeStart;
  142. N:=LookForElement(PE,PC,False);
  143. end
  144. end;
  145. If (N<>Nil) then
  146. begin
  147. Result:=N as TDomElement
  148. end
  149. else if AElement.Name<>'' then
  150. begin // N=NIL, PE might be nil.
  151. Inc(ACount);
  152. Result:=FClassTree.CreateElement(UTF8Decode(AElement.Name));
  153. If Not (AElement is TPasUnresolvedTypeRef) then
  154. begin
  155. M:=AElement.GetModule;
  156. if Assigned(M) then
  157. Result['unit']:=UTF8Decode(M.Name);
  158. end;
  159. if PE=Nil then
  160. begin
  161. PE:=FTreeStart
  162. end;
  163. // if not assigned, probably needs to be assigned to something else.
  164. if assigned(PE) then
  165. PE.AppendChild(Result);
  166. end;
  167. end;
  168. end.