Skip to content
Open
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
68 changes: 18 additions & 50 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,27 +250,6 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
return D.getName().empty() && getTypedefName(&D).empty() &&
D.isEmbeddedInDeclarator() && !D.isFreeStanding();
}

void maybeMergeWithAnonymousTag(const DeclaratorDecl &D,
RecordContext *NewRecordContext) {
if (!NewRecordContext)
return;
auto *Tag = D.getType()->getAsTagDecl();
if (!Tag) {
if (const auto *AT = D.getASTContext().getAsArrayType(D.getType())) {
Tag = AT->getElementType()->getAsTagDecl();
}
}
SmallString<128> TagUSR;
clang::index::generateUSRForDecl(Tag, TagUSR);
if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
API.findRecordForUSR(TagUSR))) {
if (Record->IsEmbeddedInVarDeclarator) {
NewRecordContext->stealRecordChain(*Record);
API.removeRecord(Record);
}
}
}
};

template <typename Derived>
Expand Down Expand Up @@ -322,14 +301,10 @@ bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
SubHeading, Access, isInSystemHeader(Decl));
} else {
// Add the global variable record to the API set.
auto *NewRecord = API.createRecord<GlobalVariableRecord>(
API.createRecord<GlobalVariableRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
SubHeading, isInSystemHeader(Decl));

// If this global variable has a non typedef'd anonymous tag type let's
// pretend the type's child records are under us in the hierarchy.
maybeMergeWithAnonymousTag(*Decl, NewRecord);
}

return true;
Expand Down Expand Up @@ -565,15 +540,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitNamespaceDecl(

template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::TraverseRecordDecl(RecordDecl *Decl) {
bool Ret = Base::TraverseRecordDecl(Decl);

if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
API.removeRecord(USR);
}

return Ret;
return Base::TraverseRecordDecl(Decl);
}

template <typename Derived>
Expand Down Expand Up @@ -620,13 +587,7 @@ template <typename Derived>
bool ExtractAPIVisitorBase<Derived>::TraverseCXXRecordDecl(
CXXRecordDecl *Decl) {
bool Ret = Base::TraverseCXXRecordDecl(Decl);

if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);
API.removeRecord(USR);
}

// Keep anonymous structs in the hierarchy to preserve path components
return Ret;
}

Expand All @@ -643,6 +604,11 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(

SmallString<128> USR;
index::generateUSRForDecl(Decl, USR);

if (API.findRecordForUSR(USR)) {
return true;
}

PresumedLoc Loc =
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
DocComment Comment;
Expand Down Expand Up @@ -679,6 +645,13 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
Record->KindForDisplay = getKindForDisplay(Decl);
Record->Bases = getBases(Decl);

// Visit nested records
for (const auto *NestedDecl : Decl->decls()) {
if (auto *NestedRecord = dyn_cast<CXXRecordDecl>(NestedDecl)) {
VisitCXXRecordDecl(NestedRecord);
}
}

return true;
}

Expand Down Expand Up @@ -1320,31 +1293,26 @@ bool ExtractAPIVisitorBase<Derived>::VisitFieldDecl(const FieldDecl *Decl) {
DeclarationFragments SubHeading =
DeclarationFragmentsBuilder::getSubHeading(Decl);

RecordContext *NewRecord = nullptr;
if (isa<CXXRecordDecl>(Decl->getDeclContext())) {
AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);

NewRecord = API.createRecord<CXXFieldRecord>(
API.createRecord<CXXFieldRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, Access, isInSystemHeader(Decl));
} else if (auto *RD = dyn_cast<RecordDecl>(Decl->getDeclContext())) {
if (RD->isUnion())
NewRecord = API.createRecord<UnionFieldRecord>(
API.createRecord<UnionFieldRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl));
else
NewRecord = API.createRecord<StructFieldRecord>(
API.createRecord<StructFieldRecord>(
USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
SubHeading, isInSystemHeader(Decl));
}

// If this field has a non typedef'd anonymous tag type let's pretend the
// type's child records are under us in the hierarchy.
maybeMergeWithAnonymousTag(*Decl, NewRecord);

return true;
}

Expand Down
24 changes: 10 additions & 14 deletions clang/test/ExtractAPI/anonymous_record_no_typedef.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ struct { char *prefix; char *content; } global;
// GLOBAL-NEXT: "global"
// GLOBAL-NEXT:]

// PREFIX: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix $ c:@global"
// PREFIX: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}"
// PREFIX-LABEL: "!testLabel": "c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@prefix"
// PREFIX: "title": "prefix"
// PREFIX: "pathComponents": [
// PREFIX-NEXT: "global",
// PREFIX-NEXT: "",
// PREFIX-NEXT: "prefix"
// PREFIX-NEXT: ]

// CONTENT: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content $ c:@global"
// CONTENT: "!testRelLabel": "memberOf $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content $ c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}"
// CONTENT-LABEL: "!testLabel": "c:@S@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@content"
// CONTENT: "title": "content"
// CONTENT: "pathComponents": [
// CONTENT-NEXT: "global",
// CONTENT-NEXT: "",
// CONTENT-NEXT: "content"
// CONTENT-NEXT: ]

Expand Down Expand Up @@ -139,21 +139,21 @@ struct Vehicle {
// INFORMATION: "text": "The information about the vehicle."
// INFORMATION: "title": "information"

// WHEELS: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels $ c:@S@Vehicle@FI@information"
// WHEELS: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}"
// WHEELS-LABEL: "!testLabel": "c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@wheels"
// WHEELS: "title": "wheels"
// WHEELS: "pathComponents": [
// WHEELS-NEXT: "Vehicle",
// WHEELS-NEXT: "information",
// WHEELS-NEXT: "",
// WHEELS-NEXT: "wheels"
// WHEELS-NEXT: ]

// NAME: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name $ c:@S@Vehicle@FI@information"
// NAME: "!testRelLabel": "memberOf $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name $ c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}"
// NAME-LABEL: "!testLabel": "c:@S@Vehicle@U@anonymous_record_no_typedef.c@{{[0-9]+}}@FI@name"
// NAME: "title": "name"
// NAME: "pathComponents": [
// NAME-NEXT: "Vehicle",
// NAME-NEXT: "information",
// NAME-NEXT: "",
// NAME-NEXT: "name"
// NAME-NEXT: ]
};
Expand Down Expand Up @@ -188,20 +188,16 @@ union Vector {
float Data[2];
};
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@FI@Data $ c:@U@Vector"
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@X $ c:@U@Vector"
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@Y $ c:@U@Vector"
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@X $ c:@U@Vector@Sa"
// VEC-DAG: "!testRelLabel": "memberOf $ c:@U@Vector@Sa@FI@Y $ c:@U@Vector@Sa"

// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix COUNTS
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix COUNTS
struct MyStruct {
struct {
int count;
} counts[1];
};
// MYSTRUCT-NOT: "spelling": ""
// MYSTRUCT-NOT: "title": ""

// COUNTS-LABEL: "!testLabel": "c:@S@MyStruct@FI@counts"
// COUNTS: "declarationFragments": [
Expand Down
Loading