[clang][ExtractAPI] Flatten all enum cases from anonymous enums at top level (#93559)
rdar://128863241
This commit is contained in:
parent
93d8d74ae6
commit
fa649df8e5
@ -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);
|
||||
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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user