Skip to content

Commit fa649df

Browse files
[clang][ExtractAPI] Flatten all enum cases from anonymous enums at top level (#93559)
rdar://128863241
1 parent 93d8d74 commit fa649df

File tree

4 files changed

+54
-168
lines changed

4 files changed

+54
-168
lines changed

clang/include/clang/ExtractAPI/ExtractAPIVisitor.h

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/AST/DeclTemplate.h"
2222
#include "clang/AST/ParentMapContext.h"
2323
#include "clang/AST/RecursiveASTVisitor.h"
24+
#include "clang/Basic/LLVM.h"
2425
#include "clang/Basic/Module.h"
2526
#include "clang/Basic/SourceManager.h"
2627
#include "clang/Basic/Specifiers.h"
@@ -127,7 +128,7 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
127128
protected:
128129
/// Collect API information for the enum constants and associate with the
129130
/// parent enum.
130-
void recordEnumConstants(EnumRecord *EnumRecord,
131+
void recordEnumConstants(SymbolReference Container,
131132
const EnumDecl::enumerator_range Constants);
132133

133134
/// Collect API information for the Objective-C methods and associate with the
@@ -248,12 +249,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
248249
clang::index::generateUSRForDecl(Tag, TagUSR);
249250
if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
250251
API.findRecordForUSR(TagUSR))) {
251-
if (Record->IsEmbeddedInVarDeclarator) {
252+
if (Record->IsEmbeddedInVarDeclarator)
252253
NewRecordContext->stealRecordChain(*Record);
253-
auto *NewRecord = cast<APIRecord>(NewRecordContext);
254-
if (NewRecord->Comment.empty())
255-
NewRecord->Comment = Record->Comment;
256-
}
257254
}
258255
}
259256
};
@@ -394,17 +391,6 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
394391
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
395392
return true;
396393

397-
SmallString<128> QualifiedNameBuffer;
398-
// Collect symbol information.
399-
StringRef Name = Decl->getName();
400-
if (Name.empty())
401-
Name = getTypedefName(Decl);
402-
if (Name.empty()) {
403-
llvm::raw_svector_ostream OS(QualifiedNameBuffer);
404-
Decl->printQualifiedName(OS);
405-
Name = QualifiedNameBuffer;
406-
}
407-
408394
SmallString<128> USR;
409395
index::generateUSRForDecl(Decl, USR);
410396
PresumedLoc Loc =
@@ -420,13 +406,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
420406
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
421407
DeclarationFragments SubHeading =
422408
DeclarationFragmentsBuilder::getSubHeading(Decl);
423-
auto *ER = API.createRecord<EnumRecord>(
424-
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
425-
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
426-
isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
409+
410+
// Collect symbol information.
411+
SymbolReference ParentContainer;
412+
413+
if (Decl->hasNameForLinkage()) {
414+
StringRef Name = Decl->getName();
415+
if (Name.empty())
416+
Name = getTypedefName(Decl);
417+
418+
auto *ER = API.createRecord<EnumRecord>(
419+
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
420+
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
421+
SubHeading, isInSystemHeader(Decl), false);
422+
ParentContainer = SymbolReference(ER);
423+
} else {
424+
// If this an anonymous enum then the parent scope of the constants is the
425+
// top level namespace.
426+
ParentContainer = {};
427+
}
427428

428429
// Now collect information about the enumerators in this enum.
429-
getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators());
430+
getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer,
431+
Decl->enumerators());
430432

431433
return true;
432434
}
@@ -1197,7 +1199,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
11971199
/// parent enum.
11981200
template <typename Derived>
11991201
void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
1200-
EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
1202+
SymbolReference Container, const EnumDecl::enumerator_range Constants) {
12011203
for (const auto *Constant : Constants) {
12021204
// Collect symbol information.
12031205
StringRef Name = Constant->getName();
@@ -1218,9 +1220,8 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
12181220
DeclarationFragmentsBuilder::getSubHeading(Constant);
12191221

12201222
API.createRecord<EnumConstantRecord>(
1221-
USR, Name, createHierarchyInformationForDecl(*Constant), Loc,
1222-
AvailabilityInfo::createFromDecl(Constant), Comment, Declaration,
1223-
SubHeading, isInSystemHeader(Constant));
1223+
USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant),
1224+
Comment, Declaration, SubHeading, isInSystemHeader(Constant));
12241225
}
12251226
}
12261227

@@ -1469,7 +1470,17 @@ class ExtractAPIVisitor
14691470

