dang updated this revision to Diff 417570.
dang added a comment.

Missed some stuff in the previous rebase.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122141/new/

https://reviews.llvm.org/D122141

Files:
  clang/include/clang/Driver/Options.td
  clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
  clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
  clang/include/clang/Frontend/FrontendOptions.h
  clang/include/clang/SymbolGraph/Serialization.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
  clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
  clang/lib/SymbolGraph/Serialization.cpp
  clang/test/ExtractAPI/global_record.c

Index: clang/test/ExtractAPI/global_record.c
===================================================================
--- clang/test/ExtractAPI/global_record.c
+++ clang/test/ExtractAPI/global_record.c
@@ -2,7 +2,7 @@
 // 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: %clang -extract-api --product-name=GlobalRecord -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.
@@ -37,7 +37,7 @@
     "generator": "?"
   },
   "module": {
-    "name": "",
+    "name": "GlobalRecord",
     "platform": {
       "architecture": "arm64",
       "operatingSystem": {
Index: clang/lib/SymbolGraph/Serialization.cpp
===================================================================
--- /dev/null
+++ clang/lib/SymbolGraph/Serialization.cpp
@@ -0,0 +1,331 @@
+//===- SymbolGraph/Serialization.cpp ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the SymbolGraph serializer and parser.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/SymbolGraph/Serialization.h"
+#include "clang/Basic/Version.h"
+#include "clang/SymbolGraph/API.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::symbolgraph;
+using namespace llvm;
+using namespace llvm::json;
+
+namespace {
+
+static void serializeObject(Object &Paren, StringRef Key,
+                            Optional<Object> Obj) {
+  if (Obj)
+    Paren[Key] = std::move(Obj.getValue());
+}
+
+static void serializeArray(Object &Paren, StringRef Key,
+                           Optional<Array> Array) {
+  if (Array)
+    Paren[Key] = std::move(Array.getValue());
+}
+
+// SymbolGraph: SemanticVersion
+static Optional<Object> serializeSemanticVersion(const VersionTuple &V) {
+  if (V.empty())
+    return None;
+
+  Object Version;
+  Version["major"] = V.getMajor();
+  Version["minor"] = V.getMinor().getValueOr(0);
+  Version["patch"] = V.getSubminor().getValueOr(0);
+  return Version;
+}
+
+static Object serializeOperatingSystem(const Triple &T) {
+  Object OS;
+  OS["name"] = T.getOSTypeName(T.getOS());
+  serializeObject(OS, "minimumVersion",
+                  serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
+  return OS;
+}
+
+// SymbolGraph: Platform
+static Object serializePlatform(const Triple &T) {
+  Object Platform;
+  Platform["architecture"] = T.getArchName();
+  Platform["vendor"] = T.getVendorName();
+  Platform["operatingSystem"] = serializeOperatingSystem(T);
+  return Platform;
+}
+
+// SymbolGraph: SourcePosition
+static Object serializeSourcePosition(const PresumedLoc &Loc,
+                                      bool IncludeFileURI = false) {
+  assert(Loc.isValid() && "invalid source position");
+
+  Object SourcePosition;
+  SourcePosition["line"] = Loc.getLine();
+  SourcePosition["character"] = Loc.getColumn();
+
+  if (IncludeFileURI) {
+    std::string FileURI = "file://";
+    FileURI += sys::path::convert_to_slash(Loc.getFilename());
+    SourcePosition["uri"] = FileURI;
+  }
+
+  return SourcePosition;
+}
+
+// SymbolGraph: SourceRange
+static Object serializeSourceRange(const PresumedLoc &BeginLoc,
+                                   const PresumedLoc &EndLoc) {
+  Object SourceRange;
+  serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
+  serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
+  return SourceRange;
+}
+
+// SymbolGraph: AvailabilityItem
+static Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
+  if (Avail.isDefault())
+    return None;
+
+  Object Availbility;
+  serializeObject(Availbility, "introducedVersion",
+                  serializeSemanticVersion(Avail.Introduced));
+  serializeObject(Availbility, "deprecatedVersion",
+                  serializeSemanticVersion(Avail.Deprecated));
+  serializeObject(Availbility, "obsoletedVersion",
+                  serializeSemanticVersion(Avail.Obsoleted));
+  if (Avail.isUnavailable())
+    Availbility["isUnconditionallyUnavailable"] = true;
+  if (Avail.isUnconditionallyDeprecated())
+    Availbility["isUnconditionallyDeprecated"] = true;
+
+  return Availbility;
+}
+
+static StringRef getLanguageName(const LangOptions &LangOpts) {
+  auto Language =
+      LangStandard::getLangStandardForKind(LangOpts.LangStd).getLanguage();
+  switch (Language) {
+  case Language::C:
+    return "c";
+  case Language::ObjC:
+    return "objc";
+
+  // Unsupported language currently
+  case Language::CXX:
+  case Language::ObjCXX:
+  case Language::OpenCL:
+  case Language::OpenCLCXX:
+  case Language::CUDA:
+  case Language::RenderScript:
+  case Language::HIP:
+
+  // Languages that the frontend cannot parse and compile
+  case Language::Unknown:
+  case Language::Asm:
+  case Language::LLVM_IR:
+    llvm_unreachable("Unsupported language kind");
+  }
+
+  llvm_unreachable("Unhandled language kind");
+}
+
+// SymbolGraph: Symbol::identifier
+static Object serializeIdentifier(const APIRecord &Record,
+                                  const LangOptions &LangOpts) {
+  Object Identifier;
+  Identifier["precise"] = Record.USR;
+  Identifier["interfaceLanguage"] = getLanguageName(LangOpts);
+
+  return Identifier;
+}
+
+// SymbolGraph: DocComment
+static Optional<Object> serializeDocComment(const DocComment &Comment) {
+  if (Comment.empty())
+    return None;
+
+  Object DocComment;
+  Array LinesArray;
+  for (const auto &CommentLine : Comment) {
+    Object Line;
+    Line["text"] = CommentLine.Text;
+    serializeObject(Line, "range",
+                    serializeSourceRange(CommentLine.Begin, CommentLine.End));
+    LinesArray.emplace_back(std::move(Line));
+  }
+  serializeArray(DocComment, "lines", LinesArray);
+
+  return DocComment;
+}
+
+static Optional<Array>
+serializeDeclarationFragments(const DeclarationFragments &DF) {
+  if (DF.getFragments().empty())
+    return None;
+
+  Array Fragments;
+  for (const auto &F : DF.getFragments()) {
+    Object Fragment;
+    Fragment["spelling"] = F.Spelling;
+    Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
+    if (!F.PreciseIdentifier.empty())
+      Fragment["preciseIdentifier"] = F.PreciseIdentifier;
+    Fragments.emplace_back(std::move(Fragment));
+  }
+
+  return Fragments;
+}
+
+static Optional<Object>
+serializeFunctionSignature(const FunctionSignature &FS) {
+  if (FS.empty())
+    return None;
+
+  Object Signature;
+  serializeArray(Signature, "returns",
+                 serializeDeclarationFragments(FS.getReturnType()));
+
+  Array Parameters;
+  for (const auto &P : FS.getParameters()) {
+    Object Parameter;
+    Parameter["name"] = P.Name;
+    serializeArray(Parameter, "declarationFragments",
+                   serializeDeclarationFragments(P.Fragments));
+    Parameters.emplace_back(std::move(Parameter));
+  }
+
+  if (!Parameters.empty())
+    Signature["parameters"] = std::move(Parameters);
+
+  return Signature;
+}
+
+static Object serializeNames(const APIRecord &Record) {
+  Object Names;
+  Names["title"] = Record.Name;
+  serializeArray(Names, "subHeading",
+                 serializeDeclarationFragments(Record.SubHeading));
+
+  return Names;
+}
+
+// SymbolGraph: Symbol::kind
+static Object serializeSymbolKind(const APIRecord &Record,
+                                  const LangOptions &LangOpts) {
+  Object Kind;
+  switch (Record.getKind()) {
+  case APIRecord::RK_Global:
+    auto *GR = dyn_cast<GlobalRecord>(&Record);
+    switch (GR->GlobalKind) {
+    case GVKind::Function:
+      Kind["identifier"] = (getLanguageName(LangOpts) + ".func").str();
+      Kind["displayName"] = "Function";
+      break;
+    case GVKind::Variable:
+      Kind["identifier"] = (getLanguageName(LangOpts) + ".var").str();
+      Kind["displayName"] = "Global Variable";
+      break;
+    case GVKind::Unknown:
+      // Unknown global kind
+      break;
+    }
+    break;
+  }
+
+  return Kind;
+}
+
+} // namespace
+
+const VersionTuple Serializer::FormatVersion{0, 5, 3};
+
+Object Serializer::serializeMetadata() const {
+  Object Metadata;
+  serializeObject(Metadata, "formatVersion",
+                  serializeSemanticVersion(FormatVersion));
+  Metadata["generator"] = clang::getClangFullVersion();
+  return Metadata;
+}
+
+Object Serializer::serializeModule() const {
+  Object Module;
+  Module["name"] = ProductName;
+  serializeObject(Module, "platform", serializePlatform(API.getTarget()));
+  return Module;
+}
+
+bool Serializer::shouldSkip(const APIRecord &Record) const {
+  // Skip unconditionally unavailable symbols
+  if (Record.Availability.isUnconditionallyUnavailable())
+    return true;
+
+  return false;
+}
+
+Optional<Object> Serializer::serializeAPIRecord(const APIRecord &Record) const {
+  if (shouldSkip(Record))
+    return None;
+
+  Object Obj;
+  serializeObject(Obj, "identifier",
+                  serializeIdentifier(Record, API.getLangOpts()));
+  serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLangOpts()));
+  serializeObject(Obj, "names", serializeNames(Record));
+  serializeObject(
+      Obj, "location",
+      serializeSourcePosition(Record.Location, /*IncludeFileURI=*/true));
+  serializeObject(Obj, "availbility",
+                  serializeAvailability(Record.Availability));
+  serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
+  serializeArray(Obj, "declarationFragments",
+                 serializeDeclarationFragments(Record.Declaration));
+
+  return Obj;
+}
+
+void Serializer::serializeGlobalRecord(const GlobalRecord &Record) {
+  auto Obj = serializeAPIRecord(Record);
+  if (!Obj)
+    return;
+
+  if (Record.GlobalKind == GVKind::Function)
+    serializeObject(*Obj, "parameters",
+                    serializeFunctionSignature(Record.Signature));
+
+  Symbols.emplace_back(std::move(*Obj));
+}
+
+Object Serializer::serialize() {
+  Object Root;
+  serializeObject(Root, "metadata", serializeMetadata());
+  serializeObject(Root, "module", serializeModule());
+
+  for (const auto &Global : API.getGlobals())
+    serializeGlobalRecord(*Global.second);
+
+  Root["symbols"] = std::move(Symbols);
+  Root["relationhips"] = std::move(Relationships);
+
+  return Root;
+}
+
+void Serializer::serialize(raw_ostream &os) {
+  Object root = serialize();
+  if (Options.Compact)
+    os << formatv("{0}", Value(std::move(root))) << "\n";
+  else
+    os << formatv("{0:2}", Value(std::move(root))) << "\n";
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -376,10 +376,9 @@
 
 Object SymbolGraphSerializer::serializeModule() const {
   Object Module;
-  // FIXME: We might not be building a module, some Clang-based languages might
-  // not have a "module" concept. Figure out a way to provide a name to
-  // describe the API set.
-  Module["name"] = "";
+  // The user is expected to always pass `--product-name=` on the command line
+  // to populate this field.
+  Module["name"] = ProductName;
   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
   return Module;
 }
Index: clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
===================================================================
--- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -183,8 +183,9 @@
 
 class ExtractAPIConsumer : public ASTConsumer {
 public:
-  ExtractAPIConsumer(ASTContext &Context, std::unique_ptr<raw_pwrite_stream> OS)
-      : Visitor(Context), OS(std::move(OS)) {}
+  ExtractAPIConsumer(ASTContext &Context, StringRef ProductName,
+                     std::unique_ptr<raw_pwrite_stream> OS)
+      : Visitor(Context), ProductName(ProductName), OS(std::move(OS)) {}
 
   void HandleTranslationUnit(ASTContext &Context) override {
     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
@@ -193,12 +194,13 @@
     // Setup a SymbolGraphSerializer to write out collected API information in
     // the Symbol Graph format.
     // FIXME: Make the kind of APISerializer configurable.
-    SymbolGraphSerializer SGSerializer(Visitor.getAPI());
+    SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName);
     SGSerializer.serialize(*OS);
   }
 
 private:
   ExtractAPIVisitor Visitor;
+  std::string ProductName;
   std::unique_ptr<raw_pwrite_stream> OS;
 };
 
@@ -209,8 +211,9 @@
   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
   if (!OS)
     return nullptr;
-  return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
-                                              std::move(OS));
+  return std::make_unique<ExtractAPIConsumer>(
+      CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName,
+      std::move(OS));
 }
 
 std::unique_ptr<raw_pwrite_stream>
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -4641,6 +4641,8 @@
     assert(JA.getType() == types::TY_API_INFO &&
            "Extract API actions must generate a API information.");
     CmdArgs.push_back("-extract-api");
