diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h index aa86e41806711..e60440e14a9fe 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -1146,11 +1146,29 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( StringRef Name = Decl->getName(); + auto nameMatches = [&Name](TagDecl *TagDecl) { + StringRef TagName = TagDecl->getName(); + + if (TagName == Name) + return true; + + // Also check whether the tag decl's name is the same as the typedef name + // with prefixed underscores + if (TagName.starts_with('_')) { + StringRef StrippedName = TagName.ltrim('_'); + + if (StrippedName == Name) + return true; + } + + return false; + }; + // If the underlying type was defined as part of the typedef modify it's // fragments directly and pretend the typedef doesn't exist. if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) { if (TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition() && - Decl->getName() == TagDecl->getName()) { + nameMatches(TagDecl)) { SmallString<128> TagUSR; index::generateUSRForDecl(TagDecl, TagUSR); if (auto *Record = API.findRecordForUSR(TagUSR)) { @@ -1164,6 +1182,11 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( .append(Name, DeclarationFragments::FragmentKind::Identifier) .appendSemicolon(); + // Replace the name and subheading in case it's underscored so we can + // use the non-underscored version + Record->Name = Name; + Record->SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); + return true; } } diff --git a/clang/test/ExtractAPI/typedef_underscore.c b/clang/test/ExtractAPI/typedef_underscore.c new file mode 100644 index 0000000000000..a42046907b46d --- /dev/null +++ b/clang/test/ExtractAPI/typedef_underscore.c @@ -0,0 +1,69 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ +// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain-c.symbols.json -verify +// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ +// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c++-header %s -o %t/typedefchain-cxx.symbols.json -verify + +// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCT +// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCT +typedef struct _MyStruct { } MyStruct; + +// MYSTRUCT-LABEL: "!testLabel": "c:@S@_MyStruct" +// MYSTRUCT: "accessLevel": "public", +// MYSTRUCT: "declarationFragments": [ +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "keyword", +// MYSTRUCT-NEXT: "spelling": "typedef" +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "text", +// MYSTRUCT-NEXT: "spelling": " " +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "keyword", +// MYSTRUCT-NEXT: "spelling": "struct" +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "text", +// MYSTRUCT-NEXT: "spelling": " " +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "identifier", +// MYSTRUCT-NEXT: "spelling": "_MyStruct" +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "text", +// MYSTRUCT-NEXT: "spelling": " { ... } " +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "identifier", +// MYSTRUCT-NEXT: "spelling": "MyStruct" +// MYSTRUCT-NEXT: }, +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "text", +// MYSTRUCT-NEXT: "spelling": ";" +// MYSTRUCT-NEXT: } +// MYSTRUCT-NEXT: ], +// MYSTRUCT: "kind": { +// MYSTRUCT-NEXT: "displayName": "Structure", +// MYSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.struct" +// MYSTRUCT: "names": { +// MYSTRUCT-NEXT: "navigator": [ +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "identifier", +// MYSTRUCT-NEXT: "spelling": "MyStruct" +// MYSTRUCT-NEXT: } +// MYSTRUCT-NEXT: ], +// MYSTRUCT-NEXT: "subHeading": [ +// MYSTRUCT-NEXT: { +// MYSTRUCT-NEXT: "kind": "identifier", +// MYSTRUCT-NEXT: "spelling": "MyStruct" +// MYSTRUCT-NEXT: } +// MYSTRUCT-NEXT: ], +// MYSTRUCT-NEXT: "title": "MyStruct" +// MYSTRUCT-NEXT: }, +// MYSTRUCT: "pathComponents": [ +// MYSTRUCT-NEXT: "MyStruct" +// MYSTRUCT-NEXT: ] + +// expected-no-diagnostics