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