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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to