Skip to content

Commit b8ea650

Browse files
authored
[clang-doc] document global variables (#145070)
Visit and map VarDecls to document variables declared in namespace scope.
1 parent de2ec22 commit b8ea650

16 files changed

+188
-25
lines changed

clang-tools-extra/clang-doc/BitcodeReader.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field,
9393
case InfoType::IT_enum:
9494
case InfoType::IT_typedef:
9595
case InfoType::IT_concept:
96+
case InfoType::IT_variable:
9697
Field = IT;
9798
return llvm::Error::success();
9899
}
@@ -416,6 +417,23 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
416417
"invalid field for ConstraintInfo");
417418
}
418419

420+
static llvm::Error parseRecord(const Record &R, unsigned ID,
421+
llvm::StringRef Blob, VarInfo *I) {
422+
switch (ID) {
423+
case VAR_USR:
424+
return decodeRecord(R, I->USR, Blob);
425+
case VAR_NAME:
426+
return decodeRecord(R, I->Name, Blob);
427+
case VAR_DEFLOCATION:
428+
return decodeRecord(R, I->DefLoc, Blob);
429+
case VAR_IS_STATIC:
430+
return decodeRecord(R, I->IsStatic, Blob);
431+
default:
432+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
433+
"invalid field for VarInfo");
434+
}
435+
}
436+
419437
template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
420438
return llvm::createStringError(llvm::inconvertibleErrorCode(),
421439
"invalid type cannot contain CommentInfo");
@@ -458,6 +476,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(ConceptInfo *I) {
458476
return &I->Description.emplace_back();
459477
}
460478

479+
template <> Expected<CommentInfo *> getCommentInfo(VarInfo *I) {
480+
return &I->Description.emplace_back();
481+
}
482+
461483
// When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on
462484
// the parent block to set it. The template specializations define what to do
463485
// for each supported parent block.
@@ -497,6 +519,11 @@ template <> llvm::Error addTypeInfo(TypedefInfo *I, TypeInfo &&T) {
497519
return llvm::Error::success();
498520
}
499521

522+
template <> llvm::Error addTypeInfo(VarInfo *I, TypeInfo &&T) {
523+
I->Type = std::move(T);
524+
return llvm::Error::success();
525+
}
526+
500527
template <typename T>
501528
static llvm::Error addReference(T I, Reference &&R, FieldId F) {
502529
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -643,6 +670,9 @@ template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) {
643670
template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) {
644671
I->Children.Concepts.emplace_back(std::move(R));
645672
}
673+
template <> void addChild(NamespaceInfo *I, VarInfo &&R) {
674+
I->Children.Variables.emplace_back(std::move(R));
675+
}
646676

