zixuw updated this revision to Diff 417430.
zixuw added a comment.
Rebase
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D122202/new/
https://reviews.llvm.org/D122202
Files:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/DeclarationFragments.h
clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/DeclarationFragments.cpp
clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
clang/test/ExtractAPI/struct.c
Index: clang/test/ExtractAPI/struct.c
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/struct.c
@@ -0,0 +1,303 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
+// RUN: %t/reference.output.json
+// RUN: %clang -extract-api -target arm64-apple-macosx \
+// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+/// Color in RGBA
+struct Color {
+ unsigned Red;
+ unsigned Green;
+ unsigned Blue;
+ /// Alpha channel for transparency
+ unsigned Alpha;
+};
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationhips": [
+ {
+ "kind": "memberOf",
+ "source": "c:@S@Color@FI@Red",
+ "target": "c:@S@Color"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:@S@Color@FI@Green",
+ "target": "c:@S@Color"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:@S@Color@FI@Blue",
+ "target": "c:@S@Color"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:@S@Color@FI@Alpha",
+ "target": "c:@S@Color"
+ }
+ ],
+ "symbols": [
+ {
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "struct"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Color"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 18,
+ "line": 1
+ },
+ "start": {
+ "character": 5,
+ "line": 1
+ }
+ },
+ "text": "Color in RGBA"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@S@Color"
+ },
+ "kind": {
+ "displayName": "Struct",
+ "identifier": "c.struct"
+ },
+ "location": {
+ "character": 8,
+ "line": 2,
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Color"
+ }
+ ],
+ "title": "Color"
+ }
+ },
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:i",
+ "spelling": "unsigned int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Red"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@S@Color@FI@Red"
+ },
+ "kind": {
+ "displayName": "Struct Field",
+ "identifier": "c.struct.field"
+ },
+ "location": {
+ "character": 12,
+ "line": 3,
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Red"
+ }
+ ],
+ "title": "Red"
+ }
+ },
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:i",
+ "spelling": "unsigned int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Green"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@S@Color@FI@Green"
+ },
+ "kind": {
+ "displayName": "Struct Field",
+ "identifier": "c.struct.field"
+ },
+ "location": {
+ "character": 12,
+ "line": 4,
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Green"
+ }
+ ],
+ "title": "Green"
+ }
+ },
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:i",
+ "spelling": "unsigned int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Blue"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@S@Color@FI@Blue"
+ },
+ "kind": {
+ "displayName": "Struct Field",
+ "identifier": "c.struct.field"
+ },
+ "location": {
+ "character": 12,
+ "line": 5,
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Blue"
+ }
+ ],
+ "title": "Blue"
+ }
+ },
+ {
+ "declarationFragments": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:i",
+ "spelling": "unsigned int"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Alpha"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 37,
+ "line": 6
+ },
+ "start": {
+ "character": 7,
+ "line": 6
+ }
+ },
+ "text": "Alpha channel for transparency"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "c",
+ "precise": "c:@S@Color@FI@Alpha"
+ },
+ "kind": {
+ "displayName": "Struct Field",
+ "identifier": "c.struct.field"
+ },
+ "location": {
+ "character": 12,
+ "line": 7,
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Alpha"
+ }
+ ],
+ "title": "Alpha"
+ }
+ }
+ ]
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -367,6 +367,14 @@
Kind["identifier"] = AddLangPrefix("enum");
Kind["displayName"] = "Enumeration";
break;
+ case APIRecord::RK_StructField:
+ Kind["identifier"] = AddLangPrefix("struct.field");
+ Kind["displayName"] = "Struct Field";
+ break;
+ case APIRecord::RK_Struct:
+ Kind["identifier"] = AddLangPrefix("struct");
+ Kind["displayName"] = "Struct";
+ break;
}
return Kind;
@@ -475,6 +483,23 @@
}
}
+void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
+ auto Struct = serializeAPIRecord(Record);
+ if (!Struct)
+ return;
+
+ Symbols.emplace_back(std::move(*Struct));
+
+ for (const auto &Field : Record.Fields) {
+ auto StructField = serializeAPIRecord(*Field);
+ if (!StructField)
+ continue;
+
+ Symbols.emplace_back(std::move(*StructField));
+ serializeRelationship(RelationshipKind::MemberOf, *Field, Record);
+ }
+}
+
Object SymbolGraphSerializer::serialize() {
Object Root;
serializeObject(Root, "metadata", serializeMetadata());
@@ -488,6 +513,10 @@
for (const auto &Enum : API.getEnums())
serializeEnumRecord(*Enum.second);
+ // Serialize struct records in the API set.
+ for (const auto &Struct: API.getStructs())
+ serializeStructRecord(*Struct.second);
+
Root["symbols"] = std::move(Symbols);
Root["relationhips"] = std::move(Relationships);
Index: clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
===================================================================
--- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -179,6 +179,41 @@
return true;
}
+ bool VisitRecordDecl(const RecordDecl *Decl) {
+ if (!Decl->isCompleteDefinition())
+ return true;
+
+ // Skip C++ structs/classes/unions
+ // TODO: support C++ records
+ if (isa<CXXRecordDecl>(Decl))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ AvailabilityInfo Availability = getAvailability(Decl);
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the struct.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ StructRecord *StructRecord = API.addStruct(
+ Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
+
+ // Now collect information about the fields in this struct.
+ recordStructFields(StructRecord, Decl->fields());
+
+ return true;
+ }
+
private:
/// Get availability information of the declaration \p D.
AvailabilityInfo getAvailability(const Decl *D) const {
@@ -238,6 +273,33 @@
}
}
+ /// Collect API information for the struct fields and associate with the
+ /// parent struct.
+ void recordStructFields(StructRecord *StructRecord,
+ const RecordDecl::field_range Fields) {
+ for (const auto *Field : Fields) {
+ // Collect symbol information.
+ StringRef Name = Field->getName();
+ StringRef USR = API.recordUSR(Field);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Field->getLocation());
+ AvailabilityInfo Availability = getAvailability(Field);
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the struct field.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForField(Field);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Field);
+
+ API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
+ Declaration, SubHeading);
+ }
+ }
+
ASTContext &Context;
APISet API;
};
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -430,6 +430,30 @@
return Fragments;
}
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
+ DeclarationFragments After;
+ return getFragmentsForType(Field->getType(), Field->getASTContext(), After)
+ .appendSpace()
+ .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After));
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
+ // TODO: After we support typedef records, if there's a typedef for this
+ // struct just use the declaration fragments of the typedef decl.
+
+ DeclarationFragments Fragments;
+ Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
+
+ if (!Record->getName().empty())
+ Fragments.appendSpace().append(
+ Record->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+ return Fragments;
+}
+
FunctionSignature
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *Func) {
FunctionSignature Signature;
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -84,6 +84,33 @@
return Result.first->second.get();
}
+StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
+ StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading) {
+ auto Record =
+ APIRecordUniquePtr<StructFieldRecord>(new (Allocator) StructFieldRecord{
+ Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
+ return Struct->Fields.emplace_back(std::move(Record)).get();
+}
+
+StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading) {
+ auto Result = Structs.insert({Name, nullptr});
+ if (Result.second) {
+ // Create the record if it does not already exist.
+ auto Record = APIRecordUniquePtr<StructRecord>(new (Allocator) StructRecord{
+ Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
+ Result.first->second = std::move(Record);
+ }
+ return Result.first->second.get();
+}
+
StringRef APISet::recordUSR(const Decl *D) {
SmallString<128> USR;
index::generateUSRForDecl(D, USR);
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -110,6 +110,9 @@
/// Serialize an enum record.
void serializeEnumRecord(const EnumRecord &Record);
+ /// Serialize a struct record.
+ void serializeStructRecord(const StructRecord &Record);
+
public:
SymbolGraphSerializer(const APISet &API, APISerializerOption Options = {})
: APISerializer(API, Options) {}
Index: clang/include/clang/ExtractAPI/DeclarationFragments.h
===================================================================
--- clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -196,6 +196,12 @@
/// Build DeclarationFragments for an enum declaration EnumDecl.
static DeclarationFragments getFragmentsForEnum(const EnumDecl *);
+ /// Build DeclarationFragments for a field declaration FieldDecl.
+ static DeclarationFragments getFragmentsForField(const FieldDecl *);
+
+ /// Build DeclarationFragments for a struct record declaration RecordDecl.
+ static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
+
/// Build sub-heading fragments for a NamedDecl.
static DeclarationFragments getSubHeading(const NamedDecl *);
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -94,6 +94,8 @@
RK_Global,
RK_EnumConstant,
RK_Enum,
+ RK_StructField,
+ RK_Struct,
};
private:
@@ -176,6 +178,36 @@
}
};
+/// This holds information associated with struct fields.
+struct StructFieldRecord : APIRecord {
+ StructFieldRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability,
+ const DocComment &Comment, DeclarationFragments Declaration,
+ DeclarationFragments SubHeading)
+ : APIRecord(RK_StructField, Name, USR, Loc, Availability,
+ LinkageInfo::none(), Comment, Declaration, SubHeading) {}
+
+ static bool classof(const APIRecord *Record) {
+ return Record->getKind() == RK_StructField;
+ }
+};
+
+/// This holds information associated with structs.
+struct StructRecord : APIRecord {
+ SmallVector<APIRecordUniquePtr<StructFieldRecord>> Fields;
+
+ StructRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability, const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading)
+ : APIRecord(RK_Struct, Name, USR, Loc, Availability, LinkageInfo::none(),
+ Comment, Declaration, SubHeading) {}
+
+ static bool classof(const APIRecord *Record) {
+ return Record->getKind() == RK_Struct;
+ }
+};
+
/// APISet holds the set of API records collected from given inputs.
class APISet {
public:
@@ -242,6 +274,21 @@
DeclarationFragments Declaration,
DeclarationFragments SubHeading);
+ /// Create and add a struct field record into the API set.
+ StructFieldRecord *addStructField(StructRecord *Struct, StringRef Name,
+ StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading);
+
+ /// Create and add a struct record into the API set.
+ StructRecord *addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
+ const AvailabilityInfo &Availability,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading);
+
/// A map to store the set of GlobalRecord%s with the declaration name as the
/// key.
using GlobalRecordMap =
@@ -252,6 +299,11 @@
using EnumRecordMap =
llvm::MapVector<StringRef, APIRecordUniquePtr<EnumRecord>>;
+ /// A map to store the set of StructRecord%s with the declaration name as the
+ /// key.
+ using StructRecordMap =
+ llvm::MapVector<StringRef, APIRecordUniquePtr<StructRecord>>;
+
/// Get the target triple for the ExtractAPI invocation.
const llvm::Triple &getTarget() const { return Target; }
@@ -260,6 +312,7 @@
const GlobalRecordMap &getGlobals() const { return Globals; }
const EnumRecordMap &getEnums() const { return Enums; }
+ const StructRecordMap &getStructs() const { return Structs; }
/// Generate and store the USR of declaration \p D.
///
@@ -285,6 +338,7 @@
GlobalRecordMap Globals;
EnumRecordMap Enums;
+ StructRecordMap Structs;
};
} // namespace extractapi
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits