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/APSInt.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringExtras.h"
23#include <array>
24#include <optional>
25#include <string>
26
27namespace clang {
28namespace doc {
29
30// SHA1'd hash of a USR.
31using SymbolID = std::array<uint8_t, 20>;
32
33struct BaseRecordInfo;
34struct EnumInfo;
35struct FunctionInfo;
36struct Info;
37struct TypedefInfo;
38struct ConceptInfo;
39struct VarInfo;
40
41enum class InfoType {
42 IT_default,
43 IT_namespace,
44 IT_record,
45 IT_function,
46 IT_enum,
47 IT_typedef,
48 IT_concept,
49 IT_variable,
50 IT_friend
51};
52
53enum class CommentKind {
54 CK_FullComment,
55 CK_ParagraphComment,
56 CK_TextComment,
57 CK_InlineCommandComment,
58 CK_HTMLStartTagComment,
59 CK_HTMLEndTagComment,
60 CK_BlockCommandComment,
61 CK_ParamCommandComment,
62 CK_TParamCommandComment,
63 CK_VerbatimBlockComment,
64 CK_VerbatimBlockLineComment,
65 CK_VerbatimLineComment,
66 CK_Unknown
67};
68
69CommentKind stringToCommentKind(llvm::StringRef KindStr);
70llvm::StringRef commentKindToString(CommentKind Kind);
71
72// A representation of a parsed comment.
73struct CommentInfo {
74 CommentInfo() = default;
75 CommentInfo(CommentInfo &Other) = delete;
76 CommentInfo(CommentInfo &&Other) = default;
77 CommentInfo &operator=(CommentInfo &&Other) = default;
78
79 bool operator==(const CommentInfo &Other) const;
80
81 // This operator is used to sort a vector of CommentInfos.
82 // No specific order (attributes more important than others) is required. Any
83 // sort is enough, the order is only needed to call std::unique after sorting
84 // the vector.
85 bool operator<(const CommentInfo &Other) const;
86
87 CommentKind Kind = CommentKind::
88 CK_Unknown; // Kind of comment (FullComment, ParagraphComment,
89 // TextComment, InlineCommandComment, HTMLStartTagComment,
90 // HTMLEndTagComment, BlockCommandComment,
91 // ParamCommandComment, TParamCommandComment,
92 // VerbatimBlockComment, VerbatimBlockLineComment,
93 // VerbatimLineComment).
94 SmallString<64> Text; // Text of the comment.
95 SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
96 SmallString<8> Direction; // Parameter direction (for (T)ParamCommand).
97 SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
98 SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
99 bool SelfClosing = false; // Indicates if tag is self-closing (for HTML).
100 bool Explicit = false; // Indicates if the direction of a param is explicit
101 // (for (T)ParamCommand).
102 llvm::SmallVector<SmallString<16>, 4>
103 AttrKeys; // List of attribute keys (for HTML).
104 llvm::SmallVector<SmallString<16>, 4>
105 AttrValues; // List of attribute values for each key (for HTML).
106 llvm::SmallVector<SmallString<16>, 4>
107 Args; // List of arguments to commands (for InlineCommand).
108 std::vector<std::unique_ptr<CommentInfo>>
109 Children; // List of child comments for this CommentInfo.
110};
111
112struct Reference {
113 // This variant (that takes no qualified name parameter) uses the Name as the
114 // QualName (very useful in unit tests to reduce verbosity). This can't use an
115 // empty string to indicate the default because we need to accept the empty
116 // string as a valid input for the global namespace (it will have
117 // "GlobalNamespace" as the name, but an empty QualName).
118 Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
119 InfoType IT = InfoType::IT_default)
120 : USR(USR), Name(Name), QualName(Name), RefType(IT) {}
121 Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
122 StringRef Path = StringRef())
123 : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {}
124
125 bool operator==(const Reference &Other) const {
126 return std::tie(args: USR, args: Name, args: QualName, args: RefType) ==
127 std::tie(args: Other.USR, args: Other.Name, args: QualName, args: Other.RefType);
128 }
129
130 bool mergeable(const Reference &Other);
131 void merge(Reference &&I);
132 bool operator<(const Reference &Other) const { return Name < Other.Name; }
133
134 /// Returns the path for this Reference relative to CurrentPath.
135 llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
136
137 /// Returns the basename that should be used for this Reference.
138 llvm::SmallString<16> getFileBaseName() const;
139
140 SymbolID USR = SymbolID(); // Unique identifier for referenced decl
141
142 // Name of type (possibly unresolved). Not including namespaces or template
143 // parameters (so for a std::vector<int> this would be "vector"). See also
144 // QualName.
145 SmallString<16> Name;
146
147 // Full qualified name of this type, including namespaces and template
148 // parameter (for example this could be "std::vector<int>"). Contrast to
149 // Name.
150 SmallString<16> QualName;
151
152 InfoType RefType = InfoType::IT_default; // Indicates the type of this
153 // Reference (namespace, record,
154 // function, enum, default).
155 // Path of directory where the clang-doc generated file will be saved
156 // (possibly unresolved)
157 llvm::SmallString<128> Path;
158};
159
160// Holds the children of a record or namespace.
161struct ScopeChildren {
162 // Namespaces and Records are references because they will be properly
163 // documented in their own info, while the entirety of Functions and Enums are
164 // included here because they should not have separate documentation from
165 // their scope.
166 //
167 // Namespaces are not syntactically valid as children of records, but making
168 // this general for all possible container types reduces code complexity.
169 std::vector<Reference> Namespaces;
170 std::vector<Reference> Records;
171 std::vector<FunctionInfo> Functions;
172 std::vector<EnumInfo> Enums;
173 std::vector<TypedefInfo> Typedefs;
174 std::vector<ConceptInfo> Concepts;
175 std::vector<VarInfo> Variables;
176
177 void sort();
178};
179
180// A base struct for TypeInfos
181struct TypeInfo {
182 TypeInfo() = default;
183 TypeInfo(const Reference &R) : Type(R) {}
184
185 // Convenience constructor for when there is no symbol ID or info type
186 // (normally used for built-in types in tests).
187 TypeInfo(StringRef Name, StringRef Path = StringRef())
188 : Type(SymbolID(), Name, InfoType::IT_default, Name, Path) {}
189
190 bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
191
192 Reference Type; // Referenced type in this info.
193
194 bool IsTemplate = false;
195 bool IsBuiltIn = false;
196};
197
198// Represents one template parameter.
199//
200// This is a very simple serialization of the text of the source code of the
201// template parameter. It is saved in a struct so there is a place to add the
202// name and default values in the future if needed.
203struct TemplateParamInfo {
204 TemplateParamInfo() = default;
205 explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {}
206
207 // The literal contents of the code for that specifies this template parameter
208 // for this declaration. Typical values will be "class T" and
209 // "typename T = int".
210 SmallString<16> Contents;
211};
212
213struct TemplateSpecializationInfo {
214 // Indicates the declaration that this specializes.
215 SymbolID SpecializationOf;
216
217 // Template parameters applying to the specialized record/function.
218 std::vector<TemplateParamInfo> Params;
219};
220
221struct ConstraintInfo {
222 ConstraintInfo() = default;
223 ConstraintInfo(SymbolID USR, StringRef Name)
224 : ConceptRef(USR, Name, InfoType::IT_concept) {}
225 Reference ConceptRef;
226
227 SmallString<16> ConstraintExpr;
228};
229
230// Records the template information for a struct or function that is a template
231// or an explicit template specialization.
232struct TemplateInfo {
233 // May be empty for non-partial specializations.
234 std::vector<TemplateParamInfo> Params;
235
236 // Set when this is a specialization of another record/function.
237 std::optional<TemplateSpecializationInfo> Specialization;
238 std::vector<ConstraintInfo> Constraints;
239};
240
241// Info for field types.
242struct FieldTypeInfo : public TypeInfo {
243 FieldTypeInfo() = default;
244 FieldTypeInfo(const TypeInfo &TI, StringRef Name = StringRef(),
245 StringRef DefaultValue = StringRef())
246 : TypeInfo(TI), Name(Name), DefaultValue(DefaultValue) {}
247
248 bool operator==(const FieldTypeInfo &Other) const {
249 return std::tie(args: Type, args: Name, args: DefaultValue) ==
250 std::tie(args: Other.Type, args: Other.Name, args: Other.DefaultValue);
251 }
252
253 SmallString<16> Name; // Name associated with this info.
254
255 // When used for function parameters, contains the string representing the
256 // expression of the default value, if any.
257 SmallString<16> DefaultValue;
258};
259
260// Info for member types.
261struct MemberTypeInfo : public FieldTypeInfo {
262 MemberTypeInfo() = default;
263 MemberTypeInfo(const TypeInfo &TI, StringRef Name, AccessSpecifier Access,
264 bool IsStatic = false)
265 : FieldTypeInfo(TI, Name), Access(Access), IsStatic(IsStatic) {}
266
267 bool operator==(const MemberTypeInfo &Other) const {
268 return std::tie(args: Type, args: Name, args: Access, args: IsStatic, args: Description) ==
269 std::tie(args: Other.Type, args: Other.Name, args: Other.Access, args: Other.IsStatic,
270 args: Other.Description);
271 }
272
273 // Access level associated with this info (public, protected, private, none).
274 // AS_public is set as default because the bitcode writer requires the enum
275 // with value 0 to be used as the default.
276 // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3)
277 AccessSpecifier Access = AccessSpecifier::AS_public;
278
279 std::vector<CommentInfo> Description; // Comment description of this field.
280 bool IsStatic = false;
281};
282
283struct Location {
284 Location(int StartLineNumber = 0, int EndLineNumber = 0,
285 StringRef Filename = StringRef(), bool IsFileInRootDir = false)
286 : StartLineNumber(StartLineNumber), EndLineNumber(EndLineNumber),
287 Filename(Filename), IsFileInRootDir(IsFileInRootDir) {}
288
289 bool operator==(const Location &Other) const {
290 return std::tie(args: StartLineNumber, args: EndLineNumber, args: Filename) ==
291 std::tie(args: Other.StartLineNumber, args: Other.EndLineNumber, args: Other.Filename);
292 }
293
294 bool operator!=(const Location &Other) const { return !(*this == Other); }
295
296 // This operator is used to sort a vector of Locations.
297 // No specific order (attributes more important than others) is required. Any
298 // sort is enough, the order is only needed to call std::unique after sorting
299 // the vector.
300 bool operator<(const Location &Other) const {
301 return std::tie(args: StartLineNumber, args: EndLineNumber, args: Filename) <
302 std::tie(args: Other.StartLineNumber, args: Other.EndLineNumber, args: Other.Filename);
303 }
304
305 int StartLineNumber = 0; // Line number of this Location.
306 int EndLineNumber = 0;
307 SmallString<32> Filename; // File for this Location.
308 bool IsFileInRootDir = false; // Indicates if file is inside root directory
309};
310
311/// A base struct for Infos.
312struct Info {
313 Info(InfoType IT = InfoType::IT_default, SymbolID USR = SymbolID(),
314 StringRef Name = StringRef(), StringRef Path = StringRef())
315 : USR(USR), IT(IT), Name(Name), Path(Path) {}
316
317 Info(const Info &Other) = delete;
318 Info(Info &&Other) = default;
319
320 virtual ~Info() = default;
321
322 Info &operator=(Info &&Other) = default;
323
324 SymbolID USR =
325 SymbolID(); // Unique identifier for the decl described by this Info.
326 InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
327 SmallString<16> Name; // Unqualified name of the decl.
328 llvm::SmallVector<Reference, 4>
329 Namespace; // List of parent namespaces for this decl.
330 std::vector<CommentInfo> Description; // Comment description of this decl.
331 llvm::SmallString<128> Path; // Path of directory where the clang-doc
332 // generated file will be saved
333
334 void mergeBase(Info &&I);
335 bool mergeable(const Info &Other);
336
337 llvm::SmallString<16> extractName() const;
338
339 /// Returns the file path for this Info relative to CurrentPath.
340 llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
341
342 /// Returns the basename that should be used for this Info.
343 llvm::SmallString<16> getFileBaseName() const;
344};
345
346// Info for namespaces.
347struct NamespaceInfo : public Info {
348 NamespaceInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
349 StringRef Path = StringRef());
350
351 void merge(NamespaceInfo &&I);
352
353 ScopeChildren Children;
354};
355
356// Info for symbols.
357struct SymbolInfo : public Info {
358 SymbolInfo(InfoType IT, SymbolID USR = SymbolID(),
359 StringRef Name = StringRef(), StringRef Path = StringRef())
360 : Info(IT, USR, Name, Path) {}
361
362 void merge(SymbolInfo &&I);
363
364 bool operator<(const SymbolInfo &Other) const {
365 // Sort by declaration location since we want the doc to be
366 // generated in the order of the source code.
367 // If the declaration location is the same, or not present
368 // we sort by defined location otherwise fallback to the extracted name
369 if (Loc.size() > 0 && Other.Loc.size() > 0 && Loc[0] != Other.Loc[0])
370 return Loc[0] < Other.Loc[0];
371
372 if (DefLoc && Other.DefLoc && *DefLoc != *Other.DefLoc)
373 return *DefLoc < *Other.DefLoc;
374
375 return extractName() < Other.extractName();
376 }
377
378 std::optional<Location> DefLoc; // Location where this decl is defined.
379 llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
380 SmallString<16> MangledName;
381 bool IsStatic = false;
382};
383
384struct FriendInfo : SymbolInfo {
385 FriendInfo() : SymbolInfo(InfoType::IT_friend) {}
386 FriendInfo(SymbolID USR) : SymbolInfo(InfoType::IT_friend, USR) {}
387 FriendInfo(const InfoType IT, const SymbolID &USR,
388 const StringRef Name = StringRef())
389 : SymbolInfo(IT, USR, Name) {}
390 bool mergeable(const FriendInfo &Other);
391 void merge(FriendInfo &&Other);
392
393 Reference Ref;
394 std::optional<TemplateInfo> Template;
395 std::optional<TypeInfo> ReturnType;
396 std::optional<SmallVector<FieldTypeInfo, 4>> Params;
397 bool IsClass = false;
398};
399
400struct VarInfo : SymbolInfo {
401 VarInfo() : SymbolInfo(InfoType::IT_variable) {}
402 explicit VarInfo(SymbolID USR) : SymbolInfo(InfoType::IT_variable, USR) {}
403
404 void merge(VarInfo &&I);
405
406 TypeInfo Type;
407};
408
409// TODO: Expand to allow for documenting templating and default args.
410// Info for functions.
411struct FunctionInfo : public SymbolInfo {
412 FunctionInfo(SymbolID USR = SymbolID())
413 : SymbolInfo(InfoType::IT_function, USR) {}
414
415 void merge(FunctionInfo &&I);
416
417 bool IsMethod = false; // Indicates whether this function is a class method.
418 Reference Parent; // Reference to the parent class decl for this method.
419 TypeInfo ReturnType; // Info about the return type of this function.
420 llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
421 // Access level for this method (public, private, protected, none).
422 // AS_public is set as default because the bitcode writer requires the enum
423 // with value 0 to be used as the default.
424 // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3)
425 AccessSpecifier Access = AccessSpecifier::AS_public;
426
427 // Full qualified name of this function, including namespaces and template
428 // specializations.
429 SmallString<16> FullName;
430
431 // Function Prototype
432 SmallString<256> Prototype;
433
434 // When present, this function is a template or specialization.
435 std::optional<TemplateInfo> Template;
436};
437
438// TODO: Expand to allow for documenting templating, inheritance access,
439// friend classes
440// Info for types.
441struct RecordInfo : public SymbolInfo {
442 RecordInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
443 StringRef Path = StringRef());
444
445 void merge(RecordInfo &&I);
446
447 // Type of this record (struct, class, union, interface).
448 TagTypeKind TagType = TagTypeKind::Struct;
449
450 // Full qualified name of this record, including namespaces and template
451 // specializations.
452 SmallString<16> FullName;
453
454 // When present, this record is a template or specialization.
455 std::optional<TemplateInfo> Template;
456
457 // Indicates if the record was declared using a typedef. Things like anonymous
458 // structs in a typedef:
459 // typedef struct { ... } foo_t;
460 // are converted into records with the typedef as the Name + this flag set.
461 bool IsTypeDef = false;
462
463 llvm::SmallVector<MemberTypeInfo, 4>
464 Members; // List of info about record members.
465 llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
466 // (does not include virtual
467 // parents).
468 llvm::SmallVector<Reference, 4>
469 VirtualParents; // List of virtual base/parent records.
470
471 std::vector<BaseRecordInfo>
472 Bases; // List of base/parent records; this includes inherited methods and
473 // attributes
474
475 std::vector<FriendInfo> Friends;
476
477 ScopeChildren Children;
478};
479
480// Info for typedef and using statements.
481struct TypedefInfo : public SymbolInfo {
482 TypedefInfo(SymbolID USR = SymbolID())
483 : SymbolInfo(InfoType::IT_typedef, USR) {}
484
485 void merge(TypedefInfo &&I);
486
487 TypeInfo Underlying;
488
489 // Underlying type declaration
490 SmallString<16> TypeDeclaration;
491
492 /// Comment description for the typedef.
493 std::vector<CommentInfo> Description;
494
495 // Indicates if this is a new C++ "using"-style typedef:
496 // using MyVector = std::vector<int>
497 // False means it's a C-style typedef:
498 // typedef std::vector<int> MyVector;
499 bool IsUsing = false;
500};
501
502struct BaseRecordInfo : public RecordInfo {
503 BaseRecordInfo();
504 BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual,
505 AccessSpecifier Access, bool IsParent);
506
507 // Indicates if base corresponds to a virtual inheritance
508 bool IsVirtual = false;
509 // Access level associated with this inherited info (public, protected,
510 // private).
511 AccessSpecifier Access = AccessSpecifier::AS_public;
512 bool IsParent = false; // Indicates if this base is a direct parent
513};
514
515// Information for a single possible value of an enumeration.
516struct EnumValueInfo {
517 explicit EnumValueInfo(StringRef Name = StringRef(),
518 StringRef Value = StringRef("0"),
519 StringRef ValueExpr = StringRef())
520 : Name(Name), Value(Value), ValueExpr(ValueExpr) {}
521
522 bool operator==(const EnumValueInfo &Other) const {
523 return std::tie(args: Name, args: Value, args: ValueExpr) ==
524 std::tie(args: Other.Name, args: Other.Value, args: Other.ValueExpr);
525 }
526
527 SmallString<16> Name;
528
529 // The computed value of the enumeration constant. This could be the result of
530 // evaluating the ValueExpr, or it could be automatically generated according
531 // to C rules.
532 SmallString<16> Value;
533
534 // Stores the user-supplied initialization expression for this enumeration
535 // constant. This will be empty for implicit enumeration values.
536 SmallString<16> ValueExpr;
537
538 /// Comment description of this field.
539 std::vector<CommentInfo> Description;
540};
541
542// TODO: Expand to allow for documenting templating.
543// Info for types.
544struct EnumInfo : public SymbolInfo {
545 EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
546 EnumInfo(SymbolID USR) : SymbolInfo(InfoType::IT_enum, USR) {}
547
548 void merge(EnumInfo &&I);
549
550 // Indicates whether this enum is scoped (e.g. enum class).
551 bool Scoped = false;
552
553 // Set to nonempty to the type when this is an explicitly typed enum. For
554 // enum Foo : short { ... };
555 // this will be "short".
556 std::optional<TypeInfo> BaseType;
557
558 llvm::SmallVector<EnumValueInfo, 4> Members; // List of enum members.
559};
560
561struct ConceptInfo : public SymbolInfo {
562 ConceptInfo() : SymbolInfo(InfoType::IT_concept) {}
563 ConceptInfo(SymbolID USR) : SymbolInfo(InfoType::IT_concept, USR) {}
564
565 void merge(ConceptInfo &&I);
566
567 bool IsType;
568 TemplateInfo Template;
569 SmallString<16> ConstraintExpression;
570};
571
572struct Index : public Reference {
573 Index() = default;
574 Index(StringRef Name) : Reference(SymbolID(), Name) {}
575 Index(StringRef Name, StringRef JumpToSection)
576 : Reference(SymbolID(), Name), JumpToSection(JumpToSection) {}
577 Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
578 : Reference(USR, Name, IT, Name, Path) {}
579 // This is used to look for a USR in a vector of Indexes using std::find
580 bool operator==(const SymbolID &Other) const { return USR == Other; }
581 bool operator<(const Index &Other) const;
582
583 std::optional<SmallString<16>> JumpToSection;
584 std::vector<Index> Children;
585
586 void sort();
587};
588
589// TODO: Add functionality to include separate markdown pages.
590
591// A standalone function to call to merge a vector of infos into one.
592// This assumes that all infos in the vector are of the same type, and will fail
593// if they are different.
594llvm::Expected<std::unique_ptr<Info>>
595mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
596
597struct ClangDocContext {
598 ClangDocContext() = default;
599 ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName,
600 bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot,
601 StringRef RepositoryUrl, StringRef RepositoryCodeLinePrefix,
602 StringRef Base, std::vector<std::string> UserStylesheets,
603 bool FTimeTrace = false);
604 tooling::ExecutionContext *ECtx;
605 std::string ProjectName; // Name of project clang-doc is documenting.
606 bool PublicOnly; // Indicates if only public declarations are documented.
607 bool FTimeTrace; // Indicates if ftime trace is turned on
608 int Granularity; // Granularity of ftime trace
609 std::string OutDirectory; // Directory for outputting generated files.
610 std::string SourceRoot; // Directory where processed files are stored. Links
611 // to definition locations will only be generated if
612 // the file is in this dir.
613 // URL of repository that hosts code used for links to definition locations.
614 std::optional<std::string> RepositoryUrl;
615 // Prefix of line code for repository.
616 std::optional<std::string> RepositoryLinePrefix;
617 // Path of CSS stylesheets that will be copied to OutDirectory and used to
618 // style all HTML files.
619 std::vector<std::string> UserStylesheets;
620 // JavaScript files that will be imported in all HTML files.
621 std::vector<std::string> JsScripts;
622 // Base directory for remote repositories.
623 StringRef Base;
624 // Maps mustache template types to specific mustache template files.
625 // Ex. comment-template -> /path/to/comment-template.mustache
626 llvm::StringMap<std::string> MustacheTemplates;
627 Index Idx;
628};
629
630} // namespace doc
631} // namespace clang
632
633#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
634

source code of clang-tools-extra/clang-doc/Representation.h