diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/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, HelpText<"Extract API information">; +def product_name_EQ: Joined<["--"], "product-name=">, Flags<[CC1Option]>, + MarshallingInfoString>; def e : JoinedOrSeparate<["-"], "e">, Flags<[LinkerInput]>, Group; def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group, Flags<[CC1Option]>, HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">, diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ b/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; }; diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/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 diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/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> PluginArgs; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/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(JA) || isa(JA)) && "Invalid action for clang tool."); diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -183,8 +183,9 @@ class ExtractAPIConsumer : public ASTConsumer { public: - ExtractAPIConsumer(ASTContext &Context, std::unique_ptr OS) - : Visitor(Context), OS(std::move(OS)) {} + ExtractAPIConsumer(ASTContext &Context, StringRef ProductName, + std::unique_ptr 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 OS; }; @@ -209,8 +211,9 @@ std::unique_ptr OS = CreateOutputFile(CI, InFile); if (!OS) return nullptr; - return std::make_unique(CI.getASTContext(), - std::move(OS)); + return std::make_unique( + CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName, + std::move(OS)); } std::unique_ptr diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/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; } diff --git a/clang/test/ExtractAPI/global_record.c b/clang/test/ExtractAPI/global_record.c --- a/clang/test/ExtractAPI/global_record.c +++ b/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": {