fpdocclasstree.pp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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 : String;
  64. begin
  65. Result:=(N.NodeType=ELEMENT_NODE);
  66. if Result then
  67. begin
  68. S:=N.NodeName;
  69. if NoPath then
  70. Begin
  71. Result:=(CompareText(S,AElement.Name)=0);
  72. end
  73. else
  74. begin
  75. IF Assigned(Aelement.GetModule) then
  76. PN:=Aelement.GetModule.PackageName
  77. else
  78. PN:=FPackage.Name;
  79. S:=PN+'.'+TDomElement(N)['unit']+'.'+S;
  80. Result:=(CompareText(S,AElement.PathName)=0);
  81. end;
  82. end;
  83. end;
  84. Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
  85. Var
  86. N : TDomNode;
  87. begin
  88. // Writeln('Enter TClassTreeBuilderLookForElement');
  89. Result:=PE;
  90. While (Result<>Nil) and Not NodeMatch(Result,AElement,NoPath) do
  91. Result:=Result.NextSibling;
  92. If (Result=Nil) then
  93. if Assigned(PE) then
  94. begin
  95. N:=PE.FirstChild;
  96. While (Result=Nil) and (N<>Nil) do
  97. begin
  98. if (N.NodeType=ELEMENT_NODE) then
  99. begin
  100. Result:=LookForElement(N as TDomElement,AElement,NoPath);
  101. end;
  102. N:=N.NextSibling;
  103. end;
  104. end;
  105. // Writeln('Exit TClassTreeBuilderLookForElement');
  106. end;
  107. Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; Var ACount : Integer) : TDomElement;
  108. // there are several codepaths that use uninitialized variables. (N,PE)
  109. // I initialized them to nil to at least make failures deterministic.
  110. Var
  111. PC : TPasClassType;
  112. PE : TDomElement;
  113. M : TPasModule;
  114. N : TDomNode;
  115. begin
  116. // Writeln('Enter TClassTreeBuilder.AddToClassTree');
  117. //if Assigned(AElement) then
  118. //Writeln('Addtoclasstree : ',aElement.Name);
  119. Result:=Nil; M:=Nil; N:=Nil;PE:=NIL;PC:=Nil;
  120. If (AElement=Nil) then
  121. begin
  122. Result:=FTreeStart;
  123. Exit;
  124. end
  125. else If (AElement is TPasUnresolvedTypeRef) then
  126. begin
  127. N:=LookForElement(FTreeStart,AElement,True);
  128. If (N=Nil) then
  129. PE:=FTreeStart;
  130. end
  131. else If (AElement is TPasClassType) then
  132. begin
  133. if (AElement=FParentObject) then
  134. Result:=FTreeStart
  135. else
  136. begin
  137. PC:=AElement as TPasClassType;
  138. PE:=AddToClassTree(PC.AncestorType,ACount);
  139. if PE=Nil then
  140. PE:=FTreeStart;
  141. N:=LookForElement(PE,PC,False);
  142. end
  143. end;
  144. If (N<>Nil) then
  145. begin
  146. Result:=N as TDomElement
  147. end
  148. else
  149. begin // N=NIL, PE might be nil.
  150. Inc(ACount);
  151. Result:=FClassTree.CreateElement(AElement.Name);
  152. If Not (AElement is TPasUnresolvedTypeRef) then
  153. begin
  154. M:=AElement.GetModule;
  155. if Assigned(M) then
  156. Result['unit']:=M.Name;
  157. end;
  158. if PE=Nil then
  159. begin
  160. PE:=FTreeStart
  161. end;
  162. // if not assigned, probably needs to be assigned to something else.
  163. if assigned(PE) then
  164. PE.AppendChild(Result);
  165. end;
  166. end;
  167. end.