aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-doc
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-doc')
-rw-r--r--clang-tools-extra/clang-doc/BitcodeReader.cpp85
-rw-r--r--clang-tools-extra/clang-doc/BitcodeWriter.cpp43
-rw-r--r--clang-tools-extra/clang-doc/BitcodeWriter.h12
-rw-r--r--clang-tools-extra/clang-doc/Representation.cpp4
-rw-r--r--clang-tools-extra/clang-doc/Representation.h84
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp126
-rw-r--r--clang-tools-extra/clang-doc/YAMLGenerator.cpp26
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>());
}
};