2
0

fpdocclasstree.pp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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; 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(FClassTree);
  46. Inherited;
  47. end;
  48. Function TClassTreeBuilder.BuildTree(AObjects : TStringList) : Integer;
  49. Var
  50. I : Integer;
  51. PC : TPasClassType;
  52. begin
  53. Result:=0;
  54. AObjects.Sorted:=True;
  55. For I:=0 to AObjects.Count-1 do
  56. begin
  57. PC:=TPasClassType(AObjects.Objects[i]);
  58. If (PC.ObjKind=FObjectKind) and Not PC.IsForward then
  59. begin
  60. AddToClassTree(PC as TPasElement,Result)
  61. end;
  62. end;
  63. end;
  64. Function TClassTreeBuilder.NodeMatch(N : TDomNode; AElement : TPasElement; NoPath : Boolean) : Boolean;
  65. Var
  66. PN,S : String;
  67. begin
  68. Result:=(N.NodeType=ELEMENT_NODE);
  69. if Result then
  70. begin
  71. S:=N.NodeName;
  72. if NoPath then
  73. Begin
  74. Result:= (CompareText(S,AElement.Name)=0);
  75. end
  76. else
  77. begin
  78. IF Assigned(Aelement.GetModule) then
  79. PN:=Aelement.GetModule.PackageName
  80. else
  81. PN:=FPackage.Name;
  82. S:=PN+'.'+TDomElement(N)['unit']+'.'+S;
  83. Result:= (CompareText(S,AElement.PathName)=0);
  84. end;
  85. end;
  86. end;
  87. Function TClassTreeBuilder.LookForElement(PE : TDomElement; AElement : TPasElement; NoPath : boolean) : TDomNode;
  88. Var
  89. N : TDomNode;
  90. begin
  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. end;
  108. Function TClassTreeBuilder.AddToClassTree(AElement : TPasElement; 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. PF : String;
  117. begin
  118. PF:=StringOfChar(' ',ACount);
  119. Result:=Nil; N:=Nil;PE:=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. begin
  130. PE:=FTreeStart;
  131. end
  132. end
  133. else If (AElement is TPasClassType) then
  134. begin
  135. if (AElement=FParentObject) then
  136. Result:=FTreeStart
  137. else
  138. begin
  139. PC:=AElement as TPasClassType;
  140. PE:=AddToClassTree(PC.AncestorType,ACount+1);
  141. if PE=Nil then
  142. PE:=FTreeStart;
  143. N:=LookForElement(PE,PC,False);
  144. end
  145. end;
  146. If (N<>Nil) then
  147. Result:=N as TDomElement
  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 assigned(PE) then // if not assigned, probably needs to be
  159. // assigned to something else.
  160. PE.AppendChild(Result);
  161. end;
  162. end;
  163. end.