1 ///===-- Representation.h - ClangDoc Representation -------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the internal representations of different declaration
10 // types for the clang-doc tool.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
15 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
16 
17 #include "clang/AST/Type.h"
18 #include "clang/Basic/Specifiers.h"
19 #include "clang/Tooling/StandaloneExecution.h"
20 #include "llvm/ADT/Optional.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include <array>
24 #include <string>
25 
26 namespace clang {
27 namespace doc {
28 
29 // SHA1'd hash of a USR.
30 using SymbolID = std::array<uint8_t, 20>;
31 
32 struct Info;
33 struct FunctionInfo;
34 struct EnumInfo;
35 struct BaseRecordInfo;
36 
37 enum class InfoType {
38   IT_default,
39   IT_namespace,
40   IT_record,
41   IT_function,
42   IT_enum
43 };
44 
45 // A representation of a parsed comment.
46 struct CommentInfo {
47   CommentInfo() = default;
48   CommentInfo(CommentInfo &Other) = delete;
49   CommentInfo(CommentInfo &&Other) = default;
50   CommentInfo &operator=(CommentInfo &&Other) = default;
51 
52   bool operator==(const CommentInfo &Other) const {
53     auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
54                             SelfClosing, Explicit, AttrKeys, AttrValues, Args);
55     auto SecondCI =
56         std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
57                  Other.ParamName, Other.CloseName, Other.SelfClosing,
58                  Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
59 
60     if (FirstCI != SecondCI || Children.size() != Other.Children.size())
61       return false;
62 
63     return std::equal(Children.begin(), Children.end(), Other.Children.begin(),
64                       llvm::deref<std::equal_to<>>{});
65   }
66 
67   // This operator is used to sort a vector of CommentInfos.
68   // No specific order (attributes more important than others) is required. Any
69   // sort is enough, the order is only needed to call std::unique after sorting
70   // the vector.
71   bool operator<(const CommentInfo &Other) const {
72     auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
73                             SelfClosing, Explicit, AttrKeys, AttrValues, Args);
74     auto SecondCI =
75         std::tie(Other.Kind, Other.Text, Other.Name, Other.Direction,
76                  Other.ParamName, Other.CloseName, Other.SelfClosing,
77                  Other.Explicit, Other.AttrKeys, Other.AttrValues, Other.Args);
78 
79     if (FirstCI < SecondCI)
80       return true;
81 
82     if (FirstCI == SecondCI) {
83       return std::lexicographical_compare(
84           Children.begin(), Children.end(), Other.Children.begin(),
85           Other.Children.end(), llvm::deref<std::less<>>());
86     }
87 
88     return false;
89   }
90 
91   SmallString<16>
92       Kind; // Kind of comment (FullComment, ParagraphComment, TextComment,
93             // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
94             // BlockCommandComment, ParamCommandComment,
95             // TParamCommandComment, VerbatimBlockComment,
96             // VerbatimBlockLineComment, VerbatimLineComment).
97   SmallString<64> Text;      // Text of the comment.
98   SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
99   SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
100   SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
101   SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
102   bool SelfClosing = false;  // Indicates if tag is self-closing (for HTML).
103   bool Explicit = false; // Indicates if the direction of a param is explicit
104                          // (for (T)ParamCommand).
105   llvm::SmallVector<SmallString<16>, 4>
106       AttrKeys; // List of attribute keys (for HTML).
107   llvm::SmallVector<SmallString<16>, 4>
108       AttrValues; // List of attribute values for each key (for HTML).
109   llvm::SmallVector<SmallString<16>, 4>
110       Args; // List of arguments to commands (for InlineCommand).
111   std::vector<std::unique_ptr<CommentInfo>>
112       Children; // List of child comments for this CommentInfo.
113 };
114 
115 struct Reference {
116   Reference() = default;
ReferenceReference117   Reference(llvm::StringRef Name) : Name(Name) {}
118   // An empty path means the info is in the global namespace because the path is
119   // a composite of the parent namespaces.
ReferenceReference120   Reference(llvm::StringRef Name, StringRef Path)
121       : Name(Name), Path(Path), IsInGlobalNamespace(Path.empty()) {}
ReferenceReference122   Reference(SymbolID USR, StringRef Name, InfoType IT)
123       : USR(USR), Name(Name), RefType(IT) {}
124   // An empty path means the info is in the global namespace because the path is
125   // a composite of the parent namespaces.
ReferenceReference126   Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
127       : USR(USR), Name(Name), RefType(IT), Path(Path),
128         IsInGlobalNamespace(Path.empty()) {}
129 
130   bool operator==(const Reference &Other) const {
131     return std::tie(USR, Name, RefType) ==
132            std::tie(Other.USR, Other.Name, Other.RefType);
133   }
134 
135   bool mergeable(const Reference &Other);
136   void merge(Reference &&I);
137 
138   /// Returns the path for this Reference relative to CurrentPath.
139   llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
140 
141   /// Returns the basename that should be used for this Reference.
142   llvm::SmallString<16> getFileBaseName() const;
143 
144   SymbolID USR = SymbolID(); // Unique identifier for referenced decl
145   SmallString<16> Name;      // Name of type (possibly unresolved).
146   InfoType RefType = InfoType::IT_default; // Indicates the type of this
147                                            // Reference (namespace, record,
148                                            // function, enum, default).
149   // Path of directory where the clang-doc generated file will be saved
150   // (possibly unresolved)
151   llvm::SmallString<128> Path;
152   // Indicates if the info's parent is the global namespace, or if the info is
153   // the global namespace
154   bool IsInGlobalNamespace = false;
155 };
156 
157 // A base struct for TypeInfos
158 struct TypeInfo {
159   TypeInfo() = default;
TypeInfoTypeInfo160   TypeInfo(SymbolID Type, StringRef Field, InfoType IT)
161       : Type(Type, Field, IT) {}
TypeInfoTypeInfo162   TypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path)
163       : Type(Type, Field, IT, Path) {}
TypeInfoTypeInfo164   TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
TypeInfoTypeInfo165   TypeInfo(llvm::StringRef RefName, StringRef Path) : Type(RefName, Path) {}
166 
167   bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
168 
169   Reference Type; // Referenced type in this info.
170 };
171 
172 // Info for field types.
173 struct FieldTypeInfo : public TypeInfo {
174   FieldTypeInfo() = default;
FieldTypeInfoFieldTypeInfo175   FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
176                 llvm::StringRef Name)
177       : TypeInfo(Type, Field, IT, Path), Name(Name) {}
FieldTypeInfoFieldTypeInfo178   FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
179       : TypeInfo(RefName), Name(Name) {}
FieldTypeInfoFieldTypeInfo180   FieldTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name)
181       : TypeInfo(RefName, Path), Name(Name) {}
182 
183   bool operator==(const FieldTypeInfo &Other) const {
184     return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
185   }
186 
187   SmallString<16> Name; // Name associated with this info.
188 };
189 
190 // Info for member types.
191 struct MemberTypeInfo : public FieldTypeInfo {
192   MemberTypeInfo() = default;
MemberTypeInfoMemberTypeInfo193   MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
194                  llvm::StringRef Name, AccessSpecifier Access)
195       : FieldTypeInfo(Type, Field, IT, Path, Name), Access(Access) {}
MemberTypeInfoMemberTypeInfo196   MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,
197                  AccessSpecifier Access)
198       : FieldTypeInfo(RefName, Name), Access(Access) {}
MemberTypeInfoMemberTypeInfo199   MemberTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name,
200                  AccessSpecifier Access)
201       : FieldTypeInfo(RefName, Path, Name), Access(Access) {}
202 
203   bool operator==(const MemberTypeInfo &Other) const {
204     return std::tie(Type, Name, Access) ==
205            std::tie(Other.Type, Other.Name, Other.Access);
206   }
207 
208   // Access level associated with this info (public, protected, private, none).
209   // AS_public is set as default because the bitcode writer requires the enum
210   // with value 0 to be used as the default.
211   // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3)
212   AccessSpecifier Access = AccessSpecifier::AS_public;
213 };
214 
215 struct Location {
216   Location() = default;
LocationLocation217   Location(int LineNumber, SmallString<16> Filename)
218       : LineNumber(LineNumber), Filename(std::move(Filename)) {}
LocationLocation219   Location(int LineNumber, SmallString<16> Filename, bool IsFileInRootDir)
220       : LineNumber(LineNumber), Filename(std::move(Filename)),
221         IsFileInRootDir(IsFileInRootDir) {}
222 
223   bool operator==(const Location &Other) const {
224     return std::tie(LineNumber, Filename) ==
225            std::tie(Other.LineNumber, Other.Filename);
226   }
227 
228   // This operator is used to sort a vector of Locations.
229   // No specific order (attributes more important than others) is required. Any
230   // sort is enough, the order is only needed to call std::unique after sorting
231   // the vector.
232   bool operator<(const Location &Other) const {
233     return std::tie(LineNumber, Filename) <
234            std::tie(Other.LineNumber, Other.Filename);
235   }
236 
237   int LineNumber;               // Line number of this Location.
238   SmallString<32> Filename;     // File for this Location.
239   bool IsFileInRootDir = false; // Indicates if file is inside root directory
240 };
241 
242 /// A base struct for Infos.
243 struct Info {
244   Info() = default;
InfoInfo245   Info(InfoType IT) : IT(IT) {}
InfoInfo246   Info(InfoType IT, SymbolID USR) : USR(USR), IT(IT) {}
InfoInfo247   Info(InfoType IT, SymbolID USR, StringRef Name)
248       : USR(USR), IT(IT), Name(Name) {}
InfoInfo249   Info(InfoType IT, SymbolID USR, StringRef Name, StringRef Path)
250       : USR(USR), IT(IT), Name(Name), Path(Path) {}
251   Info(const Info &Other) = delete;
252   Info(Info &&Other) = default;
253 
254   virtual ~Info() = default;
255 
256   SymbolID USR =
257       SymbolID(); // Unique identifier for the decl described by this Info.
258   const InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
259   SmallString<16> Name;                     // Unqualified name of the decl.
260   llvm::SmallVector<Reference, 4>
261       Namespace; // List of parent namespaces for this decl.
262   std::vector<CommentInfo> Description; // Comment description of this decl.
263   llvm::SmallString<128> Path;          // Path of directory where the clang-doc
264                                         // generated file will be saved
265 
266   void mergeBase(Info &&I);
267   bool mergeable(const Info &Other);
268 
269   llvm::SmallString<16> extractName() const;
270 
271   /// Returns the file path for this Info relative to CurrentPath.
272   llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
273 
274   /// Returns the basename that should be used for this Info.
275   llvm::SmallString<16> getFileBaseName() const;
276 
277   // Returns a reference to the parent scope (that is, the immediate parent
278   // namespace or class in which this decl resides).
279   llvm::Expected<Reference> getEnclosingScope();
280 };
281 
282 // Info for namespaces.
283 struct NamespaceInfo : public Info {
NamespaceInfoNamespaceInfo284   NamespaceInfo() : Info(InfoType::IT_namespace) {}
NamespaceInfoNamespaceInfo285   NamespaceInfo(SymbolID USR) : Info(InfoType::IT_namespace, USR) {}
NamespaceInfoNamespaceInfo286   NamespaceInfo(SymbolID USR, StringRef Name)
287       : Info(InfoType::IT_namespace, USR, Name) {}
NamespaceInfoNamespaceInfo288   NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
289       : Info(InfoType::IT_namespace, USR, Name, Path) {}
290 
291   void merge(NamespaceInfo &&I);
292 
293   // Namespaces and Records are references because they will be properly
294   // documented in their own info, while the entirety of Functions and Enums are
295   // included here because they should not have separate documentation from
296   // their scope.
297   std::vector<Reference> ChildNamespaces;
298   std::vector<Reference> ChildRecords;
299   std::vector<FunctionInfo> ChildFunctions;
300   std::vector<EnumInfo> ChildEnums;
301 };
302 
303 // Info for symbols.
304 struct SymbolInfo : public Info {
SymbolInfoSymbolInfo305   SymbolInfo(InfoType IT) : Info(IT) {}
SymbolInfoSymbolInfo306   SymbolInfo(InfoType IT, SymbolID USR) : Info(IT, USR) {}
SymbolInfoSymbolInfo307   SymbolInfo(InfoType IT, SymbolID USR, StringRef Name) : Info(IT, USR, Name) {}
SymbolInfoSymbolInfo308   SymbolInfo(InfoType IT, SymbolID USR, StringRef Name, StringRef Path)
309       : Info(IT, USR, Name, Path) {}
310 
311   void merge(SymbolInfo &&I);
312 
313   llvm::Optional<Location> DefLoc;    // Location where this decl is defined.
314   llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
315 };
316 
317 // TODO: Expand to allow for documenting templating and default args.
318 // Info for functions.
319 struct FunctionInfo : public SymbolInfo {
FunctionInfoFunctionInfo320   FunctionInfo() : SymbolInfo(InfoType::IT_function) {}
FunctionInfoFunctionInfo321   FunctionInfo(SymbolID USR) : SymbolInfo(InfoType::IT_function, USR) {}
322 
323   void merge(FunctionInfo &&I);
324 
325   bool IsMethod = false; // Indicates whether this function is a class method.
326   Reference Parent;      // Reference to the parent class decl for this method.
327   TypeInfo ReturnType;   // Info about the return type of this function.
328   llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
329   // Access level for this method (public, private, protected, none).
330   // AS_public is set as default because the bitcode writer requires the enum
331   // with value 0 to be used as the default.
332   // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3)
333   AccessSpecifier Access = AccessSpecifier::AS_public;
334 };
335 
336 // TODO: Expand to allow for documenting templating, inheritance access,
337 // friend classes
338 // Info for types.
339 struct RecordInfo : public SymbolInfo {
RecordInfoRecordInfo340   RecordInfo() : SymbolInfo(InfoType::IT_record) {}
RecordInfoRecordInfo341   RecordInfo(SymbolID USR) : SymbolInfo(InfoType::IT_record, USR) {}
RecordInfoRecordInfo342   RecordInfo(SymbolID USR, StringRef Name)
343       : SymbolInfo(InfoType::IT_record, USR, Name) {}
RecordInfoRecordInfo344   RecordInfo(SymbolID USR, StringRef Name, StringRef Path)
345       : SymbolInfo(InfoType::IT_record, USR, Name, Path) {}
346 
347   void merge(RecordInfo &&I);
348 
349   TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record
350                                                  // (struct, class, union,
351                                                  // interface).
352   bool IsTypeDef = false; // Indicates if record was declared using typedef
353   llvm::SmallVector<MemberTypeInfo, 4>
354       Members;                             // List of info about record members.
355   llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
356                                            // (does not include virtual
357                                            // parents).
358   llvm::SmallVector<Reference, 4>
359       VirtualParents; // List of virtual base/parent records.
360 
361   std::vector<BaseRecordInfo>
362       Bases; // List of base/parent records; this includes inherited methods and
363              // attributes
364 
365   // Records are references because they will be properly documented in their
366   // own info, while the entirety of Functions and Enums are included here
367   // because they should not have separate documentation from their scope.
368   std::vector<Reference> ChildRecords;
369   std::vector<FunctionInfo> ChildFunctions;
370   std::vector<EnumInfo> ChildEnums;
371 };
372 
373 struct BaseRecordInfo : public RecordInfo {
BaseRecordInfoBaseRecordInfo374   BaseRecordInfo() : RecordInfo() {}
BaseRecordInfoBaseRecordInfo375   BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual,
376                  AccessSpecifier Access, bool IsParent)
377       : RecordInfo(USR, Name, Path), IsVirtual(IsVirtual), Access(Access),
378         IsParent(IsParent) {}
379 
380   // Indicates if base corresponds to a virtual inheritance
381   bool IsVirtual = false;
382   // Access level associated with this inherited info (public, protected,
383   // private).
384   AccessSpecifier Access = AccessSpecifier::AS_public;
385   bool IsParent = false; // Indicates if this base is a direct parent
386 };
387 
388 // TODO: Expand to allow for documenting templating.
389 // Info for types.
390 struct EnumInfo : public SymbolInfo {
EnumInfoEnumInfo391   EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
EnumInfoEnumInfo392   EnumInfo(SymbolID USR) : SymbolInfo(InfoType::IT_enum, USR) {}
393 
394   void merge(EnumInfo &&I);
395 
396   bool Scoped =
397       false; // Indicates whether this enum is scoped (e.g. enum class).
398   llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
399 };
400 
401 struct Index : public Reference {
402   Index() = default;
IndexIndex403   Index(StringRef Name) : Reference(Name) {}
IndexIndex404   Index(StringRef Name, StringRef JumpToSection)
405       : Reference(Name), JumpToSection(JumpToSection) {}
IndexIndex406   Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
407       : Reference(USR, Name, IT, Path) {}
408   // This is used to look for a USR in a vector of Indexes using std::find
409   bool operator==(const SymbolID &Other) const { return USR == Other; }
410   bool operator<(const Index &Other) const;
411 
412   llvm::Optional<SmallString<16>> JumpToSection;
413   std::vector<Index> Children;
414 
415   void sort();
416 };
417 
418 // TODO: Add functionality to include separate markdown pages.
419 
420 // A standalone function to call to merge a vector of infos into one.
421 // This assumes that all infos in the vector are of the same type, and will fail
422 // if they are different.
423 llvm::Expected<std::unique_ptr<Info>>
424 mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
425 
426 struct ClangDocContext {
427   ClangDocContext() = default;
428   ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName,
429                   bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot,
430                   StringRef RepositoryUrl,
431                   std::vector<std::string> UserStylesheets,
432                   std::vector<std::string> JsScripts);
433   tooling::ExecutionContext *ECtx;
434   std::string ProjectName; // Name of project clang-doc is documenting.
435   bool PublicOnly; // Indicates if only public declarations are documented.
436   std::string OutDirectory; // Directory for outputting generated files.
437   std::string SourceRoot;   // Directory where processed files are stored. Links
438                             // to definition locations will only be generated if
439                             // the file is in this dir.
440   // URL of repository that hosts code used for links to definition locations.
441   llvm::Optional<std::string> RepositoryUrl;
442   // Path of CSS stylesheets that will be copied to OutDirectory and used to
443   // style all HTML files.
444   std::vector<std::string> UserStylesheets;
445   // JavaScript files that will be imported in allHTML file.
446   std::vector<std::string> JsScripts;
447   // Other files that should be copied to OutDirectory, besides UserStylesheets.
448   std::vector<std::string> FilesToCopy;
449   Index Idx;
450 };
451 
452 } // namespace doc
453 } // namespace clang
454 
455 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
456