Skip to content

Commit 263d6fa

Browse files
[clang][ExtractAPI] combine typedef records if the underlying type's name is underscored (#9978)
fixes rdar://137214218 When 'typedef struct' decls are encountered, the records are combined if the underlying type is either anonymous or has the same name as the typedef. Extend this behavior to also combine records when the underlying type has an underscored name that is equivalent to the typedef name when the leading underscores are removed.
1 parent a9e3fcf commit 263d6fa

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

clang/include/clang/ExtractAPI/ExtractAPIVisitor.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,11 +1146,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
11461146

11471147
StringRef Name = Decl->getName();
11481148

1149+
auto nameMatches = [&Name](TagDecl *TagDecl) {
1150+
StringRef TagName = TagDecl->getName();
1151+
1152+
if (TagName == Name)
1153+
return true;
1154+
1155+
// Also check whether the tag decl's name is the same as the typedef name
1156+
// with prefixed underscores
1157+
if (TagName.starts_with('_')) {
1158+
StringRef StrippedName = TagName.ltrim('_');
1159+
1160+
if (StrippedName == Name)
1161+
return true;
1162+
}
1163+
1164+
return false;
1165+
};
1166+
11491167
// If the underlying type was defined as part of the typedef modify it's
11501168
// fragments directly and pretend the typedef doesn't exist.
11511169
if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) {
11521170
if (TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition() &&
1153-
Decl->getName() == TagDecl->getName()) {
1171+
nameMatches(TagDecl)) {
11541172
SmallString<128> TagUSR;
11551173
index::generateUSRForDecl(TagDecl, TagUSR);
11561174
if (auto *Record = API.findRecordForUSR(TagUSR)) {
@@ -1164,6 +1182,11 @@ bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
11641182
.append(Name, DeclarationFragments::FragmentKind::Identifier)
11651183
.appendSemicolon();
11661184

1185+
// Replace the name and subheading in case it's underscored so we can
1186+
// use the non-underscored version
1187+
Record->Name = Name;
1188+
Record->SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl);
1189+
11671190
return true;
11681191
}
11691192
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
3+
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain-c.symbols.json -verify
4+
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
5+
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c++-header %s -o %t/typedefchain-cxx.symbols.json -verify
6+
7+
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCT
8+
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCT
9+
typedef struct _MyStruct { } MyStruct;
10+
11+
// MYSTRUCT-LABEL: "!testLabel": "c:@S@_MyStruct"
12+
// MYSTRUCT: "accessLevel": "public",
13+
// MYSTRUCT: "declarationFragments": [
14+
// MYSTRUCT-NEXT: {
15+
// MYSTRUCT-NEXT: "kind": "keyword",
16+
// MYSTRUCT-NEXT: "spelling": "typedef"
17+
// MYSTRUCT-NEXT: },
18+
// MYSTRUCT-NEXT: {
19+
// MYSTRUCT-NEXT: "kind": "text",
20+
// MYSTRUCT-NEXT: "spelling": " "
21+
// MYSTRUCT-NEXT: },
22+
// MYSTRUCT-NEXT: {
23+
// MYSTRUCT-NEXT: "kind": "keyword",
24+
// MYSTRUCT-NEXT: "spelling": "struct"
25+
// MYSTRUCT-NEXT: },
26+
// MYSTRUCT-NEXT: {
27+
// MYSTRUCT-NEXT: "kind": "text",
28+
// MYSTRUCT-NEXT: "spelling": " "
29+
// MYSTRUCT-NEXT: },
30+
// MYSTRUCT-NEXT: {
31+
// MYSTRUCT-NEXT: "kind": "identifier",
32+
// MYSTRUCT-NEXT: "spelling": "_MyStruct"
33+
// MYSTRUCT-NEXT: },
34+
// MYSTRUCT-NEXT: {
35+
// MYSTRUCT-NEXT: "kind": "text",
36+
// MYSTRUCT-NEXT: "spelling": " { ... } "
37+
// MYSTRUCT-NEXT: },
38+
// MYSTRUCT-NEXT: {
39+
// MYSTRUCT-NEXT: "kind": "identifier",
40+
// MYSTRUCT-NEXT: "spelling": "MyStruct"
41+
// MYSTRUCT-NEXT: },
42+
// MYSTRUCT-NEXT: {
43+
// MYSTRUCT-NEXT: "kind": "text",
44+
// MYSTRUCT-NEXT: "spelling": ";"
45+
// MYSTRUCT-NEXT: }
46+
// MYSTRUCT-NEXT: ],
47+
// MYSTRUCT: "kind": {
48+
// MYSTRUCT-NEXT: "displayName": "Structure",
49+
// MYSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.struct"
50+
// MYSTRUCT: "names": {
51+
// MYSTRUCT-NEXT: "navigator": [
52+
// MYSTRUCT-NEXT: {
53+
// MYSTRUCT-NEXT: "kind": "identifier",
54+
// MYSTRUCT-NEXT: "spelling": "MyStruct"
55+
// MYSTRUCT-NEXT: }
56+
// MYSTRUCT-NEXT: ],
57+
// MYSTRUCT-NEXT: "subHeading": [
58+
// MYSTRUCT-NEXT: {
59+
// MYSTRUCT-NEXT: "kind": "identifier",
60+
// MYSTRUCT-NEXT: "spelling": "MyStruct"
61+
// MYSTRUCT-NEXT: }
62+
// MYSTRUCT-NEXT: ],
63+
// MYSTRUCT-NEXT: "title": "MyStruct"
64+
// MYSTRUCT-NEXT: },
65+
// MYSTRUCT: "pathComponents": [
66+
// MYSTRUCT-NEXT: "MyStruct"
67+
// MYSTRUCT-NEXT: ]
68+
69+
// expected-no-diagnostics

0 commit comments

Comments
 (0)