Skip to content

Commit 0a9ef3d

Browse files
ilovepiIanWood1
authored andcommitted
[clang-doc] Handle static members and functions (llvm#135457)
clang-doc didn't visit VarDecl, and hence never collected info from class statics members and functions. Fixes llvm#59813.
1 parent fbc6219 commit 0a9ef3d

File tree

9 files changed

+85
-40
lines changed

9 files changed

+85
-40
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
274274
return decodeRecord(R, I->Access, Blob);
275275
case FUNCTION_IS_METHOD:
276276
return decodeRecord(R, I->IsMethod, Blob);
277+
case FUNCTION_IS_STATIC:
278+
return decodeRecord(R, I->IsStatic, Blob);
277279
default:
278280
return llvm::createStringError(llvm::inconvertibleErrorCode(),
279281
"invalid field for FunctionInfo");
@@ -305,6 +307,8 @@ llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
305307
return decodeRecord(R, I->Name, Blob);
306308
case MEMBER_TYPE_ACCESS:
307309
return decodeRecord(R, I->Access, Blob);
310+
case MEMBER_TYPE_IS_STATIC:
311+
return decodeRecord(R, I->IsStatic, Blob);
308312
default:
309313
return llvm::createStringError(llvm::inconvertibleErrorCode(),
310314
"invalid field for MemberTypeInfo");

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
156156
{FIELD_DEFAULT_VALUE, {"DefaultValue", &StringAbbrev}},
157157
{MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
158158
{MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
159+
{MEMBER_TYPE_IS_STATIC, {"IsStatic", &BoolAbbrev}},
159160
{NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
160161
{NAMESPACE_NAME, {"Name", &StringAbbrev}},
161162
{NAMESPACE_PATH, {"Path", &StringAbbrev}},
@@ -187,6 +188,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
187188
{FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
188189
{FUNCTION_ACCESS, {"Access", &IntAbbrev}},
189190
{FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
191+
{FUNCTION_IS_STATIC, {"IsStatic", &BoolAbbrev}},
190192
{REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
191193
{REFERENCE_NAME, {"Name", &StringAbbrev}},
192194
{REFERENCE_QUAL_NAME, {"QualName", &StringAbbrev}},
@@ -222,7 +224,8 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
222224
// FieldType Block
223225
{BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}},
224226
// MemberType Block
225-
{BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
227+
{BI_MEMBER_TYPE_BLOCK_ID,
228+
{MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS, MEMBER_TYPE_IS_STATIC}},
226229
// Enum Block
227230
{BI_ENUM_BLOCK_ID,
228231
{ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},
@@ -247,7 +250,7 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
247250
// Function Block
248251
{BI_FUNCTION_BLOCK_ID,
249252
{FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
250-
FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
253+
FUNCTION_ACCESS, FUNCTION_IS_METHOD, FUNCTION_IS_STATIC}},
251254
// Reference Block
252255
{BI_REFERENCE_BLOCK_ID,
253256
{REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
@@ -465,6 +468,7 @@ void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
465468
emitBlock(T.Type, FieldId::F_type);
466469
emitRecord(T.Name, MEMBER_TYPE_NAME);
467470
emitRecord(T.Access, MEMBER_TYPE_ACCESS);
471+
emitRecord(T.IsStatic, MEMBER_TYPE_IS_STATIC);
468472
for (const auto &CI : T.Description)
469473
emitBlock(CI);
470474
}
@@ -600,6 +604,7 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
600604
emitBlock(CI);
601605
emitRecord(I.Access, FUNCTION_ACCESS);
602606
emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
607+
emitRecord(I.IsStatic, FUNCTION_IS_STATIC);
603608
if (I.DefLoc)
604609
emitRecord(*I.DefLoc, FUNCTION_DEFLOCATION);
605610
for (const auto &L : I.Loc)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ enum RecordId {
8181
FUNCTION_LOCATION,
8282
FUNCTION_ACCESS,
8383
FUNCTION_IS_METHOD,
84+
FUNCTION_IS_STATIC,
8485
COMMENT_KIND,
8586
COMMENT_TEXT,
8687
COMMENT_NAME,
@@ -96,6 +97,7 @@ enum RecordId {
9697
FIELD_DEFAULT_VALUE,
9798
MEMBER_TYPE_NAME,
9899
MEMBER_TYPE_ACCESS,
100+
MEMBER_TYPE_IS_STATIC,
99101
NAMESPACE_USR,
100102
NAMESPACE_NAME,
101103
NAMESPACE_PATH,

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,14 @@ genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
416416
Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
417417
auto &ULBody = Out.back();
418418
for (const auto &M : Members) {
419-
std::string Access = getAccessSpelling(M.Access).str();
420-
if (Access != "")
421-
Access = Access + " ";
419+
StringRef Access = getAccessSpelling(M.Access);
422420
auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
423421
auto MemberDecl = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
424-
MemberDecl->Children.emplace_back(std::make_unique<TextNode>(Access));
422+
if (!Access.empty())
423+
MemberDecl->Children.emplace_back(
424+
std::make_unique<TextNode>(Access + " "));
425+
if (M.IsStatic)
426+
MemberDecl->Children.emplace_back(std::make_unique<TextNode>("static "));
425427
MemberDecl->Children.emplace_back(genReference(M.Type, ParentInfoDir));
426428
MemberDecl->Children.emplace_back(std::make_unique<TextNode>(" " + M.Name));
427429
if (!M.Description.empty())
@@ -739,6 +741,9 @@ genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
739741
if (Access != "")
740742
FunctionHeader->Children.emplace_back(
741743
std::make_unique<TextNode>(Access + " "));
744+
if (I.IsStatic)
745+
FunctionHeader->Children.emplace_back(
746+
std::make_unique<TextNode>("static "));
742747
if (I.ReturnType.Type.Name != "") {
743748
FunctionHeader->Children.emplace_back(
744749
genReference(I.ReturnType.Type, ParentInfoDir));

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

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,12 @@ static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
169169
First = false;
170170
}
171171
writeHeader(I.Name, 3, OS);
172-
std::string Access = getAccessSpelling(I.Access).str();
173-
if (Access != "")
174-
writeLine(genItalic(Access + " " + I.ReturnType.Type.QualName + " " +
175-
I.Name + "(" + Stream.str() + ")"),
176-
OS);
177-
else
178-
writeLine(genItalic(I.ReturnType.Type.QualName + " " + I.Name + "(" +
179-
Stream.str() + ")"),
180-
OS);
172+
StringRef Access = getAccessSpelling(I.Access);
173+
writeLine(genItalic(Twine(Access) + (!Access.empty() ? " " : "") +
174+
(I.IsStatic ? "static " : "") +
175+
I.ReturnType.Type.QualName.str() + " " + I.Name.str() +
176+
"(" + Twine(Stream.str()) + ")"),
177+
OS);
181178

182179
maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc);
183180

@@ -262,11 +259,11 @@ static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I,
262259
if (!I.Members.empty()) {
263260
writeHeader("Members", 2, OS);
264261
for (const auto &Member : I.Members) {
265-
std::string Access = getAccessSpelling(Member.Access).str();
266-
if (Access != "")
267-
writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
268-
else
269-
writeLine(Member.Type.Name + " " + Member.Name, OS);
262+
StringRef Access = getAccessSpelling(Member.Access);
263+
writeLine(Twine(Access) + (Access.empty() ? "" : " ") +
264+
(Member.IsStatic ? "static " : "") +
265+
Member.Type.Name.str() + " " + Member.Name.str(),
266+
OS);
270267
}
271268
writeNewLine(OS);
272269
}

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,14 @@ struct FieldTypeInfo : public TypeInfo {
220220
// Info for member types.
221221
struct MemberTypeInfo : public FieldTypeInfo {
222222
MemberTypeInfo() = default;
223-
MemberTypeInfo(const TypeInfo &TI, StringRef Name, AccessSpecifier Access)
224-
: FieldTypeInfo(TI, Name), Access(Access) {}
223+
MemberTypeInfo(const TypeInfo &TI, StringRef Name, AccessSpecifier Access,
224+
bool IsStatic = false)
225+
: FieldTypeInfo(TI, Name), Access(Access), IsStatic(IsStatic) {}
225226

226227
bool operator==(const MemberTypeInfo &Other) const {
227-
return std::tie(Type, Name, Access, Description) ==
228-
std::tie(Other.Type, Other.Name, Other.Access, Other.Description);
228+
return std::tie(Type, Name, Access, IsStatic, Description) ==
229+
std::tie(Other.Type, Other.Name, Other.Access, Other.IsStatic,
230+
Other.Description);
229231
}
230232

231233
// Access level associated with this info (public, protected, private, none).
@@ -235,6 +237,7 @@ struct MemberTypeInfo : public FieldTypeInfo {
235237
AccessSpecifier Access = AccessSpecifier::AS_public;
236238

237239
std::vector<CommentInfo> Description; // Comment description of this field.
240+
bool IsStatic = false;
238241
};
239242

240243
struct Location {
@@ -320,9 +323,6 @@ struct SymbolInfo : public Info {
320323

321324
void merge(SymbolInfo &&I);
322325

323-
std::optional<Location> DefLoc; // Location where this decl is defined.
324-
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
325-
326326
bool operator<(const SymbolInfo &Other) const {
327327
// Sort by declaration location since we want the doc to be
328328
// generated in the order of the source code.
@@ -336,6 +336,10 @@ struct SymbolInfo : public Info {
336336

337337
return extractName() < Other.extractName();
338338
}
339+
340+
std::optional<Location> DefLoc; // Location where this decl is defined.
341+
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
342+
bool IsStatic = false;
339343
};
340344

341345
// TODO: Expand to allow for documenting templating and default args.

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

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ static void
3030
populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
3131
const T *D, bool &IsAnonymousNamespace);
3232

33-
static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D);
33+
static void populateMemberTypeInfo(MemberTypeInfo &I, const Decl *D);
34+
static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
35+
const DeclaratorDecl *D,
36+
bool IsStatic = false);
3437

3538
// A function to extract the appropriate relative path for a given info's
3639
// documentation. The path returned is a composite of the parent namespaces.
@@ -378,15 +381,19 @@ static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
378381
for (const FieldDecl *F : D->fields()) {
379382
if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
380383
continue;
384+
populateMemberTypeInfo(I, Access, F);
385+
}
386+
const auto *CxxRD = dyn_cast<CXXRecordDecl>(D);
387+
if (!CxxRD)
388+
return;
389+
for (Decl *CxxDecl : CxxRD->decls()) {
390+
auto *VD = dyn_cast<VarDecl>(CxxDecl);
391+
if (!VD ||
392+
!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, VD))
393+
continue;
381394

382-
auto &LO = F->getLangOpts();
383-
// Use getAccessUnsafe so that we just get the default AS_none if it's not
384-
// valid, as opposed to an assert.
385-
MemberTypeInfo &NewMember = I.Members.emplace_back(
386-
getTypeInfoForType(F->getTypeSourceInfo()->getType(), LO),
387-
F->getNameAsString(),
388-
getFinalAccessSpecifier(Access, F->getAccessUnsafe()));
389-
populateMemberTypeInfo(NewMember, F);
395+
if (VD->isStaticDataMember())
396+
populateMemberTypeInfo(I, Access, VD, /*IsStatic=*/true);
390397
}
391398
}
392399

@@ -568,7 +575,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
568575
}
569576
}
570577

571-
static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
578+
static void populateMemberTypeInfo(MemberTypeInfo &I, const Decl *D) {
572579
assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
573580

574581
ASTContext& Context = D->getASTContext();
@@ -585,6 +592,17 @@ static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
585592
}
586593
}
587594

595+
static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
596+
const DeclaratorDecl *D, bool IsStatic) {
597+
// Use getAccessUnsafe so that we just get the default AS_none if it's not
598+
// valid, as opposed to an assert.
599+
MemberTypeInfo &NewMember = I.Members.emplace_back(
600+
getTypeInfoForType(D->getTypeSourceInfo()->getType(), D->getLangOpts()),
601+
D->getNameAsString(),
602+
getFinalAccessSpecifier(Access, D->getAccessUnsafe()), IsStatic);
603+
populateMemberTypeInfo(NewMember, D);
604+
}
605+
588606
static void
589607
parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
590608
bool PublicOnly, bool IsParent,
@@ -619,6 +637,7 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
619637
continue;
620638
FunctionInfo FI;
621639
FI.IsMethod = true;
640+
FI.IsStatic = MD->isStatic();
622641
// The seventh arg in populateFunctionInfo is a boolean passed by
623642
// reference, its value is not relevant in here so it's not used
624643
// anywhere besides the function call.
@@ -702,7 +721,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
702721
dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
703722
Specialization.SpecializationOf = getUSRForDecl(CTPSD);
704723

705-
// Parameters to the specilization. For partial specializations, get the
724+
// Parameters to the specialization. For partial specializations, get the
706725
// parameters "as written" from the ClassTemplatePartialSpecializationDecl
707726
// because the non-explicit template parameters will have generated internal
708727
// placeholder names rather than the names the user typed that match the
@@ -755,6 +774,7 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
755774
return {};
756775

757776
Func.IsMethod = true;
777+
Func.IsStatic = D->isStatic();
758778

759779
const NamedDecl *Parent = nullptr;
760780
if (const auto *SD =

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
5252
emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
5353
StringRef File, bool IsFileInRootDir, bool PublicOnly);
5454

55+
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
56+
emitInfo(const VarDecl *D, const FullComment *FC, int LineNumber,
57+
StringRef File, bool IsFileInRootDir, bool PublicOnly);
58+
5559
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
5660
emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
5761
StringRef File, bool IsFileInRootDir, bool PublicOnly);

clang-tools-extra/test/clang-doc/basic-project.test

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@
134134
// HTML-CALC: <div>brief</div>
135135
// HTML-CALC: <p> Holds a public value.</p>
136136
// HTML-CALC: <div>public int public_val</div>
137+
// HTML-CALC: <div>brief</div>
138+
// HTML-CALC: <p> A static value.</p>
139+
// HTML-CALC: <div>public static const int static_val</div>
137140

138141
// HTML-CALC: <h2 id="Functions">Functions</h2>
139142
// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">add</h3>
@@ -191,7 +194,7 @@
191194
// HTML-CALC: <div>throw</div>
192195
// HTML-CALC: <p>if b is zero.</p>
193196

194-
// HTML-CALC: <p>public int mod(int a, int b)</p>
197+
// HTML-CALC: <p>public static int mod(int a, int b)</p>
195198
// CALC-NO-REPOSITORY: Defined at line 54 of file .{{.}}include{{.}}Calculator.h
196199
// CALC-REPOSITORY: Defined at line
197200
// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./include/Calculator.h#54">54</a>
@@ -326,6 +329,7 @@
326329
// MD-CALC: Provides basic arithmetic operations.
327330
// MD-CALC: ## Members
328331
// MD-CALC: public int public_val
332+
// MD-CALC: public static const int static_val
329333
// MD-CALC: ## Functions
330334
// MD-CALC: ### add
331335
// MD-CALC: *public int add(int a, int b)*
@@ -357,7 +361,7 @@
357361
// MD-CALC: **return** double The result of a / b.
358362
// MD-CALC: **throw**if b is zero.
359363
// MD-CALC: ### mod
360-
// MD-CALC: *public int mod(int a, int b)*
364+
// MD-CALC: *public static int mod(int a, int b)*
361365
// MD-CALC: *Defined at ./include{{[\/]}}Calculator.h#54*
362366
// MD-CALC: **brief** Performs the mod operation on integers.
363367
// MD-CALC: **a** First integer.

0 commit comments

Comments
 (0)