[clang] [clang][ExtractAPI] Fix handling of anonymous TagDecls (PR #87772)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 5 05:41:37 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Daniel Grumberg (daniel-grumberg)
<details>
<summary>Changes</summary>
This changes the handling of anonymous TagDecls to the following rules:
- If the TagDecl is embedded in the declaration for some VarDecl (this is the only possibility for RecordDecls), then pretend the child decls belong to the VarDecl
- If it's an EnumDecl proceed as we did previously, i.e., embed it in the enclosing DeclContext.
Additionally this fixes a few issues with declaration fragments not consistently including "{ ... }" for anonymous TagDecls. To make testing these additions easier this patch fixes some text declaration fragments merging issues and updates tests accordingly.
---
Patch is 56.69 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87772.diff
14 Files Affected:
- (modified) clang/include/clang/ExtractAPI/API.h (+88-44)
- (modified) clang/include/clang/ExtractAPI/APIRecords.inc (+14-2)
- (modified) clang/include/clang/ExtractAPI/DeclarationFragments.h (+57-27)
- (modified) clang/include/clang/ExtractAPI/ExtractAPIVisitor.h (+53-23)
- (modified) clang/lib/ExtractAPI/API.cpp (+8)
- (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+13-4)
- (modified) clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (+8)
- (modified) clang/test/ExtractAPI/anonymous_record_no_typedef.c (+165-400)
- (modified) clang/test/ExtractAPI/enum.c (+6-6)
- (modified) clang/test/ExtractAPI/function_noexcepts.cpp (+3-15)
- (modified) clang/test/ExtractAPI/methods.cpp (+1-5)
- (modified) clang/test/ExtractAPI/objc_block.m (+8-40)
- (modified) clang/test/ExtractAPI/typedef_anonymous_record.c (+2-2)
- (modified) clang/test/ExtractAPI/typedef_struct_enum.c (+1-1)
``````````diff
diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index 92cacf65c7d64e..05cfabd072a560 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -208,20 +208,20 @@ struct APIRecord {
RK_ClassTemplate,
RK_ClassTemplateSpecialization,
RK_ClassTemplatePartialSpecialization,
- RK_LastRecordContext,
- RK_GlobalFunction,
- RK_GlobalFunctionTemplate,
- RK_GlobalFunctionTemplateSpecialization,
+ RK_StructField,
+ RK_UnionField,
+ RK_CXXField,
+ RK_StaticField,
+ RK_CXXFieldTemplate,
RK_GlobalVariable,
RK_GlobalVariableTemplate,
RK_GlobalVariableTemplateSpecialization,
RK_GlobalVariableTemplatePartialSpecialization,
+ RK_LastRecordContext,
+ RK_GlobalFunction,
+ RK_GlobalFunctionTemplate,
+ RK_GlobalFunctionTemplateSpecialization,
RK_EnumConstant,
- RK_StructField,
- RK_UnionField,
- RK_StaticField,
- RK_CXXField,
- RK_CXXFieldTemplate,
RK_Concept,
RK_CXXStaticMethod,
RK_CXXInstanceMethod,
@@ -321,6 +321,8 @@ class RecordContext {
RecordContext(APIRecord::RecordKind Kind) : Kind(Kind) {}
+ void stealRecordChain(RecordContext &Other);
+
APIRecord::RecordKind getKind() const { return Kind; }
struct record_iterator {
@@ -475,7 +477,7 @@ struct GlobalFunctionTemplateSpecializationRecord : GlobalFunctionRecord {
};
/// This holds information associated with global functions.
-struct GlobalVariableRecord : APIRecord {
+struct GlobalVariableRecord : APIRecord, RecordContext {
GlobalVariableRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
LinkageInfo Linkage, const DocComment &Comment,
@@ -483,23 +485,28 @@ struct GlobalVariableRecord : APIRecord {
DeclarationFragments SubHeading, bool IsFromSystemHeader)
: APIRecord(RK_GlobalVariable, USR, Name, Parent, Loc,
std::move(Availability), Linkage, Comment, Declaration,
- SubHeading, IsFromSystemHeader) {}
+ SubHeading, IsFromSystemHeader),
+ RecordContext(RK_GlobalVariable) {}
GlobalVariableRecord(RecordKind Kind, StringRef USR, StringRef Name,
- SymbolReference Parent,
-
- PresumedLoc Loc, AvailabilityInfo Availability,
- LinkageInfo Linkage, const DocComment &Comment,
+ SymbolReference Parent, PresumedLoc Loc,
+ AvailabilityInfo Availability, LinkageInfo Linkage,
+ const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
Linkage, Comment, Declaration, SubHeading,
- IsFromSystemHeader) {}
+ IsFromSystemHeader),
+ RecordContext(Kind) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
}
- static bool classofKind(RecordKind K) { return K == RK_GlobalVariable; }
+ static bool classofKind(RecordKind K) {
+ return K == RK_GlobalVariable || K == RK_GlobalVariableTemplate ||
+ K == RK_GlobalVariableTemplateSpecialization ||
+ K == RK_GlobalVariableTemplatePartialSpecialization;
+ }
private:
virtual void anchor();
@@ -591,20 +598,47 @@ struct EnumConstantRecord : APIRecord {
virtual void anchor();
};
+struct TagRecord : APIRecord, RecordContext {
+ TagRecord(RecordKind Kind, StringRef USR, StringRef Name,
+ SymbolReference Parent, PresumedLoc Loc,
+ AvailabilityInfo Availability, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
+ bool IsFromSystemHeader, bool IsEmbeddedInVarDeclarator,
+ AccessControl Access = AccessControl())
+ : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
+ LinkageInfo::none(), Comment, Declaration, SubHeading,
+ IsFromSystemHeader, std::move(Access)),
+ RecordContext(Kind),
+ IsEmbeddedInVarDeclarator(IsEmbeddedInVarDeclarator){};
+
+ static bool classof(const APIRecord *Record) {
+ return classofKind(Record->getKind());
+ }
+ static bool classofKind(RecordKind K) {
+ return K == RK_Struct || K == RK_Union || K == RK_Enum;
+ }
+
+ bool IsEmbeddedInVarDeclarator;
+
+ virtual ~TagRecord() = 0;
+};
+
/// This holds information associated with enums.
-struct EnumRecord : APIRecord, RecordContext {
+struct EnumRecord : TagRecord {
EnumRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
- : APIRecord(RK_Enum, USR, Name, Parent, Loc, std::move(Availability),
- LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader),
- RecordContext(RK_Enum) {}
+ DeclarationFragments SubHeading, bool IsFromSystemHeader,
+ bool IsEmbeddedInVarDeclarator,
+ AccessControl Access = AccessControl())
+ : TagRecord(RK_Enum, USR, Name, Parent, Loc, std::move(Availability),
+ Comment, Declaration, SubHeading, IsFromSystemHeader,
+ IsEmbeddedInVarDeclarator, std::move(Access)) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
}
+
static bool classofKind(RecordKind K) { return K == RK_Enum; }
private:
@@ -612,7 +646,7 @@ struct EnumRecord : APIRecord, RecordContext {
};
/// This holds information associated with struct or union fields fields.
-struct RecordFieldRecord : APIRecord {
+struct RecordFieldRecord : APIRecord, RecordContext {
RecordFieldRecord(RecordKind Kind, StringRef USR, StringRef Name,
SymbolReference Parent, PresumedLoc Loc,
AvailabilityInfo Availability, const DocComment &Comment,
@@ -620,7 +654,8 @@ struct RecordFieldRecord : APIRecord {
DeclarationFragments SubHeading, bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader) {}
+ IsFromSystemHeader),
+ RecordContext(Kind) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
@@ -633,16 +668,17 @@ struct RecordFieldRecord : APIRecord {
};
/// This holds information associated with structs and unions.
-struct RecordRecord : APIRecord, RecordContext {
+struct RecordRecord : TagRecord {
RecordRecord(RecordKind Kind, StringRef USR, StringRef Name,
SymbolReference Parent, PresumedLoc Loc,
AvailabilityInfo Availability, const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
- : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
- LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader),
- RecordContext(Kind) {}
+ DeclarationFragments SubHeading, bool IsFromSystemHeader,
+ bool IsEmbeddedInVarDeclarator,
+ AccessControl Access = AccessControl())
+ : TagRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
+ Comment, Declaration, SubHeading, IsFromSystemHeader,
+ IsEmbeddedInVarDeclarator, std::move(Access)) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
@@ -651,6 +687,8 @@ struct RecordRecord : APIRecord, RecordContext {
return K == RK_Struct || K == RK_Union;
}
+ bool isAnonymousWithNoTypedef() { return Name.empty(); }
+
virtual ~RecordRecord() = 0;
};
@@ -676,9 +714,11 @@ struct StructRecord : RecordRecord {
StructRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
+ DeclarationFragments SubHeading, bool IsFromSystemHeader,
+ bool IsEmbeddedInVarDeclarator)
: RecordRecord(RK_Struct, USR, Name, Parent, Loc, std::move(Availability),
- Comment, Declaration, SubHeading, IsFromSystemHeader) {}
+ Comment, Declaration, SubHeading, IsFromSystemHeader,
+ IsEmbeddedInVarDeclarator) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
@@ -711,9 +751,11 @@ struct UnionRecord : RecordRecord {
UnionRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading, bool IsFromSystemHeader)
+ DeclarationFragments SubHeading, bool IsFromSystemHeader,
+ bool IsEmbeddedInVarDeclarator)
: RecordRecord(RK_Union, USR, Name, Parent, Loc, std::move(Availability),
- Comment, Declaration, SubHeading, IsFromSystemHeader) {}
+ Comment, Declaration, SubHeading, IsFromSystemHeader,
+ IsEmbeddedInVarDeclarator) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
@@ -724,7 +766,7 @@ struct UnionRecord : RecordRecord {
virtual void anchor();
};
-struct CXXFieldRecord : APIRecord {
+struct CXXFieldRecord : APIRecord, RecordContext {
CXXFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
const DocComment &Comment, DeclarationFragments Declaration,
@@ -732,7 +774,8 @@ struct CXXFieldRecord : APIRecord {
bool IsFromSystemHeader)
: APIRecord(RK_CXXField, USR, Name, Parent, Loc, std::move(Availability),
LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader, std::move(Access)) {}
+ IsFromSystemHeader, std::move(Access)),
+ RecordContext(RK_CXXField) {}
CXXFieldRecord(RecordKind Kind, StringRef USR, StringRef Name,
SymbolReference Parent, PresumedLoc Loc,
@@ -742,7 +785,8 @@ struct CXXFieldRecord : APIRecord {
bool IsFromSystemHeader)
: APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader, std::move(Access)) {}
+ IsFromSystemHeader, std::move(Access)),
+ RecordContext(Kind) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
@@ -1118,18 +1162,18 @@ struct ObjCContainerRecord : APIRecord, RecordContext {
virtual ~ObjCContainerRecord() = 0;
};
-struct CXXClassRecord : APIRecord, RecordContext {
+struct CXXClassRecord : RecordRecord {
SmallVector<SymbolReference> Bases;
CXXClassRecord(StringRef USR, StringRef Name, SymbolReference Parent,
PresumedLoc Loc, AvailabilityInfo Availability,
const DocComment &Comment, DeclarationFragments Declaration,
DeclarationFragments SubHeading, RecordKind Kind,
- AccessControl Access, bool IsFromSystemHeader)
- : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
- LinkageInfo::none(), Comment, Declaration, SubHeading,
- IsFromSystemHeader, std::move(Access)),
- RecordContext(Kind) {}
+ AccessControl Access, bool IsFromSystemHeader,
+ bool IsEmbeddedInVarDeclarator = false)
+ : RecordRecord(Kind, USR, Name, Parent, Loc, std::move(Availability),
+ Comment, Declaration, SubHeading, IsFromSystemHeader,
+ IsEmbeddedInVarDeclarator, std::move(Access)) {}
static bool classof(const APIRecord *Record) {
return classofKind(Record->getKind());
diff --git a/clang/include/clang/ExtractAPI/APIRecords.inc b/clang/include/clang/ExtractAPI/APIRecords.inc
index 15fee809656d9a..4cda4ef2f9be63 100644
--- a/clang/include/clang/ExtractAPI/APIRecords.inc
+++ b/clang/include/clang/ExtractAPI/APIRecords.inc
@@ -35,10 +35,11 @@ CONCRETE_RECORD(GlobalVariableTemplateSpecializationRecord,
CONCRETE_RECORD(GlobalVariableTemplatePartialSpecializationRecord,
GlobalVariableRecord,
RK_GlobalVariableTemplatePartialSpecialization)
+ABSTRACT_RECORD(TagRecord, APIRecord)
CONCRETE_RECORD(EnumConstantRecord, APIRecord, RK_EnumConstant)
-CONCRETE_RECORD(EnumRecord, APIRecord, RK_Enum)
+CONCRETE_RECORD(EnumRecord, TagRecord, RK_Enum)
ABSTRACT_RECORD(RecordFieldRecord, APIRecord)
-ABSTRACT_RECORD(RecordRecord, APIRecord)
+ABSTRACT_RECORD(RecordRecord, TagRecord)
CONCRETE_RECORD(StructFieldRecord, RecordFieldRecord, RK_StructField)
CONCRETE_RECORD(StructRecord, APIRecord, RK_Struct)
CONCRETE_RECORD(UnionFieldRecord, RecordFieldRecord, RK_UnionField)
@@ -99,5 +100,16 @@ RECORD_CONTEXT(ClassTemplateSpecializationRecord,
RK_ClassTemplateSpecialization)
RECORD_CONTEXT(ClassTemplatePartialSpecializationRecord,
RK_ClassTemplatePartialSpecialization)
+RECORD_CONTEXT(StructFieldRecord, RK_StructField)
+RECORD_CONTEXT(UnionFieldRecord, RK_UnionField)
+RECORD_CONTEXT(CXXFieldRecord, RK_CXXField)
+RECORD_CONTEXT(StaticFieldRecord, RK_StaticField)
+RECORD_CONTEXT(CXXFieldTemplateRecord, RK_CXXFieldTemplate)
+RECORD_CONTEXT(GlobalVariableRecord, RK_GlobalVariable)
+RECORD_CONTEXT(GlobalVariableTemplateRecord, RK_GlobalVariableTemplate)
+RECORD_CONTEXT(GlobalVariableTemplateSpecializationRecord,
+ RK_GlobalVariableTemplateSpecialization)
+RECORD_CONTEXT(GlobalVariableTemplatePartialSpecializationRecord,
+ RK_GlobalVariableTemplatePartialSpecialization)
#undef RECORD_CONTEXT
diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index 94392c18516595..535da90b98284b 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -27,6 +27,8 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/MacroInfo.h"
+#include <iterator>
+#include <utility>
#include <vector>
namespace clang {
@@ -113,28 +115,26 @@ class DeclarationFragments {
ConstFragmentIterator cend() const { return Fragments.cend(); }
- // Add a new Fragment at an arbitrary offset.
- DeclarationFragments &insert(FragmentIterator It, StringRef Spelling,
- FragmentKind Kind,
- StringRef PreciseIdentifier = "",
- const Decl *Declaration = nullptr) {
- Fragments.insert(It,
- Fragment(Spelling, Kind, PreciseIdentifier, Declaration));
- return *this;
+ /// Prepend another DeclarationFragments to the beginning.
+ ///
+ /// \returns a reference to the DeclarationFragments object itself after
+ /// appending to chain up consecutive operations.
+ DeclarationFragments &prepend(DeclarationFragments Other) {
+ return insert(begin(), std::move(Other));
}
- DeclarationFragments &insert(FragmentIterator It,
- DeclarationFragments &&Other) {
- Fragments.insert(It, std::make_move_iterator(Other.Fragments.begin()),
- std::make_move_iterator(Other.Fragments.end()));
- Other.Fragments.clear();
- return *this;
+ /// Append another DeclarationFragments to the end.
+ ///
+ /// \returns a reference to the DeclarationFragments object itself after
+ /// appending to chain up consecutive operations.
+ DeclarationFragments &append(DeclarationFragments Other) {
+ return insert(end(), std::move(Other));
}
/// Append a new Fragment to the end of the Fragments.
///
/// \returns a reference to the DeclarationFragments object itself after
- /// appending to chain up consecutive appends.
+ /// appending to chain up consecutive operations.
DeclarationFragments &append(StringRef Spelling, FragmentKind Kind,
StringRef PreciseIdentifier = "",
const Decl *Declaration = nullptr) {
@@ -149,18 +149,48 @@ class DeclarationFragments {
return *this;
}
- /// Append another DeclarationFragments to the end.
- ///
- /// Note: \p Other is moved from and cannot be used after a call to this
- /// method.
+ /// Inserts another DeclarationFragments at \p It.
///
/// \returns a reference to the DeclarationFragments object itself after
- /// appending to chain up consecutive appends.
- DeclarationFragments &append(DeclarationFragments &&Other) {
- Fragments.insert(Fragments.end(),
- std::make_move_iterator(Other.Fragments.begin()),
- std::make_move_iterator(Other.Fragments.end()));
- Other.Fragments.clear();
+ /// appending to chain up consecutive operations.
+ DeclarationFragments &insert(FragmentIterator It,
+ DeclarationFragments Other) {
+ if (Other.Fragments.empty())
+ return *this;
+
+ if (Fragments.empty()) {
+ Fragments = std::move(Other.Fragments);
+ return *this;
+ }
+
+ const auto &OtherFrags = Other.Fragments;
+ auto ToInsertBegin = std::make_move_iterator(Other.begin());
+ auto ToInsertEnd = std::make_move_iterator(Other.end());
+
+ // If we aren't inserting at the end let's make sure that we merge their
+ // last fragment with It if both are text fragments.
+ if (It != end() && It->Kind == FragmentKind::Text &&
+ OtherFrags.back().Kind == FragmentKind::Text) {
+ auto &TheirBackSpelling = OtherFrags.back().Spelling;
+ It->Spelling.reserve(It->Spelling.size() + TheirBackSpelling.size());
+ It->Spelling.insert(It->Spelling.begin(), TheirBackSpelling.begin(),
+ TheirBackSpelling.end());
+ --ToInsertEnd;
+ }
+
+ // If we aren't inserting at the beginning we want to merge their first
+ // fragment with the fragment before It if both are text fragments.
+ if (It != begin() && std::prev(It)->Kind == FragmentKind::Text &&
+ OtherFrags.front().Kind == FragmentKind::Text) {
+ auto PrevIt = std::prev(It);
+ auto &TheirFrontSpelling = OtherFrags.front().Spelling;
+ PrevIt->Spelling.reserve(PrevIt->Spelling.size() +
+ TheirFrontSpelling.size());
+ PrevIt->Spelling.append(TheirFrontSpelling);
+ ++ToInsertBegin;
+ }
+
+ Fragments.insert(It, ToInsertBegin, ToInsertEnd);
return *this;
}
@@ -177,13 +207,13 @@ class DeclarationFragments {
/// Append a text Fragment of a space character.
///
/// \returns a reference to the DeclarationFragments object itself after
- /// appending to chain up consecutive appends.
+ /// appending to chain up consecutive operations.
DeclarationFragments &appendSpace();
/// Append a text Fragment of a semicolon character.
///
/// \returns a reference to the DeclarationFragments object itself after
- /// appending to chain up consecutive appends.
+ /// appending to chain up consecutive operations.
DeclarationFragments &appendSemicolon();
/// Removes a trailing semicolon character if present.
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index 4cb866892b5d00..97cc457ea2a926 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -224,6 +224,29 @@ class ExtractAPIVisitorBase : publ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/87772
More information about the cfe-commits
mailing list