647677
// Record children:
648678
template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
@@ -887,6 +917,13 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
887917
addChild(I, std::move(CI));
888918
return llvm::Error::success();
889919
}
920+
case BI_VAR_BLOCK_ID: {
921+
VarInfo VI;
922+
if (auto Err = readBlock(ID, &VI))
923+
return Err;
924+
addChild(I, std::move(VI));
925+
return llvm::Error::success();
926+
}
890927
default:
891928
return llvm::createStringError(llvm::inconvertibleErrorCode(),
892929
"invalid subblock type");
@@ -996,6 +1033,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
9961033
return createInfo<ConceptInfo>(ID);
9971034
case BI_FUNCTION_BLOCK_ID:
9981035
return createInfo<FunctionInfo>(ID);
1036+
case BI_VAR_BLOCK_ID:
1037+
return createInfo<VarInfo>(ID);
9991038
default:
10001039
return llvm::createStringError(llvm::inconvertibleErrorCode(),
10011040
"cannot create info");
@@ -1035,6 +1074,7 @@ ClangDocBitcodeReader::readBitcode() {
10351074
case BI_ENUM_BLOCK_ID:
10361075
case BI_TYPEDEF_BLOCK_ID:
10371076
case BI_CONCEPT_BLOCK_ID:
1077+
case BI_VAR_BLOCK_ID:
10381078
case BI_FUNCTION_BLOCK_ID: {
10391079
auto InfoOrErr = readBlockToInfo(ID);
10401080
if (!InfoOrErr)

clang-tools-extra/clang-doc/BitcodeWriter.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
130130
{BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
131131
{BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"},
132132
{BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},
133-
{BI_CONCEPT_BLOCK_ID, "ConceptBlock"}};
133+
{BI_CONCEPT_BLOCK_ID, "ConceptBlock"},
134+
{BI_VAR_BLOCK_ID, "VarBlock"}};
134135
assert(Inits.size() == BlockIdCount);
135136
for (const auto &Init : Inits)
136137
BlockIdNameMap[Init.first] = Init.second;
@@ -213,7 +214,12 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
213214
{CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},
214215
{CONCEPT_CONSTRAINT_EXPRESSION,
215216
{"ConstraintExpression", &genStringAbbrev}},
216-
{CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}}};
217+
{CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}},
218+
{VAR_USR, {"USR", &genSymbolIdAbbrev}},
219+
{VAR_NAME, {"Name", &genStringAbbrev}},
220+
{VAR_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
221+
{VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}}};
222+
217223
assert(Inits.size() == RecordIdCount);
218224
for (const auto &Init : Inits) {
219225
RecordIdNameMap[Init.first] = Init.second;
@@ -277,7 +283,8 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
277283
{CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,
278284
CONCEPT_CONSTRAINT_EXPRESSION}},
279285
// Constraint Block
280-
{BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}}};
286+
{BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}},
287+
{BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}}};
281288

282289
// AbbreviationMap
283290

@@ -540,6 +547,8 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
540547
emitBlock(C);
541548
for (const auto &C : I.Children.Concepts)
542549
emitBlock(C);
550+
for (const auto &C : I.Children.Variables)
551+
emitBlock(C);
543552
}
544553

545554
void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
@@ -682,6 +691,20 @@ void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) {
682691
emitBlock(C.ConceptRef, FieldId::F_concept);
683692
}
684693

694+
void ClangDocBitcodeWriter::emitBlock(const VarInfo &I) {
695+
StreamSubBlockGuard Block(Stream, BI_VAR_BLOCK_ID);
696+
emitRecord(I.USR, VAR_USR);
697+
emitRecord(I.Name, VAR_NAME);
698+
for (const auto &N : I.Namespace)
699+
emitBlock(N, FieldId::F_namespace);
700+
for (const auto &CI : I.Description)
701+
emitBlock(CI);
702+
if (I.DefLoc)
703+
emitRecord(*I.DefLoc, VAR_DEFLOCATION);
704+
emitRecord(I.IsStatic, VAR_IS_STATIC);
705+
emitBlock(I.Type);
706+
}
707+
685708
bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
686709
switch (I->IT) {
687710
case InfoType::IT_namespace:
@@ -702,6 +725,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
702725
case InfoType::IT_concept:
703726
emitBlock(*static_cast<clang::doc::ConceptInfo *>(I));
704727
break;
728+
case InfoType::IT_variable:
729+
emitBlock(*static_cast<VarInfo *>(I));
730+
break;
705731
case InfoType::IT_default:
706732
llvm::errs() << "Unexpected info, unable to write.\n";
707733
return true;

clang-tools-extra/clang-doc/BitcodeWriter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ enum BlockId {
6969
BI_CONSTRAINT_BLOCK_ID,
7070
BI_TYPEDEF_BLOCK_ID,
7171
BI_CONCEPT_BLOCK_ID,
72+
BI_VAR_BLOCK_ID,
7273
BI_LAST,
7374
BI_FIRST = BI_VERSION_BLOCK_ID
7475
};
@@ -142,6 +143,10 @@ enum RecordId {
142143
CONCEPT_IS_TYPE,
143144
CONCEPT_CONSTRAINT_EXPRESSION,
144145
CONSTRAINT_EXPRESSION,
146+
VAR_USR,
147+
VAR_NAME,
148+
VAR_DEFLOCATION,
149+
VAR_IS_STATIC,
145150
RI_LAST,
146151
RI_FIRST = VERSION
147152
};
@@ -190,6 +195,7 @@ class ClangDocBitcodeWriter {
190195
void emitBlock(const ConceptInfo &T);
191196
void emitBlock(const ConstraintInfo &T);
192197
void emitBlock(const Reference &B, FieldId F);
198+
void emitBlock(const VarInfo &B);
193199

194200
private:
195201
class AbbreviationMap {

clang-tools-extra/clang-doc/HTMLGenerator.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
986986
genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
987987
break;
988988
case InfoType::IT_concept:
989+
case InfoType::IT_variable:
989990
break;
990991
case InfoType::IT_default:
991992
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -1015,6 +1016,8 @@ static std::string getRefType(InfoType IT) {
10151016
return "typedef";
10161017
case InfoType::IT_concept:
10171018
return "concept";
1019+
case InfoType::IT_variable:
1020+
return "variable";
10181021
}
10191022
llvm_unreachable("Unknown InfoType");
10201023
}

clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,8 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
587587
break;
588588
case InfoType::IT_concept:
589589
break;
590+
case InfoType::IT_variable:
591+
break;
590592
case InfoType::IT_default:
591593
return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
592594
}

clang-tools-extra/clang-doc/JSONGenerator.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,15 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
482482
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
483483
}
484484

