Skip to content

Commit c24df2c

Browse files
committed
[clang][ExtractAPI] Fix for nested types are not enabled.
Recursively extract nested types. Keep anonymous structs/unions embedded in var declarators Fixes #61477
1 parent 2b937da commit c24df2c

File tree

4 files changed

+850
-64
lines changed

4 files changed

+850
-64
lines changed

clang/include/clang/ExtractAPI/ExtractAPIVisitor.h

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -250,27 +250,6 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
250250
return D.getName().empty() && getTypedefName(&D).empty() &&
251251
D.isEmbeddedInDeclarator() && !D.isFreeStanding();
252252
}
253-
254-
void maybeMergeWithAnonymousTag(const DeclaratorDecl &D,
255-
RecordContext *NewRecordContext) {
256-
if (!NewRecordContext)
257-
return;
258-
auto *Tag = D.getType()->getAsTagDecl();
259-
if (!Tag) {
260-
if (const auto *AT = D.getASTContext().getAsArrayType(D.getType())) {
261-
Tag = AT->getElementType()->getAsTagDecl();
262-
}
263-
}
264-
SmallString<128> TagUSR;
265-
clang::index::generateUSRForDecl(Tag, TagUSR);
266-
if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
267-
API.findRecordForUSR(TagUSR))) {
268-
if (Record->IsEmbeddedInVarDeclarator) {
269-
NewRecordContext->stealRecordChain(*Record);
270-
API.removeRecord(Record);
271-
}
272-
}
273-
}
274253
};
275254

276255
template <typename Derived>
@@ -322,14 +301,10 @@ bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
322301
SubHeading, Access, isInSystemHeader(Decl));
323302
} else {
324303
// Add the global variable record to the API set.
325-
auto *NewRecord = API.createRecord<GlobalVariableRecord>(
304+
API.createRecord<GlobalVariableRecord>(
326305
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
327306
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
328307
SubHeading, isInSystemHeader(Decl));
329-
330-
// If this global variable has a non typedef'd anonymous tag type let's
331-
// pretend the type's child records are under us in the hierarchy.
332-
maybeMergeWithAnonymousTag(*Decl, NewRecord);
333308
}
334309

335310
return true;
@@ -565,15 +540,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitNamespaceDecl(
565540

566541
template <typename Derived>
567542
bool ExtractAPIVisitorBase<Derived>::TraverseRecordDecl(RecordDecl *Decl) {
568-
bool Ret = Base::TraverseRecordDecl(Decl);
569-
570-
if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
571-
SmallString<128> USR;
572-
index::generateUSRForDecl(Decl, USR);
573-
API.removeRecord(USR);
574-
}
575-
576-
return Ret;
543+
return Base::TraverseRecordDecl(Decl);
577544
}
578545

579546
template <typename Derived>
@@ -620,13 +587,7 @@ template <typename Derived>
620587
bool ExtractAPIVisitorBase<Derived>::TraverseCXXRecordDecl(
621588
CXXRecordDecl *Decl) {
622589
bool Ret = Base::TraverseCXXRecordDecl(Decl);
623-
624-
if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
625-
SmallString<128> USR;
626-
index::generateUSRForDecl(Decl, USR);
627-
API.removeRecord(USR);
628-
}
629-
590+
// Keep anonymous structs in the hierarchy to preserve path components
630591
return Ret;
631592
}
632593

@@ -643,6 +604,11 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
643604

644605
SmallString<128> USR;
645606
index::generateUSRForDecl(Decl, USR);
607+
608+
if (API.findRecordForUSR(USR)) {
609+
return true;
610+
}
611+
646612
PresumedLoc Loc =
647613
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
648614
DocComment Comment;
@@ -679,6 +645,13 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
679645
Record->KindForDisplay = getKindForDisplay(Decl);
680646
Record->Bases = getBases(Decl);
681647

648+
// Visit nested records
649+
for (const auto *NestedDecl : Decl->decls()) {
650+
if (auto *NestedRecord = dyn_cast<CXXRecordDecl>(NestedDecl)) {
651+
VisitCXXRecordDecl(NestedRecord);
652+
}
653+
}
654+
682655
return true;
683656
}
684657

