-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][ExtractAPI] Fix for nested types are not enabled. #159698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clang Author: NagaChaitanya Vellanki (chaitanyav) ChangesKeep anonymous structs/unions embedded in var declarators Fixes #61477 Full diff: https://github.com/llvm/llvm-project/pull/159698.diff 1 Files Affected:
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index 9ea664f57f828..5b7a8266d2092 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -261,15 +261,9 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
Tag = AT->getElementType()->getAsTagDecl();
}
}
- SmallString<128> TagUSR;
- clang::index::generateUSRForDecl(Tag, TagUSR);
- if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
- API.findRecordForUSR(TagUSR))) {
- if (Record->IsEmbeddedInVarDeclarator) {
- NewRecordContext->stealRecordChain(*Record);
- API.removeRecord(Record);
- }
- }
+ // For anonymous structs/unions embedded in var declarators,
+ // we keep them in the hierarchy (don't remove them)
+ // This preserves the path components while maintaining relationships
}
};
@@ -566,13 +560,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitNamespaceDecl(
template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::TraverseRecordDecl(RecordDecl *Decl) {
bool Ret = Base::TraverseRecordDecl(Decl);
-
- if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
- SmallString<128> USR;
- index::generateUSRForDecl(Decl, USR);
- API.removeRecord(USR);
- }
-
+ // Keep anonymous structs in the hierarchy to preserve path components
return Ret;
}
@@ -620,13 +608,7 @@ template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::TraverseCXXRecordDecl(
CXXRecordDecl *Decl) {
bool Ret = Base::TraverseCXXRecordDecl(Decl);
-
- if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
- SmallString<128> USR;
- index::generateUSRForDecl(Decl, USR);
- API.removeRecord(USR);
- }
-
+ // Keep anonymous structs in the hierarchy to preserve path components
return Ret;
}
@@ -643,6 +625,11 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
+
+ if (auto *USRRecord = API.findRecordForUSR(USR)) {
+ return true;
+ }
+
PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
DocComment Comment;
@@ -679,6 +666,13 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
Record->KindForDisplay = getKindForDisplay(Decl);
Record->Bases = getBases(Decl);
+ // Visit nested records
+ for (const auto *NestedDecl : Decl->decls()) {
+ if (auto *NestedRecord = dyn_cast<CXXRecordDecl>(NestedDecl)) {
+ VisitCXXRecordDecl(NestedRecord);
+ }
+ }
+
return true;
}
|
|
Some examples. Example 1struct MyStruct {
struct {
int count;
} counts[1];
};{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "clang version 22.0.0git ([email protected]:chaitanyav/llvm-project.git 9628061e055c9f695ff80f9a74e4f6e524b34993)"
},
"module": {
"name": "",
"platform": {
"architecture": "arm64",
"operatingSystem": {
"minimumVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"name": "macosx"
},
"vendor": "apple"
}
},
"relationships": [
{
"kind": "memberOf",
"source": "c:@S@MyStruct@S@test_nested_types1.h@22",
"target": "c:@S@MyStruct",
"targetFallback": "MyStruct"
},
{
"kind": "memberOf",
"source": "c:@S@MyStruct@S@test_nested_types1.h@22@FI@count",
"target": "c:@S@MyStruct@S@test_nested_types1.h@22",
"targetFallback": ""
},
{
"kind": "memberOf",
"source": "c:@S@MyStruct@FI@counts",
"target": "c:@S@MyStruct",
"targetFallback": "MyStruct"
}
],
"symbols": [
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "MyStruct"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@MyStruct"
},
"kind": {
"displayName": "Structure",
"identifier": "c++.struct"
},
"location": {
"position": {
"character": 7,
"line": 0
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "MyStruct"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "MyStruct"
}
],
"title": "MyStruct"
},
"pathComponents": [
"MyStruct"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@MyStruct@S@test_nested_types1.h@22"
},
"kind": {
"displayName": "Structure",
"identifier": "c++.struct"
},
"location": {
"position": {
"character": 4,
"line": 1
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": ""
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": ""
}
],
"title": ""
},
"pathComponents": [
"MyStruct",
""
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:I",
"spelling": "int"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "count"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@MyStruct@S@test_nested_types1.h@22@FI@count"
},
"kind": {
"displayName": "Instance Property",
"identifier": "c++.property"
},
"location": {
"position": {
"character": 12,
"line": 2
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "count"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "count"
}
],
"title": "count"
},
"pathComponents": [
"MyStruct",
"",
"count"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": " { ... } "
},
{
"kind": "identifier",
"spelling": "counts"
},
{
"kind": "text",
"spelling": "["
},
{
"kind": "number",
"spelling": "1"
},
{
"kind": "text",
"spelling": "];"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@MyStruct@FI@counts"
},
"kind": {
"displayName": "Instance Property",
"identifier": "c++.property"
},
"location": {
"position": {
"character": 6,
"line": 3
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "counts"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "counts"
}
],
"title": "counts"
},
"pathComponents": [
"MyStruct",
"counts"
]
}
]
}
Example 2class Outer {
class Inner1 {
class DeeplyNested {
int value;
};
};
struct Inner2 {
enum Status { READY, PENDING };
};
};{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "clang version 22.0.0git ([email protected]:chaitanyav/llvm-project.git 1e6840e67eee77e0ef4538732c0d1ab7d570ba31)"
},
"module": {
"name": "",
"platform": {
"architecture": "arm64",
"operatingSystem": {
"minimumVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"name": "macosx"
},
"vendor": "apple"
}
},
"relationships": [
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner1",
"target": "c:@S@Outer",
"targetFallback": "Outer"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner1@S@DeeplyNested",
"target": "c:@S@Outer@S@Inner1",
"targetFallback": "Inner1"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner1@S@DeeplyNested@FI@value",
"target": "c:@S@Outer@S@Inner1@S@DeeplyNested",
"targetFallback": "DeeplyNested"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner2",
"target": "c:@S@Outer",
"targetFallback": "Outer"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner2@E@Status",
"target": "c:@S@Outer@S@Inner2",
"targetFallback": "Inner2"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner2@E@Status@READY",
"target": "c:@S@Outer@S@Inner2@E@Status",
"targetFallback": "Status"
},
{
"kind": "memberOf",
"source": "c:@S@Outer@S@Inner2@E@Status@PENDING",
"target": "c:@S@Outer@S@Inner2@E@Status",
"targetFallback": "Status"
}
],
"symbols": [
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "class"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "Outer"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer"
},
"kind": {
"displayName": "Class",
"identifier": "c++.class"
},
"location": {
"position": {
"character": 6,
"line": 0
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "Outer"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "Outer"
}
],
"title": "Outer"
},
"pathComponents": [
"Outer"
]
},
{
"accessLevel": "private",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "class"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "Inner1"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner1"
},
"kind": {
"displayName": "Class",
"identifier": "c++.class"
},
"location": {
"position": {
"character": 10,
"line": 1
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "Inner1"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "Inner1"
}
],
"title": "Inner1"
},
"pathComponents": [
"Outer",
"Inner1"
]
},
{
"accessLevel": "private",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "class"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "DeeplyNested"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner1@S@DeeplyNested"
},
"kind": {
"displayName": "Class",
"identifier": "c++.class"
},
"location": {
"position": {
"character": 14,
"line": 2
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "DeeplyNested"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "DeeplyNested"
}
],
"title": "DeeplyNested"
},
"pathComponents": [
"Outer",
"Inner1",
"DeeplyNested"
]
},
{
"accessLevel": "private",
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:I",
"spelling": "int"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "value"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner1@S@DeeplyNested@FI@value"
},
"kind": {
"displayName": "Instance Property",
"identifier": "c++.property"
},
"location": {
"position": {
"character": 16,
"line": 3
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "value"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "value"
}
],
"title": "value"
},
"pathComponents": [
"Outer",
"Inner1",
"DeeplyNested",
"value"
]
},
{
"accessLevel": "private",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "Inner2"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner2"
},
"kind": {
"displayName": "Structure",
"identifier": "c++.struct"
},
"location": {
"position": {
"character": 11,
"line": 7
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "Inner2"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "Inner2"
}
],
"title": "Inner2"
},
"pathComponents": [
"Outer",
"Inner2"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "enum"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "Status"
},
{
"kind": "text",
"spelling": " : "
},
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:i",
"spelling": "unsigned int"
},
{
"kind": "text",
"spelling": ";"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner2@E@Status"
},
"kind": {
"displayName": "Enumeration",
"identifier": "c++.enum"
},
"location": {
"position": {
"character": 13,
"line": 8
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "Status"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "Status"
}
],
"title": "Status"
},
"pathComponents": [
"Outer",
"Inner2",
"Status"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "identifier",
"spelling": "READY"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner2@E@Status@READY"
},
"kind": {
"displayName": "Enumeration Case",
"identifier": "c++.enum.case"
},
"location": {
"position": {
"character": 22,
"line": 8
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "READY"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "READY"
}
],
"title": "READY"
},
"pathComponents": [
"Outer",
"Inner2",
"Status",
"READY"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "identifier",
"spelling": "PENDING"
}
],
"identifier": {
"interfaceLanguage": "c++",
"precise": "c:@S@Outer@S@Inner2@E@Status@PENDING"
},
"kind": {
"displayName": "Enumeration Case",
"identifier": "c++.enum.case"
},
"location": {
"position": {
"character": 29,
"line": 8
},
"uri": "file://./test_nested_types1.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "PENDING"
}
],
"subHeading": [
{
"kind": "identifier",
"spelling": "PENDING"
}
],
"title": "PENDING"
},
"pathComponents": [
"Outer",
"Inner2",
"Status",
"PENDING"
]
}
]
}
|
|
Working on adding new tests and fixing existing tests |
|
cc @daniel-grumberg, i don't 100% remember the full context or the desired/current state of the world, but i do remember that we went back and forth about the state of "anonymous types in var declarators" a couple times. |
101054c to
6b638a9
Compare
Recursively extract nested types. Keep anonymous structs/unions embedded in var declarators Fixes llvm#61477
6b638a9 to
c24df2c
Compare
|
@daniel-grumberg please review. |
|
@daniel-grumberg gentle ping on the PR. |
Keep anonymous structs/unions embedded in var declarators
Fixes #61477