+    if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ))
+      ProductNameArg->render(Args, CmdArgs);
   } else {
     assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
            "Invalid action for clang tool.");
Index: clang/include/clang/SymbolGraph/Serialization.h
===================================================================
--- /dev/null
+++ clang/include/clang/SymbolGraph/Serialization.h
@@ -0,0 +1,60 @@
+//===- SymbolGraph/Serialization.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the SymbolGraph serializer and parser.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SYMBOLGRAPH_SERIALIZATION_H
+#define LLVM_CLANG_SYMBOLGRAPH_SERIALIZATION_H
+
+#include "clang/SymbolGraph/API.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace symbolgraph {
+
+using namespace llvm::json;
+
+struct SerializerOption {
+  bool Compact;
+};
+
+class Serializer {
+public:
+  Serializer(const APISet &API, StringRef ProductName,
+             SerializerOption Options = {})
+      : API(API), ProductName(ProductName), Options(Options) {}
+
+  Object serialize();
+  void serialize(raw_ostream &os);
+
+private:
+  Object serializeMetadata() const;
+  Object serializeModule() const;
+  Optional<Object> serializeAPIRecord(const APIRecord &Record) const;
+  void serializeGlobalRecord(const GlobalRecord &Record);
+
+  bool shouldSkip(const APIRecord &Record) const;
+
+  const APISet &API;
+  StringRef ProductName;
+  SerializerOption Options;
+  Array Symbols;
+  Array Relationships;
+
+  static const VersionTuple FormatVersion;
+};
+
+} // namespace symbolgraph
+} // namespace clang
+
+#endif // LLVM_CLANG_SYMBOLGRAPH_SERIALIZATION_H
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -410,6 +410,10 @@
   /// The name of the action to run when using a plugin action.
   std::string ActionName;
 