@@ -1320,31 +1293,26 @@ bool ExtractAPIVisitorBase<Derived>::VisitFieldDecl(const FieldDecl *Decl) {
13201293
DeclarationFragments SubHeading =
13211294
DeclarationFragmentsBuilder::getSubHeading(Decl);
13221295

1323-
RecordContext *NewRecord = nullptr;
13241296
if (isa<CXXRecordDecl>(Decl->getDeclContext())) {
13251297
AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
13261298

1327-
NewRecord = API.createRecord<CXXFieldRecord>(
1299+
API.createRecord<CXXFieldRecord>(
13281300
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
13291301
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
13301302
SubHeading, Access, isInSystemHeader(Decl));
13311303
} else if (auto *RD = dyn_cast<RecordDecl>(Decl->getDeclContext())) {
13321304
if (RD->isUnion())
1333-
NewRecord = API.createRecord<UnionFieldRecord>(
1305+
API.createRecord<UnionFieldRecord>(
13341306
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
13351307
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
13361308
SubHeading, isInSystemHeader(Decl));
13371309
else
1338-
NewRecord = API.createRecord<StructFieldRecord>(
1310+
API.createRecord<StructFieldRecord>(
13391311
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
13401312
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
13411313
SubHeading, isInSystemHeader(Decl));
13421314
}
13431315

1344-
// If this field has a non typedef'd anonymous tag type let's pretend the
1345-
// type's child records are under us in the hierarchy.
1346-
maybeMergeWithAnonymousTag(*Decl, NewRecord);
1347-
13481316
return true;
13491317
}
13501318

clang/test/ExtractAPI/anonymous_record_no_typedef.c

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ struct { char *prefix; char *content; } global;
4343
// GLOBAL-NEXT: "global"
4444
// GLOBAL-NEXT:]
4545

46-
// PREFIX: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix $ c:@global"
46+
// PREFIX: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}"
4747
// PREFIX-LABEL: "!testLabel": "c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix"
4848
// PREFIX: "title": "prefix"
4949
// PREFIX: "pathComponents": [
50-
// PREFIX-NEXT: "global",
50+
// PREFIX-NEXT: "",
5151
// PREFIX-NEXT: "prefix"
5252
// PREFIX-NEXT: ]
5353

54-
// CONTENT: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content $ c:@global"
54+
// CONTENT: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}"
5555
// CONTENT-LABEL: "!testLabel": "c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content"
5656
// CONTENT: "title": "content"
5757
// CONTENT: "pathComponents": [
58-
// CONTENT-NEXT: "global",
58+
// CONTENT-NEXT: "",
5959
// CONTENT-NEXT: "content"
6060
// CONTENT-NEXT: ]
6161

@@ -139,21 +139,21 @@ struct Vehicle {
139139
// INFORMATION: "text": "The information about the vehicle."
140140
// INFORMATION: "title": "information"
141141

142-
// WHEELS: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels $ c:@S@Vehicle@FI@information"
142+
// WHEELS: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}"
143143
// WHEELS-LABEL: "!testLabel": "c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels"
144144
// WHEELS: "title": "wheels"
145145
// WHEELS: "pathComponents": [
146146
// WHEELS-NEXT: "Vehicle",
147-
// WHEELS-NEXT: "information",
147+
// WHEELS-NEXT: "",
148148
// WHEELS-NEXT: "wheels"
149149
// WHEELS-NEXT: ]
150150

151-
// NAME: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name $ c:@S@Vehicle@FI@information"
151+
// NAME: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}"
152152
// NAME-LABEL: "!testLabel": "c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name"
153153
// NAME: "title": "name"
154154
// NAME: "pathComponents": [
155155
// NAME-NEXT: "Vehicle",
156-
// NAME-NEXT: "information",
156+
// NAME-NEXT: "",
157157
// NAME-NEXT: "name"
158158
// NAME-NEXT: ]
159159
};
@@ -188,20 +188,16 @@ union Vector {
188188
float Data[2];
189189
};
190190
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@FI@Data $ c:@U@Vector"
191-
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@X $ c:@U@Vector"
192-
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@Y $ c:@U@Vector"
191+
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@X $ c:@U@Vector@Sa"
192+
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@Y $ c:@U@Vector@Sa"
193193

194-
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix MYSTRUCT
195-
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix MYSTRUCT
196194
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix COUNTS
197195
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix COUNTS
198196
struct MyStruct {
199197
struct {
200198
int count;
201199
} counts[1];
202200
};
203-
// MYSTRUCT-NOT: "spelling": ""
204-
// MYSTRUCT-NOT: "title": ""
205201

206202
// COUNTS-LABEL: "!testLabel": "c:@S@MyStruct@FI@counts"
207203
// COUNTS: "declarationFragments": [

0 commit comments

Comments
 (0)