[clang][ExtractAPI] Flatten all enum cases from anonymous enums at top level (#93559)

rdar://128863241
This commit is contained in:
Daniel Grumberg 2024-05-29 09:47:23 +01:00 committed by GitHub
parent 93d8d74ae6
commit fa649df8e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 168 deletions

View File

@ -21,6 +21,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
@ -127,7 +128,7 @@ public:
protected:
/// Collect API information for the enum constants and associate with the
/// parent enum.
void recordEnumConstants(EnumRecord *EnumRecord,
void recordEnumConstants(SymbolReference Container,
const EnumDecl::enumerator_range Constants);
/// Collect API information for the Objective-C methods and associate with the
@ -248,12 +249,8 @@ protected:
clang::index::generateUSRForDecl(Tag, TagUSR);
if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
API.findRecordForUSR(TagUSR))) {
if (Record->IsEmbeddedInVarDeclarator) {
if (Record->IsEmbeddedInVarDeclarator)
NewRecordContext->stealRecordChain(*Record);
auto *NewRecord = cast<APIRecord>(NewRecordContext);
if (NewRecord->Comment.empty())
NewRecord->Comment = Record->Comment;
}
}
}
};
@ -394,17 +391,6 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
return true;
SmallString<128> QualifiedNameBuffer;
// Collect symbol information.
StringRef Name = Decl->getName();
if (Name.empty())
Name = getTypedefName(Decl);
if (Name.empty()) {
llvm::raw_svector_ostream OS(QualifiedNameBuffer);
Decl->printQualifiedName(OS);
Name = QualifiedNameBuffer;
}
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
PresumedLoc Loc =
@ -420,13 +406,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
// Collect symbol information.
SymbolReference ParentContainer;
if (Decl->hasNameForLinkage()) {
StringRef Name = Decl->getName();
if (Name.empty())
Name = getTypedefName(Decl);
auto *ER = API.createRecord<EnumRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl), false);
ParentContainer = SymbolReference(ER);
} else {
// If this an anonymous enum then the parent scope of the constants is the
// top level namespace.
ParentContainer = {};
}
// Now collect information about the enumerators in this enum.
getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators());
getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer,
Decl->enumerators());
return true;
}
@ -1197,7 +1199,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
/// parent enum.
template <typename Derived>
void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
SymbolReference Container, const EnumDecl::enumerator_range Constants) {
for (const auto *Constant : Constants) {
// Collect symbol information.
StringRef Name = Constant->getName();
@ -1218,9 +1220,8 @@ void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
DeclarationFragmentsBuilder::getSubHeading(Constant);
API.createRecord<EnumConstantRecord>(
USR, Name, createHierarchyInformationForDecl(*Constant), Loc,
AvailabilityInfo::createFromDecl(Constant), Comment, Declaration,
SubHeading, isInSystemHeader(Constant));
USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant),
Comment, Declaration, SubHeading, isInSystemHeader(Constant));
}
}
@ -1469,7 +1470,17 @@ public:
bool shouldDeclBeIncluded(const Decl *D) const { return true; }
const RawComment *fetchRawCommentForDecl(const Decl *D) const {
return this->Context.getRawCommentForDeclNoCache(D);
if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D))
return Comment;
if (const auto *Declarator = dyn_cast<DeclaratorDecl>(D)) {
const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl();
if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() &&
TagTypeDecl->isCompleteDefinition())
return this->Context.getRawCommentForDeclNoCache(TagTypeDecl);
}
return nullptr;
}
};

View File