+  // Currently this is only used as part of the `-extract-api` action.
+  /// The name of the product the input files belong too.
+  std::string ProductName;
+
   /// Args to pass to the plugins
   std::map<std::string, std::vector<std::string>> PluginArgs;
 
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -90,8 +90,9 @@
   void serializeGlobalRecord(const GlobalRecord &Record);
 
 public:
-  SymbolGraphSerializer(const APISet &API, APISerializerOption Options = {})
-      : APISerializer(API, Options) {}
+  SymbolGraphSerializer(const APISet &API, StringRef ProductName,
+                        APISerializerOption Options = {})
+      : APISerializer(API, ProductName, Options) {}
 };
 
 } // namespace extractapi
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -34,6 +34,12 @@
 
 protected:
   const APISet &API;
+
+  /// The product name of API.
+  ///
+  /// Note: This should be used for populating metadata about the API.
+  StringRef ProductName;
+
   APISerializerOption Options;
 
 public:
@@ -44,8 +50,9 @@
   APISerializer &operator=(APISerializer &&) = delete;
 
 protected:
-  APISerializer(const APISet &API, APISerializerOption Options = {})
-      : API(API), Options(Options) {}
+  APISerializer(const APISet &API, StringRef ProductName,
+                APISerializerOption Options = {})
+      : API(API), ProductName(ProductName), Options(Options) {}
 
   virtual ~APISerializer() = default;
 };
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1091,6 +1091,8 @@
 def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
 def extract_api : Flag<["-"], "extract-api">, Flags<[CC1Option]>, Group<Action_Group>,
   HelpText<"Extract API information">;
+def product_name_EQ: Joined<["--"], "product-name=">, Flags<[CC1Option]>,
+  MarshallingInfoString<FrontendOpts<"ProductName">>;
 def e : JoinedOrSeparate<["-"], "e">, Flags<[LinkerInput]>, Group<Link_Group>;
 def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to