14701471
bool shouldDeclBeIncluded(const Decl *D) const { return true; }
14711472
const RawComment *fetchRawCommentForDecl(const Decl *D) const {
1472-
return this->Context.getRawCommentForDeclNoCache(D);
1473+
if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D))
1474+
return Comment;
1475+
1476+
if (const auto *Declarator = dyn_cast<DeclaratorDecl>(D)) {
1477+
const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl();
1478+
if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() &&
1479+
TagTypeDecl->isCompleteDefinition())
1480+
return this->Context.getRawCommentForDeclNoCache(TagTypeDecl);
1481+
}
1482+
1483+
return nullptr;
14731484
}
14741485
};
14751486

clang/test/ExtractAPI/anonymous_record_no_typedef.c

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,15 @@ struct Vehicle {
8484
// TYPE: "text": "The type of vehicle."
8585
// TYPE: "title": "type"
8686

87-
// BICYCLE: "!testRelLabel": "memberOf $ c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Bicycle $ c:@S@Vehicle@FI@type"
8887
// BICYCLE-LABEL: "!testLabel": "c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Bicycle"
8988
// BICYCLE: "title": "Bicycle"
9089
// BICYCLE: "pathComponents": [
91-
// BICYCLE-NEXT: "Vehicle",
92-
// BICYCLE-NEXT: "type",
9390
// BICYCLE-NEXT: "Bicycle"
9491
// BICYCLE-NEXT: ]
9592

96-
// CAR: "!testRelLabel": "memberOf $ c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Car $ c:@S@Vehicle@FI@type"
9793
// CAR-LABEL: "!testLabel": "c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Car"
9894
// CAR: "title": "Car"
9995
// CAR: "pathComponents": [
100-
// CAR-NEXT: "Vehicle",
101-
// CAR-NEXT: "type",
10296
// CAR-NEXT: "Car"
10397
// CAR-NEXT: ]
10498

@@ -151,32 +145,22 @@ struct Vehicle {
151145
// NAME-NEXT: ]
152146
};
153147

154-
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALENUM
148+
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALCASE
149+
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALOTHERCASE
155150
enum {
156151
GlobalCase,
157152
GlobalOtherCase
158153
};
159-
// GLOBALENUM-DAG: "!testRelLabel": "memberOf $ c:@Ea@GlobalCase@GlobalCase $ c:@Ea@GlobalCase"
160-
// GLOBALENUM-DAG: "!testRelLabel": "memberOf $ c:@Ea@GlobalCase@GlobalOtherCase $ c:@Ea@GlobalCase"
161-
// GLOBALENUM-LABEL: "!testLabel": "c:@Ea@GlobalCase"
162-
// GLOBALENUM: "declarationFragments": [
163-
// GLOBALENUM-NEXT: {
164-
// GLOBALENUM-NEXT: "kind": "keyword",
165-
// GLOBALENUM-NEXT: "spelling": "enum"
166-
// GLOBALENUM-NEXT: },
167-
// GLOBALENUM-NEXT: {
168-
// GLOBALENUM-NEXT: "kind": "text",
169-
// GLOBALENUM-NEXT: "spelling": " : "
170-
// GLOBALENUM-NEXT: },
171-
// GLOBALENUM-NEXT: {
172-
// GLOBALENUM-NEXT: "kind": "typeIdentifier",
173-
// GLOBALENUM-NEXT: "preciseIdentifier": "c:i",
174-
// GLOBALENUM-NEXT: "spelling": "unsigned int"
175-
// GLOBALENUM-NEXT: },
176-
// GLOBALENUM-NEXT: {
177-
// GLOBALENUM-NEXT: "kind": "text",
178-
// GLOBALENUM-NEXT: "spelling": " { ... };"
179-
// GLOBALENUM-NEXT: }
180-
// GLOBALENUM-NEXT: ]
154+
// GLOBALCASE-LABEL: "!testLabel": "c:@Ea@GlobalCase@GlobalCase"
155+
// GLOBALCASE: "title": "GlobalCase"
156+
// GLOBALCASE: "pathComponents": [
157+
// GLOBALCASE-NEXT: "GlobalCase"
158+
// GLOBALCASE-NEXT: ]
159+
160+
// GLOBALOTHERCASE-LABEL: "!testLabel": "c:@Ea@GlobalCase@GlobalOtherCase"
161+
// GLOBALOTHERCASE: "title": "GlobalOtherCase"
162+
// GLOBALOTHERCASE: "pathComponents": [
163+
// GLOBALOTHERCASE-NEXT: "GlobalOtherCase"
164+
// GLOBALOTHERCASE-NEXT: ]
181165

182166
// expected-no-diagnostics

clang/test/ExtractAPI/enum.c

Lines changed: 0 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ enum {
115115
"source": "c:@E@Direction@West",
116116
"target": "c:@E@Direction",
117117
"targetFallback": "Direction"
118-
},
119-
{
120-
"kind": "memberOf",
121-
"source": "c:@Ea@Constant@Constant",
122-
"target": "c:@Ea@Constant",
123-
"targetFallback": "enum (unnamed)"
124-
},
125-
{
126-
"kind": "memberOf",
127-
"source": "c:@Ea@OtherConstant@OtherConstant",
128-
"target": "c:@Ea@OtherConstant",
129-
"targetFallback": "enum (unnamed)"
130118
}
131119
],
132120
"symbols": [
@@ -677,55 +665,6 @@ enum {
677665
"West"
678666
]
679667
},
680-
{
681-
"accessLevel": "public",
682-
"declarationFragments": [
683-
{
684-
"kind": "keyword",
685-
"spelling": "enum"
686-
},
687-
{
688-
"kind": "text",
689-
"spelling": " : "
690-
},
691-
{
692-
"kind": "typeIdentifier",
693-
"preciseIdentifier": "c:i",
694-
"spelling": "unsigned int"
695-
},
696-
{
697-
"kind": "text",
698-
"spelling": " { ... };"
699-
}
700-
],
701-
"identifier": {
702-
"interfaceLanguage": "c",
703-
"precise": "c:@Ea@Constant"
704-
},
705-
"kind": {
706-
"displayName": "Enumeration",
707-
"identifier": "c.enum"
708-
},
709-
"location": {
710-
"position": {
711-
"character": 0,
712-
"line": 16
713-
},
714-
"uri": "file://INPUT_DIR/input.h"
715-
},
716-
"names": {
717-
"navigator": [
718-
{
719-
"kind": "identifier",
720-
"spelling": "enum (unnamed)"
721-
}
722-
],
723-
"title": "enum (unnamed)"
724-
},
725-
"pathComponents": [
726-
"enum (unnamed)"
727-
]
728-
},
729668
{
730669
"accessLevel": "public",
731670
"declarationFragments": [
@@ -765,59 +704,9 @@ enum {
765704
"title": "Constant"
766705
},
767706
"pathComponents": [
768-
"enum (unnamed)",
769707
"Constant"
770708
]
771709
},
772-
{
773-
"accessLevel": "public",
774-
"declarationFragments": [
775-
{
776-
"kind": "keyword",
777-
"spelling": "enum"
778-
},
779-
{
780-
"kind": "text",
781-
"spelling": " : "
782-
},
783-
{
784-
"kind": "typeIdentifier",
785-
"preciseIdentifier": "c:i",
786-
"spelling": "unsigned int"
787-
},
788-
{
789-
"kind": "text",
790-
"spelling": " { ... };"
791-
}
792-
],
793-
"identifier": {
794-
"interfaceLanguage": "c",
795-
"precise": "c:@Ea@OtherConstant"
796-
},
797-
"kind": {
798-
"displayName": "Enumeration",
799-
"identifier": "c.enum"
800-
},
801-
"location": {
802-
"position": {
803-
"character": 0,
804-
"line": 20
805-
},
806-
"uri": "file://INPUT_DIR/input.h"
807-
},
808-
"names": {
809-
"navigator": [
810-
{
811-
"kind": "identifier",
812-
"spelling": "enum (unnamed)"
813-
}
814-
],
815-
"title": "enum (unnamed)"
816-
},
817-
"pathComponents": [
818-
"enum (unnamed)"
819-
]
820-
},
821710
{
822711
"accessLevel": "public",
823712
"declarationFragments": [
@@ -857,7 +746,6 @@ enum {
857746
"title": "OtherConstant"
858747
},
859748
"pathComponents": [
860-
"enum (unnamed)",
861749
"OtherConstant"
862750
]
863751
}

clang/tools/libclang/CXExtractAPI.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ struct LibClangExtractAPIVisitor
4545
: ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {}
4646

4747
const RawComment *fetchRawCommentForDecl(const Decl *D) const {
48+
if (const auto *Comment = Base::fetchRawCommentForDecl(D))
49+
return Comment;
50+
4851
return Context.getRawCommentForAnyRedecl(D);
4952
}
5053

0 commit comments

Comments
 (0)