diff --git a/clang/include/clang/SymbolGraph/API.h b/clang/include/clang/ExtractAPI/API.h rename from clang/include/clang/SymbolGraph/API.h rename to clang/include/clang/ExtractAPI/API.h --- a/clang/include/clang/SymbolGraph/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -1,4 +1,4 @@ -//===- SymbolGraph/API.h ----------------------------------------*- C++ -*-===// +//===- ExtractAPI/API.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. @@ -7,18 +7,20 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines SymbolGraph API records. +/// This file defines the data representation of APIs used by ExtractAPI: +/// APIRecord and derived record structs, and the APISet class that holds the +/// records. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SYMBOLGRAPH_API_H -#define LLVM_CLANG_SYMBOLGRAPH_API_H +#ifndef LLVM_CLANG_EXTRACTAPI_API_H +#define LLVM_CLANG_EXTRACTAPI_API_H #include "clang/AST/Decl.h" #include "clang/AST/RawCommentList.h" #include "clang/Basic/SourceLocation.h" -#include "clang/SymbolGraph/AvailabilityInfo.h" -#include "clang/SymbolGraph/DeclarationFragments.h" +#include "clang/ExtractAPI/AvailabilityInfo.h" +#include "clang/ExtractAPI/DeclarationFragments.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -27,18 +29,43 @@ #include namespace clang { -namespace symbolgraph { +namespace extractapi { +/// Documentation comment is a vector of RawComment::CommentLine. +/// +/// Each line represents one line of striped documentation comment, +/// with source range information. This could simplify calculating the source +/// location of a character in the doc comment for pointing back to the source +/// file. +/// e.g. +/// \code +/// /// This is a documentation comment +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. +/// /// with multiple lines. +/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. +/// \endcode using DocComment = std::vector; +/// The base representation of an API record. Holds common symbol information. struct APIRecord { StringRef Name; StringRef USR; PresumedLoc Location; AvailabilityInfo Availability; LinkageInfo Linkage; + + /// Documentation comment lines attached to this symbol declaration. DocComment Comment; + + /// Declaration fragments of this symbol declaration. DeclarationFragments Declaration; + + /// SubHeading provides a more detailed representation than the plain + /// declaration name. + /// + /// SubHeading is an array of declaration fragments of tagged declaration + /// name, with potentially more tokens (for example the \c +/- symbol for + /// Objective-C class/instance methods). DeclarationFragments SubHeading; /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) @@ -66,14 +93,18 @@ virtual ~APIRecord() = 0; }; +/// The kind of a global record. enum class GVKind : uint8_t { Unknown = 0, Variable = 1, Function = 2, }; +/// GlobalRecord holds information of a global variable or a function. struct GlobalRecord : APIRecord { GVKind GlobalKind; + + /// The function signature of the record if it is a function. FunctionSignature Signature; GlobalRecord(GVKind Kind, StringRef Name, StringRef USR, PresumedLoc Loc, @@ -87,16 +118,15 @@ static bool classof(const APIRecord *Record) { return Record->getKind() == RK_Global; } + +private: + virtual void anchor(); }; +/// APISet holds the set of API records collected from given inputs. class APISet { public: - APISet(const llvm::Triple &Target, const LangOptions &LangOpts) - : Target(Target), LangOpts(LangOpts) {} - - const llvm::Triple &getTarget() const { return Target; } - const LangOptions &getLangOpts() const { return LangOpts; } - + /// Create and add a GlobalRecord of kind \p Kind into the API set. GlobalRecord *addGlobal(GVKind Kind, StringRef Name, StringRef USR, PresumedLoc Loc, const AvailabilityInfo &Availability, LinkageInfo Linkage, const DocComment &Comment, @@ -104,12 +134,14 @@ DeclarationFragments SubHeading, FunctionSignature Signature); + /// Create and add a global variable record into the API set. GlobalRecord *addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, const AvailabilityInfo &Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading); + /// Create and add a function record into the API set. GlobalRecord *addFunction(StringRef Name, StringRef USR, PresumedLoc Loc, const AvailabilityInfo &Availability, LinkageInfo Linkage, const DocComment &Comment, @@ -117,10 +149,6 @@ DeclarationFragments SubHeading, FunctionSignature Signature); - StringRef recordUSR(const Decl *D); - StringRef copyString(StringRef String, llvm::BumpPtrAllocator &Allocator); - StringRef copyString(StringRef String); - private: /// \brief A custom deleter used for ``std::unique_ptr`` to APIRecords stored /// in the BumpPtrAllocator. @@ -138,20 +166,50 @@ using APIRecordUniquePtr = std::unique_ptr>; + /// A map to store the set of GlobalRecords with the declaration name as the + /// key. using GlobalRecordMap = llvm::MapVector>; + /// Get the target triple for the ExtractAPI invocation. + const llvm::Triple &getTarget() const { return Target; } + + /// Get the language options used to parse the APIs. + const LangOptions &getLangOpts() const { return LangOpts; } + const GlobalRecordMap &getGlobals() const { return Globals; } + /// Generate and store the USR of declaration \p D. + /// + /// Note: The USR string is stored in and owned by Allocator. + /// + /// \returns a StringRef of the generated USR string. + StringRef recordUSR(const Decl *D); + + /// Copy \p String into \p Allocator to keep it alive. + /// + /// \returns a StringRef of the copied string in the \p Allocator. + StringRef copyString(StringRef String, llvm::BumpPtrAllocator &Allocator); + + /// Copy \p String into the Allocator in this APISet. + /// + /// \returns a StringRef of the copied string in the Allocator. + StringRef copyString(StringRef String); + + APISet(const llvm::Triple &Target, const LangOptions &LangOpts) + : Target(Target), LangOpts(LangOpts) {} + private: + /// BumpPtrAllocator to store APIRecords and generated/copied strings. llvm::BumpPtrAllocator Allocator; + const llvm::Triple Target; const LangOptions LangOpts; GlobalRecordMap Globals; }; -} // namespace symbolgraph +} // namespace extractapi } // namespace clang -#endif // LLVM_CLANG_SYMBOLGRAPH_API_H +#endif // LLVM_CLANG_EXTRACTAPI_API_H diff --git a/clang/include/clang/SymbolGraph/AvailabilityInfo.h b/clang/include/clang/ExtractAPI/AvailabilityInfo.h rename from clang/include/clang/SymbolGraph/AvailabilityInfo.h rename to clang/include/clang/ExtractAPI/AvailabilityInfo.h --- a/clang/include/clang/SymbolGraph/AvailabilityInfo.h +++ b/clang/include/clang/ExtractAPI/AvailabilityInfo.h @@ -1,4 +1,4 @@ -//===- SymbolGraph/AvailabilityInfo.h - Availability Info -------*- C++ -*-===// +//===- ExtractAPI/AvailabilityInfo.h - Availability Info --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines the Availability Info for a declaration. +/// This file defines the AvailabilityInfo struct that collects availability +/// attributes of a symbol. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SYMBOLGRAPH_AVAILABILITY_INFO_H -#define LLVM_CLANG_SYMBOLGRAPH_AVAILABILITY_INFO_H +#ifndef LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H +#define LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H #include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" @@ -21,8 +22,9 @@ using llvm::VersionTuple; namespace clang { -namespace symbolgraph { +namespace extractapi { +/// Stores availability attributes of a symbol. struct AvailabilityInfo { VersionTuple Introduced; VersionTuple Deprecated; @@ -31,21 +33,31 @@ bool UnconditionallyDeprecated{false}; bool UnconditionallyUnavailable{false}; - explicit AvailabilityInfo(bool Unavailable = false) - : Unavailable(Unavailable) {} - - AvailabilityInfo(VersionTuple I, VersionTuple D, VersionTuple O, bool U, - bool UD, bool UU) - : Introduced(I), Deprecated(D), Obsoleted(O), Unavailable(U), - UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {} - + /// Determine if this AvailabilityInfo represents the default availability. bool isDefault() const { return *this == AvailabilityInfo(); } + + /// Check if the symbol is unavailable. bool isUnavailable() const { return Unavailable; } + + /// Check if the symbol is unconditionally deprecated. + /// + /// i.e. \code __attribute__((deprecated)) \endcode bool isUnconditionallyDeprecated() const { return UnconditionallyDeprecated; } + + /// Check if the symbol is unconditionally unavailable. + /// + /// i.e. \code __attribute__((unavailable)) \endcode bool isUnconditionallyUnavailable() const { return UnconditionallyUnavailable; } + AvailabilityInfo() = default; + + AvailabilityInfo(VersionTuple I, VersionTuple D, VersionTuple O, bool U, + bool UD, bool UU) + : Introduced(I), Deprecated(D), Obsoleted(O), Unavailable(U), + UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {} + friend bool operator==(const AvailabilityInfo &Lhs, const AvailabilityInfo &Rhs); }; @@ -60,7 +72,7 @@ Rhs.UnconditionallyUnavailable); } -} // namespace symbolgraph +} // namespace extractapi } // namespace clang -#endif // LLVM_CLANG_SYMBOLGRAPH_AVAILABILITY_INFO_H +#endif // LLVM_CLANG_EXTRACTAPI_AVAILABILITY_INFO_H diff --git a/clang/include/clang/SymbolGraph/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h rename from clang/include/clang/SymbolGraph/DeclarationFragments.h rename to clang/include/clang/ExtractAPI/DeclarationFragments.h --- a/clang/include/clang/SymbolGraph/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -1,4 +1,4 @@ -//===- SymbolGraph/DeclarationFragments.h -----------------------*- C++ -*-===// +//===- ExtractAPI/DeclarationFragments.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. @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines SymbolGraph Declaration Fragments related classes. +/// This file defines the Declaration Fragments related classes. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SYMBOLGRAPH_DECLARATION_FRAGMENTS_H -#define LLVM_CLANG_SYMBOLGRAPH_DECLARATION_FRAGMENTS_H +#ifndef LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H +#define LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -21,29 +21,62 @@ #include namespace clang { -namespace symbolgraph { +namespace extractapi { +/// DeclarationFragments is a vector of tagged important parts of a symbol's +/// declaration. +/// +/// The fragments sequence can be joined to form spans of declaration text, with +/// attached information useful for purposes like syntax-highlighting etc. +/// For example: +/// \code +/// const -> keyword "const" +/// int -> type "int" +/// pi; -> identifier "pi" +/// \endcode class DeclarationFragments { public: DeclarationFragments() = default; + /// The kind of a fragment. enum class FragmentKind { + /// Unknown fragment kind. None, + Keyword, Attribute, NumberLiteral, StringLiteral, Identifier, + + /// Identifier that refers to a type in the context. TypeIdentifier, + + /// Parameter that's used as generics in the context. For example template + /// parameters. GenericParameter, + + /// External parameters in Objective-C methods. + /// + /// For example, \c forKey in + /// \code - (void) setValue:(Value)value forKey(Key)key \endcode ExternalParam, + + /// Internal/local parameters in Objective-C methods. + /// + /// For example, \c key in + /// \code - (void) setValue:(Value)value forKey(Key)key \endcode InternalParam, + Text, }; + /// Fragment holds information of a single fragment. struct Fragment { std::string Spelling; FragmentKind Kind; + + /// The USR of the fragment symbol, if applicable. std::string PreciseIdentifier; Fragment(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier) @@ -53,10 +86,16 @@ const std::vector &getFragments() const { return Fragments; } + /// 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. DeclarationFragments &append(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier = "") { if (Kind == FragmentKind::Text && !Fragments.empty() && Fragments.back().Kind == FragmentKind::Text) { + // If appending a text fragment, and the last fragment is also text, + // merge into the last fragment. Fragments.back().Spelling.append(Spelling.data(), Spelling.size()); } else { Fragments.emplace_back(Spelling, Kind, PreciseIdentifier); @@ -64,6 +103,13 @@ return *this; } + /// Append another DeclarationFragments to the end. + /// + /// A helper function to quicking move the fragments in another + /// DeclarationFragments and concatenate. + /// + /// \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()), @@ -72,19 +118,29 @@ return *this; } + /// Append a text Fragment of a space character. + /// + /// \returns a reference to the DeclarationFragments object itself after + /// appending to chain up consecutive appends. DeclarationFragments &appendSpace(); + /// Get the string description of a FragmentKind \p Kind. static StringRef getFragmentKindString(FragmentKind Kind); + + /// Get the corresponding FragmentKind from string \p S. static FragmentKind parseFragmentKindFromString(StringRef S); private: std::vector Fragments; }; +/// Store function signature information with DeclarationFragments of the +/// return type and parameters. class FunctionSignature { public: FunctionSignature() = default; + /// Parameter holds the name and DeclarationFragments of a single parameter. struct Parameter { std::string Name; DeclarationFragments Fragments; @@ -104,6 +160,10 @@ void setReturnType(DeclarationFragments RT) { ReturnType = RT; } + /// Determine if the FunctionSignature is empty. + /// + /// \returns true if the return type DeclarationFragments is empty and there + /// is no parameter, otherwise false. bool empty() const { return Parameters.empty() && ReturnType.getFragments().empty(); } @@ -113,28 +173,46 @@ DeclarationFragments ReturnType; }; +/// A factory class to build DeclarationFragments for different kinds of Decl. class DeclarationFragmentsBuilder { public: + /// Build DeclarationFragments for a variable declaration VarDecl. static DeclarationFragments getFragmentsForVar(const VarDecl *); + + /// Build DeclarationFragments for a function declaration FunctionDecl. static DeclarationFragments getFragmentsForFunction(const FunctionDecl *); + + /// Build sub-heading fragments for a NamedDecl. static DeclarationFragments getSubHeading(const NamedDecl *); + + /// Build FunctionSignature for a function declaration FunctionDecl. static FunctionSignature getFunctionSignature(const FunctionDecl *); private: DeclarationFragmentsBuilder() = delete; + /// Build DeclarationFragments for a QualType. static DeclarationFragments getFragmentsForType(const QualType, ASTContext &, DeclarationFragments &); + + /// Build DeclarationFragments for a Type. static DeclarationFragments getFragmentsForType(const Type *, ASTContext &, DeclarationFragments &); + + /// Build DeclarationFragments for a NestedNameSpecifier. static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *, ASTContext &, DeclarationFragments &); + + /// Build DeclarationFragments for Qualifiers. static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals); + + /// Build DeclarationFragments for a parameter variable declaration + /// ParmVarDecl. static DeclarationFragments getFragmentsForParam(const ParmVarDecl *); }; -} // namespace symbolgraph +} // namespace extractapi } // namespace clang -#endif // LLVM_CLANG_SYMBOLGRAPH_DECLARATION_FRAGMENTS_H +#endif // LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H diff --git a/clang/include/clang/SymbolGraph/FrontendActions.h b/clang/include/clang/ExtractAPI/FrontendActions.h rename from clang/include/clang/SymbolGraph/FrontendActions.h rename to clang/include/clang/ExtractAPI/FrontendActions.h --- a/clang/include/clang/SymbolGraph/FrontendActions.h +++ b/clang/include/clang/ExtractAPI/FrontendActions.h @@ -1,4 +1,4 @@ -//===- SymbolGraph/FrontendActions.h -----------------------*- C++ -*-===// +//===- ExtractAPI/FrontendActions.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. @@ -7,17 +7,18 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines SymbolGraph frontend actions. +/// This file defines the ExtractAPIAction frontend action. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SYMBOLGRAPH_FRONTEND_ACTIONS_H -#define LLVM_CLANG_SYMBOLGRAPH_FRONTEND_ACTIONS_H +#ifndef LLVM_CLANG_EXTRACTAPI_FRONTEND_ACTIONS_H +#define LLVM_CLANG_EXTRACTAPI_FRONTEND_ACTIONS_H #include "clang/Frontend/FrontendAction.h" namespace clang { +/// ExtractAPIAction sets up the output file and creates the ExtractAPIVisitor. class ExtractAPIAction : public ASTFrontendAction { protected: std::unique_ptr CreateASTConsumer(CompilerInstance &CI, @@ -30,4 +31,4 @@ } // namespace clang -#endif // LLVM_CLANG_SYMBOLGRAPH_FRONTEND_ACTIONS_H +#endif // LLVM_CLANG_EXTRACTAPI_FRONTEND_ACTIONS_H diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h @@ -0,0 +1,62 @@ +//===- ExtractAPI/Serialization/SerializerBase.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 +/// This file defines the ExtractAPI APIJSONSerializer interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H +#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H + +#include "clang/ExtractAPI/API.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace extractapi { + +using namespace llvm::json; + +/// Common options to customize the JSON serializer output. +struct APIJSONSerializerOption { + /// Do not include unnecessary whitespaces to save space. + bool Compact; +}; + +/// The base interface of JSON serializers for API information. +class APIJSONSerializer { +public: + /// Serialize the API information into a JSON object. + virtual Object serialize() = 0; + + /// Wrap \c serialize() and write out the API information to \p os. + void serialize(raw_ostream &os); + +protected: + const APISet &API; + APIJSONSerializerOption Options; + +public: + APIJSONSerializer() = delete; + APIJSONSerializer(const APIJSONSerializer &) = delete; + APIJSONSerializer(APIJSONSerializer &&) = delete; + APIJSONSerializer &operator=(const APIJSONSerializer &) = delete; + APIJSONSerializer &operator=(APIJSONSerializer &&) = delete; + +protected: + APIJSONSerializer(const APISet &API, APIJSONSerializerOption Options = {}) + : API(API), Options(Options) {} + + virtual ~APIJSONSerializer() = default; +}; + +} // namespace extractapi +} // namespace clang + +#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -0,0 +1,96 @@ +//===- ExtractAPI/Serialization/SymbolGraphSerializer.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 +/// This file defines the SymbolGraphSerializer class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H +#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H + +#include "clang/ExtractAPI/API.h" +#include "clang/ExtractAPI/Serialization/SerializerBase.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace extractapi { + +using namespace llvm::json; + +/// The serializer that organizes API information in the Symbol Graph format. +/// +/// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit) +/// models an API set as a directed graph, where nodes are symbol declarations, +/// and edges are relationships between the connected symbols. +class SymbolGraphSerializer : public APIJSONSerializer { + virtual void anchor(); + + /// A JSON array of formatted symbols in \c APISet. + Array Symbols; + + /// A JSON array of formatted symbol relationships in \c APISet. + Array Relationships; + + /// The Symbol Graph format version used by this serializer. + static const VersionTuple FormatVersion; + +public: + /// Bring in the \c serialize(raw_ostream &) helper method from base. + using APIJSONSerializer::serialize; + + /// Serialize the APIs in \c APISet in the Symbol Graph format. + /// + /// \returns a JSON object that contains the root of the formatted + /// Symbol Graph. + Object serialize() override; + +private: + /// Synthesize the metadata section of the Symbol Graph format. + /// + /// The metadata section describes information about the Symbol Graph itself, + /// including the format version and the generator information. + Object serializeMetadata() const; + + /// Synthesize the module section of the Symbol Graph format. + /// + /// The module section contains information about the product that is defined + /// by the given API set. + /// Note that "module" here is not to be confused with the Clang/C++ module + /// concept. + Object serializeModule() const; + + /// Determine if the given \p Record should be skipped during serialization. + bool shouldSkip(const APIRecord &Record) const; + + /// Format the common API information for \p Record. + /// + /// This handles the shared information of all kinds of API records, + /// for example identifier and source location. The resulting object is then + /// augmented with kind-specific symbol information by the caller. + /// This method also checks if the given \p Record should be skipped during + /// serialization. + /// + /// \returns \c None if this \p Record should be skipped, or a JSON object + /// containing common symbol information of \p Record. + Optional serializeAPIRecord(const APIRecord &Record) const; + + /// Serialize a global record. + void serializeGlobalRecord(const GlobalRecord &Record); + +public: + SymbolGraphSerializer(const APISet &API, APIJSONSerializerOption Options = {}) + : APIJSONSerializer(API, Options) {} +}; + +} // namespace extractapi +} // namespace clang + +#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H diff --git a/clang/include/clang/SymbolGraph/Serialization.h b/clang/include/clang/SymbolGraph/Serialization.h deleted file mode 100644 --- a/clang/include/clang/SymbolGraph/Serialization.h +++ /dev/null @@ -1,58 +0,0 @@ -//===- 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, SerializerOption Options = {}) - : API(API), Options(Options) {} - - Object serialize(); - void serialize(raw_ostream &os); - -private: - Object serializeMetadata() const; - Object serializeModule() const; - Optional serializeAPIRecord(const APIRecord &Record) const; - void serializeGlobalRecord(const GlobalRecord &Record); - - bool shouldSkip(const APIRecord &Record) const; - - const APISet &API; - SerializerOption Options; - Array Symbols; - Array Relationships; - - static const VersionTuple FormatVersion; -}; - -} // namespace symbolgraph -} // namespace clang - -#endif // LLVM_CLANG_SYMBOLGRAPH_SERIALIZATION_H diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(CodeGen) add_subdirectory(Analysis) add_subdirectory(Edit) +add_subdirectory(ExtractAPI) add_subdirectory(Rewrite) if(CLANG_ENABLE_ARCMT) add_subdirectory(ARCMigrate) @@ -23,7 +24,6 @@ add_subdirectory(Index) add_subdirectory(IndexSerialization) add_subdirectory(StaticAnalyzer) -add_subdirectory(SymbolGraph) add_subdirectory(Format) add_subdirectory(Testing) add_subdirectory(Interpreter) diff --git a/clang/lib/SymbolGraph/API.cpp b/clang/lib/ExtractAPI/API.cpp rename from clang/lib/SymbolGraph/API.cpp rename to clang/lib/ExtractAPI/API.cpp --- a/clang/lib/SymbolGraph/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -1,4 +1,4 @@ -//===- SymbolGraph/API.cpp --------------------------------------*- C++ -*-===// +//===- ExtractAPI/API.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. @@ -7,21 +7,20 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines SymbolGraph API records. +/// This file implements the APIRecord and derived record structs, +/// and the APISet class. /// //===----------------------------------------------------------------------===// -#include "clang/SymbolGraph/API.h" +#include "clang/ExtractAPI/API.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/CommentLexer.h" #include "clang/AST/RawCommentList.h" #include "clang/Index/USRGeneration.h" #include "llvm/Support/Allocator.h" -namespace clang { -namespace symbolgraph { - -APIRecord::~APIRecord() {} +using namespace clang::extractapi; +using namespace llvm; GlobalRecord *APISet::addGlobal(GVKind Kind, StringRef Name, StringRef USR, PresumedLoc Loc, @@ -32,6 +31,7 @@ FunctionSignature Signature) { auto Result = Globals.insert({Name, nullptr}); if (Result.second) { + // Create the record if not already exist. auto Record = APIRecordUniquePtr(new (Allocator) GlobalRecord{ Kind, Name, USR, Loc, Availability, Linkage, Comment, Fragments, SubHeading, Signature}); @@ -70,6 +70,7 @@ if (String.empty()) return {}; + // No need to allocate memory and copy if the string has already been stored. if (Allocator.identifyObject(String.data())) return String; @@ -82,5 +83,6 @@ return copyString(String, Allocator); } -} // namespace symbolgraph -} // namespace clang +APIRecord::~APIRecord() {} + +void GlobalRecord::anchor() {} diff --git a/clang/lib/SymbolGraph/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt rename from clang/lib/SymbolGraph/CMakeLists.txt rename to clang/lib/ExtractAPI/CMakeLists.txt --- a/clang/lib/SymbolGraph/CMakeLists.txt +++ b/clang/lib/ExtractAPI/CMakeLists.txt @@ -2,11 +2,12 @@ Support ) -add_clang_library(clangSymbolGraph +add_clang_library(clangExtractAPI API.cpp ExtractAPIConsumer.cpp DeclarationFragments.cpp - Serialization.cpp + Serialization/SerializerBase.cpp + Serialization/SymbolGraphSerializer.cpp LINK_LIBS clangAST diff --git a/clang/lib/SymbolGraph/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp rename from clang/lib/SymbolGraph/DeclarationFragments.cpp rename to clang/lib/ExtractAPI/DeclarationFragments.cpp --- a/clang/lib/SymbolGraph/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -1,4 +1,4 @@ -//===- SymbolGraph/DeclarationFragments.cpp ---------------------*- C++ -*-===// +//===- ExtractAPI/DeclarationFragments.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. @@ -7,22 +7,24 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines SymbolGraph Declaration Fragments related classes. +/// This file implements Declaration Fragments related classes. /// //===----------------------------------------------------------------------===// -#include "clang/SymbolGraph/DeclarationFragments.h" +#include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringSwitch.h" -namespace clang { -namespace symbolgraph { +using namespace clang::extractapi; +using namespace llvm; DeclarationFragments &DeclarationFragments::appendSpace() { if (!Fragments.empty()) { Fragment Last = Fragments.back(); if (Last.Kind == FragmentKind::Text) { - if (Last.Spelling.back() != ' ') { + // Merge the extra space into the last fragment if the last fragment is + // also text. + if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. Last.Spelling.push_back(' '); } } else { @@ -429,6 +431,3 @@ DeclarationFragments::FragmentKind::Identifier); return Fragments; } - -} // namespace symbolgraph -} // namespace clang diff --git a/clang/lib/SymbolGraph/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp rename from clang/lib/SymbolGraph/ExtractAPIConsumer.cpp rename to clang/lib/ExtractAPI/ExtractAPIConsumer.cpp --- a/clang/lib/SymbolGraph/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -1,4 +1,4 @@ -//===- ExtractAPIConsumer.cpp -----------------------------------*- C++ -*-===// +//===- ExtractAPI/ExtractAPIConsumer.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. @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines the ExtractAPI AST visitor to collect API information. +/// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to +/// collect API information. /// //===----------------------------------------------------------------------===// -// #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -20,19 +20,22 @@ #include "clang/AST/RawCommentList.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/TargetInfo.h" +#include "clang/ExtractAPI/API.h" +#include "clang/ExtractAPI/AvailabilityInfo.h" +#include "clang/ExtractAPI/DeclarationFragments.h" +#include "clang/ExtractAPI/FrontendActions.h" +#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/SymbolGraph/API.h" -#include "clang/SymbolGraph/AvailabilityInfo.h" -#include "clang/SymbolGraph/DeclarationFragments.h" -#include "clang/SymbolGraph/FrontendActions.h" -#include "clang/SymbolGraph/Serialization.h" #include "llvm/Support/raw_ostream.h" using namespace clang; -using namespace symbolgraph; +using namespace extractapi; namespace { + +/// The RecursiveASTVisitor to traverse symbol declarations and collect API +/// information. class ExtractAPIVisitor : public RecursiveASTVisitor { public: explicit ExtractAPIVisitor(ASTContext &Context) @@ -59,6 +62,7 @@ Decl->getTemplateSpecializationKind() == TSK_Undeclared) return true; + // Collect symbol information. StringRef Name = Decl->getName(); StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = @@ -69,11 +73,14 @@ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the variable. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForVar(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); + // Add the global variable record to the API set. API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, Declaration, SubHeading); return true; @@ -112,6 +119,7 @@ return true; } + // Collect symbol information. StringRef Name = Decl->getName(); StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = @@ -122,6 +130,8 @@ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) Comment = RawComment->getFormattedLines(Context.getSourceManager(), Context.getDiagnostics()); + + // Build declaration fragments, sub-heading, and signature of the function. DeclarationFragments Declaration = DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); DeclarationFragments SubHeading = @@ -129,16 +139,19 @@ FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); + // Add the function record to the API set. API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, SubHeading, Signature); return true; } private: + /// Get availability information of the declaration \p D. AvailabilityInfo getAvailability(const Decl *D) const { StringRef PlatformName = Context.getTargetInfo().getPlatformName(); AvailabilityInfo Availability; + // Collect availability attributes from all redeclarations. for (const auto *RD : D->redecls()) { for (const auto *A : RD->specific_attrs()) { if (A->getPlatform()->getName() != PlatformName) @@ -174,15 +187,20 @@ : Visitor(Context), OS(std::move(OS)) {} void HandleTranslationUnit(ASTContext &Context) override { + // Use ExtractAPIVisitor to traverse symbol declarations in the context. Visitor.TraverseDecl(Context.getTranslationUnitDecl()); - Serializer Serializer(Visitor.getAPI()); - Serializer.serialize(*OS); + + // Setup a SymbolGraphSerializer to write out collected API information in + // the Symbol Graph format. + SymbolGraphSerializer SGSerializer(Visitor.getAPI()); + SGSerializer.serialize(*OS); } private: ExtractAPIVisitor Visitor; std::unique_ptr OS; }; + } // namespace std::unique_ptr diff --git a/clang/lib/ExtractAPI/Serialization/SerializerBase.cpp b/clang/lib/ExtractAPI/Serialization/SerializerBase.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/ExtractAPI/Serialization/SerializerBase.cpp @@ -0,0 +1,26 @@ +//===- ExtractAPI/Serialization/SerializerBase.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 +/// This file implements the APIJSONSerializer interface. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ExtractAPI/Serialization/SerializerBase.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::extractapi; + +void APIJSONSerializer::serialize(llvm::raw_ostream &os) { + llvm::json::Object root = serialize(); + if (Options.Compact) + os << llvm::formatv("{0}", Value(std::move(root))) << "\n"; + else + os << llvm::formatv("{0:2}", Value(std::move(root))) << "\n"; +} diff --git a/clang/lib/SymbolGraph/Serialization.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp rename from clang/lib/SymbolGraph/Serialization.cpp rename to clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp --- a/clang/lib/SymbolGraph/Serialization.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -1,4 +1,4 @@ -//===- SymbolGraph/Serialization.cpp ----------------------------*- C++ -*-===// +//===- ExtractAPI/Serialization/SymbolGraphSerializer.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. @@ -7,38 +7,56 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Defines the SymbolGraph serializer and parser. +/// This file implements the SymbolGraphSerializer. /// //===----------------------------------------------------------------------===// -#include "clang/SymbolGraph/Serialization.h" +#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Basic/Version.h" -#include "clang/SymbolGraph/API.h" +#include "clang/ExtractAPI/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 clang::extractapi; using namespace llvm; using namespace llvm::json; -namespace { +namespace { // Helper functions. +/// Helper function to inject a JSON object \p Obj into another object \p Paren +/// at position \p Key. static void serializeObject(Object &Paren, StringRef Key, Optional Obj) { if (Obj) Paren[Key] = std::move(Obj.getValue()); } +/// Helper function to inject a JSON array \p Array into object \p Paren at +/// position \p Key. static void serializeArray(Object &Paren, StringRef Key, Optional Array) { if (Array) Paren[Key] = std::move(Array.getValue()); } -// SymbolGraph: SemanticVersion +/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version +/// format. +/// +/// A semantic version object contains three numeric fields, representing the +/// \c major, \c minor, and \c patch parts of the version tuple. +/// For example version tuple 1.0.3 is serialized as: +/// \code +/// { +/// "major" : 1, +/// "minor" : 0, +/// "patch" : 3 +/// } +/// \endcode +/// +/// \returns \c None if the version \p V is empty, or an \c Object containing +/// the semantic version representation of \p V. static Optional serializeSemanticVersion(const VersionTuple &V) { if (V.empty()) return None; @@ -50,6 +68,10 @@ return Version; } +/// Serialize the OS information in the Symbol Graph platform property. +/// +/// The OS information in Symbol Graph contains the \c name of the OS, and an +/// optional \c minimumVersion semantic version field. static Object serializeOperatingSystem(const Triple &T) { Object OS; OS["name"] = T.getOSTypeName(T.getOS()); @@ -58,7 +80,10 @@ return OS; } -// SymbolGraph: Platform +/// Serialize the platform information in the Symbol Graph module section. +/// +/// The platform object describes a target platform triple in corresponding +/// three fields: \c architecture, \c vendor, and \c operatingSystem. static Object serializePlatform(const Triple &T) { Object Platform; Platform["architecture"] = T.getArchName(); @@ -67,7 +92,11 @@ return Platform; } -// SymbolGraph: SourcePosition +/// Serialize a source location in file. +/// +/// \param Loc The presumed location to serialize. +/// \param IncludeFileURI If true, include the file path of \p Loc as a URI. +/// Defaults to false. static Object serializeSourcePosition(const PresumedLoc &Loc, bool IncludeFileURI = false) { assert(Loc.isValid() && "invalid source position"); @@ -78,6 +107,7 @@ if (IncludeFileURI) { std::string FileURI = "file://"; + // Normalize file path to use forward slashes for the URI. FileURI += sys::path::convert_to_slash(Loc.getFilename()); SourcePosition["uri"] = FileURI; } @@ -85,7 +115,7 @@ return SourcePosition; } -// SymbolGraph: SourceRange +/// Serialize a source range with begin and end locations. static Object serializeSourceRange(const PresumedLoc &BeginLoc, const PresumedLoc &EndLoc) { Object SourceRange; @@ -94,7 +124,16 @@ return SourceRange; } -// SymbolGraph: AvailabilityItem +/// Serialize the availability attributes of a symbol. +/// +/// Availability information contains the introduced, deprecated, and obsoleted +/// versions of the symbol as semantic versions, if not default. +/// Availability information also contains flags to indicate if the symbol is +/// unconditionally unavailable or deprecated, +/// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). +/// +/// \returns \c None if the symbol has default availability attributes, or +/// an \c Object containing the formatted availability information. static Optional serializeAvailability(const AvailabilityInfo &Avail) { if (Avail.isDefault()) return None; @@ -114,6 +153,7 @@ return Availbility; } +/// Get the short language name string for interface language references. static StringRef getLanguageName(const LangOptions &LangOpts) { auto Language = LangStandard::getLangStandardForKind(LangOpts.LangStd).getLanguage(); @@ -142,7 +182,10 @@ llvm_unreachable("Unhandled language kind"); } -// SymbolGraph: Symbol::identifier +/// Serialize the identifier object as specified by the Symbol Graph format. +/// +/// The identifier property of a symbol contains the USR for precise and unique +/// references, and the interface language name. static Object serializeIdentifier(const APIRecord &Record, const LangOptions &LangOpts) { Object Identifier; @@ -152,7 +195,22 @@ return Identifier; } -// SymbolGraph: DocComment +/// Serialize the documentation comments attached to a symbol, as specified by +/// the Symbol Graph format. +/// +/// The Symbol Graph \c docComment object contains an array of lines. Each line +/// represents one line of striped documentation comment, with source range +/// information. +/// e.g. +/// \code +/// /// This is a documentation comment +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. +/// /// with multiple lines. +/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. +/// \endcode +/// +/// \returns \c None if \p Comment is empty, or an \c Object containing the +/// formatted lines. static Optional serializeDocComment(const DocComment &Comment) { if (Comment.empty()) return None; @@ -171,6 +229,40 @@ return DocComment; } +/// Serialize the declaration fragments of a symbol. +/// +/// The Symbol Graph declaration fragments is an array of tagged important +/// parts of a symbol's declaration. The fragments sequence can be joined to +/// form spans of declaration text, with attached information useful for +/// purposes like syntax-highlighting etc. For example: +/// \code +/// const int pi; -> "declarationFragments" : [ +/// { +/// "kind" : "keyword", +/// "spelling" : "const" +/// }, +/// { +/// "kind" : "text", +/// "spelling" : " " +/// }, +/// { +/// "kind" : "typeIdentifier", +/// "preciseIdentifier" : "c:I", +/// "spelling" : "int" +/// }, +/// { +/// "kind" : "text", +/// "spelling" : " " +/// }, +/// { +/// "kind" : "identifier", +/// "spelling" : "pi" +/// } +/// ] +/// \endcode +/// +/// \returns \c None if \p DF is empty, or an \c Array containing the formatted +/// declaration fragments array. static Optional serializeDeclarationFragments(const DeclarationFragments &DF) { if (DF.getFragments().empty()) @@ -189,6 +281,16 @@ return Fragments; } +/// Serialize the function signature field of a function, as specified by the +/// Symbol Graph format. +/// +/// The Symbol Graph function signature property contains two arrays. +/// - The \c returns array is the declaration fragments of the return type; +/// - The \c parameters array contains names and declaration fragments of the +/// parameters. +/// +/// \returns \c None if \p FS is empty, or an \c Object containing the +/// formatted function signature. static Optional serializeFunctionSignature(const FunctionSignature &FS) { if (FS.empty()) @@ -213,6 +315,15 @@ return Signature; } +/// Serialize the \c names field of a symbol as specified by the Symbol Graph +/// format. +/// +/// The Symbol Graph names field contains multiple representations of a symbol +/// that can be used for different applications: +/// - \c title : The simple declared name of the symbol; +/// - \c subHeading : An array of declaration fragments that provides tags, +/// and potentially more tokens (for example the \c +/- symbol for +/// Objective-C methods). Can be used as sub-headings for documentation. static Object serializeNames(const APIRecord &Record) { Object Names; Names["title"] = Record.Name; @@ -222,7 +333,11 @@ return Names; } -// SymbolGraph: Symbol::kind +/// Serialize the symbol kind information. +/// +/// The Symbol Graph symbol kind property contains a shorthand \c identifier +/// which is prefixed by the source language name, useful for tooling to parse +/// the kind, and a \c displayName for rendering human-readable names. static Object serializeSymbolKind(const APIRecord &Record, const LangOptions &LangOpts) { Object Kind; @@ -250,9 +365,12 @@ } // namespace -const VersionTuple Serializer::FormatVersion{0, 5, 3}; +void SymbolGraphSerializer::anchor() {} + +/// Defines the format version emitted by SymbolGraphSerializer. +const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; -Object Serializer::serializeMetadata() const { +Object SymbolGraphSerializer::serializeMetadata() const { Object Metadata; serializeObject(Metadata, "formatVersion", serializeSemanticVersion(FormatVersion)); @@ -260,15 +378,17 @@ return Metadata; } -Object Serializer::serializeModule() const { +Object SymbolGraphSerializer::serializeModule() const { Object Module; - // FIXME: What to put in here? + // 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"] = ""; serializeObject(Module, "platform", serializePlatform(API.getTarget())); return Module; } -bool Serializer::shouldSkip(const APIRecord &Record) const { +bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { // Skip unconditionally unavailable symbols if (Record.Availability.isUnconditionallyUnavailable()) return true; @@ -276,7 +396,8 @@ return false; } -Optional Serializer::serializeAPIRecord(const APIRecord &Record) const { +Optional +SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const { if (shouldSkip(Record)) return None; @@ -297,7 +418,7 @@ return Obj; } -void Serializer::serializeGlobalRecord(const GlobalRecord &Record) { +void SymbolGraphSerializer::serializeGlobalRecord(const GlobalRecord &Record) { auto Obj = serializeAPIRecord(Record); if (!Obj) return; @@ -309,11 +430,12 @@ Symbols.emplace_back(std::move(*Obj)); } -Object Serializer::serialize() { +Object SymbolGraphSerializer::serialize() { Object Root; serializeObject(Root, "metadata", serializeMetadata()); serializeObject(Root, "module", serializeModule()); + // Serialize global records in the API set. for (const auto &Global : API.getGlobals()) serializeGlobalRecord(*Global.second); @@ -322,11 +444,3 @@ 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"; -} diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt --- a/clang/lib/FrontendTool/CMakeLists.txt +++ b/clang/lib/FrontendTool/CMakeLists.txt @@ -7,9 +7,9 @@ clangBasic clangCodeGen clangDriver + clangExtractAPI clangFrontend clangRewriteFrontend - clangSymbolGraph ) if(CLANG_ENABLE_ARCMT) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -15,6 +15,7 @@ #include "clang/CodeGen/CodeGenAction.h" #include "clang/Config/config.h" #include "clang/Driver/Options.h" +#include "clang/ExtractAPI/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" @@ -25,7 +26,6 @@ #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" -#include "clang/SymbolGraph/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/Support/BuryPointer.h"