485+
static void serializeInfo(const VarInfo &I, json::Object &Obj,
486+
std::optional<StringRef> RepositoryUrl) {
487+
serializeCommonAttributes(I, Obj, RepositoryUrl);
488+
Obj["IsStatic"] = I.IsStatic;
489+
auto TypeObj = Object();
490+
serializeInfo(I.Type, TypeObj);
491+
Obj["Type"] = std::move(TypeObj);
492+
}
493+
485494
static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
486495
std::optional<StringRef> RepositoryUrl) {
487496
serializeCommonAttributes(I, Obj, RepositoryUrl);
@@ -519,6 +528,10 @@ static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
519528
if (!I.Children.Concepts.empty())
520529
serializeArray(I.Children.Concepts, Obj, "Concepts", SerializeInfo);
521530

531+
if (!I.Children.Variables.empty()) {
532+
serializeArray(I.Children.Variables, Obj, "Variables", SerializeInfo);
533+
}
534+
522535
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
523536
}
524537

@@ -573,6 +586,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
573586
case InfoType::IT_enum:
574587
case InfoType::IT_function:
575588
case InfoType::IT_typedef:
589+
case InfoType::IT_variable:
576590
break;
577591
case InfoType::IT_default:
578592
return createStringError(inconvertibleErrorCode(), "unexpected info type");

