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 |
16 | |
17 | #include "clang/AST/Type.h" |
18 | #include "clang/Basic/Specifiers.h" |
19 | #include "clang/Tooling/StandaloneExecution.h" |
20 | #include "llvm/ADT/APSInt.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringExtras.h" |
23 | #include <array> |
24 | #include <optional> |
25 | #include <string> |
26 | |
27 | namespace clang { |
28 | namespace doc { |
29 | |
30 | // SHA1'd hash of a USR. |
31 | using SymbolID = std::array<uint8_t, 20>; |
32 | |
33 | struct BaseRecordInfo; |
34 | struct EnumInfo; |
35 | struct FunctionInfo; |
36 | struct Info; |
37 | struct TypedefInfo; |
38 | |
39 | enum class InfoType { |
40 | IT_default, |
41 | IT_namespace, |
42 | IT_record, |
43 | IT_function, |
44 | IT_enum, |
45 | IT_typedef |
46 | }; |
47 | |
48 | // A representation of a parsed comment. |
49 | struct { |
50 | () = default; |
51 | (CommentInfo &Other) = delete; |
52 | (CommentInfo &&Other) = default; |
53 | CommentInfo &(CommentInfo &&Other) = default; |
54 | |
55 | bool (const CommentInfo &Other) const; |
56 | |
57 | // This operator is used to sort a vector of CommentInfos. |
58 | // No specific order (attributes more important than others) is required. Any |
59 | // sort is enough, the order is only needed to call std::unique after sorting |
60 | // the vector. |
61 | bool (const CommentInfo &Other) const; |
62 | |
63 | SmallString<16> |
64 | ; // Kind of comment (FullComment, ParagraphComment, TextComment, |
65 | // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment, |
66 | // BlockCommandComment, ParamCommandComment, |
67 | // TParamCommandComment, VerbatimBlockComment, |
68 | // VerbatimBlockLineComment, VerbatimLineComment). |
69 | SmallString<64> ; // Text of the comment. |
70 | SmallString<16> ; // Name of the comment (for Verbatim and HTML). |
71 | SmallString<8> ; // Parameter direction (for (T)ParamCommand). |
72 | SmallString<16> ; // Parameter name (for (T)ParamCommand). |
73 | SmallString<16> ; // Closing tag name (for VerbatimBlock). |
74 | bool = false; // Indicates if tag is self-closing (for HTML). |
75 | bool = false; // Indicates if the direction of a param is explicit |
76 | // (for (T)ParamCommand). |
77 | llvm::SmallVector<SmallString<16>, 4> |
78 | ; // List of attribute keys (for HTML). |
79 | llvm::SmallVector<SmallString<16>, 4> |
80 | ; // List of attribute values for each key (for HTML). |
81 | llvm::SmallVector<SmallString<16>, 4> |
82 | ; // List of arguments to commands (for InlineCommand). |
83 | std::vector<std::unique_ptr<CommentInfo>> |
84 | ; // List of child comments for this CommentInfo. |
85 | }; |
86 | |
87 | struct Reference { |
88 | // This variant (that takes no qualified name parameter) uses the Name as the |
89 | // QualName (very useful in unit tests to reduce verbosity). This can't use an |
90 | // empty string to indicate the default because we need to accept the empty |
91 | // string as a valid input for the global namespace (it will have |
92 | // "GlobalNamespace" as the name, but an empty QualName). |
93 | Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(), |
94 | InfoType IT = InfoType::IT_default) |
95 | : USR(USR), Name(Name), QualName(Name), RefType(IT) {} |
96 | Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, |
97 | StringRef Path = StringRef()) |
98 | : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {} |
99 | |
100 | bool operator==(const Reference &Other) const { |
101 | return std::tie(args: USR, args: Name, args: QualName, args: RefType) == |
102 | std::tie(args: Other.USR, args: Other.Name, args: QualName, args: Other.RefType); |
103 | } |
104 | |
105 | bool mergeable(const Reference &Other); |
106 | void merge(Reference &&I); |
107 | |
108 | /// Returns the path for this Reference relative to CurrentPath. |
109 | llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const; |
110 | |
111 | /// Returns the basename that should be used for this Reference. |
112 | llvm::SmallString<16> getFileBaseName() const; |
113 | |
114 | SymbolID USR = SymbolID(); // Unique identifier for referenced decl |
115 | |
116 | // Name of type (possibly unresolved). Not including namespaces or template |
117 | // parameters (so for a std::vector<int> this would be "vector"). See also |
118 | // QualName. |
119 | SmallString<16> Name; |
120 | |
121 | // Full qualified name of this type, including namespaces and template |
122 | // parameter (for example this could be "std::vector<int>"). Contrast to |
123 | // Name. |
124 | SmallString<16> QualName; |
125 | |
126 | InfoType RefType = InfoType::IT_default; // Indicates the type of this |
127 | // Reference (namespace, record, |
128 | // function, enum, default). |
129 | // Path of directory where the clang-doc generated file will be saved |
130 | // (possibly unresolved) |
131 | llvm::SmallString<128> Path; |
132 | }; |
133 | |
134 | // Holds the children of a record or namespace. |
135 | struct ScopeChildren { |
136 | // Namespaces and Records are references because they will be properly |
137 | // documented in their own info, while the entirety of Functions and Enums are |
138 | // included here because they should not have separate documentation from |
139 | // their scope. |
140 | // |
141 | // Namespaces are not syntactically valid as children of records, but making |
142 | // this general for all possible container types reduces code complexity. |
143 | std::vector<Reference> Namespaces; |
144 | std::vector<Reference> Records; |
145 | std::vector<FunctionInfo> Functions; |
146 | std::vector<EnumInfo> Enums; |
147 | std::vector<TypedefInfo> Typedefs; |
148 | }; |
149 | |
150 | // A base struct for TypeInfos |
151 | struct TypeInfo { |
152 | TypeInfo() = default; |
153 | TypeInfo(const Reference &R) : Type(R) {} |
154 | |
155 | // Convenience constructor for when there is no symbol ID or info type |
156 | // (normally used for built-in types in tests). |
157 | TypeInfo(StringRef Name, StringRef Path = StringRef()) |
158 | : Type(SymbolID(), Name, InfoType::IT_default, Name, Path) {} |
159 | |
160 | bool operator==(const TypeInfo &Other) const { return Type == Other.Type; } |
161 | |
162 | Reference Type; // Referenced type in this info. |
163 | }; |
164 | |
165 | // Represents one template parameter. |
166 | // |
167 | // This is a very simple serialization of the text of the source code of the |
168 | // template parameter. It is saved in a struct so there is a place to add the |
169 | // name and default values in the future if needed. |
170 | struct TemplateParamInfo { |
171 | TemplateParamInfo() = default; |
172 | explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {} |
173 | |
174 | // The literal contents of the code for that specifies this template parameter |
175 | // for this declaration. Typical values will be "class T" and |
176 | // "typename T = int". |
177 | SmallString<16> Contents; |
178 | }; |
179 | |
180 | struct TemplateSpecializationInfo { |
181 | // Indicates the declaration that this specializes. |
182 | SymbolID SpecializationOf; |
183 | |
184 | // Template parameters applying to the specialized record/function. |
185 | std::vector<TemplateParamInfo> Params; |
186 | }; |
187 | |
188 | // Records the template information for a struct or function that is a template |
189 | // or an explicit template specialization. |
190 | struct TemplateInfo { |
191 | // May be empty for non-partial specializations. |
192 | std::vector<TemplateParamInfo> Params; |
193 | |
194 | // Set when this is a specialization of another record/function. |
195 | std::optional<TemplateSpecializationInfo> Specialization; |
196 | }; |
197 | |
198 | // Info for field types. |
199 | struct FieldTypeInfo : public TypeInfo { |
200 | FieldTypeInfo() = default; |
201 | FieldTypeInfo(const TypeInfo &TI, StringRef Name = StringRef(), |
202 | StringRef DefaultValue = StringRef()) |
203 | : TypeInfo(TI), Name(Name), DefaultValue(DefaultValue) {} |
204 | |
205 | bool operator==(const FieldTypeInfo &Other) const { |
206 | return std::tie(args: Type, args: Name, args: DefaultValue) == |
207 | std::tie(args: Other.Type, args: Other.Name, args: Other.DefaultValue); |
208 | } |
209 | |
210 | SmallString<16> Name; // Name associated with this info. |
211 | |
212 | // When used for function parameters, contains the string representing the |
213 | // expression of the default value, if any. |
214 | SmallString<16> DefaultValue; |
215 | }; |
216 | |
217 | // Info for member types. |
218 | struct MemberTypeInfo : public FieldTypeInfo { |
219 | MemberTypeInfo() = default; |
220 | MemberTypeInfo(const TypeInfo &TI, StringRef Name, AccessSpecifier Access) |
221 | : FieldTypeInfo(TI, Name), Access(Access) {} |
222 | |
223 | bool operator==(const MemberTypeInfo &Other) const { |
224 | return std::tie(args: Type, args: Name, args: Access, args: Description) == |
225 | std::tie(args: Other.Type, args: Other.Name, args: Other.Access, args: Other.Description); |
226 | } |
227 | |
228 | // Access level associated with this info (public, protected, private, none). |
229 | // AS_public is set as default because the bitcode writer requires the enum |
230 | // with value 0 to be used as the default. |
231 | // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3) |
232 | AccessSpecifier Access = AccessSpecifier::AS_public; |
233 | |
234 | std::vector<CommentInfo> Description; // Comment description of this field. |
235 | }; |
236 | |
237 | struct Location { |
238 | Location(int LineNumber = 0, StringRef Filename = StringRef(), |
239 | bool IsFileInRootDir = false) |
240 | : LineNumber(LineNumber), Filename(Filename), |
241 | IsFileInRootDir(IsFileInRootDir) {} |
242 | |
243 | bool operator==(const Location &Other) const { |
244 | return std::tie(args: LineNumber, args: Filename) == |
245 | std::tie(args: Other.LineNumber, args: Other.Filename); |
246 | } |
247 | |
248 | // This operator is used to sort a vector of Locations. |
249 | // No specific order (attributes more important than others) is required. Any |
250 | // sort is enough, the order is only needed to call std::unique after sorting |
251 | // the vector. |
252 | bool operator<(const Location &Other) const { |
253 | return std::tie(args: LineNumber, args: Filename) < |
254 | std::tie(args: Other.LineNumber, args: Other.Filename); |
255 | } |
256 | |
257 | int LineNumber = 0; // Line number of this Location. |
258 | SmallString<32> Filename; // File for this Location. |
259 | bool IsFileInRootDir = false; // Indicates if file is inside root directory |
260 | }; |
261 | |
262 | /// A base struct for Infos. |
263 | struct Info { |
264 | Info(InfoType IT = InfoType::IT_default, SymbolID USR = SymbolID(), |
265 | StringRef Name = StringRef(), StringRef Path = StringRef()) |
266 | : USR(USR), IT(IT), Name(Name), Path(Path) {} |
267 | |
268 | Info(const Info &Other) = delete; |
269 | Info(Info &&Other) = default; |
270 | |
271 | virtual ~Info() = default; |
272 | |
273 | SymbolID USR = |
274 | SymbolID(); // Unique identifier for the decl described by this Info. |
275 | const InfoType IT = InfoType::IT_default; // InfoType of this particular Info. |
276 | SmallString<16> Name; // Unqualified name of the decl. |
277 | llvm::SmallVector<Reference, 4> |
278 | Namespace; // List of parent namespaces for this decl. |
279 | std::vector<CommentInfo> Description; // Comment description of this decl. |
280 | llvm::SmallString<128> Path; // Path of directory where the clang-doc |
281 | // generated file will be saved |
282 | |
283 | void mergeBase(Info &&I); |
284 | bool mergeable(const Info &Other); |
285 | |
286 | llvm::SmallString<16> () const; |
287 | |
288 | /// Returns the file path for this Info relative to CurrentPath. |
289 | llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const; |
290 | |
291 | /// Returns the basename that should be used for this Info. |
292 | llvm::SmallString<16> getFileBaseName() const; |
293 | }; |
294 | |
295 | // Info for namespaces. |
296 | struct NamespaceInfo : public Info { |
297 | NamespaceInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(), |
298 | StringRef Path = StringRef()); |
299 | |
300 | void merge(NamespaceInfo &&I); |
301 | |
302 | ScopeChildren Children; |
303 | }; |
304 | |
305 | // Info for symbols. |
306 | struct SymbolInfo : public Info { |
307 | SymbolInfo(InfoType IT, SymbolID USR = SymbolID(), |
308 | StringRef Name = StringRef(), StringRef Path = StringRef()) |
309 | : Info(IT, USR, Name, Path) {} |
310 | |
311 | void merge(SymbolInfo &&I); |
312 | |
313 | std::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 { |
320 | FunctionInfo(SymbolID USR = SymbolID()) |
321 | : 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 | // Full qualified name of this function, including namespaces and template |
336 | // specializations. |
337 | SmallString<16> FullName; |
338 | |
339 | // When present, this function is a template or specialization. |
340 | std::optional<TemplateInfo> Template; |
341 | }; |
342 | |
343 | // TODO: Expand to allow for documenting templating, inheritance access, |
344 | // friend classes |
345 | // Info for types. |
346 | struct RecordInfo : public SymbolInfo { |
347 | RecordInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(), |
348 | StringRef Path = StringRef()); |
349 | |
350 | void merge(RecordInfo &&I); |
351 | |
352 | // Type of this record (struct, class, union, interface). |
353 | TagTypeKind TagType = TagTypeKind::Struct; |
354 | |
355 | // Full qualified name of this record, including namespaces and template |
356 | // specializations. |
357 | SmallString<16> FullName; |
358 | |
359 | // When present, this record is a template or specialization. |
360 | std::optional<TemplateInfo> Template; |
361 | |
362 | // Indicates if the record was declared using a typedef. Things like anonymous |
363 | // structs in a typedef: |
364 | // typedef struct { ... } foo_t; |
365 | // are converted into records with the typedef as the Name + this flag set. |
366 | bool IsTypeDef = false; |
367 | |
368 | llvm::SmallVector<MemberTypeInfo, 4> |
369 | Members; // List of info about record members. |
370 | llvm::SmallVector<Reference, 4> Parents; // List of base/parent records |
371 | // (does not include virtual |
372 | // parents). |
373 | llvm::SmallVector<Reference, 4> |
374 | VirtualParents; // List of virtual base/parent records. |
375 | |
376 | std::vector<BaseRecordInfo> |
377 | Bases; // List of base/parent records; this includes inherited methods and |
378 | // attributes |
379 | |
380 | ScopeChildren Children; |
381 | }; |
382 | |
383 | // Info for typedef and using statements. |
384 | struct TypedefInfo : public SymbolInfo { |
385 | TypedefInfo(SymbolID USR = SymbolID()) |
386 | : SymbolInfo(InfoType::IT_typedef, USR) {} |
387 | |
388 | void merge(TypedefInfo &&I); |
389 | |
390 | TypeInfo Underlying; |
391 | |
392 | // Inidicates if this is a new C++ "using"-style typedef: |
393 | // using MyVector = std::vector<int> |
394 | // False means it's a C-style typedef: |
395 | // typedef std::vector<int> MyVector; |
396 | bool IsUsing = false; |
397 | }; |
398 | |
399 | struct BaseRecordInfo : public RecordInfo { |
400 | BaseRecordInfo(); |
401 | BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual, |
402 | AccessSpecifier Access, bool IsParent); |
403 | |
404 | // Indicates if base corresponds to a virtual inheritance |
405 | bool IsVirtual = false; |
406 | // Access level associated with this inherited info (public, protected, |
407 | // private). |
408 | AccessSpecifier Access = AccessSpecifier::AS_public; |
409 | bool IsParent = false; // Indicates if this base is a direct parent |
410 | }; |
411 | |
412 | // Information for a single possible value of an enumeration. |
413 | struct EnumValueInfo { |
414 | explicit EnumValueInfo(StringRef Name = StringRef(), |
415 | StringRef Value = StringRef("0" ), |
416 | StringRef ValueExpr = StringRef()) |
417 | : Name(Name), Value(Value), ValueExpr(ValueExpr) {} |
418 | |
419 | bool operator==(const EnumValueInfo &Other) const { |
420 | return std::tie(args: Name, args: Value, args: ValueExpr) == |
421 | std::tie(args: Other.Name, args: Other.Value, args: Other.ValueExpr); |
422 | } |
423 | |
424 | SmallString<16> Name; |
425 | |
426 | // The computed value of the enumeration constant. This could be the result of |
427 | // evaluating the ValueExpr, or it could be automatically generated according |
428 | // to C rules. |
429 | SmallString<16> Value; |
430 | |
431 | // Stores the user-supplied initialization expression for this enumeration |
432 | // constant. This will be empty for implicit enumeration values. |
433 | SmallString<16> ValueExpr; |
434 | }; |
435 | |
436 | // TODO: Expand to allow for documenting templating. |
437 | // Info for types. |
438 | struct EnumInfo : public SymbolInfo { |
439 | EnumInfo() : SymbolInfo(InfoType::IT_enum) {} |
440 | EnumInfo(SymbolID USR) : SymbolInfo(InfoType::IT_enum, USR) {} |
441 | |
442 | void merge(EnumInfo &&I); |
443 | |
444 | // Indicates whether this enum is scoped (e.g. enum class). |
445 | bool Scoped = false; |
446 | |
447 | // Set to nonempty to the type when this is an explicitly typed enum. For |
448 | // enum Foo : short { ... }; |
449 | // this will be "short". |
450 | std::optional<TypeInfo> BaseType; |
451 | |
452 | llvm::SmallVector<EnumValueInfo, 4> Members; // List of enum members. |
453 | }; |
454 | |
455 | struct Index : public Reference { |
456 | Index() = default; |
457 | Index(StringRef Name) : Reference(SymbolID(), Name) {} |
458 | Index(StringRef Name, StringRef JumpToSection) |
459 | : Reference(SymbolID(), Name), JumpToSection(JumpToSection) {} |
460 | Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path) |
461 | : Reference(USR, Name, IT, Name, Path) {} |
462 | // This is used to look for a USR in a vector of Indexes using std::find |
463 | bool operator==(const SymbolID &Other) const { return USR == Other; } |
464 | bool operator<(const Index &Other) const; |
465 | |
466 | std::optional<SmallString<16>> JumpToSection; |
467 | std::vector<Index> Children; |
468 | |
469 | void sort(); |
470 | }; |
471 | |
472 | // TODO: Add functionality to include separate markdown pages. |
473 | |
474 | // A standalone function to call to merge a vector of infos into one. |
475 | // This assumes that all infos in the vector are of the same type, and will fail |
476 | // if they are different. |
477 | llvm::Expected<std::unique_ptr<Info>> |
478 | mergeInfos(std::vector<std::unique_ptr<Info>> &Values); |
479 | |
480 | struct ClangDocContext { |
481 | ClangDocContext() = default; |
482 | ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, |
483 | bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, |
484 | StringRef RepositoryUrl, |
485 | std::vector<std::string> UserStylesheets, |
486 | std::vector<std::string> JsScripts); |
487 | tooling::ExecutionContext *ECtx; |
488 | std::string ProjectName; // Name of project clang-doc is documenting. |
489 | bool PublicOnly; // Indicates if only public declarations are documented. |
490 | std::string OutDirectory; // Directory for outputting generated files. |
491 | std::string SourceRoot; // Directory where processed files are stored. Links |
492 | // to definition locations will only be generated if |
493 | // the file is in this dir. |
494 | // URL of repository that hosts code used for links to definition locations. |
495 | std::optional<std::string> RepositoryUrl; |
496 | // Path of CSS stylesheets that will be copied to OutDirectory and used to |
497 | // style all HTML files. |
498 | std::vector<std::string> UserStylesheets; |
499 | // JavaScript files that will be imported in allHTML file. |
500 | std::vector<std::string> JsScripts; |
501 | // Other files that should be copied to OutDirectory, besides UserStylesheets. |
502 | std::vector<std::string> FilesToCopy; |
503 | Index Idx; |
504 | }; |
505 | |
506 | } // namespace doc |
507 | } // namespace clang |
508 | |
509 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H |
510 | |