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