@ -84,21 +84,15 @@ struct Vehicle {
// TYPE: "text": "The type of vehicle."
// TYPE: "title": "type"
// BICYCLE: "!testRelLabel": "memberOf $ c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Bicycle $ c:@S@Vehicle@FI@type"
// BICYCLE-LABEL: "!testLabel": "c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Bicycle"
// BICYCLE: "title": "Bicycle"
// BICYCLE: "pathComponents": [
// BICYCLE-NEXT: "Vehicle",
// BICYCLE-NEXT: "type",
// BICYCLE-NEXT: "Bicycle"
// BICYCLE-NEXT: ]
// CAR: "!testRelLabel": "memberOf $ c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Car $ c:@S@Vehicle@FI@type"
// CAR-LABEL: "!testLabel": "c:@S@Vehicle@E@anonymous_record_no_typedef.c@{{[0-9]+}}@Car"
// CAR: "title": "Car"
// CAR: "pathComponents": [
// CAR-NEXT: "Vehicle",
// CAR-NEXT: "type",
// CAR-NEXT: "Car"
// CAR-NEXT: ]
@ -151,32 +145,22 @@ struct Vehicle {
// NAME-NEXT: ]
};
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALENUM
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALOTHERCASE
enum {
GlobalCase,
GlobalOtherCase
};
// GLOBALENUM-DAG: "!testRelLabel": "memberOf $ c:@Ea@GlobalCase@GlobalCase $ c:@Ea@GlobalCase"
// GLOBALENUM-DAG: "!testRelLabel": "memberOf $ c:@Ea@GlobalCase@GlobalOtherCase $ c:@Ea@GlobalCase"
// GLOBALENUM-LABEL: "!testLabel": "c:@Ea@GlobalCase"
// GLOBALENUM: "declarationFragments": [
// GLOBALENUM-NEXT: {
// GLOBALENUM-NEXT: "kind": "keyword",
// GLOBALENUM-NEXT: "spelling": "enum"
// GLOBALENUM-NEXT: },
// GLOBALENUM-NEXT: {
// GLOBALENUM-NEXT: "kind": "text",
// GLOBALENUM-NEXT: "spelling": " : "
// GLOBALENUM-NEXT: },
// GLOBALENUM-NEXT: {
// GLOBALENUM-NEXT: "kind": "typeIdentifier",
// GLOBALENUM-NEXT: "preciseIdentifier": "c:i",
// GLOBALENUM-NEXT: "spelling": "unsigned int"
// GLOBALENUM-NEXT: },
// GLOBALENUM-NEXT: {
// GLOBALENUM-NEXT: "kind": "text",
// GLOBALENUM-NEXT: "spelling": " { ... };"
// GLOBALENUM-NEXT: }
// GLOBALENUM-NEXT: ]
// GLOBALCASE-LABEL: "!testLabel": "c:@Ea@GlobalCase@GlobalCase"
// GLOBALCASE: "title": "GlobalCase"
// GLOBALCASE: "pathComponents": [
// GLOBALCASE-NEXT: "GlobalCase"
// GLOBALCASE-NEXT: ]
// GLOBALOTHERCASE-LABEL: "!testLabel": "c:@Ea@GlobalCase@GlobalOtherCase"
// GLOBALOTHERCASE: "title": "GlobalOtherCase"
// GLOBALOTHERCASE: "pathComponents": [
// GLOBALOTHERCASE-NEXT: "GlobalOtherCase"
// GLOBALOTHERCASE-NEXT: ]
// expected-no-diagnostics

View File

@ -115,18 +115,6 @@ enum {
"source": "c:@E@Direction@West",
"target": "c:@E@Direction",
"targetFallback": "Direction"
},
{
"kind": "memberOf",
"source": "c:@Ea@Constant@Constant",
"target": "c:@Ea@Constant",
"targetFallback": "enum (unnamed)"
},
{
"kind": "memberOf",
"source": "c:@Ea@OtherConstant@OtherConstant",
"target": "c:@Ea@OtherConstant",
"targetFallback": "enum (unnamed)"
}
],
"symbols": [
@ -677,55 +665,6 @@ enum {
"West"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "enum"
},
{
"kind": "text",
"spelling": " : "
},
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:i",
"spelling": "unsigned int"
},
{
"kind": "text",
"spelling": " { ... };"
}
],
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@Ea@Constant"
},
"kind": {
"displayName": "Enumeration",
"identifier": "c.enum"
},
"location": {
"position": {
"character": 0,
"line": 16
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "enum (unnamed)"
}
],
"title": "enum (unnamed)"
},
"pathComponents": [
"enum (unnamed)"
]
},
{
"accessLevel": "public",
"declarationFragments": [
@ -765,59 +704,9 @@ enum {
"title": "Constant"
},
"pathComponents": [
"enum (unnamed)",
"Constant"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "keyword",
"spelling": "enum"
},
{
"kind": "text",
"spelling": " : "
},
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:i",
"spelling": "unsigned int"
},
{
"kind": "text",
"spelling": " { ... };"
}
],
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@Ea@OtherConstant"
},
"kind": {
"displayName": "Enumeration",
"identifier": "c.enum"
},
"location": {
"position": {
"character": 0,
"line": 20
},
"uri": "file://INPUT_DIR/input.h"
},
"names": {
"navigator": [
{
"kind": "identifier",
"spelling": "enum (unnamed)"
}
],
"title": "enum (unnamed)"
},
"pathComponents": [
"enum (unnamed)"
]
},
{
"accessLevel": "public",
"declarationFragments": [
@ -857,7 +746,6 @@ enum {
"title": "OtherConstant"
},
"pathComponents": [
"enum (unnamed)",
"OtherConstant"
]
}

View File

@ -45,6 +45,9 @@ struct LibClangExtractAPIVisitor
: ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {}
const RawComment *fetchRawCommentForDecl(const Decl *D) const {
if (const auto *Comment = Base::fetchRawCommentForDecl(D))
return Comment;
return Context.getRawCommentForAnyRedecl(D);
}