clang-tools-extra/clang-doc/MDGenerator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
375375
case InfoType::IT_concept:
376376
Type = "Concept";
377377
break;
378+
case InfoType::IT_variable:
379+
Type = "Variable";
380+
break;
378381
case InfoType::IT_default:
379382
Type = "Other";
380383
}
@@ -468,6 +471,7 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
468471
genMarkdown(CDCtx, *static_cast<clang::doc::TypedefInfo *>(I), OS);
469472
break;
470473
case InfoType::IT_concept:
474+
case InfoType::IT_variable:
471475
break;
472476
case InfoType::IT_default:
473477
return createStringError(llvm::inconvertibleErrorCode(),

clang-tools-extra/clang-doc/Mapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ bool MapASTVisitor::VisitConceptDecl(const ConceptDecl *D) {
138138
return mapDecl(D, true);
139139
}
140140

141+
bool MapASTVisitor::VisitVarDecl(const VarDecl *D) {
142+
if (D->isCXXClassMember())
143+
return true;
144+
return mapDecl(D, D->isThisDeclarationADefinition());
145+
}
146+
141147
comments::FullComment *
142148
MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
143149
RawComment *Comment = Context.getRawCommentForDeclNoCache(D);

clang-tools-extra/clang-doc/Mapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
4242
bool VisitTypedefDecl(const TypedefDecl *D);
4343
bool VisitTypeAliasDecl(const TypeAliasDecl *D);
4444
bool VisitConceptDecl(const ConceptDecl *D);
45+
bool VisitVarDecl(const VarDecl *D);
4546

4647
private:
4748
template <typename T> bool mapDecl(const T *D, bool IsDefinition);

clang-tools-extra/clang-doc/Representation.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
145145
return reduce<TypedefInfo>(Values);
146146
case InfoType::IT_concept:
147147
return reduce<ConceptInfo>(Values);
148+
case InfoType::IT_variable:
149+
return reduce<VarInfo>(Values);
148150
case InfoType::IT_default:
149151
return llvm::createStringError(llvm::inconvertibleErrorCode(),
150152
"unexpected info type");
@@ -291,6 +293,7 @@ void NamespaceInfo::merge(NamespaceInfo &&Other) {
291293
reduceChildren(Children.Enums, std::move(Other.Children.Enums));
292294
reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
293295
reduceChildren(Children.Concepts, std::move(Other.Children.Concepts));
296+
reduceChildren(Children.Variables, std::move(Other.Children.Variables));
294297
mergeBase(std::move(Other));
295298
}
296299

@@ -368,6 +371,15 @@ void ConceptInfo::merge(ConceptInfo &&Other) {
368371
SymbolInfo::merge(std::move(Other));
369372
}
370373

374+
void VarInfo::merge(VarInfo &&Other) {
375+
assert(mergeable(Other));
376+
if (!IsStatic)
377+
IsStatic = Other.IsStatic;
378+
if (Type.Type.USR == EmptySID && Type.Type.Name == "")
379+
Type = std::move(Other.Type);
380+
SymbolInfo::merge(std::move(Other));
381+
}
382+
371383
BaseRecordInfo::BaseRecordInfo() : RecordInfo() {}
372384

373385
BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path,
@@ -407,6 +419,9 @@ llvm::SmallString<16> Info::extractName() const {
407419
case InfoType::IT_concept:
408420
return llvm::SmallString<16>("@nonymous_concept_" +
409421
toHex(llvm::toStringRef(USR)));
422+
case InfoType::IT_variable:
423+
return llvm::SmallString<16>("@nonymous_variable_" +
424+
toHex(llvm::toStringRef(USR)));
410425
case InfoType::IT_default:
411426
return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
412427
}
@@ -473,6 +488,7 @@ void ScopeChildren::sort() {
473488
llvm::sort(Enums.begin(), Enums.end());
474489
llvm::sort(Typedefs.begin(), Typedefs.end());
475490
llvm::sort(Concepts.begin(), Concepts.end());
491+
llvm::sort(Variables.begin(), Variables.end());
476492
}
477493
} // namespace doc
478494
} // namespace clang

clang-tools-extra/clang-doc/Representation.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct FunctionInfo;
3636
struct Info;
3737
struct TypedefInfo;
3838
struct ConceptInfo;
39+
struct VarInfo;
3940

4041
enum class InfoType {
4142
IT_default,
@@ -44,7 +45,8 @@ enum class InfoType {
4445
IT_function,
4546
IT_enum,
4647
IT_typedef,
47-
IT_concept
48+
IT_concept,
49+
IT_variable
4850
};
4951

5052
enum class CommentKind {
@@ -169,6 +171,7 @@ struct ScopeChildren {
169171
std::vector<EnumInfo> Enums;
170172
std::vector<TypedefInfo> Typedefs;
171173
std::vector<ConceptInfo> Concepts;
174+
std::vector<VarInfo> Variables;
172175

173176
void sort();
174177
};
@@ -376,6 +379,15 @@ struct SymbolInfo : public Info {
376379
bool IsStatic = false;
377380
};
378381

382+
struct VarInfo : SymbolInfo {
383+
VarInfo() : SymbolInfo(InfoType::IT_variable) {}
384+
explicit VarInfo(SymbolID USR) : SymbolInfo(InfoType::IT_variable, USR) {}
385+
386+
void merge(VarInfo &&I);
387+
388+
TypeInfo Type;
389+
};
390+
379391
// TODO: Expand to allow for documenting templating and default args.
380392
// Info for functions.
381393
struct FunctionInfo : public SymbolInfo {

0 commit comments

Comments
 (0)