diff options
Diffstat (limited to 'clang-tools-extra/clang-doc')
-rw-r--r-- | clang-tools-extra/clang-doc/BitcodeReader.cpp | 85 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/BitcodeWriter.cpp | 43 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/BitcodeWriter.h | 12 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/Representation.cpp | 4 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/Representation.h | 84 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/Serialize.cpp | 126 | ||||
-rw-r--r-- | clang-tools-extra/clang-doc/YAMLGenerator.cpp | 26 |
7 files changed, 346 insertions, 34 deletions
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index c6928f6..9ac60fa 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -350,6 +350,8 @@ llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, return decodeRecord(R, I->USR, Blob); case REFERENCE_NAME: return decodeRecord(R, I->Name, Blob); + case REFERENCE_QUAL_NAME: + return decodeRecord(R, I->QualName, Blob); case REFERENCE_TYPE: return decodeRecord(R, I->RefType, Blob); case REFERENCE_PATH: @@ -362,6 +364,29 @@ llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, } } +llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, + TemplateInfo *I) { + // Currently there are no child records of TemplateInfo (only child blocks). + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for TemplateParamInfo"); +} + +llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, + TemplateSpecializationInfo *I) { + if (ID == TEMPLATE_SPECIALIZATION_OF) + return decodeRecord(R, I->SpecializationOf, Blob); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for TemplateParamInfo"); +} + +llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob, + TemplateParamInfo *I) { + if (ID == TEMPLATE_PARAM_CONTENTS) + return decodeRecord(R, I->Contents, Blob); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid field for TemplateParamInfo"); +} + template <typename T> llvm::Expected<CommentInfo *> getCommentInfo(T I) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid type cannot contain CommentInfo"); @@ -594,6 +619,45 @@ template <> void addChild(BaseRecordInfo *I, FunctionInfo &&R) { I->Children.Functions.emplace_back(std::move(R)); } +// TemplateParam children. These go into either a TemplateInfo (for template +// parameters) or TemplateSpecializationInfo (for the specialization's +// parameters). +template <typename T> void addTemplateParam(T I, TemplateParamInfo &&P) { + llvm::errs() << "invalid container for template parameter"; + exit(1); +} +template <> void addTemplateParam(TemplateInfo *I, TemplateParamInfo &&P) { + I->Params.emplace_back(std::move(P)); +} +template <> +void addTemplateParam(TemplateSpecializationInfo *I, TemplateParamInfo &&P) { + I->Params.emplace_back(std::move(P)); +} + +// Template info. These apply to either records or functions. +template <typename T> void addTemplate(T I, TemplateInfo &&P) { + llvm::errs() << "invalid container for template info"; + exit(1); +} +template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) { + I->Template.emplace(std::move(P)); +} +template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) { + I->Template.emplace(std::move(P)); +} + +// Template specializations go only into template records. +template <typename T> +void addTemplateSpecialization(T I, TemplateSpecializationInfo &&TSI) { + llvm::errs() << "invalid container for template specialization info"; + exit(1); +} +template <> +void addTemplateSpecialization(TemplateInfo *I, + TemplateSpecializationInfo &&TSI) { + I->Specialization.emplace(std::move(TSI)); +} + // Read records from bitcode into a given info. template <typename T> llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) { @@ -718,6 +782,27 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { addChild(I, std::move(EV)); return llvm::Error::success(); } + case BI_TEMPLATE_BLOCK_ID: { + TemplateInfo TI; + if (auto Err = readBlock(ID, &TI)) + return Err; + addTemplate(I, std::move(TI)); + return llvm::Error::success(); + } + case BI_TEMPLATE_SPECIALIZATION_BLOCK_ID: { + TemplateSpecializationInfo TSI; + if (auto Err = readBlock(ID, &TSI)) + return Err; + addTemplateSpecialization(I, std::move(TSI)); + return llvm::Error::success(); + } + case BI_TEMPLATE_PARAM_BLOCK_ID: { + TemplateParamInfo TPI; + if (auto Err = readBlock(ID, &TPI)) + return Err; + addTemplateParam(I, std::move(TPI)); + return llvm::Error::success(); + } case BI_TYPEDEF_BLOCK_ID: { TypedefInfo TI; if (auto Err = readBlock(ID, &TI)) diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index bb0698a..8a5647c 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -121,7 +121,10 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"}, {BI_FUNCTION_BLOCK_ID, "FunctionBlock"}, {BI_COMMENT_BLOCK_ID, "CommentBlock"}, - {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}}; + {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}, + {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"}, + {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"}, + {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}}; assert(Inits.size() == BlockIdCount); for (const auto &Init : Inits) BlockIdNameMap[Init.first] = Init.second; @@ -186,9 +189,12 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}}, {REFERENCE_USR, {"USR", &SymbolIDAbbrev}}, {REFERENCE_NAME, {"Name", &StringAbbrev}}, + {REFERENCE_QUAL_NAME, {"QualName", &StringAbbrev}}, {REFERENCE_TYPE, {"RefType", &IntAbbrev}}, {REFERENCE_PATH, {"Path", &StringAbbrev}}, {REFERENCE_FIELD, {"Field", &IntAbbrev}}, + {TEMPLATE_PARAM_CONTENTS, {"Contents", &StringAbbrev}}, + {TEMPLATE_SPECIALIZATION_OF, {"SpecializationOf", &SymbolIDAbbrev}}, {TYPEDEF_USR, {"USR", &SymbolIDAbbrev}}, {TYPEDEF_NAME, {"Name", &StringAbbrev}}, {TYPEDEF_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, @@ -244,8 +250,12 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>> FUNCTION_ACCESS, FUNCTION_IS_METHOD}}, // Reference Block {BI_REFERENCE_BLOCK_ID, - {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH, - REFERENCE_FIELD}}}; + {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE, + REFERENCE_PATH, REFERENCE_FIELD}}, + // Template Blocks. + {BI_TEMPLATE_BLOCK_ID, {}}, + {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}}, + {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}}; // AbbreviationMap @@ -378,6 +388,8 @@ void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) { Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record); } +void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {} + bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) { assert(RecordIdNameMap[ID] && "Unknown RecordId."); if (!ShouldEmit) @@ -416,6 +428,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID); emitRecord(R.USR, REFERENCE_USR); emitRecord(R.Name, REFERENCE_NAME); + emitRecord(R.QualName, REFERENCE_QUAL_NAME); emitRecord((unsigned)R.RefType, REFERENCE_TYPE); emitRecord(R.Path, REFERENCE_PATH); emitRecord((unsigned)Field, REFERENCE_FIELD); @@ -556,6 +569,8 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) { emitBlock(C); for (const auto &C : I.Children.Typedefs) emitBlock(C); + if (I.Template) + emitBlock(*I.Template); } void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) { @@ -591,6 +606,28 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) { emitBlock(I.ReturnType); for (const auto &N : I.Params) emitBlock(N); + if (I.Template) + emitBlock(*I.Template); +} + +void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) { + StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID); + for (const auto &P : T.Params) + emitBlock(P); + if (T.Specialization) + emitBlock(*T.Specialization); +} + +void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) { + StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID); + emitRecord(T.SpecializationOf, TEMPLATE_SPECIALIZATION_OF); + for (const auto &P : T.Params) + emitBlock(P); +} + +void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) { + StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID); + emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS); } bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h index 5a2514a..9a572e4 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -17,7 +17,6 @@ #include "Representation.h" #include "clang/AST/AST.h" -#include "llvm/ADT/APSInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -64,6 +63,9 @@ enum BlockId { BI_FUNCTION_BLOCK_ID, BI_COMMENT_BLOCK_ID, BI_REFERENCE_BLOCK_ID, + BI_TEMPLATE_BLOCK_ID, + BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, + BI_TEMPLATE_PARAM_BLOCK_ID, BI_TYPEDEF_BLOCK_ID, BI_LAST, BI_FIRST = BI_VERSION_BLOCK_ID @@ -121,9 +123,12 @@ enum RecordId { BASE_RECORD_IS_PARENT, REFERENCE_USR, REFERENCE_NAME, + REFERENCE_QUAL_NAME, REFERENCE_TYPE, REFERENCE_PATH, REFERENCE_FIELD, + TEMPLATE_PARAM_CONTENTS, + TEMPLATE_SPECIALIZATION_OF, TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, @@ -169,6 +174,9 @@ public: void emitBlock(const FieldTypeInfo &B); void emitBlock(const MemberTypeInfo &T); void emitBlock(const CommentInfo &B); + void emitBlock(const TemplateInfo &T); + void emitBlock(const TemplateSpecializationInfo &T); + void emitBlock(const TemplateParamInfo &T); void emitBlock(const Reference &B, FieldId F); private: @@ -215,7 +223,7 @@ private: void emitRecord(bool Value, RecordId ID); void emitRecord(int Value, RecordId ID); void emitRecord(unsigned Value, RecordId ID); - void emitRecord(llvm::APSInt Value, RecordId ID); + void emitRecord(const TemplateInfo &Templ); bool prepRecordData(RecordId ID, bool ShouldEmit = true); // Emission of appropriate abbreviation type. diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 27b83d6..c127999 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -250,6 +250,8 @@ void RecordInfo::merge(RecordInfo &&Other) { reduceChildren(Children.Enums, std::move(Other.Children.Enums)); reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs)); SymbolInfo::merge(std::move(Other)); + if (!Template) + Template = Other.Template; } void EnumInfo::merge(EnumInfo &&Other) { @@ -274,6 +276,8 @@ void FunctionInfo::merge(FunctionInfo &&Other) { if (Params.empty()) Params = std::move(Other.Params); SymbolInfo::merge(std::move(Other)); + if (!Template) + Template = Other.Template; } void TypedefInfo::merge(TypedefInfo &&Other) { diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 2a69088..564488c 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -18,7 +18,6 @@ #include "clang/Basic/Specifiers.h" #include "clang/Tooling/StandaloneExecution.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include <array> @@ -117,13 +116,21 @@ struct CommentInfo { }; struct Reference { + // This variant (that takes no qualified name parameter) uses the Name as the + // QualName (very useful in unit tests to reduce verbosity). This can't use an + // empty string to indicate the default because we need to accept the empty + // string as a valid input for the global namespace (it will have + // "GlobalNamespace" as the name, but an empty QualName). Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(), - InfoType IT = InfoType::IT_default, StringRef Path = StringRef()) - : USR(USR), Name(Name), RefType(IT), Path(Path) {} + InfoType IT = InfoType::IT_default) + : USR(USR), Name(Name), QualName(Name), RefType(IT) {} + Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, + StringRef Path = StringRef()) + : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {} bool operator==(const Reference &Other) const { - return std::tie(USR, Name, RefType) == - std::tie(Other.USR, Other.Name, Other.RefType); + return std::tie(USR, Name, QualName, RefType) == + std::tie(Other.USR, Other.Name, QualName, Other.RefType); } bool mergeable(const Reference &Other); @@ -136,7 +143,17 @@ struct Reference { llvm::SmallString<16> getFileBaseName() const; SymbolID USR = SymbolID(); // Unique identifier for referenced decl - SmallString<16> Name; // Name of type (possibly unresolved). + + // Name of type (possibly unresolved). Not including namespaces or template + // parameters (so for a std::vector<int> this would be "vector"). See also + // QualName. + SmallString<16> Name; + + // Full qualified name of this type, including namespaces and template + // parameter (for example this could be "std::vector<int>"). Contrast to + // Name. + SmallString<16> QualName; + InfoType RefType = InfoType::IT_default; // Indicates the type of this // Reference (namespace, record, // function, enum, default). @@ -169,13 +186,46 @@ struct TypeInfo { // Convenience constructor for when there is no symbol ID or info type // (normally used for built-in types in tests). TypeInfo(StringRef Name, StringRef Path = StringRef()) - : Type(SymbolID(), Name, InfoType::IT_default, Path) {} + : Type(SymbolID(), Name, InfoType::IT_default, Name, Path) {} bool operator==(const TypeInfo &Other) const { return Type == Other.Type; } Reference Type; // Referenced type in this info. }; +// Represents one template parameter. +// +// This is a very simple serialization of the text of the source code of the +// template parameter. It is saved in a struct so there is a place to add the +// name and default values in the future if needed. +struct TemplateParamInfo { + TemplateParamInfo() = default; + explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {} + + // The literal contents of the code for that specifies this template parameter + // for this declaration. Typical values will be "class T" and + // "typename T = int". + SmallString<16> Contents; +}; + +struct TemplateSpecializationInfo { + // Indicates the declaration that this specializes. + SymbolID SpecializationOf; + + // Template parameters applying to the specialized record/function. + std::vector<TemplateParamInfo> Params; +}; + +// Records the template information for a struct or function that is a template +// or an explicit template specialization. +struct TemplateInfo { + // May be empty for non-partial specializations. + std::vector<TemplateParamInfo> Params; + + // Set when this is a specialization of another record/function. + std::optional<TemplateSpecializationInfo> Specialization; +}; + // Info for field types. struct FieldTypeInfo : public TypeInfo { FieldTypeInfo() = default; @@ -317,6 +367,13 @@ struct FunctionInfo : public SymbolInfo { // with value 0 to be used as the default. // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3) AccessSpecifier Access = AccessSpecifier::AS_public; + + // Full qualified name of this function, including namespaces and template + // specializations. + SmallString<16> FullName; + + // When present, this function is a template or specialization. + std::optional<TemplateInfo> Template; }; // TODO: Expand to allow for documenting templating, inheritance access, @@ -332,6 +389,13 @@ struct RecordInfo : public SymbolInfo { // Type of this record (struct, class, union, interface). TagTypeKind TagType = TagTypeKind::TTK_Struct; + // Full qualified name of this record, including namespaces and template + // specializations. + SmallString<16> FullName; + + // When present, this record is a template or specialization. + std::optional<TemplateInfo> Template; + // Indicates if the record was declared using a typedef. Things like anonymous // structs in a typedef: // typedef struct { ... } foo_t; @@ -433,12 +497,12 @@ struct Index : public Reference { Index(StringRef Name, StringRef JumpToSection) : Reference(SymbolID(), Name), JumpToSection(JumpToSection) {} Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path) - : Reference(USR, Name, IT, Path) {} + : Reference(USR, Name, IT, Name, Path) {} // This is used to look for a USR in a vector of Indexes using std::find bool operator==(const SymbolID &Other) const { return USR == Other; } bool operator<(const Index &Other) const; - llvm::Optional<SmallString<16>> JumpToSection; + std::optional<SmallString<16>> JumpToSection; std::vector<Index> Children; void sort(); @@ -467,7 +531,7 @@ struct ClangDocContext { // to definition locations will only be generated if // the file is in this dir. // URL of repository that hosts code used for links to definition locations. - llvm::Optional<std::string> RepositoryUrl; + std::optional<std::string> RepositoryUrl; // Path of CSS stylesheets that will be copied to OutDirectory and used to // style all HTML files. std::vector<std::string> UserStylesheets; diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 66a938d..ac8e253 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -250,7 +250,7 @@ TypeInfo getTypeInfoForType(const QualType &T) { IT = InfoType::IT_default; } return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT, - getInfoRelativePath(TD))); + T.getAsString(), getInfoRelativePath(TD))); } static bool isPublic(const clang::AccessSpecifier AS, @@ -281,12 +281,12 @@ static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, // See MakeAndInsertIntoParent(). static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) { Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace, - getInfoRelativePath(Info.Namespace)); + Info.Name, getInfoRelativePath(Info.Namespace)); } static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) { Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record, - getInfoRelativePath(Info.Namespace)); + Info.Name, getInfoRelativePath(Info.Namespace)); } static void InsertChild(ScopeChildren &Scope, EnumInfo Info) { @@ -405,10 +405,7 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { for (const ParmVarDecl *P : D->parameters()) { FieldTypeInfo &FieldInfo = I.Params.emplace_back( getTypeInfoForType(P->getOriginalType()), P->getNameAsString()); - - if (const Expr *DefaultArg = P->getDefaultArg()) { - FieldInfo.DefaultValue = getSourceCode(D, DefaultArg->getSourceRange()); - } + FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange()); } } @@ -424,18 +421,19 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) { if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) { const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl(); I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(), - InfoType::IT_record); + InfoType::IT_record, B.getType().getAsString()); } else if (const RecordDecl *P = getRecordDeclForType(B.getType())) I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), - InfoType::IT_record, getInfoRelativePath(P)); + InfoType::IT_record, P->getQualifiedNameAsString(), + getInfoRelativePath(P)); else I.Parents.emplace_back(SymbolID(), B.getType().getAsString()); } for (const CXXBaseSpecifier &B : D->vbases()) { if (const RecordDecl *P = getRecordDeclForType(B.getType())) - I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(), - InfoType::IT_record, - getInfoRelativePath(P)); + I.VirtualParents.emplace_back( + getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record, + P->getQualifiedNameAsString(), getInfoRelativePath(P)); else I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString()); } @@ -455,16 +453,19 @@ populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, } else Namespace = N->getNameAsString(); Namespaces.emplace_back(getUSRForDecl(N), Namespace, - InfoType::IT_namespace); + InfoType::IT_namespace, + N->getQualifiedNameAsString()); } else if (const auto *N = dyn_cast<RecordDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), - InfoType::IT_record); + InfoType::IT_record, + N->getQualifiedNameAsString()); else if (const auto *N = dyn_cast<FunctionDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), - InfoType::IT_function); + InfoType::IT_function, + N->getQualifiedNameAsString()); else if (const auto *N = dyn_cast<EnumDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), - InfoType::IT_enum); + InfoType::IT_enum, N->getQualifiedNameAsString()); } while ((DC = DC->getParent())); // The global namespace should be added to the list of namespaces if the decl // corresponds to a Record and if it doesn't have any namespace (because this @@ -476,6 +477,30 @@ populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, InfoType::IT_namespace); } +void PopulateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo, + const clang::Decl *D) { + if (const TemplateParameterList *ParamList = + D->getDescribedTemplateParams()) { + if (!TemplateInfo) { + TemplateInfo.emplace(); + } + for (const NamedDecl *ND : *ParamList) { + TemplateInfo->Params.emplace_back( + getSourceCode(ND, ND->getSourceRange())); + } + } +} + +TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D, + const TemplateArgument &Arg) { + // The TemplateArgument's pretty printing handles all the normal cases + // well enough for our requirements. + std::string Str; + llvm::raw_string_ostream Stream(Str); + Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false); + return TemplateParamInfo(Str); +} + template <typename T> static void populateInfo(Info &I, const T *D, const FullComment *C, bool &IsInAnonymousNamespace) { @@ -508,6 +533,26 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, IsInAnonymousNamespace); I.ReturnType = getTypeInfoForType(D->getReturnType()); parseParameters(I, D); + + PopulateTemplateParameters(I.Template, D); + + // Handle function template specializations. + if (const FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) { + if (!I.Template) + I.Template.emplace(); + I.Template->Specialization.emplace(); + auto &Specialization = *I.Template->Specialization; + + Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate()); + + // Template parameters to the specialization. + if (FTSI->TemplateArguments) { + for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) { + Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg)); + } + } + } } static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) { @@ -627,6 +672,46 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, } I->Path = getInfoRelativePath(I->Namespace); + PopulateTemplateParameters(I->Template, D); + + // Full and partial specializations. + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + if (!I->Template) + I->Template.emplace(); + I->Template->Specialization.emplace(); + auto &Specialization = *I->Template->Specialization; + + // What this is a specialization of. + auto SpecOf = CTSD->getSpecializedTemplateOrPartial(); + if (SpecOf.is<ClassTemplateDecl *>()) { + Specialization.SpecializationOf = + getUSRForDecl(SpecOf.get<ClassTemplateDecl *>()); + } else if (SpecOf.is<ClassTemplatePartialSpecializationDecl *>()) { + Specialization.SpecializationOf = + getUSRForDecl(SpecOf.get<ClassTemplatePartialSpecializationDecl *>()); + } + + // Parameters to the specilization. For partial specializations, get the + // parameters "as written" from the ClassTemplatePartialSpecializationDecl + // because the non-explicit template parameters will have generated internal + // placeholder names rather than the names the user typed that match the + // template parameters. + if (const ClassTemplatePartialSpecializationDecl *CTPSD = + dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { + if (const ASTTemplateArgumentListInfo *AsWritten = + CTPSD->getTemplateArgsAsWritten()) { + for (unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) { + Specialization.Params.emplace_back( + getSourceCode(D, (*AsWritten)[i].getSourceRange())); + } + } + } else { + for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) { + Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg)); + } + } + } + // Records are inserted into the parent by reference, so we need to return // both the parent and the record itself. auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I); @@ -669,7 +754,8 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, SymbolID ParentUSR = getUSRForDecl(Parent); Func.Parent = - Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record}; + Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record, + Parent->getQualifiedNameAsString()}; Func.Access = D->getAccess(); // Info is wrapped in its parent scope so is returned in the second position. @@ -731,8 +817,10 @@ emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, return {}; Enum.Scoped = D->isScoped(); - if (D->isFixed()) - Enum.BaseType = TypeInfo(D->getIntegerType().getAsString()); + if (D->isFixed()) { + auto Name = D->getIntegerType().getAsString(); + Enum.BaseType = TypeInfo(Name, Name); + } parseEnumerators(Enum, D); // Info is wrapped in its parent scope so is returned in the second position. diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp index 0e662c0..57cb294e 100644 --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -9,6 +9,7 @@ //===----------------------------------------------------------------------===// #include "Generators.h" +#include "Representation.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <optional> @@ -24,6 +25,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>) @@ -143,6 +145,7 @@ static void RecordInfoMapping(IO &IO, RecordInfo &I) { IO.mapOptional("ChildFunctions", I.Children.Functions); IO.mapOptional("ChildEnums", I.Children.Enums); IO.mapOptional("ChildTypedefs", I.Children.Typedefs); + IO.mapOptional("Template", I.Template); } static void CommentInfoMapping(IO &IO, CommentInfo &I) { @@ -175,6 +178,7 @@ template <> struct MappingTraits<Reference> { static void mapping(IO &IO, Reference &Ref) { IO.mapOptional("Type", Ref.RefType, InfoType::IT_default); IO.mapOptional("Name", Ref.Name, SmallString<16>()); + IO.mapOptional("QualName", Ref.QualName, SmallString<16>()); IO.mapOptional("USR", Ref.USR, SymbolID()); IO.mapOptional("Path", Ref.Path, SmallString<128>()); } @@ -268,6 +272,28 @@ template <> struct MappingTraits<FunctionInfo> { // the AS that shouldn't be part of the output. Even though AS_public is the // default in the struct, it should be displayed in the YAML output. IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none); + IO.mapOptional("Template", I.Template); + } +}; + +template <> struct MappingTraits<TemplateParamInfo> { + static void mapping(IO &IO, TemplateParamInfo &I) { + IO.mapOptional("Contents", I.Contents); + } +}; + +template <> struct MappingTraits<TemplateSpecializationInfo> { + static void mapping(IO &IO, TemplateSpecializationInfo &I) { + IO.mapOptional("SpecializationOf", I.SpecializationOf); + IO.mapOptional("Params", I.Params); + } +}; + +template <> struct MappingTraits<TemplateInfo> { + static void mapping(IO &IO, TemplateInfo &I) { + IO.mapOptional("Params", I.Params); + IO.mapOptional("Specialization", I.Specialization, + std::optional<TemplateSpecializationInfo>()); } }; |