Skip to content

Commit

Permalink
[clang-doc] Add template support.
Browse files Browse the repository at this point in the history
Reads template information from the AST and adds template parameters and
specialization information to the corresponding clang-doc structures.

Add a "QualName" to the Reference struct which includes the full
qualified type name. The Reference object represents a link in the
HTML/MD generators so is based on the unqualified name. But this does
not encode C-V qualifiers or template information that decorate the
name. The new QualName member encodes all of this information and also
makes it easier for the generators or downsteam YAML consumers to
generate the full name (before they had to process the "Path").

In test code that was changed, remove made-up paths to built-in types
like "int". In addition to slightnly cleaning up the code, these types
do not have paths in real execution, and generating incorrect references
to nonexistant data may complicate future changes in the generators.

Differential Revision: https://reviews.llvm.org/D139154
  • Loading branch information
brettw committed Dec 7, 2022
1 parent 538f69f commit 0f6dbb5
Show file tree
Hide file tree
Showing 13 changed files with 587 additions and 80 deletions.
85 changes: 85 additions & 0 deletions clang-tools-extra/clang-doc/BitcodeReader.cpp
Expand Up @@ -351,6 +351,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:
Expand All @@ -363,6 +365,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");
Expand Down Expand Up @@ -595,6 +620,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) {
Expand Down Expand Up @@ -719,6 +783,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))
Expand Down
43 changes: 40 additions & 3 deletions clang-tools-extra/clang-doc/BitcodeWriter.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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}},
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
12 changes: 10 additions & 2 deletions clang-tools-extra/clang-doc/BitcodeWriter.h
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -169,6 +174,9 @@ class ClangDocBitcodeWriter {
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:
Expand Down Expand Up @@ -215,7 +223,7 @@ class ClangDocBitcodeWriter {
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.
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clang-doc/Representation.cpp
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down

0 comments on commit 0f6dbb5

Please sign in to comment.