Skip to content

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

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

Merged
merged 1 commit into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 38 additions & 27 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -127,7 +128,7 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
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
Expand Down Expand Up @@ -248,12 +249,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
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;
}
}
}
};
Expand Down Expand Up @@ -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 =
Expand All @@ -420,13 +406,29 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);
auto *ER = API.createRecord<EnumRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*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), 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;
}
Expand Down Expand Up @@ -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();
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -1469,7 +1470,17 @@ class ExtractAPIVisitor

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;
}
};

Expand Down
42 changes: 13 additions & 29 deletions clang/test/ExtractAPI/anonymous_record_no_typedef.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: ]

Expand Down Expand Up @@ -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
112 changes: 0 additions & 112 deletions clang/test/ExtractAPI/enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -857,7 +746,6 @@ enum {
"title": "OtherConstant"
},
"pathComponents": [
"enum (unnamed)",
"OtherConstant"
]
}
Expand Down
3 changes: 3 additions & 0 deletions clang/tools/libclang/CXExtractAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Loading