fpdocclasstree.pp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. Var
  28. N : TDomNode;
  29. begin
  30. FCLassTree:=TXMLDocument.Create;
  31. FPackage:=APAckage;
  32. FObjectKind:=AObjectKind;
  33. Case FObjectkind of
  34. okObject : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
  35. okClass : FParentObject:=TPasClassType.Create('System.TObject',FPackage);
  36. okInterface : FParentObject:=TPasClassType.Create('System.IInterface',FPackage);
  37. end;
  38. FParentObject.ObjKind:=FObjectKind;
  39. FTreeStart:=FClassTree.CreateElement('TObject');
  40. FTreeStart['unit']:='System';
  41. ClassTree.AppendChild(FTreeStart);
  42. end;
  43. destructor TClassTreeBuilder.Destroy;
  44. begin
  45. FreeAndNil(FParentObject);
  46. FreeAndNil(FClassTree);
  47. Inherited;
  48. end;
  49. Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
  50. Var
  51. I : Integer;
  52. PC : TPasClassType;
  53. begin
  54. Result:=0;
  55. AObjects.Sorted:=True;
  56. For I:=0 to AObjects.Count-1 do
  57. begin
  58. PC:=AObjects.Objects[i] as TPasClassType;
  59. If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
  60. AddToClassTree(PC,Result);
  61. end;
  62. end;
  63. Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
  64. Var
  65. PN,S : String;
  66. begin
  67. Result:=(N.NodeType=ELEMENT_NODE);
  68. if Result then
  69. begin
  70. S:=N.NodeName;
  71. if NoPath then
  72. Begin
  73. Result:= (CompareText(S,AElement.Name)=0);
  74. end
  75. else
  76. begin
  77. IF Assigned(Aelement.GetModule) then
  78. PN:=Aelement.GetModule.PackageName
  79. else
  80. PN:=FPackage.Name;
  81. S:=PN+'.'+TDomElement(N)['unit']+'.'+S;
  82. Result:=(CompareText(S,AElement.PathName)=0);
  83. end;
  84. end;
  85. end;
  86. Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
  87. Var
  88. N : TDomNode;
  89. begin
  90. // Writeln('Enter TClassTreeBuilderLookForElement');
  91. Result:=PE;
  92. While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
  93. Result:=Result.NextSibling;
  94. If (Result=Nil) then
  95. if Assigned(PE) then
  96. begin
  97. N:=PE.FirstChild;
  98. While (Result=Nil) and (N<>Nil) do
  99. begin
  100. if (N.NodeType=ELEMENT_NODE) then
  101. begin
  102. Result:=LookForElement(N as TDomElement,AElement,NoPath);
  103. end;
  104. N:=N.NextSibling;
  105. end;
  106. end;
  107. // Writeln('Exit TClassTreeBuilderLookForElement');
  108. end;
  109. Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
  110. // there are several codepaths that use uninitialized variables. (N,PE)
  111. // I initialized them to nil to at least make failures deterministic.
  112. Var
  113. PC : TPasClassType;
  114. PE : TDomElement;
  115. M : TPasModule;
  116. N : TDomNode;
  117. begin
  118. //Writeln('Enter TClassTreeBuilder.AddToClassTree');
  119. //if Assigned(AElement) then
  120. //Writeln('Addtoclasstree : ',aElement.Name);
  121. Result:=Nil; N:=Nil;PE:=NIL;
  122. If (AElement=Nil) then
  123. begin
  124. Result:=FTreeStart;
  125. Exit;
  126. end
  127. else If (AElement is TPasUnresolvedTypeRef) then
  128. begin
  129. N:=LookForElement(FTreeStart,AElement,True);
  130. If (N=Nil) then
  131. begin
  132. PE:=FTreeStart;
  133. end
  134. end
  135. else If (AElement is TPasClassType) then
  136. begin
  137. if (AElement=FParentObject) then
  138. Result:=FTreeStart
  139. else
  140. begin
  141. PC:=AElement as TPasClassType;
  142. PE:=AddToClassTree(PC.AncestorType,ACount);
  143. if PE=Nil then
  144. PE:=FTreeStart;
  145. N:=LookForElement(PE,PC,False);
  146. end
  147. end;
  148. If (N<>Nil) then
  149. begin
  150. // if Assigned(PC) then
  151. // Writeln(PC.Name,' already in tree');
  152. Result:=N as TDomElement
  153. end
  154. else
  155. begin // N=NIL, PE might be nil.
  156. Inc(ACount);
  157. Result:=FClassTree.CreateElement(AElement.Name);
  158. If Not (AElement is TPasUnresolvedTypeRef) then
  159. begin
  160. M:=AElement.GetModule;
  161. if Assigned(M) then
  162. Result['unit']:=M.Name;
  163. end;
  164. if PE=Nil then
  165. begin
  166. //Writeln('PE = nil detected for ',AElement.PathName);
  167. PE:=FTreeStart
  168. end;
  169. //Writeln('Appending to ',PE.NodeName);
  170. // if not assigned, probably needs to be assigned to something else.
  171. if assigned(PE) then
  172. PE.AppendChild(Result);
  173. end;
  174. end;
  175. end.