diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 3d86f7510bde2..592ed3bda5150 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -548,12 +548,6 @@ def err_drv_extract_api_wrong_kind : Error< "header file '%0' input '%1' does not match the type of prior input " "in api extraction; use '-x %2' to override">; -def err_drv_missing_symbol_graph_dir: Error< - "Must provide a symbol graph output directory using --symbol-graph-dir=">; - -def err_drv_unexpected_symbol_graph_output : Error< - "Unexpected output symbol graph '%1'; please provide --symbol-graph-dir= instead">; - def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">, InGroup>; def note_use_dashdash : Note< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 241544b2b8c6f..ba23cf84c5e34 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -366,6 +366,4 @@ def warn_profile_data_misexpect : Warning< def err_extract_api_ignores_file_not_found : Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal; -def warn_missing_symbol_graph_dir : Warning<"Missing symbol graph output directory, defaulting to working directory">; - } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c3e90a70925b7..f5289fb00c895 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1507,29 +1507,14 @@ def extract_api : Flag<["-"], "extract-api">, def product_name_EQ: Joined<["--"], "product-name=">, Visibility<[ClangOption, CC1Option]>, MarshallingInfoString>; -def emit_symbol_graph: Flag<["-"], "emit-symbol-graph">, +def emit_symbol_graph_EQ: JoinedOrSeparate<["--"], "emit-symbol-graph=">, Visibility<[ClangOption, CC1Option]>, - HelpText<"Generate Extract API information as a side effect of compilation.">, - MarshallingInfoFlag>; -def emit_extension_symbol_graphs: Flag<["--"], "emit-extension-symbol-graphs">, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Generate additional symbol graphs for extended modules.">, - MarshallingInfoFlag>; + HelpText<"Generate Extract API information as a side effect of compilation.">, + MarshallingInfoString>; def extract_api_ignores_EQ: CommaJoined<["--"], "extract-api-ignores=">, Visibility<[ClangOption, CC1Option]>, HelpText<"Comma separated list of files containing a new line separated list of API symbols to ignore when extracting API information.">, MarshallingInfoStringVector>; -def symbol_graph_dir_EQ: Joined<["--"], "symbol-graph-dir=">, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Directory in which to emit symbol graphs.">, - MarshallingInfoString>; -def emit_pretty_sgf: Flag<["--"], "pretty-sgf">, - Visibility<[ClangOption, CC1Option]>, - HelpText<"Emit pretty printed symbol graphs">, - MarshallingInfoFlag>; -def emit_sgf_symbol_labels_for_testing: Flag<["--"], "emit-sgf-symbol-labels-for-testing">, - Visibility<[CC1Option]>, - MarshallingInfoFlag>; def e : Separate<["-"], "e">, Flags<[LinkerInput]>, Group; def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h index 92cacf65c7d64..b220db294101d 100644 --- a/clang/include/clang/ExtractAPI/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -20,25 +20,17 @@ #include "clang/AST/Availability.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RawCommentList.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/DeclarationFragments.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" -#include -#include #include -#include #include namespace clang { @@ -157,58 +149,15 @@ class Template { /// \endcode using DocComment = std::vector; -struct APIRecord; - -// This represents a reference to another symbol that might come from external -/// sources. -struct SymbolReference { - StringRef Name; - StringRef USR; - - /// The source project/module/product of the referred symbol. - StringRef Source; - - // A Pointer to the APIRecord for this reference if known - const APIRecord *Record = nullptr; - - SymbolReference() = default; - SymbolReference(StringRef Name, StringRef USR, StringRef Source = "") - : Name(Name), USR(USR), Source(Source) {} - SymbolReference(const APIRecord *R); - - /// Determine if this SymbolReference is empty. - /// - /// \returns true if and only if all \c Name, \c USR, and \c Source is empty. - bool empty() const { return Name.empty() && USR.empty() && Source.empty(); } -}; - -class RecordContext; - -// Concrete classes deriving from APIRecord need to have a construct with first -// arguments USR, and Name, in that order. This is so that they -// are compatible with `APISet::createRecord`. -// When adding a new kind of record don't forget to update APIRecords.inc! +// Classes deriving from APIRecord need to have USR be the first constructor +// argument. This is so that they are compatible with `addTopLevelRecord` +// defined in API.cpp /// The base representation of an API record. Holds common symbol information. struct APIRecord { /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) enum RecordKind { RK_Unknown, - // If adding a record context record kind here make sure to update - // RecordContext::classof if needed and add a RECORD_CONTEXT entry to - // APIRecords.inc - RK_FirstRecordContext, RK_Namespace, - RK_Enum, - RK_Struct, - RK_Union, - RK_ObjCInterface, - RK_ObjCCategory, - RK_ObjCProtocol, - RK_CXXClass, - RK_ClassTemplate, - RK_ClassTemplateSpecialization, - RK_ClassTemplatePartialSpecialization, - RK_LastRecordContext, RK_GlobalFunction, RK_GlobalFunctionTemplate, RK_GlobalFunctionTemplateSpecialization, @@ -217,11 +166,18 @@ struct APIRecord { RK_GlobalVariableTemplateSpecialization, RK_GlobalVariableTemplatePartialSpecialization, RK_EnumConstant, + RK_Enum, RK_StructField, + RK_Struct, RK_UnionField, + RK_Union, RK_StaticField, RK_CXXField, RK_CXXFieldTemplate, + RK_CXXClass, + RK_ClassTemplate, + RK_ClassTemplateSpecialization, + RK_ClassTemplatePartialSpecialization, RK_Concept, RK_CXXStaticMethod, RK_CXXInstanceMethod, @@ -234,15 +190,40 @@ struct APIRecord { RK_ObjCIvar, RK_ObjCClassMethod, RK_ObjCInstanceMethod, + RK_ObjCInterface, + RK_ObjCCategory, + RK_ObjCCategoryModule, + RK_ObjCProtocol, RK_MacroDefinition, RK_Typedef, }; + /// Stores information about the context of the declaration of this API. + /// This is roughly analogous to the DeclContext hierarchy for an AST Node. + struct HierarchyInformation { + /// The USR of the parent API. + StringRef ParentUSR; + /// The name of the parent API. + StringRef ParentName; + /// The record kind of the parent API. + RecordKind ParentKind = RK_Unknown; + /// A pointer to the parent APIRecord if known. + APIRecord *ParentRecord = nullptr; + + HierarchyInformation() = default; + HierarchyInformation(StringRef ParentUSR, StringRef ParentName, + RecordKind Kind, APIRecord *ParentRecord = nullptr) + : ParentUSR(ParentUSR), ParentName(ParentName), ParentKind(Kind), + ParentRecord(ParentRecord) {} + + bool empty() const { + return ParentUSR.empty() && ParentName.empty() && + ParentKind == RK_Unknown && ParentRecord == nullptr; + } + }; + StringRef USR; StringRef Name; - - SymbolReference Parent; - PresumedLoc Location; AvailabilityInfo Availability; LinkageInfo Linkage; @@ -261,169 +242,79 @@ struct APIRecord { /// Objective-C class/instance methods). DeclarationFragments SubHeading; + /// Information about the parent record of this record. + HierarchyInformation ParentInformation; + /// Whether the symbol was defined in a system header. bool IsFromSystemHeader; - AccessControl Access; - private: const RecordKind Kind; - friend class RecordContext; - // Used to store the next child record in RecordContext. This works because - // APIRecords semantically only have one parent. - mutable APIRecord *NextInContext = nullptr; public: - APIRecord *getNextInContext() const { return NextInContext; } - RecordKind getKind() const { return Kind; } - static APIRecord *castFromRecordContext(const RecordContext *Ctx); - static RecordContext *castToRecordContext(const APIRecord *Record); - APIRecord() = delete; APIRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Location, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader, - AccessControl Access = AccessControl()) - : USR(USR), Name(Name), Parent(std::move(Parent)), Location(Location), + PresumedLoc Location, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + bool IsFromSystemHeader) + : USR(USR), Name(Name), Location(Location), Availability(std::move(Availability)), Linkage(Linkage), Comment(Comment), Declaration(Declaration), SubHeading(SubHeading), - IsFromSystemHeader(IsFromSystemHeader), Access(std::move(Access)), - Kind(Kind) {} + IsFromSystemHeader(IsFromSystemHeader), Kind(Kind) {} APIRecord(RecordKind Kind, StringRef USR, StringRef Name) : USR(USR), Name(Name), Kind(Kind) {} // Pure virtual destructor to make APIRecord abstract virtual ~APIRecord() = 0; - static bool classof(const APIRecord *Record) { return true; } - static bool classofKind(RecordKind K) { return true; } - static bool classof(const RecordContext *Ctx) { return true; } -}; - -/// Base class used for specific record types that have children records this is -/// analogous to the DeclContext for the AST -class RecordContext { -public: - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(APIRecord::RecordKind K) { - return K > APIRecord::RK_FirstRecordContext && - K < APIRecord::RK_LastRecordContext; - } - - static bool classof(const RecordContext *Context) { return true; } - - RecordContext(APIRecord::RecordKind Kind) : Kind(Kind) {} - - APIRecord::RecordKind getKind() const { return Kind; } - - struct record_iterator { - private: - APIRecord *Current = nullptr; - - public: - using value_type = APIRecord *; - using reference = const value_type &; - using pointer = const value_type *; - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - - record_iterator() = default; - explicit record_iterator(value_type R) : Current(R) {} - reference operator*() const { return Current; } - // This doesn't strictly meet the iterator requirements, but it's the - // behavior we want here. - value_type operator->() const { return Current; } - record_iterator &operator++() { - Current = Current->getNextInContext(); - return *this; - } - record_iterator operator++(int) { - record_iterator tmp(*this); - ++(*this); - return tmp; - } - - friend bool operator==(record_iterator x, record_iterator y) { - return x.Current == y.Current; - } - friend bool operator!=(record_iterator x, record_iterator y) { - return x.Current != y.Current; - } - }; - - using record_range = llvm::iterator_range; - record_range records() const { - return record_range(records_begin(), records_end()); - } - record_iterator records_begin() const { return record_iterator(First); }; - record_iterator records_end() const { return record_iterator(); } - bool records_empty() const { return First == nullptr; }; - -private: - APIRecord::RecordKind Kind; - mutable APIRecord *First = nullptr; - mutable APIRecord *Last = nullptr; - -protected: - friend class APISet; - void addToRecordChain(APIRecord *) const; }; -struct NamespaceRecord : APIRecord, RecordContext { - NamespaceRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, +struct NamespaceRecord : APIRecord { + NamespaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_Namespace, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(RK_Namespace, USR, Name, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader), - RecordContext(RK_Namespace) {} + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_Namespace; } - static bool classofKind(RecordKind K) { return K == RK_Namespace; } }; /// This holds information associated with global functions. struct GlobalFunctionRecord : APIRecord { FunctionSignature Signature; - GlobalFunctionRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, + GlobalFunctionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(RK_GlobalFunction, USR, Name, Parent, Loc, - std::move(Availability), Linkage, Comment, Declaration, - SubHeading, IsFromSystemHeader), + : APIRecord(RK_GlobalFunction, USR, Name, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, + IsFromSystemHeader), Signature(Signature) {} GlobalFunctionRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, IsFromSystemHeader), Signature(Signature) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_GlobalFunction; } - static bool classofKind(RecordKind K) { return K == RK_GlobalFunction; } private: virtual void anchor(); @@ -432,74 +323,63 @@ struct GlobalFunctionRecord : APIRecord { struct GlobalFunctionTemplateRecord : GlobalFunctionRecord { Template Templ; - GlobalFunctionTemplateRecord(StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, + GlobalFunctionTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, Template Template, bool IsFromSystemHeader) - : GlobalFunctionRecord(RK_GlobalFunctionTemplate, USR, Name, Parent, Loc, + : GlobalFunctionRecord(RK_GlobalFunctionTemplate, USR, Name, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, Signature, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_GlobalFunctionTemplate; + return Record->getKind() == RK_GlobalFunctionTemplate; } }; struct GlobalFunctionTemplateSpecializationRecord : GlobalFunctionRecord { GlobalFunctionTemplateSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) : GlobalFunctionRecord(RK_GlobalFunctionTemplateSpecialization, USR, Name, - Parent, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, Signature, + Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_GlobalFunctionTemplateSpecialization; + return Record->getKind() == RK_GlobalFunctionTemplateSpecialization; } }; /// This holds information associated with global functions. struct GlobalVariableRecord : APIRecord { - GlobalVariableRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, + GlobalVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_GlobalVariable, USR, Name, Parent, Loc, - std::move(Availability), Linkage, Comment, Declaration, - SubHeading, IsFromSystemHeader) {} + : APIRecord(RK_GlobalVariable, USR, Name, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, + IsFromSystemHeader) {} GlobalVariableRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_GlobalVariable; } - static bool classofKind(RecordKind K) { return K == RK_GlobalVariable; } private: virtual void anchor(); @@ -508,42 +388,34 @@ struct GlobalVariableRecord : APIRecord { struct GlobalVariableTemplateRecord : GlobalVariableRecord { Template Templ; - GlobalVariableTemplateRecord(StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, + GlobalVariableTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, class Template Template, bool IsFromSystemHeader) - : GlobalVariableRecord(RK_GlobalVariableTemplate, USR, Name, Parent, Loc, + : GlobalVariableRecord(RK_GlobalVariableTemplate, USR, Name, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_GlobalVariableTemplate; + return Record->getKind() == RK_GlobalVariableTemplate; } }; struct GlobalVariableTemplateSpecializationRecord : GlobalVariableRecord { GlobalVariableTemplateSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) : GlobalVariableRecord(RK_GlobalVariableTemplateSpecialization, USR, Name, - Parent, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_GlobalVariableTemplateSpecialization; + return Record->getKind() == RK_GlobalVariableTemplateSpecialization; } }; @@ -552,203 +424,126 @@ struct GlobalVariableTemplatePartialSpecializationRecord Template Templ; GlobalVariableTemplatePartialSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, class Template Template, bool IsFromSystemHeader) : GlobalVariableRecord(RK_GlobalVariableTemplatePartialSpecialization, - USR, Name, Parent, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, + USR, Name, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_GlobalVariableTemplatePartialSpecialization; + return Record->getKind() == RK_GlobalVariableTemplatePartialSpecialization; } }; /// This holds information associated with enum constants. struct EnumConstantRecord : APIRecord { - EnumConstantRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + EnumConstantRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_EnumConstant, USR, Name, Parent, Loc, - std::move(Availability), LinkageInfo::none(), Comment, - Declaration, SubHeading, IsFromSystemHeader) {} + : APIRecord(RK_EnumConstant, USR, Name, Loc, std::move(Availability), + LinkageInfo::none(), Comment, Declaration, SubHeading, + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_EnumConstant; } - static bool classofKind(RecordKind K) { return K == RK_EnumConstant; } private: virtual void anchor(); }; /// This holds information associated with enums. -struct EnumRecord : APIRecord, RecordContext { - EnumRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_Enum, USR, Name, Parent, Loc, std::move(Availability), +struct EnumRecord : APIRecord { + SmallVector> Constants; + + EnumRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + bool IsFromSystemHeader) + : APIRecord(RK_Enum, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - RecordContext(RK_Enum) {} + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_Enum; } - static bool classofKind(RecordKind K) { return K == RK_Enum; } private: virtual void anchor(); }; -/// This holds information associated with struct or union fields fields. +/// This holds information associated with struct fields. struct RecordFieldRecord : APIRecord { - RecordFieldRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, + RecordFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + DeclarationFragments SubHeading, RecordKind Kind, + bool IsFromSystemHeader) + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_StructField || K == RK_UnionField; + return Record->getKind() == RK_StructField || + Record->getKind() == RK_UnionField; } - virtual ~RecordFieldRecord() = 0; -}; - -/// This holds information associated with structs and unions. -struct RecordRecord : APIRecord, RecordContext { - RecordRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), - LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - RecordContext(Kind) {} - - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_Struct || K == RK_Union; - } - - virtual ~RecordRecord() = 0; -}; - -struct StructFieldRecord : RecordFieldRecord { - StructFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : RecordFieldRecord(RK_StructField, USR, Name, Parent, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader) {} - - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { return K == RK_StructField; } - private: virtual void anchor(); }; -struct StructRecord : RecordRecord { - StructRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : RecordRecord(RK_Struct, USR, Name, Parent, Loc, std::move(Availability), - Comment, Declaration, SubHeading, IsFromSystemHeader) {} - - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { return K == RK_Struct; } - -private: - virtual void anchor(); -}; - -struct UnionFieldRecord : RecordFieldRecord { - UnionFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : RecordFieldRecord(RK_UnionField, USR, Name, Parent, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader) {} - - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { return K == RK_UnionField; } +/// This holds information associated with structs. +struct RecordRecord : APIRecord { + SmallVector> Fields; -private: - virtual void anchor(); -}; - -struct UnionRecord : RecordRecord { - UnionRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) - : RecordRecord(RK_Union, USR, Name, Parent, Loc, std::move(Availability), - Comment, Declaration, SubHeading, IsFromSystemHeader) {} + RecordRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, RecordKind Kind, + bool IsFromSystemHeader) + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + LinkageInfo::none(), Comment, Declaration, SubHeading, + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_Struct || Record->getKind() == RK_Union; } - static bool classofKind(RecordKind K) { return K == RK_Union; } private: virtual void anchor(); }; struct CXXFieldRecord : APIRecord { - CXXFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + AccessControl Access; + + CXXFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(RK_CXXField, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(RK_CXXField, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader, std::move(Access)) {} + IsFromSystemHeader), + Access(Access) {} CXXFieldRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader, std::move(Access)) {} + IsFromSystemHeader), + Access(Access) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_CXXField || K == RK_CXXFieldTemplate || K == RK_StaticField; + return Record->getKind() == RK_CXXField; } private: @@ -758,122 +553,111 @@ struct CXXFieldRecord : APIRecord { struct CXXFieldTemplateRecord : CXXFieldRecord { Template Templ; - CXXFieldTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + CXXFieldTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, Template Template, bool IsFromSystemHeader) - : CXXFieldRecord(RK_CXXFieldTemplate, USR, Name, Parent, Loc, + : CXXFieldRecord(RK_CXXFieldTemplate, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, std::move(Access), IsFromSystemHeader), + SubHeading, Access, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXFieldTemplate; } - static bool classofKind(RecordKind K) { return K == RK_CXXFieldTemplate; } }; struct CXXMethodRecord : APIRecord { FunctionSignature Signature; + AccessControl Access; CXXMethodRecord() = delete; CXXMethodRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader, std::move(Access)), - Signature(Signature) {} + IsFromSystemHeader), + Signature(Signature), Access(Access) {} virtual ~CXXMethodRecord() = 0; }; struct CXXConstructorRecord : CXXMethodRecord { - CXXConstructorRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + CXXConstructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXConstructorMethod, USR, Name, Parent, Loc, + : CXXMethodRecord(RK_CXXConstructorMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader) {} + SubHeading, Signature, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXConstructorMethod; } - static bool classofKind(RecordKind K) { return K == RK_CXXConstructorMethod; } private: virtual void anchor(); }; struct CXXDestructorRecord : CXXMethodRecord { - CXXDestructorRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + CXXDestructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXDestructorMethod, USR, Name, Parent, Loc, + : CXXMethodRecord(RK_CXXDestructorMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader) {} + SubHeading, Signature, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXDestructorMethod; } - static bool classofKind(RecordKind K) { return K == RK_CXXDestructorMethod; } private: virtual void anchor(); }; struct CXXStaticMethodRecord : CXXMethodRecord { - CXXStaticMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + CXXStaticMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXStaticMethod, USR, Name, Parent, Loc, + : CXXMethodRecord(RK_CXXStaticMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader) {} + SubHeading, Signature, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXStaticMethod; } - static bool classofKind(RecordKind K) { return K == RK_CXXStaticMethod; } private: virtual void anchor(); }; struct CXXInstanceMethodRecord : CXXMethodRecord { - CXXInstanceMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + CXXInstanceMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXInstanceMethod, USR, Name, Parent, Loc, + : CXXMethodRecord(RK_CXXInstanceMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader) {} + SubHeading, Signature, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXInstanceMethod; } - static bool classofKind(RecordKind K) { return K == RK_CXXInstanceMethod; } private: virtual void anchor(); @@ -882,42 +666,36 @@ struct CXXInstanceMethodRecord : CXXMethodRecord { struct CXXMethodTemplateRecord : CXXMethodRecord { Template Templ; - CXXMethodTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + CXXMethodTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, Template Template, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXMethodTemplate, USR, Name, Parent, Loc, + : CXXMethodRecord(RK_CXXMethodTemplate, USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader), + SubHeading, Signature, Access, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_CXXMethodTemplate; } - static bool classofKind(RecordKind K) { return K == RK_CXXMethodTemplate; } }; struct CXXMethodTemplateSpecializationRecord : CXXMethodRecord { CXXMethodTemplateSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXMethodTemplateSpecialization, USR, Name, Parent, - Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, std::move(Access), - IsFromSystemHeader) {} + : CXXMethodRecord(RK_CXXMethodTemplateSpecialization, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Signature, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_CXXMethodTemplateSpecialization; + return Record->getKind() == RK_CXXMethodTemplateSpecialization; } }; @@ -936,13 +714,13 @@ struct ObjCPropertyRecord : APIRecord { bool IsOptional; ObjCPropertyRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AttributeKind Attributes, StringRef GetterName, StringRef SetterName, bool IsOptional, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Attributes(Attributes), GetterName(GetterName), SetterName(SetterName), @@ -955,44 +733,44 @@ struct ObjCPropertyRecord : APIRecord { }; struct ObjCInstancePropertyRecord : ObjCPropertyRecord { - ObjCInstancePropertyRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AttributeKind Attributes, StringRef GetterName, StringRef SetterName, - bool IsOptional, bool IsFromSystemHeader) - : ObjCPropertyRecord(RK_ObjCInstanceProperty, USR, Name, Parent, Loc, + ObjCInstancePropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + AttributeKind Attributes, StringRef GetterName, + StringRef SetterName, bool IsOptional, + bool IsFromSystemHeader) + : ObjCPropertyRecord(RK_ObjCInstanceProperty, USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, Attributes, GetterName, SetterName, IsOptional, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCInstanceProperty; } - static bool classofKind(RecordKind K) { return K == RK_ObjCInstanceProperty; } private: virtual void anchor(); }; struct ObjCClassPropertyRecord : ObjCPropertyRecord { - ObjCClassPropertyRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + ObjCClassPropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AttributeKind Attributes, StringRef GetterName, StringRef SetterName, bool IsOptional, bool IsFromSystemHeader) - : ObjCPropertyRecord(RK_ObjCClassProperty, USR, Name, Parent, Loc, + : ObjCPropertyRecord(RK_ObjCClassProperty, USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, Attributes, GetterName, SetterName, IsOptional, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCClassProperty; } - static bool classofKind(RecordKind K) { return K == RK_ObjCClassProperty; } private: virtual void anchor(); @@ -1000,21 +778,23 @@ struct ObjCClassPropertyRecord : ObjCPropertyRecord { /// This holds information associated with Objective-C instance variables. struct ObjCInstanceVariableRecord : APIRecord { - ObjCInstanceVariableRecord(StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, + using AccessControl = ObjCIvarDecl::AccessControl; + AccessControl Access; + + ObjCInstanceVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, - bool IsFromSystemHeader) - : APIRecord(RK_ObjCIvar, USR, Name, Parent, Loc, std::move(Availability), + AccessControl Access, bool IsFromSystemHeader) + : APIRecord(RK_ObjCIvar, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + IsFromSystemHeader), + Access(Access) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCIvar; } - static bool classofKind(RecordKind K) { return K == RK_ObjCIvar; } private: virtual void anchor(); @@ -1027,12 +807,11 @@ struct ObjCMethodRecord : APIRecord { ObjCMethodRecord() = delete; ObjCMethodRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Signature(Signature) {} @@ -1041,103 +820,122 @@ struct ObjCMethodRecord : APIRecord { }; struct ObjCInstanceMethodRecord : ObjCMethodRecord { - ObjCInstanceMethodRecord(StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, + ObjCInstanceMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : ObjCMethodRecord(RK_ObjCInstanceMethod, USR, Name, Parent, Loc, + : ObjCMethodRecord(RK_ObjCInstanceMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCInstanceMethod; } - static bool classofKind(RecordKind K) { return K == RK_ObjCInstanceMethod; } private: virtual void anchor(); }; struct ObjCClassMethodRecord : ObjCMethodRecord { - ObjCClassMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, + ObjCClassMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : ObjCMethodRecord(RK_ObjCClassMethod, USR, Name, Parent, Loc, + : ObjCMethodRecord(RK_ObjCClassMethod, USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCClassMethod; } - static bool classofKind(RecordKind K) { return K == RK_ObjCClassMethod; } private: virtual void anchor(); }; +/// This represents a reference to another symbol that might come from external +/// sources. +struct SymbolReference { + StringRef Name; + StringRef USR; + + /// The source project/module/product of the referred symbol. + StringRef Source; + + SymbolReference() = default; + SymbolReference(StringRef Name, StringRef USR = "", StringRef Source = "") + : Name(Name), USR(USR), Source(Source) {} + SymbolReference(const APIRecord &Record) + : Name(Record.Name), USR(Record.USR) {} + SymbolReference(const APIRecord *Record) + : Name(Record->Name), USR(Record->USR) {} + + /// Determine if this SymbolReference is empty. + /// + /// \returns true if and only if all \c Name, \c USR, and \c Source is empty. + bool empty() const { return Name.empty() && USR.empty() && Source.empty(); } +}; + struct StaticFieldRecord : CXXFieldRecord { - StaticFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, AccessControl Access, - bool IsFromSystemHeader) - : CXXFieldRecord(RK_StaticField, USR, Name, Parent, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, std::move(Access), IsFromSystemHeader) {} + SymbolReference Context; + + StaticFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, SymbolReference Context, + AccessControl Access, bool IsFromSystemHeader) + : CXXFieldRecord(RK_StaticField, USR, Name, Loc, std::move(Availability), + Comment, Declaration, SubHeading, Access, + IsFromSystemHeader), + Context(Context) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_StaticField; } - static bool classofKind(RecordKind K) { return K == RK_StaticField; } }; /// The base representation of an Objective-C container record. Holds common /// information associated with Objective-C containers. -struct ObjCContainerRecord : APIRecord, RecordContext { +struct ObjCContainerRecord : APIRecord { + SmallVector> Methods; + SmallVector> Properties; + SmallVector> Ivars; SmallVector Protocols; ObjCContainerRecord() = delete; ObjCContainerRecord(RecordKind Kind, StringRef USR, StringRef Name, - SymbolReference Parent, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader), - RecordContext(Kind) {} + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, IsFromSystemHeader) {} virtual ~ObjCContainerRecord() = 0; }; -struct CXXClassRecord : APIRecord, RecordContext { +struct CXXClassRecord : APIRecord { + SmallVector> Fields; + SmallVector> Methods; SmallVector Bases; + AccessControl Access; - CXXClassRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + CXXClassRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, RecordKind Kind, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader, std::move(Access)), - RecordContext(Kind) {} + IsFromSystemHeader), + Access(Access) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_CXXClass || K == RK_ClassTemplate || - K == RK_ClassTemplateSpecialization || - K == RK_ClassTemplatePartialSpecialization; + return (Record->getKind() == RK_CXXClass); } private: @@ -1147,108 +945,86 @@ struct CXXClassRecord : APIRecord, RecordContext { struct ClassTemplateRecord : CXXClassRecord { Template Templ; - ClassTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + ClassTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, - Declaration, SubHeading, RK_ClassTemplate, - std::move(Access), IsFromSystemHeader), + : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, + Declaration, SubHeading, RK_ClassTemplate, Access, + IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ClassTemplate; } - static bool classofKind(RecordKind K) { return K == RK_ClassTemplate; } }; struct ClassTemplateSpecializationRecord : CXXClassRecord { ClassTemplateSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, + : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, RK_ClassTemplateSpecialization, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_ClassTemplateSpecialization; + return Record->getKind() == RK_ClassTemplateSpecialization; } }; struct ClassTemplatePartialSpecializationRecord : CXXClassRecord { Template Templ; ClassTemplatePartialSpecializationRecord( - StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + StringRef USR, StringRef Name, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, - Declaration, SubHeading, - RK_ClassTemplatePartialSpecialization, Access, - IsFromSystemHeader), + : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, + Declaration, SubHeading, RK_ClassTemplateSpecialization, + Access, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { - return K == RK_ClassTemplatePartialSpecialization; + return Record->getKind() == RK_ClassTemplatePartialSpecialization; } }; struct ConceptRecord : APIRecord { Template Templ; - ConceptRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + ConceptRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, bool IsFromSystemHeader) - : APIRecord(RK_Concept, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(RK_Concept, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} - - static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { return K == RK_Concept; } }; /// This holds information associated with Objective-C categories. struct ObjCCategoryRecord : ObjCContainerRecord { SymbolReference Interface; + /// Determine whether the Category is derived from external class interface. + bool IsFromExternalModule = false; - ObjCCategoryRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + ObjCCategoryRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference Interface, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCCategory, USR, Name, Parent, Loc, + : ObjCContainerRecord(RK_ObjCCategory, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Interface(Interface) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); - } - static bool classofKind(RecordKind K) { return K == RK_ObjCCategory; } - - bool isExtendingExternalModule() const { return !Interface.Source.empty(); } - - std::optional getExtendedExternalModule() const { - if (!isExtendingExternalModule()) - return {}; - return Interface.Source; + return Record->getKind() == RK_ObjCCategory; } private: @@ -1258,22 +1034,23 @@ struct ObjCCategoryRecord : ObjCContainerRecord { /// This holds information associated with Objective-C interfaces/classes. struct ObjCInterfaceRecord : ObjCContainerRecord { SymbolReference SuperClass; + // ObjCCategoryRecord%s are stored in and owned by APISet. + SmallVector Categories; - ObjCInterfaceRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, + ObjCInterfaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference SuperClass, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCInterface, USR, Name, Parent, Loc, + : ObjCContainerRecord(RK_ObjCInterface, USR, Name, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader), SuperClass(SuperClass) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCInterface; } - static bool classofKind(RecordKind K) { return K == RK_ObjCInterface; } private: virtual void anchor(); @@ -1281,20 +1058,18 @@ struct ObjCInterfaceRecord : ObjCContainerRecord { /// This holds information associated with Objective-C protocols. struct ObjCProtocolRecord : ObjCContainerRecord { - ObjCProtocolRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + ObjCProtocolRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Parent, Loc, + : ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_ObjCProtocol; } - static bool classofKind(RecordKind K) { return K == RK_ObjCProtocol; } private: virtual void anchor(); @@ -1302,18 +1077,17 @@ struct ObjCProtocolRecord : ObjCContainerRecord { /// This holds information associated with macro definitions. struct MacroDefinitionRecord : APIRecord { - MacroDefinitionRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, DeclarationFragments Declaration, + MacroDefinitionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_MacroDefinition, USR, Name, Parent, Loc, - AvailabilityInfo(), LinkageInfo(), {}, Declaration, - SubHeading, IsFromSystemHeader) {} + : APIRecord(RK_MacroDefinition, USR, Name, Loc, AvailabilityInfo(), + LinkageInfo(), {}, Declaration, SubHeading, + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_MacroDefinition; } - static bool classofKind(RecordKind K) { return K == RK_MacroDefinition; } private: virtual void anchor(); @@ -1327,228 +1101,575 @@ struct MacroDefinitionRecord : APIRecord { struct TypedefRecord : APIRecord { SymbolReference UnderlyingType; - TypedefRecord(StringRef USR, StringRef Name, SymbolReference Parent, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + TypedefRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference UnderlyingType, bool IsFromSystemHeader) - : APIRecord(RK_Typedef, USR, Name, Parent, Loc, std::move(Availability), + : APIRecord(RK_Typedef, USR, Name, Loc, std::move(Availability), LinkageInfo(), Comment, Declaration, SubHeading, IsFromSystemHeader), UnderlyingType(UnderlyingType) {} static bool classof(const APIRecord *Record) { - return classofKind(Record->getKind()); + return Record->getKind() == RK_Typedef; } - static bool classofKind(RecordKind K) { return K == RK_Typedef; } private: virtual void anchor(); }; +/// Check if a record type has a function signature mixin. +/// +/// This is denoted by the record type having a ``Signature`` field of type +/// FunctionSignature. +template +struct has_function_signature : public std::false_type {}; +template <> +struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; +template <> +struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature : public std::true_type {}; +template <> +struct has_function_signature : public std::true_type { +}; +template <> +struct has_function_signature + : public std::true_type {}; + +template struct has_access : public std::false_type {}; +template <> struct has_access : public std::true_type {}; +template <> struct has_access : public std::true_type {}; +template <> struct has_access : public std::true_type {}; +template <> +struct has_access : public std::true_type {}; +template <> +struct has_access + : public std::true_type {}; +template <> +struct has_access : public std::true_type {}; +template <> struct has_access : public std::true_type {}; +template <> struct has_access : public std::true_type {}; +template <> +struct has_access : public std::true_type {}; +template <> +struct has_access + : public std::true_type {}; + +template struct has_template : public std::false_type {}; +template <> struct has_template : public std::true_type {}; +template <> +struct has_template + : public std::true_type {}; +template <> struct has_template : public std::true_type {}; +template <> +struct has_template : public std::true_type {}; +template <> +struct has_template + : public std::true_type {}; +template <> +struct has_template : public std::true_type {}; +template <> +struct has_template : public std::true_type {}; + +template <> +struct has_template : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; +template <> +struct has_function_signature + : public std::true_type {}; + /// APISet holds the set of API records collected from given inputs. class APISet { public: - /// Get the target triple for the ExtractAPI invocation. - const llvm::Triple &getTarget() const { return Target; } + NamespaceRecord *addNamespace(APIRecord *Parent, StringRef Name, + StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeaderg); + /// Create and add a global variable record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + GlobalVariableRecord * + addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeadin, bool IsFromSystemHeaderg); - /// Get the language used by the APIs. - Language getLanguage() const { return Lang; } + GlobalVariableTemplateRecord * + addGlobalVariableTemplate(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader); - /// Finds the APIRecord for a given USR. + /// Create and add a function record into the API set. /// - /// \returns a pointer to the APIRecord associated with that USR or nullptr. - APIRecord *findRecordForUSR(StringRef USR) const; + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + GlobalFunctionRecord * + addGlobalFunction(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, + FunctionSignature Signature, bool IsFromSystemHeader); - /// Copy \p String into the Allocator in this APISet. + GlobalFunctionTemplateRecord *addGlobalFunctionTemplate( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, FunctionSignature Signature, + Template Template, bool IsFromSystemHeader); + + GlobalFunctionTemplateSpecializationRecord * + addGlobalFunctionTemplateSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, FunctionSignature Signature, + bool IsFromSystemHeader); + + /// Create and add an enum constant record into the API set. /// - /// \returns a StringRef of the copied string in APISet::Allocator. - StringRef copyString(StringRef String); + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + EnumConstantRecord * + addEnumConstant(EnumRecord *Enum, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader); - SymbolReference createSymbolReference(StringRef Name, StringRef USR, - StringRef Source = ""); + /// Create and add an enum record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader); - /// Create a subclass of \p APIRecord and store it in the APISet. + /// Create and add a record field record into the API set. /// - /// \returns A pointer to the created record or the already existing record - /// matching this USR. - template - typename std::enable_if_t, RecordTy> * - createRecord(StringRef USR, StringRef Name, CtorArgsContTy &&...CtorArgs); - - ArrayRef getTopLevelRecords() const { - return TopLevelRecords; - } + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + RecordFieldRecord * + addRecordField(RecordRecord *Record, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, APIRecord::RecordKind Kind, + bool IsFromSystemHeader); - APISet(const llvm::Triple &Target, Language Lang, - const std::string &ProductName) - : Target(Target), Lang(Lang), ProductName(ProductName) {} + /// Create and add a record record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + RecordRecord *addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + APIRecord::RecordKind Kind, bool IsFromSystemHeader); - // Prevent moves and copies - APISet(const APISet &Other) = delete; - APISet &operator=(const APISet &Other) = delete; - APISet(APISet &&Other) = delete; - APISet &operator=(APISet &&Other) = delete; + StaticFieldRecord * + addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, SymbolReference Context, + AccessControl Access, bool IsFromSystemHeaderg); + + CXXFieldRecord *addCXXField(APIRecord *CXXClass, StringRef Name, + StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + AccessControl Access, bool IsFromSystemHeader); + + CXXFieldTemplateRecord *addCXXFieldTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + AccessControl Access, Template Template, bool IsFromSystemHeader); + + CXXClassRecord *addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + APIRecord::RecordKind Kind, AccessControl Access, + bool IsFromSystemHeader); + + ClassTemplateRecord * + addClassTemplate(APIRecord *Parent, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + AccessControl Access, bool IsFromSystemHeader); -private: - /// BumpPtrAllocator that serves as the memory arena for the allocated objects - llvm::BumpPtrAllocator Allocator; + ClassTemplateSpecializationRecord *addClassTemplateSpecialization( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + AccessControl Access, bool IsFromSystemHeader); - const llvm::Triple Target; - const Language Lang; + ClassTemplatePartialSpecializationRecord * + addClassTemplatePartialSpecialization( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + Template Template, AccessControl Access, bool IsFromSystemHeader); - struct APIRecordDeleter { - void operator()(APIRecord *Record) { Record->~APIRecord(); } - }; + GlobalVariableTemplateSpecializationRecord * + addGlobalVariableTemplateSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader); - // Ensure that the destructor of each record is called when the LookupTable is - // destroyed without calling delete operator as the memory for the record - // lives in the BumpPtrAllocator. - using APIRecordStoredPtr = std::unique_ptr; - llvm::DenseMap USRBasedLookupTable; - std::vector TopLevelRecords; + GlobalVariableTemplatePartialSpecializationRecord * + addGlobalVariableTemplatePartialSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader); -public: - const std::string ProductName; -}; + CXXMethodRecord *addCXXInstanceMethod( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader); -template -typename std::enable_if_t, RecordTy> * -APISet::createRecord(StringRef USR, StringRef Name, - CtorArgsContTy &&...CtorArgs) { - // Ensure USR refers to a String stored in the allocator. - auto USRString = copyString(USR); - auto Result = USRBasedLookupTable.insert({USRString, nullptr}); - RecordTy *Record; - - // Create the record if it does not already exist - if (Result.second) { - Record = new (Allocator) RecordTy( - USRString, copyString(Name), std::forward(CtorArgs)...); - // Store the record in the record lookup map - Result.first->second = APIRecordStoredPtr(Record); - - if (auto *ParentContext = - dyn_cast_if_present(Record->Parent.Record)) - ParentContext->addToRecordChain(Record); - else - TopLevelRecords.push_back(Record); - } else { - Record = dyn_cast(Result.first->second.get()); - } + CXXMethodRecord *addCXXStaticMethod( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader); - return Record; -} + CXXMethodRecord *addCXXSpecialMethod( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader); -// Helper type for implementing casting to RecordContext pointers. -// Selected when FromTy not a known subclass of RecordContext. -template > -struct ToRecordContextCastInfoWrapper { - static_assert(std::is_base_of_v, - "Can only cast APIRecord and derived classes to RecordContext"); + CXXMethodTemplateRecord *addCXXMethodTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, Template Template, + bool IsFromSystemHeader); - static bool isPossible(FromTy *From) { return RecordContext::classof(From); } + CXXMethodTemplateSpecializationRecord *addCXXMethodTemplateSpec( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader); - static RecordContext *doCast(FromTy *From) { - return APIRecord::castToRecordContext(From); - } -}; + ConceptRecord *addConcept(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader); -// Selected when FromTy is a known subclass of RecordContext. -template struct ToRecordContextCastInfoWrapper { - static_assert(std::is_base_of_v, - "Can only cast APIRecord and derived classes to RecordContext"); - static bool isPossible(const FromTy *From) { return true; } - static RecordContext *doCast(FromTy *From) { - return static_cast(From); - } -}; + /// Create and add an Objective-C category record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCCategoryRecord * + addObjCCategory(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, SymbolReference Interface, + bool IsFromSystemHeader, bool IsFromExternalModule); -// Helper type for implementing casting to RecordContext pointers. -// Selected when ToTy isn't a known subclass of RecordContext -template > -struct FromRecordContextCastInfoWrapper { - static_assert( - std::is_base_of_v, - "Can only class RecordContext to APIRecord and derived classes"); - - static bool isPossible(RecordContext *Ctx) { - return ToTy::classofKind(Ctx->getKind()); - } + /// Create and add an Objective-C interface record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCInterfaceRecord * + addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, SymbolReference SuperClass, + bool IsFromSystemHeader); - static ToTy *doCast(RecordContext *Ctx) { - return APIRecord::castFromRecordContext(Ctx); - } -}; + /// Create and add an Objective-C method record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCMethodRecord * + addObjCMethod(ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, FunctionSignature Signature, + bool IsInstanceMethod, bool IsFromSystemHeader); + + /// Create and add an Objective-C property record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCPropertyRecord * + addObjCProperty(ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, + ObjCPropertyRecord::AttributeKind Attributes, + StringRef GetterName, StringRef SetterName, bool IsOptional, + bool IsInstanceProperty, bool IsFromSystemHeader); + + /// Create and add an Objective-C instance variable record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCInstanceVariableRecord *addObjCInstanceVariable( + ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + ObjCInstanceVariableRecord::AccessControl Access, + bool IsFromSystemHeader); + + /// Create and add an Objective-C protocol record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + ObjCProtocolRecord * + addObjCProtocol(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader); -// Selected when ToTy is a known subclass of RecordContext. -template struct FromRecordContextCastInfoWrapper { - static_assert( - std::is_base_of_v, - "Can only class RecordContext to APIRecord and derived classes"); - static bool isPossible(RecordContext *Ctx) { - return ToTy::classof(Ctx->getKind()); + /// Create a macro definition record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSRForMacro(StringRef Name, + /// SourceLocation SL, const SourceManager &SM) is a helper method to generate + /// the USR for the macro and keep it alive in APISet. + MacroDefinitionRecord *addMacroDefinition(StringRef Name, StringRef USR, + PresumedLoc Loc, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeader); + + /// Create a typedef record into the API set. + /// + /// Note: the caller is responsible for keeping the StringRef \p Name and + /// \p USR alive. APISet::copyString provides a way to copy strings into + /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method + /// to generate the USR for \c D and keep it alive in APISet. + TypedefRecord * + addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + SymbolReference UnderlyingType, bool IsFromSystemHeader); + + /// A mapping type to store a set of APIRecord%s with the USR as the key. + template ::value>> + using RecordMap = llvm::MapVector>; + + /// Get the target triple for the ExtractAPI invocation. + const llvm::Triple &getTarget() const { return Target; } + + /// Get the language used by the APIs. + Language getLanguage() const { return Lang; } + + const RecordMap &getNamespaces() const { return Namespaces; } + const RecordMap &getGlobalFunctions() const { + return GlobalFunctions; } - static RecordContext *doCast(RecordContext *Ctx) { - return static_cast(Ctx); + const RecordMap & + getGlobalFunctionTemplates() const { + return GlobalFunctionTemplates; } -}; + const RecordMap & + getGlobalFunctionTemplateSpecializations() const { + return GlobalFunctionTemplateSpecializations; + } + const RecordMap &getGlobalVariables() const { + return GlobalVariables; + } + const RecordMap & + getGlobalVariableTemplates() const { + return GlobalVariableTemplates; + } + const RecordMap &getStaticFields() const { + return StaticFields; + } + const RecordMap & + getGlobalVariableTemplateSpecializations() const { + return GlobalVariableTemplateSpecializations; + } + const RecordMap & + getGlobalVariableTemplatePartialSpecializations() const { + return GlobalVariableTemplatePartialSpecializations; + } + const RecordMap &getEnums() const { return Enums; } + const RecordMap &getRecords() const { return Records; } + const RecordMap &getCXXClasses() const { return CXXClasses; } + const RecordMap &getCXXMethodTemplates() const { + return CXXMethodTemplates; + } + const RecordMap &getCXXInstanceMethods() const { + return CXXInstanceMethods; + } + const RecordMap &getCXXStaticMethods() const { + return CXXStaticMethods; + } + const RecordMap &getCXXFields() const { return CXXFields; } + const RecordMap & + getCXXMethodTemplateSpecializations() const { + return CXXMethodTemplateSpecializations; + } + const RecordMap &getCXXFieldTemplates() const { + return CXXFieldTemplates; + } + const RecordMap &getClassTemplates() const { + return ClassTemplates; + } + const RecordMap & + getClassTemplateSpecializations() const { + return ClassTemplateSpecializations; + } + const RecordMap & + getClassTemplatePartialSpecializations() const { + return ClassTemplatePartialSpecializations; + } + const RecordMap &getConcepts() const { return Concepts; } + const RecordMap &getObjCCategories() const { + return ObjCCategories; + } + const RecordMap &getObjCInterfaces() const { + return ObjCInterfaces; + } + const RecordMap &getObjCProtocols() const { + return ObjCProtocols; + } + const RecordMap &getMacros() const { return Macros; } + const RecordMap &getTypedefs() const { return Typedefs; } -} // namespace extractapi -} // namespace clang + /// Finds the APIRecord for a given USR. + /// + /// \returns a pointer to the APIRecord associated with that USR or nullptr. + APIRecord *findRecordForUSR(StringRef USR) const; -// Implement APIRecord (and derived classes) to and from RecordContext -// conversions -namespace llvm { - -template -struct CastInfo<::clang::extractapi::RecordContext, FromTy *> - : public NullableValueCastFailed<::clang::extractapi::RecordContext *>, - public DefaultDoCastIfPossible< - ::clang::extractapi::RecordContext *, FromTy *, - CastInfo<::clang::extractapi::RecordContext, FromTy *>> { - static inline bool isPossible(FromTy *From) { - return ::clang::extractapi::ToRecordContextCastInfoWrapper< - FromTy>::isPossible(From); - } + /// 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); - static inline ::clang::extractapi::RecordContext *doCast(FromTy *From) { - return ::clang::extractapi::ToRecordContextCastInfoWrapper::doCast( - From); - } -}; + /// Generate and store the USR for a macro \p Name. + /// + /// Note: The USR string is stored in and owned by Allocator. + /// + /// \returns a StringRef to the generate USR string. + StringRef recordUSRForMacro(StringRef Name, SourceLocation SL, + const SourceManager &SM); -template -struct CastInfo<::clang::extractapi::RecordContext, const FromTy *> - : public ConstStrippingForwardingCast< - ::clang::extractapi::RecordContext, const FromTy *, - CastInfo<::clang::extractapi::RecordContext, FromTy *>> {}; - -template -struct CastInfo - : public NullableValueCastFailed, - public DefaultDoCastIfPossible< - ToTy *, ::clang::extractapi::RecordContext *, - CastInfo> { - static inline bool isPossible(::clang::extractapi::RecordContext *Ctx) { - return ::clang::extractapi::FromRecordContextCastInfoWrapper< - ToTy>::isPossible(Ctx); - } + /// Copy \p String into the Allocator in this APISet. + /// + /// \returns a StringRef of the copied string in APISet::Allocator. + StringRef copyString(StringRef String); - static inline ToTy *doCast(::clang::extractapi::RecordContext *Ctx) { - return ::clang::extractapi::FromRecordContextCastInfoWrapper::doCast( - Ctx); - } -}; + APISet(const llvm::Triple &Target, Language Lang, + const std::string &ProductName) + : Target(Target), Lang(Lang), ProductName(ProductName) {} + +private: + /// BumpPtrAllocator to store generated/copied strings. + /// + /// Note: The main use for this is being able to deduplicate strings. + llvm::BumpPtrAllocator StringAllocator; + + const llvm::Triple Target; + const Language Lang; -template -struct CastInfo - : public ConstStrippingForwardingCast< - ToTy, const ::clang::extractapi::RecordContext *, - CastInfo> {}; + llvm::DenseMap USRBasedLookupTable; + RecordMap Namespaces; + RecordMap GlobalFunctions; + RecordMap GlobalFunctionTemplates; + RecordMap + GlobalFunctionTemplateSpecializations; + RecordMap GlobalVariables; + RecordMap GlobalVariableTemplates; + RecordMap + GlobalVariableTemplateSpecializations; + RecordMap + GlobalVariableTemplatePartialSpecializations; + RecordMap Concepts; + RecordMap StaticFields; + RecordMap Enums; + RecordMap Records; + RecordMap CXXClasses; + RecordMap CXXFields; + RecordMap CXXMethods; + RecordMap CXXInstanceMethods; + RecordMap CXXStaticMethods; + RecordMap CXXMethodTemplates; + RecordMap + CXXMethodTemplateSpecializations; + RecordMap CXXFieldTemplates; + RecordMap ClassTemplates; + RecordMap ClassTemplateSpecializations; + RecordMap + ClassTemplatePartialSpecializations; + RecordMap ObjCCategories; + RecordMap ObjCInterfaces; + RecordMap ObjCProtocols; + RecordMap Macros; + RecordMap Typedefs; -} // namespace llvm +public: + const std::string ProductName; +}; + +} // namespace extractapi +} // namespace clang #endif // LLVM_CLANG_EXTRACTAPI_API_H diff --git a/clang/include/clang/ExtractAPI/APIRecords.inc b/clang/include/clang/ExtractAPI/APIRecords.inc deleted file mode 100644 index 15fee809656d9..0000000000000 --- a/clang/include/clang/ExtractAPI/APIRecords.inc +++ /dev/null @@ -1,103 +0,0 @@ -//===- ExtractAPI/APIRecords.inc --------------------------------*- 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 classes defined from ExtractAPI's APIRecord -/// -//===----------------------------------------------------------------------===// - -#ifndef ABSTRACT_RECORD -#define ABSTRACT_RECORD(CLASS, BASE) RECORD(CLASS, BASE) -#endif -#ifndef CONCRETE_RECORD -#define CONCRETE_RECORD(CLASS, BASE, KIND) RECORD(CLASS, BASE) -#endif -#ifndef RECORD -#define RECORD(CLASS, BASE) -#endif - -CONCRETE_RECORD(NamespaceRecord, APIRecord, RK_Namespace) -CONCRETE_RECORD(GlobalFunctionRecord, APIRecord, RK_GlobalFunction) -CONCRETE_RECORD(GlobalFunctionTemplateRecord, GlobalFunctionRecord, - RK_GlobalFunctionTemplate) -CONCRETE_RECORD(GlobalFunctionTemplateSpecializationRecord, - GlobalFunctionRecord, RK_GlobalFunctionTemplateSpecialization) -CONCRETE_RECORD(GlobalVariableRecord, APIRecord, RK_GlobalVariable) -CONCRETE_RECORD(GlobalVariableTemplateRecord, GlobalVariableRecord, - RK_GlobalVariableTemplate) -CONCRETE_RECORD(GlobalVariableTemplateSpecializationRecord, - GlobalVariableRecord, RK_GlobalVariableTemplateSpecialization) -CONCRETE_RECORD(GlobalVariableTemplatePartialSpecializationRecord, - GlobalVariableRecord, - RK_GlobalVariableTemplatePartialSpecialization) -CONCRETE_RECORD(EnumConstantRecord, APIRecord, RK_EnumConstant) -CONCRETE_RECORD(EnumRecord, APIRecord, RK_Enum) -ABSTRACT_RECORD(RecordFieldRecord, APIRecord) -ABSTRACT_RECORD(RecordRecord, APIRecord) -CONCRETE_RECORD(StructFieldRecord, RecordFieldRecord, RK_StructField) -CONCRETE_RECORD(StructRecord, APIRecord, RK_Struct) -CONCRETE_RECORD(UnionFieldRecord, RecordFieldRecord, RK_UnionField) -CONCRETE_RECORD(UnionRecord, APIRecord, RK_Union) -CONCRETE_RECORD(CXXFieldRecord, APIRecord, RK_CXXField) -CONCRETE_RECORD(CXXFieldTemplateRecord, CXXFieldRecord, RK_CXXFieldTemplate) -ABSTRACT_RECORD(CXXMethodRecord, APIRecord) -CONCRETE_RECORD(CXXConstructorRecord, CXXMethodRecord, RK_CXXConstructorMethod) -CONCRETE_RECORD(CXXDestructorRecord, CXXMethodRecord, RK_CXXDestructorMethod) -CONCRETE_RECORD(CXXStaticMethodRecord, CXXMethodRecord, RK_CXXStaticMethod) -CONCRETE_RECORD(CXXInstanceMethodRecord, CXXMethodRecord, RK_CXXInstanceMethod) -CONCRETE_RECORD(CXXMethodTemplateRecord, CXXMethodRecord, RK_CXXMethodTemplate) -CONCRETE_RECORD(CXXMethodTemplateSpecializationRecord, CXXMethodRecord, - RK_CXXMethodTemplateSpecialization) -ABSTRACT_RECORD(ObjCPropertyRecord, APIRecord) -CONCRETE_RECORD(ObjCInstancePropertyRecord, ObjCPropertyRecord, - RK_ObjCInstanceProperty) -CONCRETE_RECORD(ObjCClassPropertyRecord, ObjCPropertyRecord, - RK_ObjCClassProperty) -CONCRETE_RECORD(ObjCInstanceVariableRecord, APIRecord, RK_ObjCIvar) -ABSTRACT_RECORD(ObjCMethodRecord, APIRecord) -CONCRETE_RECORD(ObjCInstanceMethodRecord, ObjCMethodRecord, - RK_ObjCInstanceMethod) -CONCRETE_RECORD(ObjCClassMethodRecord, ObjCMethodRecord, RK_ObjCClassMethod) -CONCRETE_RECORD(StaticFieldRecord, CXXFieldRecord, RK_StaticField) -ABSTRACT_RECORD(ObjCContainerRecord, APIRecord) -CONCRETE_RECORD(CXXClassRecord, APIRecord, RK_CXXClass) -CONCRETE_RECORD(ClassTemplateRecord, CXXClassRecord, RK_ClassTemplate) -CONCRETE_RECORD(ClassTemplateSpecializationRecord, CXXClassRecord, - RK_ClassTemplateSpecialization) -CONCRETE_RECORD(ClassTemplatePartialSpecializationRecord, CXXClassRecord, - RK_ClassTemplatePartialSpecialization) -CONCRETE_RECORD(ConceptRecord, APIRecord, RK_Concept) -CONCRETE_RECORD(ObjCCategoryRecord, ObjCContainerRecord, RK_ObjCCategory) -CONCRETE_RECORD(ObjCInterfaceRecord, ObjCContainerRecord, RK_ObjCInterface) -CONCRETE_RECORD(ObjCProtocolRecord, ObjCContainerRecord, RK_ObjCProtocol) -CONCRETE_RECORD(MacroDefinitionRecord, APIRecord, RK_MacroDefinition) -CONCRETE_RECORD(TypedefRecord, APIRecord, RK_Typedef) - -#undef CONCRETE_RECORD -#undef ABSTRACT_RECORD -#undef RECORD - -#ifndef RECORD_CONTEXT -#define RECORD_CONTEXT(CLASS, KIND) -#endif - -RECORD_CONTEXT(NamespaceRecord, RK_Namespace) -RECORD_CONTEXT(EnumRecord, RK_Enum) -RECORD_CONTEXT(StructRecord, RK_Struct) -RECORD_CONTEXT(UnionRecord, RK_Union) -RECORD_CONTEXT(ObjCCategoryRecord, RK_ObjCCategory) -RECORD_CONTEXT(ObjCInterfaceRecord, RK_ObjCInterface) -RECORD_CONTEXT(ObjCProtocolRecord, RK_ObjCProtocol) -RECORD_CONTEXT(CXXClassRecord, RK_CXXClass) -RECORD_CONTEXT(ClassTemplateRecord, RK_ClassTemplate) -RECORD_CONTEXT(ClassTemplateSpecializationRecord, - RK_ClassTemplateSpecialization) -RECORD_CONTEXT(ClassTemplatePartialSpecializationRecord, - RK_ClassTemplatePartialSpecialization) - -#undef RECORD_CONTEXT diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index ec97c2e3e254c..b85a5d21d6121 100644 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -182,18 +182,6 @@ class DeclarationFragments { /// appending to chain up consecutive appends. DeclarationFragments &appendSpace(); - /// Append a text Fragment of a semicolon character. - /// - /// \returns a reference to the DeclarationFragments object itself after - /// appending to chain up consecutive appends. - DeclarationFragments &appendSemicolon(); - - /// Removes a trailing semicolon character if present. - /// - /// \returns a reference to the DeclarationFragments object itself after - /// removing to chain up consecutive operations. - DeclarationFragments &removeTrailingSemicolon(); - /// Get the string description of a FragmentKind \p Kind. static StringRef getFragmentKindString(FragmentKind Kind); @@ -206,14 +194,12 @@ class DeclarationFragments { static DeclarationFragments getStructureTypeFragment(const RecordDecl *Decl); private: - DeclarationFragments &appendUnduplicatedTextCharacter(char Character); std::vector Fragments; }; class AccessControl { public: AccessControl(std::string Access) : Access(Access) {} - AccessControl() : Access("public") {} const std::string &getAccess() const { return Access; } diff --git a/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h b/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h index 08210a7ee0595..ac4f391db5f14 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h @@ -17,8 +17,6 @@ #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/APIIgnoresList.h" -#include "clang/Frontend/CompilerInstance.h" -#include "llvm/Support/raw_ostream.h" namespace clang { @@ -31,8 +29,8 @@ class ExtractAPIActionBase { /// A representation of the APIs this action extracts. std::unique_ptr API; - /// A stream to the main output file of this action. - std::unique_ptr OS; + /// A stream to the output file of this action. + std::unique_ptr OS; /// The product this action is extracting API information for. std::string ProductName; @@ -48,7 +46,7 @@ class ExtractAPIActionBase { /// /// Use the serializer to generate output symbol graph files from /// the information gathered during the execution of Action. - void ImplEndSourceFileAction(CompilerInstance &CI); + void ImplEndSourceFileAction(); }; } // namespace clang diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h index 4cb866892b5d0..e1c3e41c750d4 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -14,23 +14,23 @@ #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H -#include "clang/AST/ASTContext.h" +#include "clang/AST/Availability.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/ExtractAPI/DeclarationFragments.h" +#include "llvm/ADT/FunctionExtras.h" + +#include "clang/AST/ASTContext.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/API.h" -#include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Casting.h" #include namespace clang { @@ -130,6 +130,12 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { void recordEnumConstants(EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants); + /// Collect API information for the record fields and associate with the + /// parent struct. + void recordRecordFields(RecordRecord *RecordRecord, + APIRecord::RecordKind FieldKind, + const RecordDecl::field_range Fields); + /// Collect API information for the Objective-C methods and associate with the /// parent container. void recordObjCMethods(ObjCContainerRecord *Container, @@ -166,7 +172,6 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { return *static_cast(this); } -protected: SmallVector getBases(const CXXRecordDecl *Decl) { // FIXME: store AccessSpecifier given by inheritance SmallVector Bases; @@ -177,54 +182,49 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor { SymbolReference BaseClass; if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) { BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString()); - if (auto *TTPTD = BaseSpecifier.getType() - ->getAs() - ->getDecl()) { - SmallString<128> USR; - index::generateUSRForDecl(TTPTD, USR); - BaseClass.USR = API.copyString(USR); - BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD)); - } + BaseClass.USR = API.recordUSR( + BaseSpecifier.getType()->getAs()->getDecl()); } else { - BaseClass = createSymbolReferenceForDecl( - *BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl()); + CXXRecordDecl *BaseClassDecl = + BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl(); + BaseClass.Name = BaseClassDecl->getName(); + BaseClass.USR = API.recordUSR(BaseClassDecl); } Bases.emplace_back(BaseClass); } return Bases; } - StringRef getOwningModuleName(const Decl &D) { - if (auto *OwningModule = D.getImportedOwningModule()) - return OwningModule->Name; + APIRecord *determineParentRecord(const DeclContext *Context) { + SmallString<128> ParentUSR; + if (Context->getDeclKind() == Decl::TranslationUnit) + return nullptr; - return {}; - } + index::generateUSRForDecl(dyn_cast(Context), ParentUSR); - SymbolReference createHierarchyInformationForDecl(const Decl &D) { - const auto *Context = cast_if_present(D.getDeclContext()); - - if (!Context || isa(Context)) - return {}; - - return createSymbolReferenceForDecl(*Context); + APIRecord *Parent = API.findRecordForUSR(ParentUSR); + return Parent; } +}; - SymbolReference createSymbolReferenceForDecl(const Decl &D) { - SmallString<128> USR; - index::generateUSRForDecl(&D, USR); - - APIRecord *Record = API.findRecordForUSR(USR); - if (Record) - return SymbolReference(Record); - - StringRef Name; - if (auto *ND = dyn_cast(&D)) - Name = ND->getName(); - - return API.createSymbolReference(Name, USR, getOwningModuleName(D)); +template +static void modifyRecords(const T &Records, const StringRef &Name) { + for (const auto &Record : Records) { + if (Name == Record.second.get()->Name) { + auto &DeclFragment = Record.second->Declaration; + DeclFragment.insert(DeclFragment.begin(), " ", + DeclarationFragments::FragmentKind::Text); + DeclFragment.insert(DeclFragment.begin(), "typedef", + DeclarationFragments::FragmentKind::Keyword, "", + nullptr); + DeclFragment.insert(--DeclFragment.end(), " { ... } ", + DeclarationFragments::FragmentKind::Text); + DeclFragment.insert(--DeclFragment.end(), Name, + DeclarationFragments::FragmentKind::Identifier); + break; + } } -}; +} template bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { @@ -251,8 +251,7 @@ bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -268,17 +267,21 @@ bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); if (Decl->isStaticDataMember()) { + SymbolReference Context; + // getDeclContext() should return a RecordDecl since we + // are currently handling a static data member. + auto *Record = cast(Decl->getDeclContext()); + Context.Name = Record->getName(); + Context.USR = API.recordUSR(Record); auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, Access, isInSystemHeader(Decl)); + API.addStaticField(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Linkage, Comment, Declaration, SubHeading, Context, + Access, isInSystemHeader(Decl)); } else // Add the global variable record to the API set. - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); + API.addGlobalVar(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Linkage, Comment, Declaration, SubHeading, + isInSystemHeader(Decl)); return true; } @@ -301,7 +304,7 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( return true; } - // Skip templated functions that aren't processed here. + // Skip templated functions. switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: case FunctionDecl::TK_DependentNonTemplate: @@ -318,8 +321,7 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -335,19 +337,18 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); if (Decl->getTemplateSpecializationInfo()) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + API.addGlobalFunctionTemplateSpecialization( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, + Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, isInSystemHeader(Decl)); else // Add the function record to the API set. - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, - DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading, - Signature, isInSystemHeader(Decl)); + API.addGlobalFunction( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, + Comment, DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), + SubHeading, Signature, isInSystemHeader(Decl)); return true; } @@ -367,8 +368,7 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { Name = QualifiedNameBuffer.str(); } - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -382,13 +382,13 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto *ER = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - isInSystemHeader(Decl)); + EnumRecord *EnumRecord = API.addEnum( + API.copyString(Name), USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Comment, Declaration, SubHeading, isInSystemHeader(Decl)); // Now collect information about the enumerators in this enum. - getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators()); + getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord, + Decl->enumerators()); return true; } @@ -476,13 +476,13 @@ bool ExtractAPIVisitorBase::WalkUpFromNamespaceDecl( template bool ExtractAPIVisitorBase::VisitNamespaceDecl( const NamespaceDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; if (Decl->isAnonymousNamespace()) return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); @@ -497,10 +497,10 @@ bool ExtractAPIVisitorBase::VisitNamespaceDecl( DeclarationFragmentsBuilder::getFragmentsForNamespace(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); + APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); + API.addNamespace(Parent, Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + Declaration, SubHeading, isInSystemHeader(Decl)); return true; } @@ -509,20 +509,14 @@ template bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; - - SmallString<128> QualifiedNameBuffer; // Collect symbol information. StringRef Name = Decl->getName(); if (Name.empty()) Name = getTypedefName(Decl); - if (Name.empty()) { - llvm::raw_svector_ostream OS(QualifiedNameBuffer); - Decl->printQualifiedName(OS); - Name = QualifiedNameBuffer.str(); - } + if (Name.empty()) + return true; - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -537,16 +531,21 @@ bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - if (Decl->isUnion()) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); - else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); + auto RecordKind = APIRecord::RK_Struct; + auto FieldRecordKind = APIRecord::RK_StructField; + + if (Decl->isUnion()) { + RecordKind = APIRecord::RK_Union; + FieldRecordKind = APIRecord::RK_UnionField; + } + + RecordRecord *RecordRecord = API.addRecord( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, RecordKind, isInSystemHeader(Decl)); + + // Now collect information about the fields in this struct. + getDerivedExtractAPIVisitor().recordRecordFields( + RecordRecord, FieldRecordKind, Decl->fields()); return true; } @@ -559,8 +558,7 @@ bool ExtractAPIVisitorBase::VisitCXXRecordDecl( return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -582,25 +580,24 @@ bool ExtractAPIVisitorBase::VisitCXXRecordDecl( Kind = APIRecord::RecordKind::RK_CXXClass; auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - CXXClassRecord *Record; + APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); + CXXClassRecord *CXXClassRecord; if (Decl->getDescribedClassTemplate()) { // Inject template fragments before class fragments. Declaration.insert( Declaration.begin(), DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate( Decl->getDescribedClassTemplate())); - Record = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Template(Decl->getDescribedClassTemplate()), Access, - isInSystemHeader(Decl)); + CXXClassRecord = API.addClassTemplate( + Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Template(Decl->getDescribedClassTemplate()), + Access, isInSystemHeader(Decl)); } else - Record = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Kind, Access, isInSystemHeader(Decl)); + CXXClassRecord = API.addCXXClass( + Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Kind, Access, isInSystemHeader(Decl)); - Record->Bases = getBases(Decl); + CXXClassRecord->Bases = getBases(Decl); return true; } @@ -617,8 +614,7 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( if (isa(Decl) || isa(Decl)) return true; - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -631,10 +627,14 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); auto Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); - if (FunctionTemplateDecl *TemplateDecl = - Decl->getDescribedFunctionTemplate()) { - API.createRecord( - USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); + auto *Parent = API.findRecordForUSR(ParentUSR); + if (Decl->isTemplated()) { + FunctionTemplateDecl *TemplateDecl = Decl->getDescribedFunctionTemplate(); + API.addCXXMethodTemplate( + API.findRecordForUSR(ParentUSR), Decl->getName(), USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate( TemplateDecl), @@ -642,27 +642,27 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( DeclarationFragmentsBuilder::getAccessControl(TemplateDecl), Template(TemplateDecl), isInSystemHeader(Decl)); } else if (Decl->getTemplateSpecializationInfo()) - API.createRecord( - USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, + API.addCXXMethodTemplateSpec( + Parent, Decl->getName(), USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isOverloadedOperator()) - API.createRecord( - USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), - Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + API.addCXXInstanceMethod( + Parent, API.copyString(Decl->getNameAsString()), USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isStatic()) - API.createRecord( - USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, + API.addCXXStaticMethod( + Parent, Decl->getName(), USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else - API.createRecord( - USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, + API.addCXXInstanceMethod( + Parent, Decl->getName(), USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); @@ -673,13 +673,9 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( template bool ExtractAPIVisitorBase::VisitCXXConstructorDecl( const CXXConstructorDecl *Decl) { - if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || - Decl->isImplicit()) - return true; - auto Name = Decl->getNameAsString(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef Name = API.copyString(Decl->getNameAsString()); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -696,24 +692,22 @@ bool ExtractAPIVisitorBase::VisitCXXConstructorDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - Signature, Access, isInSystemHeader(Decl)); + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); + API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Signature, Access, + isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitCXXDestructorDecl( const CXXDestructorDecl *Decl) { - if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || - Decl->isImplicit()) - return true; - auto Name = Decl->getNameAsString(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef Name = API.copyString(Decl->getNameAsString()); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -730,10 +724,13 @@ bool ExtractAPIVisitorBase::VisitCXXDestructorDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - Signature, Access, isInSystemHeader(Decl)); + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); + API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Signature, Access, + isInSystemHeader(Decl)); return true; } @@ -743,8 +740,7 @@ bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -756,10 +752,9 @@ bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForConcept(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - Template(Decl), isInSystemHeader(Decl)); + API.addConcept(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Comment, Declaration, SubHeading, Template(Decl), + isInSystemHeader(Decl)); return true; } @@ -770,8 +765,7 @@ bool ExtractAPIVisitorBase::VisitClassTemplateSpecializationDecl( return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -785,13 +779,14 @@ bool ExtractAPIVisitorBase::VisitClassTemplateSpecializationDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto *CTSR = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); + auto *ClassTemplateSpecializationRecord = API.addClassTemplateSpecialization( + Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), isInSystemHeader(Decl)); - CTSR->Bases = getBases(Decl); + ClassTemplateSpecializationRecord->Bases = getBases(Decl); return true; } @@ -804,8 +799,7 @@ bool ExtractAPIVisitorBase:: return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -817,13 +811,15 @@ bool ExtractAPIVisitorBase:: getFragmentsForClassTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto *CTPSR = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - Template(Decl), DeclarationFragmentsBuilder::getAccessControl(Decl), - isInSystemHeader(Decl)); + APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); + auto *ClassTemplatePartialSpecRecord = + API.addClassTemplatePartialSpecialization( + Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Comment, Declaration, SubHeading, Template(Decl), + DeclarationFragmentsBuilder::getAccessControl(Decl), + isInSystemHeader(Decl)); - CTPSR->Bases = getBases(Decl); + ClassTemplatePartialSpecRecord->Bases = getBases(Decl); return true; } @@ -836,8 +832,7 @@ bool ExtractAPIVisitorBase::VisitVarTemplateDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -858,17 +853,20 @@ bool ExtractAPIVisitorBase::VisitVarTemplateDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); if (Decl->getDeclContext()->getDeclKind() == Decl::CXXRecord) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), - Template(Decl), isInSystemHeader(Decl)); + API.addCXXFieldTemplate(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, + DeclarationFragmentsBuilder::getAccessControl(Decl), + Template(Decl), isInSystemHeader(Decl)); else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, Template(Decl), isInSystemHeader(Decl)); + API.addGlobalVariableTemplate(Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), + Linkage, Comment, Declaration, SubHeading, + Template(Decl), isInSystemHeader(Decl)); return true; } @@ -880,8 +878,7 @@ bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -897,10 +894,9 @@ bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); + API.addGlobalVariableTemplateSpecialization( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + Declaration, SubHeading, isInSystemHeader(Decl)); return true; } @@ -912,8 +908,7 @@ bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -928,10 +923,9 @@ bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( getFragmentsForVarTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, Template(Decl), isInSystemHeader(Decl)); + API.addGlobalVariableTemplatePartialSpecialization( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + Declaration, SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } @@ -945,8 +939,7 @@ bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -961,9 +954,8 @@ bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature( Decl->getTemplatedDecl()); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + API.addGlobalFunctionTemplate( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl), SubHeading, Signature, Template(Decl), isInSystemHeader(Decl)); @@ -978,8 +970,7 @@ bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -997,23 +988,24 @@ bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( // Collect super class information. SymbolReference SuperClass; - if (const auto *SuperClassDecl = Decl->getSuperClass()) - SuperClass = createSymbolReferenceForDecl(*SuperClassDecl); + if (const auto *SuperClassDecl = Decl->getSuperClass()) { + SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); + SuperClass.USR = API.recordUSR(SuperClassDecl); + } - auto *InterfaceRecord = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, - SubHeading, SuperClass, isInSystemHeader(Decl)); + ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + Declaration, SubHeading, SuperClass, isInSystemHeader(Decl)); // Record all methods (selectors). This doesn't include automatically // synthesized property methods. - getDerivedExtractAPIVisitor().recordObjCMethods(InterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(InterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCInstanceVariables(InterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); - getDerivedExtractAPIVisitor().recordObjCProtocols(InterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); return true; @@ -1027,8 +1019,7 @@ bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1043,15 +1034,15 @@ bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto *ProtoRecord = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - isInSystemHeader(Decl)); + ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, isInSystemHeader(Decl)); - getDerivedExtractAPIVisitor().recordObjCMethods(ProtoRecord, Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(ProtoRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord, + Decl->methods()); + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCProtocols(ProtoRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); return true; @@ -1070,36 +1061,25 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; - StringRef Name = Decl->getName(); - - // If the underlying type was defined as part of the typedef modify it's - // fragments directly and pretend the typedef doesn't exist. - if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) { - if (TagDecl->getName() == Decl->getName() && - TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition()) { - SmallString<128> TagUSR; - index::generateUSRForDecl(TagDecl, TagUSR); - if (auto *Record = API.findRecordForUSR(TagUSR)) { - DeclarationFragments LeadingFragments; - LeadingFragments.append("typedef", - DeclarationFragments::FragmentKind::Keyword, "", - nullptr); - LeadingFragments.appendSpace(); - Record->Declaration.removeTrailingSemicolon() - .insert(Record->Declaration.begin(), std::move(LeadingFragments)) - .append(" { ... } ", DeclarationFragments::FragmentKind::Text) - .append(Name, DeclarationFragments::FragmentKind::Identifier) - .appendSemicolon(); - - return true; + // Add the notion of typedef for tag type (struct or enum) of the same name. + if (const ElaboratedType *ET = + dyn_cast(Decl->getUnderlyingType())) { + if (const TagType *TagTy = dyn_cast(ET->desugar())) { + if (Decl->getName() == TagTy->getDecl()->getName()) { + if (isa(TagTy->getDecl())) { + modifyRecords(API.getRecords(), Decl->getName()); + } + if (TagTy->getDecl()->isEnum()) { + modifyRecords(API.getEnums(), Decl->getName()); + } } } } PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) @@ -1111,12 +1091,11 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, API); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), - DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, - isInSystemHeader(Decl)); + API.addTypedef(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), + Comment, + DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), + DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, + isInSystemHeader(Decl)); return true; } @@ -1128,8 +1107,7 @@ bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( return true; StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1144,20 +1122,29 @@ bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( DeclarationFragmentsBuilder::getSubHeading(Decl); const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); - SymbolReference Interface = createSymbolReferenceForDecl(*InterfaceDecl); + SymbolReference Interface(InterfaceDecl->getName(), + API.recordUSR(InterfaceDecl)); + + bool IsFromExternalModule = true; + for (const auto &Interface : API.getObjCInterfaces()) { + if (InterfaceDecl->getName() == Interface.second.get()->Name) { + IsFromExternalModule = false; + break; + } + } - auto *CategoryRecord = API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, - Interface, isInSystemHeader(Decl)); + ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Interface, isInSystemHeader(Decl), + IsFromExternalModule); - getDerivedExtractAPIVisitor().recordObjCMethods(CategoryRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord, Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(CategoryRecord, + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCInstanceVariables(CategoryRecord, + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars()); - getDerivedExtractAPIVisitor().recordObjCProtocols(CategoryRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord, Decl->protocols()); return true; @@ -1171,8 +1158,7 @@ void ExtractAPIVisitorBase::recordEnumConstants( for (const auto *Constant : Constants) { // Collect symbol information. StringRef Name = Constant->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Constant, USR); + StringRef USR = API.recordUSR(Constant); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Constant->getLocation()); DocComment Comment; @@ -1187,26 +1173,51 @@ void ExtractAPIVisitorBase::recordEnumConstants( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Constant); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Constant), Loc, - AvailabilityInfo::createFromDecl(Constant), Comment, Declaration, - SubHeading, isInSystemHeader(Constant)); + API.addEnumConstant(EnumRecord, Name, USR, Loc, + AvailabilityInfo::createFromDecl(Constant), Comment, + Declaration, SubHeading, isInSystemHeader(Constant)); + } +} + +/// Collect API information for the struct fields and associate with the +/// parent struct. +template +void ExtractAPIVisitorBase::recordRecordFields( + RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind, + 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()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(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.addRecordField( + RecordRecord, Name, USR, Loc, AvailabilityInfo::createFromDecl(Field), + Comment, Declaration, SubHeading, FieldKind, isInSystemHeader(Field)); } } template bool ExtractAPIVisitorBase::VisitFieldDecl(const FieldDecl *Decl) { - // ObjCIvars are handled separately - if (isa(Decl) || isa(Decl)) + if (Decl->getDeclContext()->getDeclKind() == Decl::Record) return true; - - if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + if (isa(Decl)) return true; - // Collect symbol information. StringRef Name = Decl->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1220,40 +1231,22 @@ bool ExtractAPIVisitorBase::VisitFieldDecl(const FieldDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForField(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); + AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - if (isa(Decl->getDeclContext())) { - AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Access, isInSystemHeader(Decl)); - } else if (auto *RD = dyn_cast(Decl->getDeclContext())) { - if (RD->isUnion()) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); - else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, isInSystemHeader(Decl)); - } - + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); + API.addCXXField(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Access, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitCXXConversionDecl( const CXXConversionDecl *Decl) { - if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || - Decl->isImplicit()) - return true; - - auto Name = Decl->getNameAsString(); - SmallString<128> USR; - index::generateUSRForDecl(Decl, USR); + StringRef Name = API.copyString(Decl->getNameAsString()); + StringRef USR = API.recordUSR(Decl); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1271,17 +1264,19 @@ bool ExtractAPIVisitorBase::VisitCXXConversionDecl( DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); + SmallString<128> ParentUSR; + index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), + ParentUSR); if (Decl->isStatic()) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Signature, Access, isInSystemHeader(Decl)); + API.addCXXStaticMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Signature, Access, + isInSystemHeader(Decl)); else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Decl), Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Signature, Access, isInSystemHeader(Decl)); - + API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + Declaration, SubHeading, Signature, Access, + isInSystemHeader(Decl)); return true; } @@ -1296,9 +1291,8 @@ void ExtractAPIVisitorBase::recordObjCMethods( if (Method->isPropertyAccessor()) continue; - auto Name = Method->getSelector().getAsString(); - SmallString<128> USR; - index::generateUSRForDecl(Method, USR); + StringRef Name = API.copyString(Method->getSelector().getAsString()); + StringRef USR = API.recordUSR(Method); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Method->getLocation()); DocComment Comment; @@ -1315,16 +1309,10 @@ void ExtractAPIVisitorBase::recordObjCMethods( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Method); - if (Method->isInstanceMethod()) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Method), Loc, - AvailabilityInfo::createFromDecl(Method), Comment, Declaration, - SubHeading, Signature, isInSystemHeader(Method)); - else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Method), Loc, - AvailabilityInfo::createFromDecl(Method), Comment, Declaration, - SubHeading, Signature, isInSystemHeader(Method)); + API.addObjCMethod(Container, Name, USR, Loc, + AvailabilityInfo::createFromDecl(Method), Comment, + Declaration, SubHeading, Signature, + Method->isInstanceMethod(), isInSystemHeader(Method)); } } @@ -1334,8 +1322,7 @@ void ExtractAPIVisitorBase::recordObjCProperties( const ObjCContainerDecl::prop_range Properties) { for (const auto *Property : Properties) { StringRef Name = Property->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Property, USR); + StringRef USR = API.recordUSR(Property); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Property->getLocation()); DocComment Comment; @@ -1350,8 +1337,10 @@ void ExtractAPIVisitorBase::recordObjCProperties( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Property); - auto GetterName = Property->getGetterName().getAsString(); - auto SetterName = Property->getSetterName().getAsString(); + StringRef GetterName = + API.copyString(Property->getGetterName().getAsString()); + StringRef SetterName = + API.copyString(Property->getSetterName().getAsString()); // Get the attributes for property. unsigned Attributes = ObjCPropertyRecord::NoAttr; @@ -1359,22 +1348,14 @@ void ExtractAPIVisitorBase::recordObjCProperties( ObjCPropertyAttribute::kind_readonly) Attributes |= ObjCPropertyRecord::ReadOnly; - if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Property), Loc, - AvailabilityInfo::createFromDecl(Property), Comment, Declaration, - SubHeading, - static_cast(Attributes), - GetterName, SetterName, Property->isOptional(), - isInSystemHeader(Property)); - else - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Property), Loc, - AvailabilityInfo::createFromDecl(Property), Comment, Declaration, - SubHeading, - static_cast(Attributes), - GetterName, SetterName, Property->isOptional(), - isInSystemHeader(Property)); + API.addObjCProperty( + Container, Name, USR, Loc, AvailabilityInfo::createFromDecl(Property), + Comment, Declaration, SubHeading, + static_cast(Attributes), GetterName, + SetterName, Property->isOptional(), + !(Property->getPropertyAttributes() & + ObjCPropertyAttribute::kind_class), + isInSystemHeader(Property)); } } @@ -1386,9 +1367,7 @@ void ExtractAPIVisitorBase::recordObjCInstanceVariables( Ivars) { for (const auto *Ivar : Ivars) { StringRef Name = Ivar->getName(); - SmallString<128> USR; - index::generateUSRForDecl(Ivar, USR); - + StringRef USR = API.recordUSR(Ivar); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); DocComment Comment; @@ -1403,10 +1382,12 @@ void ExtractAPIVisitorBase::recordObjCInstanceVariables( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Ivar); - API.createRecord( - USR, Name, createHierarchyInformationForDecl(*Ivar), Loc, - AvailabilityInfo::createFromDecl(Ivar), Comment, Declaration, - SubHeading, isInSystemHeader(Ivar)); + ObjCInstanceVariableRecord::AccessControl Access = + Ivar->getCanonicalAccessControl(); + + API.addObjCInstanceVariable( + Container, Name, USR, Loc, AvailabilityInfo::createFromDecl(Ivar), + Comment, Declaration, SubHeading, Access, isInSystemHeader(Ivar)); } } @@ -1415,7 +1396,8 @@ void ExtractAPIVisitorBase::recordObjCProtocols( ObjCContainerRecord *Container, ObjCInterfaceDecl::protocol_range Protocols) { for (const auto *Protocol : Protocols) - Container->Protocols.emplace_back(createSymbolReferenceForDecl(*Protocol)); + Container->Protocols.emplace_back(Protocol->getName(), + API.recordUSR(Protocol)); } } // namespace impl diff --git a/clang/include/clang/ExtractAPI/FrontendActions.h b/clang/include/clang/ExtractAPI/FrontendActions.h index 08045a30823db..c67864aac9af9 100644 --- a/clang/include/clang/ExtractAPI/FrontendActions.h +++ b/clang/include/clang/ExtractAPI/FrontendActions.h @@ -49,6 +49,9 @@ class ExtractAPIAction : public ASTFrontendAction, void EndSourceFileAction() override; static StringRef getInputBufferName() { return ""; } + + static std::unique_ptr + CreateOutputFile(CompilerInstance &CI, StringRef InFile); }; /// Wrap ExtractAPIAction on top of a pre-existing action @@ -82,6 +85,9 @@ class WrappingExtractAPIAction : public WrapperFrontendAction, /// actions. This is the place where all the gathered symbol graph /// information is emited. void EndSourceFileAction() override; + + static std::unique_ptr + CreateOutputFile(CompilerInstance &CI, StringRef InFile); }; } // namespace clang diff --git a/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h b/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h deleted file mode 100644 index 07f14f349f3dd..0000000000000 --- a/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h +++ /dev/null @@ -1,172 +0,0 @@ -//===- ExtractAPI/Serialization/APISetVisitor.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 APISetVisitor interface. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H -#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H - -#include "clang/ExtractAPI/API.h" - -namespace clang { -namespace extractapi { - -// A helper macro to implement short-circuiting when recursing. It -// invokes CALL_EXPR, which must be a method call, on the derived -// object (s.t. a user of RecursiveASTVisitor can override the method -// in CALL_EXPR). -#define TRY_TO(CALL_EXPR) \ - do { \ - if (!getDerived()->CALL_EXPR) \ - return false; \ - } while (false) - -/// The base interface of visitors for API information, the interface and usage -/// is almost identical to RecurisveASTVistor. This class performs three -/// distinct tasks: -/// 1. traverse the APISet (i.e. go to every record); -/// 2. at a given record, walk up the class hierarchy starting from the record's -/// dynamic type until APIRecord is reached. -/// 3. given a (record, class) combination where 'class' is some base class of -/// the dynamic type of 'record', call a user-overridable function to actually -/// visit the record. -/// -/// These tasks are done by three groups of methods, respectively: -/// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for -/// traversing the records starting from x. This method simply forwards to -/// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls -/// walkUpFromFoo(x) and then recursively visits the child records of x. -/// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of -/// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent -/// class of Foo (unless Foo has no parent) and then calls visitFoo(x). -/// 3. visitFoo(Foo *x) does task #3. -/// -/// These three method groups are tiered (traverse* > walkUpFrom* > -/// visit*). A method (e.g. traverse*) may call methods from the same -/// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*). -/// It may not call methods from a higher tier. -/// -/// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar -/// is Foo's super class) before calling visitFoo(), the result is -/// that the visit*() methods for a given record are called in the -/// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the -/// order will be visitRecord(), visitObjCPropertyRecord(), and then -/// visitObjCInstancePropertyRecord()). -/// -/// This scheme guarantees that all visit*() calls for the same record -/// are grouped together. In other words, visit*() methods for different -/// records are never interleaved. -/// -/// Clients of this visitor should subclass the visitor (providing -/// themselves as the template argument, using the curiously recurring -/// template pattern) and override any of the traverse*, walkUpFrom*, -/// and visit* methods for records where the visitor should customize -/// behavior. Most users only need to override visit*. Advanced -/// users may override traverse* and walkUpFrom* to implement custom -/// traversal strategies. Returning false from one of these overridden -/// functions will abort the entire traversal. -template class APISetVisitor { -public: - bool traverseAPISet() { - for (const APIRecord *TLR : API.getTopLevelRecords()) { - TRY_TO(traverseAPIRecord(TLR)); - } - return true; - } - - bool traverseAPIRecord(const APIRecord *Record); - bool walkUpFromAPIRecord(const APIRecord *Record) { - TRY_TO(visitAPIRecord(Record)); - return true; - } - bool visitAPIRecord(const APIRecord *Record) { return true; } - -#define GENERATE_TRAVERSE_METHOD(CLASS, BASE) \ - bool traverse##CLASS(const CLASS *Record) { \ - TRY_TO(walkUpFrom##CLASS(Record)); \ - TRY_TO(traverseRecordContext(dyn_cast(Record))); \ - return true; \ - } - -#define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) \ - bool walkUpFrom##CLASS(const CLASS *Record) { \ - TRY_TO(walkUpFrom##BASE(Record)); \ - TRY_TO(visit##CLASS(Record)); \ - return true; \ - } \ - bool visit##CLASS(const CLASS *Record) { return true; } - -#define CONCRETE_RECORD(CLASS, BASE, KIND) \ - GENERATE_TRAVERSE_METHOD(CLASS, BASE) \ - GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) - -#define ABSTRACT_RECORD(CLASS, BASE) \ - GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) - -#include "../APIRecords.inc" - -#undef GENERATE_WALKUP_AND_VISIT_METHODS -#undef GENERATE_TRAVERSE_METHOD - - bool traverseRecordContext(const RecordContext *); - -protected: - const APISet &API; - -public: - APISetVisitor() = delete; - APISetVisitor(const APISetVisitor &) = delete; - APISetVisitor(APISetVisitor &&) = delete; - APISetVisitor &operator=(const APISetVisitor &) = delete; - APISetVisitor &operator=(APISetVisitor &&) = delete; - -protected: - APISetVisitor(const APISet &API) : API(API) {} - ~APISetVisitor() = default; - - Derived *getDerived() { return static_cast(this); }; -}; - -template -bool APISetVisitor::traverseRecordContext( - const RecordContext *Context) { - if (!Context) - return true; - - for (auto *Child : Context->records()) - TRY_TO(traverseAPIRecord(Child)); - - return true; -} - -template -bool APISetVisitor::traverseAPIRecord(const APIRecord *Record) { - switch (Record->getKind()) { -#define CONCRETE_RECORD(CLASS, BASE, KIND) \ - case APIRecord::KIND: { \ - TRY_TO(traverse##CLASS(static_cast(Record))); \ - break; \ - } -#include "../APIRecords.inc" - case APIRecord::RK_Unknown: { - TRY_TO(walkUpFromAPIRecord(static_cast(Record))); - break; - } - default: - llvm_unreachable("API Record with uninstantiable kind"); - } - return true; -} - -} // namespace extractapi -} // namespace clang - -#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h new file mode 100644 index 0000000000000..f0629a9ad56b0 --- /dev/null +++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h @@ -0,0 +1,314 @@ +//===- 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 APISetVisitor interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H +#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H + +#include "clang/ExtractAPI/API.h" + +namespace clang { +namespace extractapi { + +/// The base interface of visitors for API information. +template class APISetVisitor { +public: + void traverseAPISet() { + getDerived()->traverseNamespaces(); + + getDerived()->traverseGlobalVariableRecords(); + + getDerived()->traverseGlobalFunctionRecords(); + + getDerived()->traverseEnumRecords(); + + getDerived()->traverseStaticFieldRecords(); + + getDerived()->traverseCXXClassRecords(); + + getDerived()->traverseClassTemplateRecords(); + + getDerived()->traverseClassTemplateSpecializationRecords(); + + getDerived()->traverseClassTemplatePartialSpecializationRecords(); + + getDerived()->traverseCXXInstanceMethods(); + + getDerived()->traverseCXXStaticMethods(); + + getDerived()->traverseCXXMethodTemplates(); + + getDerived()->traverseCXXMethodTemplateSpecializations(); + + getDerived()->traverseCXXFields(); + + getDerived()->traverseCXXFieldTemplates(); + + getDerived()->traverseConcepts(); + + getDerived()->traverseGlobalVariableTemplateRecords(); + + getDerived()->traverseGlobalVariableTemplateSpecializationRecords(); + + getDerived()->traverseGlobalVariableTemplatePartialSpecializationRecords(); + + getDerived()->traverseGlobalFunctionTemplateRecords(); + + getDerived()->traverseGlobalFunctionTemplateSpecializationRecords(); + + getDerived()->traverseRecordRecords(); + + getDerived()->traverseObjCInterfaces(); + + getDerived()->traverseObjCProtocols(); + + getDerived()->traverseObjCCategories(); + + getDerived()->traverseMacroDefinitionRecords(); + + getDerived()->traverseTypedefRecords(); + } + + void traverseNamespaces() { + for (const auto &Namespace : API.getNamespaces()) + getDerived()->visitNamespaceRecord(*Namespace.second); + } + + void traverseGlobalFunctionRecords() { + for (const auto &GlobalFunction : API.getGlobalFunctions()) + getDerived()->visitGlobalFunctionRecord(*GlobalFunction.second); + } + + void traverseGlobalVariableRecords() { + for (const auto &GlobalVariable : API.getGlobalVariables()) + getDerived()->visitGlobalVariableRecord(*GlobalVariable.second); + } + + void traverseEnumRecords() { + for (const auto &Enum : API.getEnums()) + getDerived()->visitEnumRecord(*Enum.second); + } + + void traverseRecordRecords() { + for (const auto &Record : API.getRecords()) + getDerived()->visitRecordRecord(*Record.second); + } + + void traverseStaticFieldRecords() { + for (const auto &StaticField : API.getStaticFields()) + getDerived()->visitStaticFieldRecord(*StaticField.second); + } + + void traverseCXXClassRecords() { + for (const auto &Class : API.getCXXClasses()) + getDerived()->visitCXXClassRecord(*Class.second); + } + + void traverseCXXMethodTemplates() { + for (const auto &MethodTemplate : API.getCXXMethodTemplates()) + getDerived()->visitMethodTemplateRecord(*MethodTemplate.second); + } + + void traverseCXXMethodTemplateSpecializations() { + for (const auto &MethodTemplateSpecialization : + API.getCXXMethodTemplateSpecializations()) + getDerived()->visitMethodTemplateSpecializationRecord( + *MethodTemplateSpecialization.second); + } + + void traverseClassTemplateRecords() { + for (const auto &ClassTemplate : API.getClassTemplates()) + getDerived()->visitClassTemplateRecord(*ClassTemplate.second); + } + + void traverseClassTemplateSpecializationRecords() { + for (const auto &ClassTemplateSpecialization : + API.getClassTemplateSpecializations()) + getDerived()->visitClassTemplateSpecializationRecord( + *ClassTemplateSpecialization.second); + } + + void traverseClassTemplatePartialSpecializationRecords() { + for (const auto &ClassTemplatePartialSpecialization : + API.getClassTemplatePartialSpecializations()) + getDerived()->visitClassTemplatePartialSpecializationRecord( + *ClassTemplatePartialSpecialization.second); + } + + void traverseCXXInstanceMethods() { + for (const auto &InstanceMethod : API.getCXXInstanceMethods()) + getDerived()->visitCXXInstanceMethodRecord(*InstanceMethod.second); + } + + void traverseCXXStaticMethods() { + for (const auto &InstanceMethod : API.getCXXStaticMethods()) + getDerived()->visitCXXStaticMethodRecord(*InstanceMethod.second); + } + + void traverseCXXFields() { + for (const auto &CXXField : API.getCXXFields()) + getDerived()->visitCXXFieldRecord(*CXXField.second); + } + + void traverseCXXFieldTemplates() { + for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates()) + getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second); + } + + void traverseGlobalVariableTemplateRecords() { + for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates()) + getDerived()->visitGlobalVariableTemplateRecord( + *GlobalVariableTemplate.second); + } + + void traverseGlobalVariableTemplateSpecializationRecords() { + for (const auto &GlobalVariableTemplateSpecialization : + API.getGlobalVariableTemplateSpecializations()) + getDerived()->visitGlobalVariableTemplateSpecializationRecord( + *GlobalVariableTemplateSpecialization.second); + } + + void traverseGlobalVariableTemplatePartialSpecializationRecords() { + for (const auto &GlobalVariableTemplatePartialSpecialization : + API.getGlobalVariableTemplatePartialSpecializations()) + getDerived()->visitGlobalVariableTemplatePartialSpecializationRecord( + *GlobalVariableTemplatePartialSpecialization.second); + } + + void traverseGlobalFunctionTemplateRecords() { + for (const auto &GlobalFunctionTemplate : API.getGlobalFunctionTemplates()) + getDerived()->visitGlobalFunctionTemplateRecord( + *GlobalFunctionTemplate.second); + } + + void traverseGlobalFunctionTemplateSpecializationRecords() { + for (const auto &GlobalFunctionTemplateSpecialization : + API.getGlobalFunctionTemplateSpecializations()) + getDerived()->visitGlobalFunctionTemplateSpecializationRecord( + *GlobalFunctionTemplateSpecialization.second); + } + + void traverseConcepts() { + for (const auto &Concept : API.getConcepts()) + getDerived()->visitConceptRecord(*Concept.second); + } + + void traverseObjCInterfaces() { + for (const auto &Interface : API.getObjCInterfaces()) + getDerived()->visitObjCContainerRecord(*Interface.second); + } + + void traverseObjCProtocols() { + for (const auto &Protocol : API.getObjCProtocols()) + getDerived()->visitObjCContainerRecord(*Protocol.second); + } + + void traverseObjCCategories() { + for (const auto &Category : API.getObjCCategories()) + getDerived()->visitObjCCategoryRecord(*Category.second); + } + + void traverseMacroDefinitionRecords() { + for (const auto &Macro : API.getMacros()) + getDerived()->visitMacroDefinitionRecord(*Macro.second); + } + + void traverseTypedefRecords() { + for (const auto &Typedef : API.getTypedefs()) + getDerived()->visitTypedefRecord(*Typedef.second); + } + + void visitNamespaceRecord(const NamespaceRecord &Record){}; + + /// Visit a global function record. + void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record){}; + + /// Visit a global variable record. + void visitGlobalVariableRecord(const GlobalVariableRecord &Record){}; + + /// Visit an enum record. + void visitEnumRecord(const EnumRecord &Record){}; + + /// Visit a record record. + void visitRecordRecord(const RecordRecord &Record){}; + + void visitStaticFieldRecord(const StaticFieldRecord &Record){}; + + void visitCXXClassRecord(const CXXClassRecord &Record){}; + + void visitClassTemplateRecord(const ClassTemplateRecord &Record){}; + + void visitClassTemplateSpecializationRecord( + const ClassTemplateSpecializationRecord &Record){}; + + void visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord &Record){}; + + void visitCXXInstanceRecord(const CXXInstanceMethodRecord &Record){}; + + void visitCXXStaticRecord(const CXXStaticMethodRecord &Record){}; + + void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record){}; + + void visitMethodTemplateSpecializationRecord( + const CXXMethodTemplateSpecializationRecord &Record){}; + + void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record){}; + + void visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord &Record) {} + + void visitGlobalVariableTemplateSpecializationRecord( + const GlobalVariableTemplateSpecializationRecord &Record){}; + + void visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord &Record){}; + + void visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord &Record){}; + + void visitGlobalFunctionTemplateSpecializationRecord( + const GlobalFunctionTemplateSpecializationRecord &Record){}; + + /// Visit an Objective-C container record. + void visitObjCContainerRecord(const ObjCContainerRecord &Record){}; + + /// Visit an Objective-C category record. + void visitObjCCategoryRecord(const ObjCCategoryRecord &Record){}; + + /// Visit a macro definition record. + void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record){}; + + /// Visit a typedef record. + void visitTypedefRecord(const TypedefRecord &Record){}; + +protected: + const APISet &API; + +public: + APISetVisitor() = delete; + APISetVisitor(const APISetVisitor &) = delete; + APISetVisitor(APISetVisitor &&) = delete; + APISetVisitor &operator=(const APISetVisitor &) = delete; + APISetVisitor &operator=(APISetVisitor &&) = delete; + +protected: + APISetVisitor(const APISet &API) : API(API) {} + ~APISetVisitor() = default; + + Derived *getDerived() { return static_cast(this); }; +}; + +} // 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 index 724b087f7aea9..4249ac405fd26 100644 --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -17,17 +17,11 @@ #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H -#include "clang/Basic/Module.h" #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/APIIgnoresList.h" -#include "clang/ExtractAPI/Serialization/APISetVisitor.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallString.h" +#include "clang/ExtractAPI/Serialization/SerializerBase.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/JSON.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" @@ -41,30 +35,7 @@ using namespace llvm::json; /// Common options to customize the visitor output. struct SymbolGraphSerializerOption { /// Do not include unnecessary whitespaces to save space. - bool Compact = true; - bool EmitSymbolLabelsForTesting = false; -}; - -/// A representation of the contents of a given module symbol graph -struct ExtendedModule { - ExtendedModule() = default; - ExtendedModule(ExtendedModule &&EM) = default; - ExtendedModule &operator=(ExtendedModule &&EM) = default; - // Copies are expensive so disable them. - ExtendedModule(const ExtendedModule &EM) = delete; - ExtendedModule &operator=(const ExtendedModule &EM) = delete; - - /// Add a symbol to the module, do not store the resulting pointer or use it - /// across insertions. - Object *addSymbol(Object &&Symbol); - - void addRelationship(Object &&Relationship); - - /// A JSON array of formatted symbols from an \c APISet. - Array Symbols; - - /// A JSON array of formatted symbol relationships from an \c APISet. - Array Relationships; + bool Compact; }; /// The visitor that organizes API information in the Symbol Graph format. @@ -73,54 +44,28 @@ struct ExtendedModule { /// models an API set as a directed graph, where nodes are symbol declarations, /// and edges are relationships between the connected symbols. class SymbolGraphSerializer : public APISetVisitor { -private: - using Base = APISetVisitor; - /// The main symbol graph that contains symbols that are either top-level or a - /// are related to symbols defined in this product/module. - ExtendedModule MainModule; + /// A JSON array of formatted symbols in \c APISet. + Array Symbols; - /// Additional symbol graphs that contain symbols that are related to symbols - /// defined in another product/module. The key of this map is the module name - /// of the extended module. - llvm::StringMap ExtendedModules; + /// 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; - /// Indicates whether to take into account the extended module. This is only + /// Indicates whether child symbols should be visited. This is mainly /// useful for \c serializeSingleSymbolSGF. - bool ForceEmitToMainModule; + bool ShouldRecurse; - // Stores the references required to construct path components for the - // currently visited APIRecord. - llvm::SmallVector Hierarchy; - - /// The list of symbols to ignore. +public: + /// Serialize the APIs in \c APISet in the Symbol Graph format. /// - /// Note: This should be consulted before emitting a symbol. - const APIIgnoresList &IgnoresList; - - const bool EmitSymbolLabelsForTesting = false; - - /// The object instantiated by the last call to serializeAPIRecord. - Object *CurrentSymbol = nullptr; + /// \returns a JSON object that contains the root of the formatted + /// Symbol Graph. + Object serialize(); - /// The module to which \p CurrentSymbol belongs too. - ExtendedModule *ModuleForCurrentSymbol = nullptr; - -public: - static void - serializeMainSymbolGraph(raw_ostream &OS, const APISet &API, - const APIIgnoresList &IgnoresList, - SymbolGraphSerializerOption Options = {}); - - static void serializeWithExtensionGraphs( - raw_ostream &MainOutput, const APISet &API, - const APIIgnoresList &IgnoresList, - llvm::function_ref< - std::unique_ptr(llvm::Twine BaseFileName)> - CreateOutputStream, - SymbolGraphSerializerOption Options = {}); + /// Wrap serialize(void) and write out the serialized JSON object to \p os. + void serialize(raw_ostream &os); /// Serialize a single symbol SGF. This is primarily used for libclang. /// @@ -130,7 +75,6 @@ class SymbolGraphSerializer : public APISetVisitor { static std::optional serializeSingleSymbolSGF(StringRef USR, const APISet &API); -private: /// The kind of a relationship between two symbols. enum RelationshipKind { /// The source symbol is a member of the target symbol. @@ -150,32 +94,16 @@ class SymbolGraphSerializer : public APISetVisitor { ExtensionTo, }; - /// Serialize a single record. - void serializeSingleRecord(const APIRecord *Record); - /// Get the string representation of the relationship kind. static StringRef getRelationshipString(RelationshipKind Kind); - void serializeRelationship(RelationshipKind Kind, - const SymbolReference &Source, - const SymbolReference &Target, - ExtendedModule &Into); - enum ConstraintKind { Conformance, ConditionalConformance }; static StringRef getConstraintString(ConstraintKind Kind); - /// Serialize the APIs in \c ExtendedModule. - /// - /// \returns a JSON object that contains the root of the formatted - /// Symbol Graph. - Object serializeGraph(StringRef ModuleName, ExtendedModule &&EM); - - /// Serialize the APIs in \c ExtendedModule in the Symbol Graph format and - /// write them to the provide stream. - void serializeGraphToStream(raw_ostream &OS, - SymbolGraphSerializerOption Options, - StringRef ModuleName, ExtendedModule &&EM); +private: + /// Just serialize the currently recorded objects in Symbol Graph format. + Object serializeCurrentGraph(); /// Synthesize the metadata section of the Symbol Graph format. /// @@ -189,92 +117,124 @@ class SymbolGraphSerializer : public APISetVisitor { /// by the given API set. /// Note that "module" here is not to be confused with the Clang/C++ module /// concept. - Object serializeModuleObject(StringRef ModuleName) const; - - Array serializePathComponents(const APIRecord *Record) const; + Object serializeModule() const; /// Determine if the given \p Record should be skipped during serialization. - bool shouldSkip(const APIRecord *Record) const; - - ExtendedModule &getModuleForCurrentSymbol(); + 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, source location and path components. The resulting - /// object is then augmented with kind-specific symbol information in - /// subsequent visit* methods by accessing the \p State member variable. This - /// method also checks if the given \p Record should be skipped during - /// serialization. This should be called only once per concrete APIRecord - /// instance and the first visit* method to be called is responsible for - /// calling this. This is normally visitAPIRecord unless a walkUpFromFoo - /// method is implemented along the inheritance hierarchy in which case the - /// visitFoo method needs to call this. + /// 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 nullptr if this \p Record should be skipped, or a pointer to - /// JSON object containing common symbol information of \p Record. Do not - /// store the returned pointer only use it to augment the object with record - /// specific information as it directly points to the object in the - /// \p ExtendedModule, the pointer won't be valid as soon as another object is - /// inserted into the module. - void serializeAPIRecord(const APIRecord *Record); + /// \returns \c std::nullopt if this \p Record should be skipped, or a JSON + /// object containing common symbol information of \p Record. + template + std::optional serializeAPIRecord(const RecordTy &Record) const; + + /// Helper method to serialize second-level member records of \p Record and + /// the member-of relationships. + template + void serializeMembers(const APIRecord &Record, + const SmallVector> &Members); + + /// Serialize the \p Kind relationship between \p Source and \p Target. + /// + /// Record the relationship between the two symbols in + /// SymbolGraphSerializer::Relationships. + void serializeRelationship(RelationshipKind Kind, SymbolReference Source, + SymbolReference Target); -public: - // Handle if records should be skipped at this level of the traversal to - // ensure that children of skipped records aren't serialized. - bool traverseAPIRecord(const APIRecord *Record); +protected: + /// The list of symbols to ignore. + /// + /// Note: This should be consulted before emitting a symbol. + const APIIgnoresList &IgnoresList; + + SymbolGraphSerializerOption Options; - bool visitAPIRecord(const APIRecord *Record); + llvm::StringSet<> visitedCategories; + +public: + void visitNamespaceRecord(const NamespaceRecord &Record); /// Visit a global function record. - bool visitGlobalFunctionRecord(const GlobalFunctionRecord *Record); + void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record); + + /// Visit a global variable record. + void visitGlobalVariableRecord(const GlobalVariableRecord &Record); + + /// Visit an enum record. + void visitEnumRecord(const EnumRecord &Record); + + /// Visit a record record. + void visitRecordRecord(const RecordRecord &Record); + + void visitStaticFieldRecord(const StaticFieldRecord &Record); + + void visitCXXClassRecord(const CXXClassRecord &Record); - bool visitCXXClassRecord(const CXXClassRecord *Record); + void visitClassTemplateRecord(const ClassTemplateRecord &Record); - bool visitClassTemplateRecord(const ClassTemplateRecord *Record); + void visitClassTemplateSpecializationRecord( + const ClassTemplateSpecializationRecord &Record); - bool visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord *Record); + void visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord &Record); - bool visitCXXMethodRecord(const CXXMethodRecord *Record); + void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record); - bool visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord *Record); + void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record); - bool visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord *Record); + void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record); - bool visitConceptRecord(const ConceptRecord *Record); + void visitMethodTemplateSpecializationRecord( + const CXXMethodTemplateSpecializationRecord &Record); - bool - visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord *Record); + void visitCXXFieldRecord(const CXXFieldRecord &Record); - bool visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord *Record); + void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record); - bool - visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord *Record); + void visitConceptRecord(const ConceptRecord &Record); - bool visitObjCContainerRecord(const ObjCContainerRecord *Record); + void + visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record); - bool visitObjCInterfaceRecord(const ObjCInterfaceRecord *Record); + void visitGlobalVariableTemplateSpecializationRecord( + const GlobalVariableTemplateSpecializationRecord &Record); - bool traverseObjCCategoryRecord(const ObjCCategoryRecord *Record); - bool walkUpFromObjCCategoryRecord(const ObjCCategoryRecord *Record); - bool visitObjCCategoryRecord(const ObjCCategoryRecord *Record); + void visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord &Record); - bool visitObjCMethodRecord(const ObjCMethodRecord *Record); + void + visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record); - bool - visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord *Record); + void visitGlobalFunctionTemplateSpecializationRecord( + const GlobalFunctionTemplateSpecializationRecord &Record); - bool walkUpFromTypedefRecord(const TypedefRecord *Record); - bool visitTypedefRecord(const TypedefRecord *Record); + /// Visit an Objective-C container record. + void visitObjCContainerRecord(const ObjCContainerRecord &Record); + + /// Visit an Objective-C category record. + void visitObjCCategoryRecord(const ObjCCategoryRecord &Record); + + /// Visit a macro definition record. + void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record); + + /// Visit a typedef record. + void visitTypedefRecord(const TypedefRecord &Record); + + /// Serialize a single record. + void serializeSingleRecord(const APIRecord *Record); SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList, - bool EmitSymbolLabelsForTesting = false, - bool ForceEmitToMainModule = false) - : Base(API), ForceEmitToMainModule(ForceEmitToMainModule), - IgnoresList(IgnoresList), - EmitSymbolLabelsForTesting(EmitSymbolLabelsForTesting) {} + SymbolGraphSerializerOption Options = {}, + bool ShouldRecurse = true) + : APISetVisitor(API), ShouldRecurse(ShouldRecurse), + IgnoresList(IgnoresList), Options(Options) {} }; } // namespace extractapi diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 864af66b33706..8085dbcbf671a 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -15,7 +15,6 @@ #include "clang/Sema/CodeCompleteOptions.h" #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include #include @@ -388,22 +387,6 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned ModulesShareFileManager : 1; - /// Whether to emit symbol graph files as a side effect of compilation. - LLVM_PREFERRED_TYPE(bool) - unsigned EmitSymbolGraph : 1; - - /// Whether to emit additional symbol graphs for extended modules. - LLVM_PREFERRED_TYPE(bool) - unsigned EmitExtensionSymbolGraphs : 1; - - /// Whether to emit symbol labels for testing in generated symbol graphs - LLVM_PREFERRED_TYPE(bool) - unsigned EmitSymbolGraphSymbolLabelsForTesting : 1; - - /// Whether to emit symbol labels for testing in generated symbol graphs - LLVM_PREFERRED_TYPE(bool) - unsigned EmitPrettySymbolGraphs : 1; - CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -513,8 +496,10 @@ class FrontendOptions { // ignore when extracting documentation. std::vector ExtractAPIIgnoresFileList; + // Currently this is only used as part of the `-emit-symbol-graph` + // action. // Location of output directory where symbol graph information would - // be dumped. This overrides regular -o output file specification + // be dumped std::string SymbolGraphOutputDir; /// Args to pass to the plugins diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e6c1767a0082d..1a0f5f27eda2f 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -49,7 +49,6 @@ #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" #include "ToolChains/ZOS.h" -#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetID.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" @@ -5890,12 +5889,6 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, &JA); } - if (JA.getType() == types::TY_API_INFO && - C.getArgs().hasArg(options::OPT_emit_extension_symbol_graphs) && - C.getArgs().hasArg(options::OPT_o)) - Diag(clang::diag::err_drv_unexpected_symbol_graph_output) - << C.getArgs().getLastArgValue(options::OPT_o); - // DXC defaults to standard out when generating assembly. We check this after // any DXC flags that might specify a file. if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode()) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 33f0b05a37696..b03ac6018d2b8 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5037,26 +5037,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(JA.getType() == types::TY_API_INFO && "Extract API actions must generate a API information."); CmdArgs.push_back("-extract-api"); - - if (Arg *PrettySGFArg = Args.getLastArg(options::OPT_emit_pretty_sgf)) - PrettySGFArg->render(Args, CmdArgs); - - Arg *SymbolGraphDirArg = Args.getLastArg(options::OPT_symbol_graph_dir_EQ); - if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ)) ProductNameArg->render(Args, CmdArgs); if (Arg *ExtractAPIIgnoresFileArg = Args.getLastArg(options::OPT_extract_api_ignores_EQ)) ExtractAPIIgnoresFileArg->render(Args, CmdArgs); - if (Arg *EmitExtensionSymbolGraphs = - Args.getLastArg(options::OPT_emit_extension_symbol_graphs)) { - if (!SymbolGraphDirArg) - D.Diag(diag::err_drv_missing_symbol_graph_dir); - - EmitExtensionSymbolGraphs->render(Args, CmdArgs); - } - if (SymbolGraphDirArg) - SymbolGraphDirArg->render(Args, CmdArgs); } else { assert((isa(JA) || isa(JA)) && "Invalid action for clang tool."); diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp index 5a62c5deb2408..aa7a1e9360f47 100644 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -13,67 +13,514 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/API.h" +#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentLexer.h" #include "clang/AST/RawCommentList.h" -#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/ErrorHandling.h" #include using namespace clang::extractapi; using namespace llvm; -SymbolReference::SymbolReference(const APIRecord *R) - : Name(R->Name), USR(R->USR), Record(R) {} +namespace { -APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { - switch (Ctx->getKind()) { -#define RECORD_CONTEXT(CLASS, KIND) \ - case KIND: \ - return static_cast(const_cast(Ctx)); -#include "clang/ExtractAPI/APIRecords.inc" - default: - return nullptr; - // llvm_unreachable("RecordContext derived class isn't propertly - // implemented"); - } +template +RecordTy *addTopLevelRecord(DenseMap &USRLookupTable, + APISet::RecordMap &RecordMap, + StringRef USR, CtorArgsTy &&...CtorArgs) { + auto Result = RecordMap.insert({USR, nullptr}); + + // Create the record if it does not already exist + if (Result.second) + Result.first->second = + std::make_unique(USR, std::forward(CtorArgs)...); + + auto *Record = Result.first->second.get(); + USRLookupTable.insert({USR, Record}); + return Record; } -RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { - if (!Record) - return nullptr; - switch (Record->getKind()) { -#define RECORD_CONTEXT(CLASS, KIND) \ - case KIND: \ - return static_cast(const_cast(Record)); -#include "clang/ExtractAPI/APIRecords.inc" - default: - return nullptr; - // llvm_unreachable("RecordContext derived class isn't propertly - // implemented"); - } +} // namespace + +NamespaceRecord * +APISet::addNamespace(APIRecord *Parent, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord( + USRBasedLookupTable, Namespaces, USR, Name, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader); + + if (Parent) + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + return Record; +} + +GlobalVariableRecord * +APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Fragments, + DeclarationFragments SubHeading, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, + std::move(Availability), Linkage, Comment, Fragments, + SubHeading, IsFromSystemHeader); +} + +GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, + Name, Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, Template, + IsFromSystemHeader); +} + +GlobalFunctionRecord *APISet::addGlobalFunction( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Fragments, + DeclarationFragments SubHeading, FunctionSignature Signature, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, + std::move(Availability), Linkage, Comment, Fragments, + SubHeading, Signature, IsFromSystemHeader); +} + +GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, FunctionSignature Signature, + Template Template, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR, + Name, Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, Signature, Template, + IsFromSystemHeader); +} + +GlobalFunctionTemplateSpecializationRecord * +APISet::addGlobalFunctionTemplateSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, FunctionSignature Signature, + bool IsFromSystemHeader) { + return addTopLevelRecord( + USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name, + Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, + Signature, IsFromSystemHeader); +} + +EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, + StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeader) { + auto Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, + IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Enum->USR, Enum->Name, Enum->getKind(), Enum); + USRBasedLookupTable.insert({USR, Record.get()}); + return Enum->Constants.emplace_back(std::move(Record)).get(); +} + +EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, IsFromSystemHeader); } -void RecordContext::addToRecordChain(APIRecord *Record) const { - if (!First) { - First = Record; - Last = Record; - return; - } +RecordFieldRecord *APISet::addRecordField( + RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + APIRecord::RecordKind Kind, bool IsFromSystemHeader) { + auto RecordField = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, + Kind, IsFromSystemHeader); + RecordField->ParentInformation = APIRecord::HierarchyInformation( + Record->USR, Record->Name, Record->getKind(), Record); + USRBasedLookupTable.insert({USR, RecordField.get()}); + return Record->Fields.emplace_back(std::move(RecordField)).get(); +} + +RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + APIRecord::RecordKind Kind, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Kind, IsFromSystemHeader); +} + +StaticFieldRecord * +APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, SymbolReference Context, + AccessControl Access, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, + std::move(Availability), Linkage, Comment, + Declaration, SubHeading, Context, Access, + IsFromSystemHeader); +} + +CXXFieldRecord * +APISet::addCXXField(APIRecord *CXXClass, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, AccessControl Access, + bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord( + USRBasedLookupTable, CXXFields, USR, Name, Loc, std::move(Availability), + Comment, Declaration, SubHeading, Access, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); + return Record; +} + +CXXFieldTemplateRecord *APISet::addCXXFieldTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + AccessControl Access, Template Template, bool IsFromSystemHeader) { + auto *Record = + addTopLevelRecord(USRBasedLookupTable, CXXFieldTemplates, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Access, Template, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + + return Record; +} + +CXXClassRecord * +APISet::addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, APIRecord::RecordKind Kind, + AccessControl Access, bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord( + USRBasedLookupTable, CXXClasses, USR, Name, Loc, std::move(Availability), + Comment, Declaration, SubHeading, Kind, Access, IsFromSystemHeader); + if (Parent) + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + return Record; +} + +ClassTemplateRecord *APISet::addClassTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + Template Template, AccessControl Access, bool IsFromSystemHeader) { + auto *Record = + addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Template, Access, IsFromSystemHeader); + if (Parent) + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + return Record; +} + +ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + AccessControl Access, bool IsFromSystemHeader) { + auto *Record = + addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, USR, + Name, Loc, std::move(Availability), Comment, + Declaration, SubHeading, Access, IsFromSystemHeader); + if (Parent) + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + return Record; +} + +ClassTemplatePartialSpecializationRecord * +APISet::addClassTemplatePartialSpecialization( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + Template Template, AccessControl Access, bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord( + USRBasedLookupTable, ClassTemplatePartialSpecializations, USR, Name, Loc, + std::move(Availability), Comment, Declaration, SubHeading, Template, + Access, IsFromSystemHeader); + if (Parent) + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + return Record; +} + +GlobalVariableTemplateSpecializationRecord * +APISet::addGlobalVariableTemplateSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, + GlobalVariableTemplateSpecializations, USR, Name, + Loc, std::move(Availability), Linkage, Comment, + Declaration, SubHeading, IsFromSystemHeader); +} - Last->NextInContext = Record; - Last = Record; +GlobalVariableTemplatePartialSpecializationRecord * +APISet::addGlobalVariableTemplatePartialSpecialization( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, Template Template, + bool IsFromSystemHeader) { + return addTopLevelRecord( + USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, + Name, Loc, std::move(Availability), Linkage, Comment, Declaration, + SubHeading, Template, IsFromSystemHeader); +} + +ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, + PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + Template Template, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Template, IsFromSystemHeader); +} + +CXXMethodRecord *APISet::addCXXInstanceMethod( + APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader) { + CXXMethodRecord *Record = + addTopLevelRecord(USRBasedLookupTable, CXXInstanceMethods, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Signature, Access, IsFromSystemHeader); + + Record->ParentInformation = APIRecord::HierarchyInformation( + CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), + CXXClassRecord); + return Record; +} + +CXXMethodRecord *APISet::addCXXStaticMethod( + APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader) { + CXXMethodRecord *Record = + addTopLevelRecord(USRBasedLookupTable, CXXStaticMethods, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Signature, Access, IsFromSystemHeader); + + Record->ParentInformation = APIRecord::HierarchyInformation( + CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), + CXXClassRecord); + return Record; +} + +CXXMethodTemplateRecord *APISet::addCXXMethodTemplate( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, Template Template, + bool IsFromSystemHeader) { + auto *Record = addTopLevelRecord(USRBasedLookupTable, CXXMethodTemplates, USR, + Name, Loc, std::move(Availability), Comment, + Declaration, SubHeading, Signature, Access, + Template, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + + return Record; +} + +CXXMethodTemplateSpecializationRecord *APISet::addCXXMethodTemplateSpec( + APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, AccessControl Access, + bool IsFromSystemHeader) { + + auto *Record = addTopLevelRecord( + USRBasedLookupTable, CXXMethodTemplateSpecializations, USR, Name, Loc, + std::move(Availability), Comment, Declaration, SubHeading, Signature, + Access, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Parent->USR, Parent->Name, Parent->getKind(), Parent); + + return Record; +} + +ObjCCategoryRecord *APISet::addObjCCategory( + StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + SymbolReference Interface, bool IsFromSystemHeader, + bool IsFromExternalModule) { + // Create the category record. + auto *Record = + addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, Interface, IsFromSystemHeader); + + Record->IsFromExternalModule = IsFromExternalModule; + + auto It = ObjCInterfaces.find(Interface.USR); + if (It != ObjCInterfaces.end()) + It->second->Categories.push_back(Record); + + return Record; +} + +ObjCInterfaceRecord * +APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + SymbolReference SuperClass, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, + std::move(Availability), Linkage, Comment, + Declaration, SubHeading, SuperClass, + IsFromSystemHeader); +} + +ObjCMethodRecord *APISet::addObjCMethod( + ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + FunctionSignature Signature, bool IsInstanceMethod, + bool IsFromSystemHeader) { + std::unique_ptr Record; + if (IsInstanceMethod) + Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, + SubHeading, Signature, IsFromSystemHeader); + else + Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, + SubHeading, Signature, IsFromSystemHeader); + + Record->ParentInformation = APIRecord::HierarchyInformation( + Container->USR, Container->Name, Container->getKind(), Container); + USRBasedLookupTable.insert({USR, Record.get()}); + return Container->Methods.emplace_back(std::move(Record)).get(); +} + +ObjCPropertyRecord *APISet::addObjCProperty( + ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, + StringRef SetterName, bool IsOptional, bool IsInstanceProperty, + bool IsFromSystemHeader) { + std::unique_ptr Record; + if (IsInstanceProperty) + Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, + SubHeading, Attributes, GetterName, SetterName, IsOptional, + IsFromSystemHeader); + else + Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, + SubHeading, Attributes, GetterName, SetterName, IsOptional, + IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Container->USR, Container->Name, Container->getKind(), Container); + USRBasedLookupTable.insert({USR, Record.get()}); + return Container->Properties.emplace_back(std::move(Record)).get(); +} + +ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( + ObjCContainerRecord *Container, StringRef Name, StringRef USR, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { + auto Record = std::make_unique( + USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, + Access, IsFromSystemHeader); + Record->ParentInformation = APIRecord::HierarchyInformation( + Container->USR, Container->Name, Container->getKind(), Container); + USRBasedLookupTable.insert({USR, Record.get()}); + return Container->Ivars.emplace_back(std::move(Record)).get(); +} + +ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, + PresumedLoc Loc, + AvailabilityInfo Availability, + const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, IsFromSystemHeader); +} + +MacroDefinitionRecord * +APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, + Declaration, SubHeading, IsFromSystemHeader); +} + +TypedefRecord * +APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, + SymbolReference UnderlyingType, bool IsFromSystemHeader) { + return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, UnderlyingType, IsFromSystemHeader); } APIRecord *APISet::findRecordForUSR(StringRef USR) const { if (USR.empty()) return nullptr; - auto FindIt = USRBasedLookupTable.find(USR); - if (FindIt != USRBasedLookupTable.end()) - return FindIt->getSecond().get(); + return USRBasedLookupTable.lookup(USR); +} + +StringRef APISet::recordUSR(const Decl *D) { + SmallString<128> USR; + index::generateUSRForDecl(D, USR); + return copyString(USR); +} - return nullptr; +StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, + const SourceManager &SM) { + SmallString<128> USR; + index::generateUSRForMacro(Name, SL, SM, USR); + return copyString(USR); } StringRef APISet::copyString(StringRef String) { @@ -81,22 +528,15 @@ StringRef APISet::copyString(StringRef String) { return {}; // No need to allocate memory and copy if the string has already been stored. - if (Allocator.identifyObject(String.data())) + if (StringAllocator.identifyObject(String.data())) return String; - void *Ptr = Allocator.Allocate(String.size(), 1); + void *Ptr = StringAllocator.Allocate(String.size(), 1); memcpy(Ptr, String.data(), String.size()); return StringRef(reinterpret_cast(Ptr), String.size()); } -SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, - StringRef Source) { - return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); -} - APIRecord::~APIRecord() {} -RecordRecord::~RecordRecord() {} -RecordFieldRecord::~RecordFieldRecord() {} ObjCContainerRecord::~ObjCContainerRecord() {} ObjCMethodRecord::~ObjCMethodRecord() {} ObjCPropertyRecord::~ObjCPropertyRecord() {} @@ -106,10 +546,8 @@ void GlobalFunctionRecord::anchor() {} void GlobalVariableRecord::anchor() {} void EnumConstantRecord::anchor() {} void EnumRecord::anchor() {} -void StructFieldRecord::anchor() {} -void StructRecord::anchor() {} -void UnionFieldRecord::anchor() {} -void UnionRecord::anchor() {} +void RecordFieldRecord::anchor() {} +void RecordRecord::anchor() {} void CXXFieldRecord::anchor() {} void CXXClassRecord::anchor() {} void CXXConstructorRecord::anchor() {} diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 0f9e1eb22a1d9..80a0a498dc400 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -60,44 +60,23 @@ void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo, } // namespace -DeclarationFragments & -DeclarationFragments::appendUnduplicatedTextCharacter(char Character) { +DeclarationFragments &DeclarationFragments::appendSpace() { if (!Fragments.empty()) { Fragment &Last = Fragments.back(); if (Last.Kind == FragmentKind::Text) { // Merge the extra space into the last fragment if the last fragment is // also text. - if (Last.Spelling.back() != Character) { // avoid duplicates at end - Last.Spelling.push_back(Character); + if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. + Last.Spelling.push_back(' '); } } else { - append("", FragmentKind::Text); - Fragments.back().Spelling.push_back(Character); + append(" ", FragmentKind::Text); } } return *this; } -DeclarationFragments &DeclarationFragments::appendSpace() { - return appendUnduplicatedTextCharacter(' '); -} - -DeclarationFragments &DeclarationFragments::appendSemicolon() { - return appendUnduplicatedTextCharacter(';'); -} - -DeclarationFragments &DeclarationFragments::removeTrailingSemicolon() { - if (Fragments.empty()) - return *this; - - Fragment &Last = Fragments.back(); - if (Last.Kind == FragmentKind::Text && Last.Spelling.back() == ';') - Last.Spelling.pop_back(); - - return *this; -} - StringRef DeclarationFragments::getFragmentKindString( DeclarationFragments::FragmentKind Kind) { switch (Kind) { @@ -490,7 +469,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace( if (!Decl->isAnonymousNamespace()) Fragments.appendSpace().append( Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -532,7 +511,7 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { return Fragments .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -564,7 +543,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) { Fragments.append(std::move(ArgumentFragment)) .appendSpace() .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); return Fragments; } @@ -733,7 +712,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { Fragments.append(DeclarationFragments::getExceptionSpecificationString( Func->getExceptionSpecType())); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( @@ -762,7 +741,7 @@ DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) .append(std::move(After)); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -778,7 +757,7 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { .appendSpace() .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( @@ -796,7 +775,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( @@ -811,7 +790,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -841,7 +820,7 @@ DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( @@ -881,7 +860,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -912,7 +891,7 @@ DeclarationFragmentsBuilder::getFragmentsForConversionFunction( Fragments.appendSpace().append("const", DeclarationFragments::FragmentKind::Keyword); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -944,7 +923,7 @@ DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } // Get fragments for template parameters, e.g. T in tempalte ... @@ -1049,7 +1028,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept( .appendSpace() .append(Concept->getName().str(), DeclarationFragments::FragmentKind::Identifier) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -1090,7 +1069,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -1112,7 +1091,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), Decl->getTemplateParameters()->asArray())) .append(">", DeclarationFragments::FragmentKind::Text) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -1131,7 +1110,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -1153,7 +1132,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), Decl->getTemplateParameters()->asArray())) .append(">", DeclarationFragments::FragmentKind::Text) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments @@ -1224,7 +1203,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) .appendSpace() - .append(Interface->getName(), + .append(Category->getClassInterface()->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, Interface) .append(" (", DeclarationFragments::FragmentKind::Text) @@ -1298,7 +1277,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( Fragments.append(getFragmentsForParam(Param)); } - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( @@ -1399,7 +1378,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( .append(Property->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .appendSemicolon(); + .append(";", DeclarationFragments::FragmentKind::Text); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( @@ -1443,7 +1422,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( .appendSpace() .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.appendSemicolon(); + return Fragments.append(";", DeclarationFragments::FragmentKind::Text); } // Instantiate template for FunctionDecl. diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index d6335854cbf26..275f49be22e15 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -30,7 +30,6 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" -#include "clang/Index/USRGeneration.h" #include "clang/InstallAPI/HeaderFile.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" @@ -40,7 +39,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -329,12 +327,11 @@ class MacroCallback : public PPCallbacks { StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); - SmallString<128> USR; - index::generateUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM, - USR); + StringRef USR = + API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); - API.createRecord( - USR, Name, SymbolReference(), Loc, + API.addMacroDefinition( + Name, USR, Loc, DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), DeclarationFragmentsBuilder::getSubHeadingForMacro(Name), SM.isInSystemHeader(PM.MacroNameToken.getLocation())); @@ -375,57 +372,40 @@ class APIMacroCallback : public MacroCallback { LocationFileChecker &LCF; }; -std::unique_ptr -createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) { - auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir; - - SmallString<256> FileName; - llvm::sys::path::append(FileName, OutputDirectory, - BaseName + ".symbols.json"); - return CI.createOutputFile( - FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false, - /*UseTemporary*/ true, /*CreateMissingDirectories*/ true); -} - } // namespace -void ExtractAPIActionBase::ImplEndSourceFileAction(CompilerInstance &CI) { - SymbolGraphSerializerOption SerializationOptions; - SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs; - SerializationOptions.EmitSymbolLabelsForTesting = - CI.getFrontendOpts().EmitSymbolGraphSymbolLabelsForTesting; - - if (CI.getFrontendOpts().EmitExtensionSymbolGraphs) { - auto ConstructOutputFile = [&CI](Twine BaseName) { - return createAdditionalSymbolGraphFile(CI, BaseName); - }; - - SymbolGraphSerializer::serializeWithExtensionGraphs( - *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions); - } else { - SymbolGraphSerializer::serializeMainSymbolGraph(*OS, *API, IgnoresList, - SerializationOptions); - } +void ExtractAPIActionBase::ImplEndSourceFileAction() { + if (!OS) + return; - // Flush the stream and close the main output stream. + // Setup a SymbolGraphSerializer to write out collected API information in + // the Symbol Graph format. + // FIXME: Make the kind of APISerializer configurable. + SymbolGraphSerializer SGSerializer(*API, IgnoresList); + SGSerializer.serialize(*OS); OS.reset(); } +std::unique_ptr +ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { + std::unique_ptr OS; + OS = CI.createDefaultOutputFile(/*Binary=*/false, InFile, + /*Extension=*/"json", + /*RemoveFileOnSignal=*/false); + if (!OS) + return nullptr; + return OS; +} + std::unique_ptr ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - auto ProductName = CI.getFrontendOpts().ProductName; - - if (CI.getFrontendOpts().SymbolGraphOutputDir.empty()) - OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile, - /*Extension*/ "symbols.json", - /*RemoveFileOnSignal*/ false, - /*CreateMissingDirectories*/ true); - else - OS = createAdditionalSymbolGraphFile(CI, ProductName); + OS = CreateOutputFile(CI, InFile); if (!OS) return nullptr; + auto ProductName = CI.getFrontendOpts().ProductName; + // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. API = std::make_unique( @@ -515,9 +495,7 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { return true; } -void ExtractAPIAction::EndSourceFileAction() { - ImplEndSourceFileAction(getCompilerInstance()); -} +void ExtractAPIAction::EndSourceFileAction() { ImplEndSourceFileAction(); } std::unique_ptr WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, @@ -528,9 +506,11 @@ WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, CreatedASTConsumer = true; - ProductName = CI.getFrontendOpts().ProductName; - auto InputFilename = llvm::sys::path::filename(InFile); - OS = createAdditionalSymbolGraphFile(CI, InputFilename); + OS = CreateOutputFile(CI, InFile); + if (!OS) + return nullptr; + + auto ProductName = CI.getFrontendOpts().ProductName; // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. @@ -572,6 +552,32 @@ void WrappingExtractAPIAction::EndSourceFileAction() { WrapperFrontendAction::EndSourceFileAction(); if (CreatedASTConsumer) { - ImplEndSourceFileAction(getCompilerInstance()); + ImplEndSourceFileAction(); } } + +std::unique_ptr +WrappingExtractAPIAction::CreateOutputFile(CompilerInstance &CI, + StringRef InFile) { + std::unique_ptr OS; + std::string OutputDir = CI.getFrontendOpts().SymbolGraphOutputDir; + + // The symbol graphs need to be generated as a side effect of regular + // compilation so the output should be dumped in the directory provided with + // the command line option. + llvm::SmallString<128> OutFilePath(OutputDir); + auto Seperator = llvm::sys::path::get_separator(); + auto Infilename = llvm::sys::path::filename(InFile); + OutFilePath.append({Seperator, Infilename}); + llvm::sys::path::replace_extension(OutFilePath, "json"); + // StringRef outputFilePathref = *OutFilePath; + + // don't use the default output file + OS = CI.createOutputFile(/*OutputPath=*/OutFilePath, /*Binary=*/false, + /*RemoveFileOnSignal=*/true, + /*UseTemporary=*/true, + /*CreateMissingDirectories=*/true); + if (!OS) + return nullptr; + return OS; +} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 57f966c8b2be3..545860acb7db8 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -14,17 +14,13 @@ #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" -#include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/DeclarationFragments.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" -#include "llvm/Support/raw_ostream.h" -#include #include #include @@ -37,27 +33,26 @@ namespace { /// Helper function to inject a JSON object \p Obj into another object \p Paren /// at position \p Key. -void serializeObject(Object &Paren, StringRef Key, - std::optional &&Obj) { +void serializeObject(Object &Paren, StringRef Key, std::optional Obj) { if (Obj) Paren[Key] = std::move(*Obj); } +/// Helper function to inject a StringRef \p String into an object \p Paren at +/// position \p Key +void serializeString(Object &Paren, StringRef Key, + std::optional String) { + if (String) + Paren[Key] = std::move(*String); +} + /// Helper function to inject a JSON array \p Array into object \p Paren at /// position \p Key. -void serializeArray(Object &Paren, StringRef Key, - std::optional &&Array) { +void serializeArray(Object &Paren, StringRef Key, std::optional Array) { if (Array) Paren[Key] = std::move(*Array); } -/// Helper function to inject a JSON array composed of the values in \p C into -/// object \p Paren at position \p Key. -template -void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { - Paren[Key] = Array(C); -} - /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version /// format. /// @@ -253,7 +248,6 @@ std::optional serializeDocComment(const DocComment &Comment) { return std::nullopt; Object DocComment; - Array LinesArray; for (const auto &CommentLine : Comment) { Object Line; @@ -262,8 +256,7 @@ std::optional serializeDocComment(const DocComment &Comment) { serializeSourceRange(CommentLine.Begin, CommentLine.End)); LinesArray.emplace_back(std::move(Line)); } - - serializeArray(DocComment, "lines", std::move(LinesArray)); + serializeArray(DocComment, "lines", LinesArray); return DocComment; } @@ -329,14 +322,19 @@ serializeDeclarationFragments(const DeclarationFragments &DF) { /// - \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. -Object serializeNames(const APIRecord *Record) { +Object serializeNames(const APIRecord &Record) { Object Names; - Names["title"] = Record->Name; + if (auto *CategoryRecord = + dyn_cast_or_null(&Record)) + Names["title"] = + (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); + else + Names["title"] = Record.Name; serializeArray(Names, "subHeading", - serializeDeclarationFragments(Record->SubHeading)); + serializeDeclarationFragments(Record.SubHeading)); DeclarationFragments NavigatorFragments; - NavigatorFragments.append(Record->Name, + NavigatorFragments.append(Record.Name, DeclarationFragments::FragmentKind::Identifier, /*PreciseIdentifier*/ ""); serializeArray(Names, "navigator", @@ -353,8 +351,7 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Object Kind; switch (RK) { case APIRecord::RK_Unknown: - Kind["identifier"] = AddLangPrefix("unknown"); - Kind["displayName"] = "Unknown"; + llvm_unreachable("Records should have an explicit kind"); break; case APIRecord::RK_Namespace: Kind["identifier"] = AddLangPrefix("namespace"); @@ -487,6 +484,10 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("class.extension"); Kind["displayName"] = "Class Extension"; break; + case APIRecord::RK_ObjCCategoryModule: + Kind["identifier"] = AddLangPrefix("module.extension"); + Kind["displayName"] = "Module Extension"; + break; case APIRecord::RK_ObjCProtocol: Kind["identifier"] = AddLangPrefix("protocol"); Kind["displayName"] = "Protocol"; @@ -499,8 +500,6 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("typealias"); Kind["displayName"] = "Type Alias"; break; - default: - llvm_unreachable("API Record with uninstantiable kind"); } return Kind; @@ -515,18 +514,12 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) { return serializeSymbolKind(Record.getKind(), Lang); } -/// Serialize the function signature field, 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. template -void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { +std::optional +serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { const auto &FS = Record.Signature; if (FS.empty()) - return; + return std::nullopt; Object Signature; serializeArray(Signature, "returns", @@ -544,14 +537,63 @@ void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { if (!Parameters.empty()) Signature["parameters"] = std::move(Parameters); - serializeObject(Paren, "functionSignature", std::move(Signature)); + return Signature; } template -void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { +std::optional +serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { + return std::nullopt; +} + +/// Serialize the function signature field, 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 std::nullopt if \p FS is empty, or an \c Object containing the +/// formatted function signature. +template +void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { + serializeObject(Paren, "functionSignature", + serializeFunctionSignatureMixinImpl( + Record, has_function_signature())); +} + +template +std::optional serializeAccessMixinImpl(const RecordTy &Record, + std::true_type) { + const auto &AccessControl = Record.Access; + std::string Access; + if (AccessControl.empty()) + return std::nullopt; + Access = AccessControl.getAccess(); + return Access; +} + +template +std::optional serializeAccessMixinImpl(const RecordTy &Record, + std::false_type) { + return std::nullopt; +} + +template +void serializeAccessMixin(Object &Paren, const RecordTy &Record) { + auto accessLevel = serializeAccessMixinImpl(Record, has_access()); + if (!accessLevel.has_value()) + accessLevel = "public"; + serializeString(Paren, "accessLevel", accessLevel); +} + +template +std::optional serializeTemplateMixinImpl(const RecordTy &Record, + std::true_type) { const auto &Template = Record.Templ; if (Template.empty()) - return; + return std::nullopt; Object Generics; Array GenericParameters; @@ -577,66 +619,97 @@ void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { if (!GenericConstraints.empty()) Generics["constraints"] = std::move(GenericConstraints); - serializeObject(Paren, "swiftGenerics", Generics); + return Generics; } -Array generateParentContexts(const SmallVectorImpl &Parents, - Language Lang) { - Array ParentContexts; - - for (const auto &Parent : Parents) { - Object Elem; - Elem["usr"] = Parent.USR; - Elem["name"] = Parent.Name; - if (Parent.Record) - Elem["kind"] = - serializeSymbolKind(Parent.Record->getKind(), Lang)["identifier"]; - else - Elem["kind"] = - serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; - ParentContexts.emplace_back(std::move(Elem)); - } +template +std::optional serializeTemplateMixinImpl(const RecordTy &Record, + std::false_type) { + return std::nullopt; +} - return ParentContexts; +template +void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { + serializeObject(Paren, "swiftGenerics", + serializeTemplateMixinImpl(Record, has_template())); } -/// Walk the records parent information in reverse to generate a hierarchy -/// suitable for serialization. -SmallVector -generateHierarchyFromRecord(const APIRecord *Record) { - SmallVector ReverseHierarchy; - for (const auto *Current = Record; Current != nullptr; - Current = Current->Parent.Record) - ReverseHierarchy.emplace_back(Current); - - return SmallVector( - std::make_move_iterator(ReverseHierarchy.rbegin()), - std::make_move_iterator(ReverseHierarchy.rend())); -} - -SymbolReference getHierarchyReference(const APIRecord *Record, - const APISet &API) { - // If the parent is a category extended from internal module then we need to - // pretend this belongs to the associated interface. - if (auto *CategoryRecord = dyn_cast_or_null(Record)) { - return CategoryRecord->Interface; - // FIXME: TODO generate path components correctly for categories extending - // an external module. +struct PathComponent { + StringRef USR; + StringRef Name; + APIRecord::RecordKind Kind; + + PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) + : USR(USR), Name(Name), Kind(Kind) {} +}; + +template +bool generatePathComponents( + const RecordTy &Record, const APISet &API, + function_ref ComponentTransformer) { + SmallVector ReverseComponenents; + ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); + const auto *CurrentParent = &Record.ParentInformation; + bool FailedToFindParent = false; + while (CurrentParent && !CurrentParent->empty()) { + PathComponent CurrentParentComponent(CurrentParent->ParentUSR, + CurrentParent->ParentName, + CurrentParent->ParentKind); + + auto *ParentRecord = CurrentParent->ParentRecord; + // Slow path if we don't have a direct reference to the ParentRecord + if (!ParentRecord) + ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); + + // If the parent is a category extended from internal module then we need to + // pretend this belongs to the associated interface. + if (auto *CategoryRecord = + dyn_cast_or_null(ParentRecord)) { + if (!CategoryRecord->IsFromExternalModule) { + ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); + CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, + CategoryRecord->Interface.Name, + APIRecord::RK_ObjCInterface); + } + } + + // The parent record doesn't exist which means the symbol shouldn't be + // treated as part of the current product. + if (!ParentRecord) { + FailedToFindParent = true; + break; + } + + ReverseComponenents.push_back(std::move(CurrentParentComponent)); + CurrentParent = &ParentRecord->ParentInformation; } - return SymbolReference(Record); -} + for (const auto &PC : reverse(ReverseComponenents)) + ComponentTransformer(PC); -} // namespace + return FailedToFindParent; +} -Object *ExtendedModule::addSymbol(Object &&Symbol) { - Symbols.emplace_back(std::move(Symbol)); - return Symbols.back().getAsObject(); +Object serializeParentContext(const PathComponent &PC, Language Lang) { + Object ParentContextElem; + ParentContextElem["usr"] = PC.USR; + ParentContextElem["name"] = PC.Name; + ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; + return ParentContextElem; } -void ExtendedModule::addRelationship(Object &&Relationship) { - Relationships.emplace_back(std::move(Relationship)); +template +Array generateParentContexts(const RecordTy &Record, const APISet &API, + Language Lang) { + Array ParentContexts; + generatePathComponents( + Record, API, [Lang, &ParentContexts](const PathComponent &PC) { + ParentContexts.push_back(serializeParentContext(PC, Lang)); + }); + + return ParentContexts; } +} // namespace /// Defines the format version emitted by SymbolGraphSerializer. const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; @@ -649,44 +722,84 @@ Object SymbolGraphSerializer::serializeMetadata() const { return Metadata; } -Object -SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { +Object SymbolGraphSerializer::serializeModule() const { Object Module; - Module["name"] = ModuleName; + // The user is expected to always pass `--product-name=` on the command line + // to populate this field. + Module["name"] = API.ProductName; serializeObject(Module, "platform", serializePlatform(API.getTarget())); return Module; } -bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { - if (!Record) +bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { + // Skip explicitly ignored symbols. + if (IgnoresList.shouldIgnore(Record.Name)) return true; // Skip unconditionally unavailable symbols - if (Record->Availability.isUnconditionallyUnavailable()) + if (Record.Availability.isUnconditionallyUnavailable()) return true; // Filter out symbols prefixed with an underscored as they are understood to // be symbols clients should not use. - if (Record->Name.starts_with("_")) - return true; - - // Skip explicitly ignored symbols. - if (IgnoresList.shouldIgnore(Record->Name)) + if (Record.Name.starts_with("_")) return true; return false; } -ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { - if (!ForceEmitToMainModule && ModuleForCurrentSymbol) - return *ModuleForCurrentSymbol; +template +std::optional +SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { + if (shouldSkip(Record)) + return std::nullopt; + + Object Obj; + serializeObject(Obj, "identifier", + serializeIdentifier(Record, API.getLanguage())); + serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); + serializeObject(Obj, "names", serializeNames(Record)); + serializeObject( + Obj, "location", + serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); + serializeArray(Obj, "availability", + serializeAvailability(Record.Availability)); + serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); + serializeArray(Obj, "declarationFragments", + serializeDeclarationFragments(Record.Declaration)); + SmallVector PathComponentsNames; + // If this returns true it indicates that we couldn't find a symbol in the + // hierarchy. + if (generatePathComponents(Record, API, + [&PathComponentsNames](const PathComponent &PC) { + PathComponentsNames.push_back(PC.Name); + })) + return {}; + + serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); - return MainModule; + serializeFunctionSignatureMixin(Obj, Record); + serializeAccessMixin(Obj, Record); + serializeTemplateMixin(Obj, Record); + + return Obj; } -Array SymbolGraphSerializer::serializePathComponents( - const APIRecord *Record) const { - return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); +template +void SymbolGraphSerializer::serializeMembers( + const APIRecord &Record, + const SmallVector> &Members) { + // Members should not be serialized if we aren't recursing. + if (!ShouldRecurse) + return; + for (const auto &Member : Members) { + auto MemberRecord = serializeAPIRecord(*Member); + if (!MemberRecord) + continue; + + Symbols.emplace_back(std::move(*MemberRecord)); + serializeRelationship(RelationshipKind::MemberOf, *Member, Record); + } } StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { @@ -703,33 +816,6 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { llvm_unreachable("Unhandled relationship kind"); } -void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, - const SymbolReference &Source, - const SymbolReference &Target, - ExtendedModule &Into) { - Object Relationship; - SmallString<64> TestRelLabel; - if (EmitSymbolLabelsForTesting) { - llvm::raw_svector_ostream OS(TestRelLabel); - OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " - << Source.USR << " $ "; - if (Target.USR.empty()) - OS << Target.Name; - else - OS << Target.USR; - Relationship["!testRelLabel"] = TestRelLabel; - } - Relationship["source"] = Source.USR; - Relationship["target"] = Target.USR; - Relationship["targetFallback"] = Target.Name; - Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); - - if (ForceEmitToMainModule) - MainModule.addRelationship(std::move(Relationship)); - else - Into.addRelationship(std::move(Relationship)); -} - StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { switch (Kind) { case ConstraintKind::Conformance: @@ -740,324 +826,430 @@ StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { llvm_unreachable("Unhandled constraint kind"); } -void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { - Object Obj; - - // If we need symbol labels for testing emit the USR as the value and the key - // starts with '!'' to ensure it ends up at the top of the object. - if (EmitSymbolLabelsForTesting) - Obj["!testLabel"] = Record->USR; +void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, + SymbolReference Source, + SymbolReference Target) { + Object Relationship; + Relationship["source"] = Source.USR; + Relationship["target"] = Target.USR; + Relationship["targetFallback"] = Target.Name; + Relationship["kind"] = getRelationshipString(Kind); - serializeObject(Obj, "identifier", - serializeIdentifier(*Record, API.getLanguage())); - serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); - serializeObject(Obj, "names", serializeNames(Record)); - serializeObject( - Obj, "location", - serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); - serializeArray(Obj, "availability", - serializeAvailability(Record->Availability)); - serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); - serializeArray(Obj, "declarationFragments", - serializeDeclarationFragments(Record->Declaration)); + Relationships.emplace_back(std::move(Relationship)); +} - Obj["pathComponents"] = serializePathComponents(Record); - Obj["accessLevel"] = Record->Access.getAccess(); +void SymbolGraphSerializer::visitNamespaceRecord( + const NamespaceRecord &Record) { + auto Namespace = serializeAPIRecord(Record); + if (!Namespace) + return; + Symbols.emplace_back(std::move(*Namespace)); + if (!Record.ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); +} - ExtendedModule &Module = getModuleForCurrentSymbol(); - // If the hierarchy has at least one parent and child. - if (Hierarchy.size() >= 2) - serializeRelationship(MemberOf, Hierarchy.back(), - Hierarchy[Hierarchy.size() - 2], Module); +void SymbolGraphSerializer::visitGlobalFunctionRecord( + const GlobalFunctionRecord &Record) { + auto Obj = serializeAPIRecord(Record); + if (!Obj) + return; - CurrentSymbol = Module.addSymbol(std::move(Obj)); + Symbols.emplace_back(std::move(*Obj)); } -bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { - if (!Record) - return true; - if (shouldSkip(Record)) - return true; - Hierarchy.push_back(getHierarchyReference(Record, API)); - // Defer traversal mechanics to APISetVisitor base implementation - auto RetVal = Base::traverseAPIRecord(Record); - Hierarchy.pop_back(); - return RetVal; +void SymbolGraphSerializer::visitGlobalVariableRecord( + const GlobalVariableRecord &Record) { + auto Obj = serializeAPIRecord(Record); + if (!Obj) + return; + + Symbols.emplace_back(std::move(*Obj)); } -bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { - serializeAPIRecord(Record); - return true; +void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { + auto Enum = serializeAPIRecord(Record); + if (!Enum) + return; + + Symbols.emplace_back(std::move(*Enum)); + serializeMembers(Record, Record.Constants); } -bool SymbolGraphSerializer::visitGlobalFunctionRecord( - const GlobalFunctionRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) { + auto SerializedRecord = serializeAPIRecord(Record); + if (!SerializedRecord) + return; - serializeFunctionSignatureMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*SerializedRecord)); + serializeMembers(Record, Record.Fields); } -bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitStaticFieldRecord( + const StaticFieldRecord &Record) { + auto StaticField = serializeAPIRecord(Record); + if (!StaticField) + return; + Symbols.emplace_back(std::move(*StaticField)); + serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); +} - for (const auto &Base : Record->Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, - getModuleForCurrentSymbol()); - return true; +void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { + auto Class = serializeAPIRecord(Record); + if (!Class) + return; + + Symbols.emplace_back(std::move(*Class)); + for (const auto &Base : Record.Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); + if (!Record.ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitClassTemplateRecord( - const ClassTemplateRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitClassTemplateRecord( + const ClassTemplateRecord &Record) { + auto Class = serializeAPIRecord(Record); + if (!Class) + return; - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*Class)); + for (const auto &Base : Record.Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); + if (!Record.ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( + const ClassTemplateSpecializationRecord &Record) { + auto Class = serializeAPIRecord(Record); + if (!Class) + return; - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*Class)); + + for (const auto &Base : Record.Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); + if (!Record.ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitCXXMethodRecord( - const CXXMethodRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord &Record) { + auto Class = serializeAPIRecord(Record); + if (!Class) + return; + + Symbols.emplace_back(std::move(*Class)); - serializeFunctionSignatureMixin(*CurrentSymbol, *Record); - return true; + for (const auto &Base : Record.Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); + if (!Record.ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( - const CXXMethodTemplateRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitCXXInstanceMethodRecord( + const CXXInstanceMethodRecord &Record) { + auto InstanceMethod = serializeAPIRecord(Record); + if (!InstanceMethod) + return; - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*InstanceMethod)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( - const CXXFieldTemplateRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitCXXStaticMethodRecord( + const CXXStaticMethodRecord &Record) { + auto StaticMethod = serializeAPIRecord(Record); + if (!StaticMethod) + return; - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*StaticMethod)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitMethodTemplateRecord( + const CXXMethodTemplateRecord &Record) { + if (!ShouldRecurse) + // Ignore child symbols + return; + auto MethodTemplate = serializeAPIRecord(Record); + if (!MethodTemplate) + return; + Symbols.emplace_back(std::move(*MethodTemplate)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); +} - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; +void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( + const CXXMethodTemplateSpecializationRecord &Record) { + if (!ShouldRecurse) + // Ignore child symbols + return; + auto MethodTemplateSpecialization = serializeAPIRecord(Record); + if (!MethodTemplateSpecialization) + return; + Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( - const GlobalVariableTemplateRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { + if (!ShouldRecurse) + return; + auto CXXField = serializeAPIRecord(Record); + if (!CXXField) + return; + Symbols.emplace_back(std::move(*CXXField)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); +} - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; +void SymbolGraphSerializer::visitCXXFieldTemplateRecord( + const CXXFieldTemplateRecord &Record) { + if (!ShouldRecurse) + // Ignore child symbols + return; + auto CXXFieldTemplate = serializeAPIRecord(Record); + if (!CXXFieldTemplate) + return; + Symbols.emplace_back(std::move(*CXXFieldTemplate)); + serializeRelationship(RelationshipKind::MemberOf, Record, + Record.ParentInformation.ParentRecord); } -bool SymbolGraphSerializer:: - visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { + auto Concept = serializeAPIRecord(Record); + if (!Concept) + return; - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; + Symbols.emplace_back(std::move(*Concept)); } -bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( - const GlobalFunctionTemplateRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord &Record) { + auto GlobalVariableTemplate = serializeAPIRecord(Record); + if (!GlobalVariableTemplate) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplate)); +} - serializeTemplateMixin(*CurrentSymbol, *Record); - return true; +void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( + const GlobalVariableTemplateSpecializationRecord &Record) { + auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); + if (!GlobalVariableTemplateSpecialization) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); } -bool SymbolGraphSerializer::visitObjCContainerRecord( - const ObjCContainerRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer:: + visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord &Record) { + auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); + if (!GlobalVariableTemplatePartialSpecialization) + return; + Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); +} - for (const auto &Protocol : Record->Protocols) - serializeRelationship(ConformsTo, Record, Protocol, - getModuleForCurrentSymbol()); +void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord &Record) { + auto GlobalFunctionTemplate = serializeAPIRecord(Record); + if (!GlobalFunctionTemplate) + return; + Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); +} - return true; +void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( + const GlobalFunctionTemplateSpecializationRecord &Record) { + auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); + if (!GlobalFunctionTemplateSpecialization) + return; + Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); } -bool SymbolGraphSerializer::visitObjCInterfaceRecord( - const ObjCInterfaceRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitObjCContainerRecord( + const ObjCContainerRecord &Record) { + auto ObjCContainer = serializeAPIRecord(Record); + if (!ObjCContainer) + return; - if (!Record->SuperClass.empty()) - serializeRelationship(InheritsFrom, Record, Record->SuperClass, - getModuleForCurrentSymbol()); - return true; + Symbols.emplace_back(std::move(*ObjCContainer)); + + serializeMembers(Record, Record.Ivars); + serializeMembers(Record, Record.Methods); + serializeMembers(Record, Record.Properties); + + for (const auto &Protocol : Record.Protocols) + // Record that Record conforms to Protocol. + serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); + + if (auto *ObjCInterface = dyn_cast(&Record)) { + if (!ObjCInterface->SuperClass.empty()) + // If Record is an Objective-C interface record and it has a super class, + // record that Record is inherited from SuperClass. + serializeRelationship(RelationshipKind::InheritsFrom, Record, + ObjCInterface->SuperClass); + + // Members of categories extending an interface are serialized as members of + // the interface. + for (const auto *Category : ObjCInterface->Categories) { + serializeMembers(Record, Category->Ivars); + serializeMembers(Record, Category->Methods); + serializeMembers(Record, Category->Properties); + + // Surface the protocols of the category to the interface. + for (const auto &Protocol : Category->Protocols) + serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); + } + } } -bool SymbolGraphSerializer::traverseObjCCategoryRecord( - const ObjCCategoryRecord *Record) { - auto *CurrentModule = ModuleForCurrentSymbol; - if (Record->isExtendingExternalModule()) - ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; +void SymbolGraphSerializer::visitObjCCategoryRecord( + const ObjCCategoryRecord &Record) { + if (!Record.IsFromExternalModule) + return; - if (!walkUpFromObjCCategoryRecord(Record)) - return false; + // Check if the current Category' parent has been visited before, if so skip. + if (!visitedCategories.contains(Record.Interface.Name)) { + visitedCategories.insert(Record.Interface.Name); + Object Obj; + serializeObject(Obj, "identifier", + serializeIdentifier(Record, API.getLanguage())); + serializeObject(Obj, "kind", + serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, + API.getLanguage())); + Obj["accessLevel"] = "public"; + Symbols.emplace_back(std::move(Obj)); + } - bool RetVal = traverseRecordContext(Record); - ModuleForCurrentSymbol = CurrentModule; - return RetVal; -} + Object Relationship; + Relationship["source"] = Record.USR; + Relationship["target"] = Record.Interface.USR; + Relationship["targetFallback"] = Record.Interface.Name; + Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); + Relationships.emplace_back(std::move(Relationship)); -bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( - const ObjCCategoryRecord *Record) { - return visitObjCCategoryRecord(Record); -} + auto ObjCCategory = serializeAPIRecord(Record); + + if (!ObjCCategory) + return; -bool SymbolGraphSerializer::visitObjCCategoryRecord( - const ObjCCategoryRecord *Record) { - // If we need to create a record for the category in the future do so here, - // otherwise everything is set up to pretend that the category is in fact the - // interface it extends. - for (const auto &Protocol : Record->Protocols) - serializeRelationship(ConformsTo, Record->Interface, Protocol, - getModuleForCurrentSymbol()); + Symbols.emplace_back(std::move(*ObjCCategory)); + serializeMembers(Record, Record.Methods); + serializeMembers(Record, Record.Properties); - return true; + // Surface the protocols of the category to the interface. + for (const auto &Protocol : Record.Protocols) + serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); } -bool SymbolGraphSerializer::visitObjCMethodRecord( - const ObjCMethodRecord *Record) { - if (!CurrentSymbol) - return true; +void SymbolGraphSerializer::visitMacroDefinitionRecord( + const MacroDefinitionRecord &Record) { + auto Macro = serializeAPIRecord(Record); - serializeFunctionSignatureMixin(*CurrentSymbol, *Record); - return true; -} + if (!Macro) + return; -bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( - const ObjCInstanceVariableRecord *Record) { - // FIXME: serialize ivar access control here. - return true; + Symbols.emplace_back(std::move(*Macro)); } -bool SymbolGraphSerializer::walkUpFromTypedefRecord( - const TypedefRecord *Record) { - // Short-circuit walking up the class hierarchy and handle creating typedef - // symbol objects manually as there are additional symbol dropping rules to - // respect. - return visitTypedefRecord(Record); +void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { + switch (Record->getKind()) { + case APIRecord::RK_Unknown: + llvm_unreachable("Records should have a known kind!"); + case APIRecord::RK_GlobalFunction: + visitGlobalFunctionRecord(*cast(Record)); + break; + case APIRecord::RK_GlobalVariable: + visitGlobalVariableRecord(*cast(Record)); + break; + case APIRecord::RK_Enum: + visitEnumRecord(*cast(Record)); + break; + case APIRecord::RK_Struct: + LLVM_FALLTHROUGH; + case APIRecord::RK_Union: + visitRecordRecord(*cast(Record)); + break; + case APIRecord::RK_StaticField: + visitStaticFieldRecord(*cast(Record)); + break; + case APIRecord::RK_CXXClass: + visitCXXClassRecord(*cast(Record)); + break; + case APIRecord::RK_ObjCInterface: + visitObjCContainerRecord(*cast(Record)); + break; + case APIRecord::RK_ObjCProtocol: + visitObjCContainerRecord(*cast(Record)); + break; + case APIRecord::RK_ObjCCategory: + visitObjCCategoryRecord(*cast(Record)); + break; + case APIRecord::RK_MacroDefinition: + visitMacroDefinitionRecord(*cast(Record)); + break; + case APIRecord::RK_Typedef: + visitTypedefRecord(*cast(Record)); + break; + default: + if (auto Obj = serializeAPIRecord(*Record)) { + Symbols.emplace_back(std::move(*Obj)); + auto &ParentInformation = Record->ParentInformation; + if (!ParentInformation.empty()) + serializeRelationship(RelationshipKind::MemberOf, *Record, + *ParentInformation.ParentRecord); + } + break; + } } -bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { +void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { // Typedefs of anonymous types have their entries unified with the underlying // type. - bool ShouldDrop = Record->UnderlyingType.Name.empty(); + bool ShouldDrop = Record.UnderlyingType.Name.empty(); // enums declared with `NS_OPTION` have a named enum and a named typedef, with // the same name - ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); + ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); if (ShouldDrop) - return true; + return; - // Create the symbol record if the other symbol droppping rules permit it. - serializeAPIRecord(Record); - if (!CurrentSymbol) - return true; + auto Typedef = serializeAPIRecord(Record); + if (!Typedef) + return; - (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; + (*Typedef)["type"] = Record.UnderlyingType.USR; - return true; + Symbols.emplace_back(std::move(*Typedef)); } -void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { - switch (Record->getKind()) { - // dispatch to the relevant walkUpFromMethod -#define CONCRETE_RECORD(CLASS, BASE, KIND) \ - case APIRecord::KIND: { \ - walkUpFrom##CLASS(static_cast(Record)); \ - break; \ - } -#include "clang/ExtractAPI/APIRecords.inc" - // otherwise fallback on the only behavior we can implement safely. - case APIRecord::RK_Unknown: - visitAPIRecord(Record); - break; - default: - llvm_unreachable("API Record with uninstantiable kind"); - } +Object SymbolGraphSerializer::serialize() { + traverseAPISet(); + return serializeCurrentGraph(); } -Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, - ExtendedModule &&EM) { +Object SymbolGraphSerializer::serializeCurrentGraph() { Object Root; serializeObject(Root, "metadata", serializeMetadata()); - serializeObject(Root, "module", serializeModuleObject(ModuleName)); + serializeObject(Root, "module", serializeModule()); - Root["symbols"] = std::move(EM.Symbols); - Root["relationships"] = std::move(EM.Relationships); + Root["symbols"] = std::move(Symbols); + Root["relationships"] = std::move(Relationships); return Root; } -void SymbolGraphSerializer::serializeGraphToStream( - raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, - ExtendedModule &&EM) { - Object Root = serializeGraph(ModuleName, std::move(EM)); +void SymbolGraphSerializer::serialize(raw_ostream &os) { + Object root = serialize(); if (Options.Compact) - OS << formatv("{0}", Value(std::move(Root))) << "\n"; + os << formatv("{0}", Value(std::move(root))) << "\n"; else - OS << formatv("{0:2}", Value(std::move(Root))) << "\n"; -} - -void SymbolGraphSerializer::serializeMainSymbolGraph( - raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, - SymbolGraphSerializerOption Options) { - SymbolGraphSerializer Serializer(API, IgnoresList, - Options.EmitSymbolLabelsForTesting); - Serializer.traverseAPISet(); - Serializer.serializeGraphToStream(OS, Options, API.ProductName, - std::move(Serializer.MainModule)); - // FIXME: TODO handle extended modules here -} - -void SymbolGraphSerializer::serializeWithExtensionGraphs( - raw_ostream &MainOutput, const APISet &API, - const APIIgnoresList &IgnoresList, - llvm::function_ref(Twine BaseName)> - CreateOutputStream, - SymbolGraphSerializerOption Options) { - SymbolGraphSerializer Serializer(API, IgnoresList, - Options.EmitSymbolLabelsForTesting); - Serializer.traverseAPISet(); - - Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, - std::move(Serializer.MainModule)); - - for (auto &ExtensionSGF : Serializer.ExtendedModules) { - if (auto ExtensionOS = - CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) - Serializer.serializeGraphToStream(*ExtensionOS, Options, - ExtensionSGF.getKey(), - std::move(ExtensionSGF.getValue())); - } + os << formatv("{0:2}", Value(std::move(root))) << "\n"; } std::optional @@ -1070,20 +1262,14 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object Root; APIIgnoresList EmptyIgnores; SymbolGraphSerializer Serializer(API, EmptyIgnores, - /*EmitSymbolLabelsForTesting*/ false, - /*ForceEmitToMainModule*/ true); - - // Set up serializer parent chain - Serializer.Hierarchy = generateHierarchyFromRecord(Record); - + /*Options.Compact*/ {true}, + /*ShouldRecurse*/ false); Serializer.serializeSingleRecord(Record); - serializeObject(Root, "symbolGraph", - Serializer.serializeGraph(API.ProductName, - std::move(Serializer.MainModule))); + serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); Language Lang = API.getLanguage(); serializeArray(Root, "parentContexts", - generateParentContexts(Serializer.Hierarchy, Lang)); + generateParentContexts(*Record, API, Lang)); Array RelatedSymbols; @@ -1101,15 +1287,14 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object RelatedSymbol; RelatedSymbol["usr"] = RelatedRecord->USR; RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); - RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); + // TODO: once we record this properly let's serialize it right. + RelatedSymbol["accessLevel"] = "public"; RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); RelatedSymbol["moduleName"] = API.ProductName; RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; serializeArray(RelatedSymbol, "parentContexts", - generateParentContexts( - generateHierarchyFromRecord(RelatedRecord), Lang)); - + generateParentContexts(*RelatedRecord, API, Lang)); RelatedSymbols.push_back(std::move(RelatedSymbol)); } diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp index 41e4e0cf1795f..3a5f62c9b2e6c 100644 --- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp +++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" -#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" using namespace clang; @@ -51,20 +50,17 @@ TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type, SmallString<128> TypeUSR; const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type); const TypedefType *TypedefTy = Type->getAs(); - StringRef OwningModuleName; if (TypeDecl) { if (!TypedefTy) TypeName = TypeDecl->getName().str(); clang::index::generateUSRForDecl(TypeDecl, TypeUSR); - if (auto *OwningModule = TypeDecl->getImportedOwningModule()) - OwningModuleName = OwningModule->Name; } else { clang::index::generateUSRForType(Type, Context, TypeUSR); } - return API.createSymbolReference(TypeName, TypeUSR, OwningModuleName); + return {API.copyString(TypeName), API.copyString(TypeUSR)}; } std::string TypedefUnderlyingTypeResolver::getUSRForType(QualType Type) const { diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index f85f0365616f9..2446aee571f44 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -181,13 +181,9 @@ CreateFrontendAction(CompilerInstance &CI) { #endif // Wrap the base FE action in an extract api action to generate - // symbol graph as a biproduct of compilation (enabled with - // --emit-symbol-graph option) - if (FEOpts.EmitSymbolGraph) { - if (FEOpts.SymbolGraphOutputDir.empty()) { - CI.getDiagnostics().Report(diag::warn_missing_symbol_graph_dir); - CI.getFrontendOpts().SymbolGraphOutputDir = "."; - } + // symbol graph as a biproduct of compilation ( enabled with + // --emit-symbol-graph option ) + if (!FEOpts.SymbolGraphOutputDir.empty()) { CI.getCodeGenOpts().ClearASTBeforeBackend = false; Act = std::make_unique(std::move(Act)); } diff --git a/clang/test/ExtractAPI/anonymous_record_no_typedef.c b/clang/test/ExtractAPI/anonymous_record_no_typedef.c index 049e8b1f85bb9..0e50f4a0948c9 100644 --- a/clang/test/ExtractAPI/anonymous_record_no_typedef.c +++ b/clang/test/ExtractAPI/anonymous_record_no_typedef.c @@ -1,9 +1,8 @@ -// XFAIL: * // RUN: rm -rf %t // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/availability.c b/clang/test/ExtractAPI/availability.c index 12ac73f0d4295..3c1ef5c45b634 100644 --- a/clang/test/ExtractAPI/availability.c +++ b/clang/test/ExtractAPI/availability.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf --product-name=Availability -triple arm64-apple-macosx -x c-header %t/input.h -o %t/output.json -verify +// RUN: %clang_cc1 -extract-api --product-name=Availability -triple arm64-apple-macosx -x c-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. // RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ diff --git a/clang/test/ExtractAPI/bool.c b/clang/test/ExtractAPI/bool.c index efab6dfeef03b..f4082edeb02ed 100644 --- a/clang/test/ExtractAPI/bool.c +++ b/clang/test/ExtractAPI/bool.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf -target arm64-apple-macosx \ +// RUN: %clang -extract-api -target arm64-apple-macosx \ // RUN: %t/input.h -o %t/output.json // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/bool.cpp b/clang/test/ExtractAPI/bool.cpp index f7d10c61dba4b..1b445e220a4a0 100644 --- a/clang/test/ExtractAPI/bool.cpp +++ b/clang/test/ExtractAPI/bool.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/class.cpp b/clang/test/ExtractAPI/class.cpp index 0c5db8e9c9d21..21cac43057524 100644 --- a/clang/test/ExtractAPI/class.cpp +++ b/clang/test/ExtractAPI/class.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/class_template.cpp b/clang/test/ExtractAPI/class_template.cpp index 4f2670d7b6997..b04dca6bffda1 100644 --- a/clang/test/ExtractAPI/class_template.cpp +++ b/clang/test/ExtractAPI/class_template.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/class_template_param_inheritance.cpp b/clang/test/ExtractAPI/class_template_param_inheritance.cpp index 3d7b09f93ed6d..0d38fd1b7f530 100644 --- a/clang/test/ExtractAPI/class_template_param_inheritance.cpp +++ b/clang/test/ExtractAPI/class_template_param_inheritance.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/class_template_partial_spec.cpp b/clang/test/ExtractAPI/class_template_partial_spec.cpp index c8d9cc78d41c5..eba069319ce45 100644 --- a/clang/test/ExtractAPI/class_template_partial_spec.cpp +++ b/clang/test/ExtractAPI/class_template_partial_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. @@ -15,7 +15,7 @@ template class Foo {}; template class Foo {}; -// expected-no-diagnostics +/// expected-no-diagnostics //--- reference.output.json.in { diff --git a/clang/test/ExtractAPI/class_template_spec.cpp b/clang/test/ExtractAPI/class_template_spec.cpp index 06a95314dc4aa..4b183cbb84458 100644 --- a/clang/test/ExtractAPI/class_template_spec.cpp +++ b/clang/test/ExtractAPI/class_template_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/concept.cpp b/clang/test/ExtractAPI/concept.cpp index 443eac2971f0e..ff4e71026e728 100644 --- a/clang/test/ExtractAPI/concept.cpp +++ b/clang/test/ExtractAPI/concept.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -std=c++20 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -std=c++20 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/constructor_destructor.cpp b/clang/test/ExtractAPI/constructor_destructor.cpp index 27112c95ac45c..9742d4bae2613 100644 --- a/clang/test/ExtractAPI/constructor_destructor.cpp +++ b/clang/test/ExtractAPI/constructor_destructor.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. @@ -137,7 +137,7 @@ class Foo { "precise": "c:@S@Foo@F@Foo#" }, "kind": { - "displayName": "Constructor", + "displayName": "Instance Method", "identifier": "c++.method" }, "location": { @@ -193,7 +193,7 @@ class Foo { "precise": "c:@S@Foo@F@~Foo#" }, "kind": { - "displayName": "Destructor", + "displayName": "Instance Method", "identifier": "c++.method" }, "location": { diff --git a/clang/test/ExtractAPI/conversions.cpp b/clang/test/ExtractAPI/conversions.cpp index 07688ff770979..fc8d067544373 100644 --- a/clang/test/ExtractAPI/conversions.cpp +++ b/clang/test/ExtractAPI/conversions.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/emit-symbol-graph/multi_file.c b/clang/test/ExtractAPI/emit-symbol-graph/multi_file.c index e668f69bc7e05..e6b72d5881e7d 100644 --- a/clang/test/ExtractAPI/emit-symbol-graph/multi_file.c +++ b/clang/test/ExtractAPI/emit-symbol-graph/multi_file.c @@ -5,19 +5,18 @@ // RUN: %t/reference.main.json.in >> %t/reference.main.json // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.test.json.in >> %t/reference.test.json -// RUN: %clang_cc1 %t/test.c %t/main.c -emit-symbol-graph --pretty-sgf \ -// RUN: --symbol-graph-dir=%t/SymbolGraphs --product-name=multifile_test -triple=x86_64-apple-macosx12.0.0 +// RUN: %clang_cc1 %t/test.c %t/main.c --emit-symbol-graph=%t/SymbolGraphs --product-name=multifile_test -triple=x86_64-apple-macosx12.0.0 // Test main.json // Generator version is not consistent across test runs, normalize it. // RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ -// RUN: %t/SymbolGraphs/main.c.symbols.json > %t/output-normalized.json +// RUN: %t/SymbolGraphs/main.json > %t/output-normalized.json // RUN: diff %t/reference.main.json %t/output-normalized.json // Test test.json // Generator version is not consistent across test runs, normalize it. // RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ -// RUN: %t/SymbolGraphs/test.c.symbols.json > %t/output-normalized.json +// RUN: %t/SymbolGraphs/test.json > %t/output-normalized.json // RUN: diff %t/reference.test.json %t/output-normalized.json // CHECK-NOT: error: diff --git a/clang/test/ExtractAPI/emit-symbol-graph/single_file.c b/clang/test/ExtractAPI/emit-symbol-graph/single_file.c index b00b5f5237c9a..8599e82e10783 100644 --- a/clang/test/ExtractAPI/emit-symbol-graph/single_file.c +++ b/clang/test/ExtractAPI/emit-symbol-graph/single_file.c @@ -3,12 +3,11 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 %t/main.c -emit-symbol-graph --pretty-sgf \ -// RUN: --symbol-graph-dir=%t/SymbolGraphs --product-name=basicfile -triple=x86_64-apple-macosx12.0.0 +// RUN: %clang_cc1 %t/main.c --emit-symbol-graph=%t/SymbolGraphs --product-name=basicfile -triple=x86_64-apple-macosx12.0.0 // Generator version is not consistent across test runs, normalize it. // RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ -// RUN: %t/SymbolGraphs/main.c.symbols.json >> %t/output-normalized.json +// RUN: %t/SymbolGraphs/main.json >> %t/output-normalized.json // RUN: diff %t/reference.output.json %t/output-normalized.json // CHECK-NOT: error: diff --git a/clang/test/ExtractAPI/enum.c b/clang/test/ExtractAPI/enum.c index 1cdf45ca3cdf4..94499d9fc3a63 100644 --- a/clang/test/ExtractAPI/enum.c +++ b/clang/test/ExtractAPI/enum.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/field_template.cpp b/clang/test/ExtractAPI/field_template.cpp index 2058ed008cfe4..f05e826a8eb49 100644 --- a/clang/test/ExtractAPI/field_template.cpp +++ b/clang/test/ExtractAPI/field_template.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/function_noexcepts.cpp b/clang/test/ExtractAPI/function_noexcepts.cpp index d95eaaa7e769a..3fc7263cd6a18 100644 --- a/clang/test/ExtractAPI/function_noexcepts.cpp +++ b/clang/test/ExtractAPI/function_noexcepts.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_func_template.cpp b/clang/test/ExtractAPI/global_func_template.cpp index f43a618ec0c36..8def9745bcce8 100644 --- a/clang/test/ExtractAPI/global_func_template.cpp +++ b/clang/test/ExtractAPI/global_func_template.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_func_template_spec.cpp b/clang/test/ExtractAPI/global_func_template_spec.cpp index fe046e9c3b9da..a24263dc14584 100644 --- a/clang/test/ExtractAPI/global_func_template_spec.cpp +++ b/clang/test/ExtractAPI/global_func_template_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_record.c b/clang/test/ExtractAPI/global_record.c index a08d51d21f955..623032b45bfd2 100644 --- 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:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf --product-name=GlobalRecord -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. diff --git a/clang/test/ExtractAPI/global_record_multifile.c b/clang/test/ExtractAPI/global_record_multifile.c index ffdfbcb7eb808..f9d3889b5d9de 100644 --- a/clang/test/ExtractAPI/global_record_multifile.c +++ b/clang/test/ExtractAPI/global_record_multifile.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf --product-name=GlobalRecord -target arm64-apple-macosx \ +// RUN: %clang -extract-api --product-name=GlobalRecord -target arm64-apple-macosx \ // RUN: %t/input1.h %t/input2.h %t/input3.h -o %t/output.json | FileCheck -allow-empty %s // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_var_template.cpp b/clang/test/ExtractAPI/global_var_template.cpp index 94f3713cd3d31..bee2ea601bd72 100644 --- a/clang/test/ExtractAPI/global_var_template.cpp +++ b/clang/test/ExtractAPI/global_var_template.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp index 91084f258878e..e98076cdb1d01 100644 --- a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp +++ b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/global_var_template_spec.cpp b/clang/test/ExtractAPI/global_var_template_spec.cpp index ff4d8d17aecbe..cca2ab3db7b8b 100644 --- a/clang/test/ExtractAPI/global_var_template_spec.cpp +++ b/clang/test/ExtractAPI/global_var_template_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/known_files_only.c b/clang/test/ExtractAPI/known_files_only.c index de1e786c1969d..68881aa9e3aad 100644 --- a/clang/test/ExtractAPI/known_files_only.c +++ b/clang/test/ExtractAPI/known_files_only.c @@ -1,7 +1,17 @@ // RUN: rm -rf %t // RUN: split-file %s %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --product-name=GlobalRecord -triple arm64-apple-macosx \ -// RUN: %t/input1.h -verify -o - | FileCheck %s +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api --product-name=GlobalRecord -target arm64-apple-macosx \ +// RUN: %t/input1.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: //--- input1.h int num; @@ -14,6 +24,87 @@ char not_emitted; void foo(int); struct Foo { int a; }; -// CHECK-NOT: input2.h - -// expected-no-diagnostics +//--- reference.output.json.in +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 5, + "patch": 3 + }, + "generator": "?" + }, + "module": { + "name": "GlobalRecord", + "platform": { + "architecture": "arm64", + "operatingSystem": { + "minimumVersion": { + "major": 11, + "minor": 0, + "patch": 0 + }, + "name": "macosx" + }, + "vendor": "apple" + } + }, + "relationships": [], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "num" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@num" + }, + "kind": { + "displayName": "Global Variable", + "identifier": "c.var" + }, + "location": { + "position": { + "character": 4, + "line": 0 + }, + "uri": "file://INPUT_DIR/input1.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "num" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "num" + } + ], + "title": "num" + }, + "pathComponents": [ + "num" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/language.c b/clang/test/ExtractAPI/language.c index 90832fd8a2aff..fe98626c84613 100644 --- a/clang/test/ExtractAPI/language.c +++ b/clang/test/ExtractAPI/language.c @@ -7,11 +7,11 @@ // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/objcpp.reference.output.json.in >> %t/objcpp.reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -x c-header -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -x c-header -triple arm64-apple-macosx \ // RUN: %t/c.h -o %t/c.output.json | FileCheck -allow-empty %s -// RUN: %clang_cc1 -extract-api --pretty-sgf -x objective-c-header -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -x objective-c-header -triple arm64-apple-macosx \ // RUN: %t/objc.h -o %t/objc.output.json | FileCheck -allow-empty %s -// RUN: %clang_cc1 -extract-api --pretty-sgf -x objective-c++-header -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -x objective-c++-header -triple arm64-apple-macosx \ // RUN: %t/objcpp.h -o %t/objcpp.output.json | FileCheck -allow-empty %s // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/macro_undefined.c b/clang/test/ExtractAPI/macro_undefined.c index ec60f95d3d6c4..1a4ed20545e0d 100644 --- a/clang/test/ExtractAPI/macro_undefined.c +++ b/clang/test/ExtractAPI/macro_undefined.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf --product-name=Macros -target arm64-apple-macosx \ +// RUN: %clang -extract-api --product-name=Macros -target arm64-apple-macosx \ // RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/macros.c b/clang/test/ExtractAPI/macros.c index 10003fe6f6e40..d5807f6377ff6 100644 --- a/clang/test/ExtractAPI/macros.c +++ b/clang/test/ExtractAPI/macros.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf --product-name=Macros -target arm64-apple-macosx \ +// RUN: %clang -extract-api --product-name=Macros -target arm64-apple-macosx \ // RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/metadata_and_module.c b/clang/test/ExtractAPI/metadata_and_module.c deleted file mode 100644 index 79574a20ed95a..0000000000000 --- a/clang/test/ExtractAPI/metadata_and_module.c +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --product-name=module -triple arm64-apple-macosx -x c-header %s -o %t/module.symbols.json -verify - -// RUN: FileCheck %s --input-file %t/module.symbols.json --check-prefix METADATA -// RUN: FileCheck %s --input-file %t/module.symbols.json --check-prefix MOD - -// expected-no-diagnostics - -// METADATA: "metadata": { -// METADATA-NEXT: "formatVersion": { -// METADATA-NEXT: "major": -// METADATA-NEXT: "minor": -// METADATA-NEXT: "patch": -// METADATA-NEXT: }, -// METADATA-NEXT: "generator": -// METADATA-NEXT: } - -// MOD: "module": { -// MOD-NEXT: "name": "module", -// MOD-NEXT: "platform": { -// MOD-NEXT: "architecture": "arm64", -// MOD-NEXT: "operatingSystem": { -// MOD-NEXT: "minimumVersion": { -// MOD-NEXT: "major": -// MOD-NEXT: "minor": -// MOD-NEXT: "patch": -// MOD-NEXT: }, -// MOD-NEXT: "name": "macosx" -// MOD-NEXT: }, -// MOD-NEXT: "vendor": "apple" -// MOD-NEXT: } -// MOD-NEXT: } diff --git a/clang/test/ExtractAPI/method_template.cpp b/clang/test/ExtractAPI/method_template.cpp index 714f9cac26c20..8d832337216a2 100644 --- a/clang/test/ExtractAPI/method_template.cpp +++ b/clang/test/ExtractAPI/method_template.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/method_template_spec.cpp b/clang/test/ExtractAPI/method_template_spec.cpp index 8eaffdefd827a..706d99da558fe 100644 --- a/clang/test/ExtractAPI/method_template_spec.cpp +++ b/clang/test/ExtractAPI/method_template_spec.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/methods.cpp b/clang/test/ExtractAPI/methods.cpp index 412c0bb3f903c..8b024a8c3036f 100644 --- a/clang/test/ExtractAPI/methods.cpp +++ b/clang/test/ExtractAPI/methods.cpp @@ -1,221 +1,467 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -triple arm64-apple-macosx -x c++-header %s -o %t/output.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ +// RUN: -x c++-header %t/input.h -o %t/output.json -verify +// 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 + +//--- input.h class Foo { - // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GETCOUNT int getCount(); - // GETCOUNT: "!testRelLabel": "memberOf $ c:@S@Foo@F@getCount# $ c:@S@Foo" - // GETCOUNT-LABEL: "!testLabel": "c:@S@Foo@F@getCount#" - // GETCOUNT: "accessLevel": "private", - // GETCOUNT: "declarationFragments": [ - // GETCOUNT-NEXT: { - // GETCOUNT-NEXT: "kind": "typeIdentifier", - // GETCOUNT-NEXT: "preciseIdentifier": "c:I", - // GETCOUNT-NEXT: "spelling": "int" - // GETCOUNT-NEXT: }, - // GETCOUNT-NEXT: { - // GETCOUNT-NEXT: "kind": "text", - // GETCOUNT-NEXT: "spelling": " " - // GETCOUNT-NEXT: }, - // GETCOUNT-NEXT: { - // GETCOUNT-NEXT: "kind": "identifier", - // GETCOUNT-NEXT: "spelling": "getCount" - // GETCOUNT-NEXT: }, - // GETCOUNT-NEXT: { - // GETCOUNT-NEXT: "kind": "text", - // GETCOUNT-NEXT: "spelling": "();" - // GETCOUNT-NEXT: } - // GETCOUNT-NEXT: ], - // GETCOUNT: "functionSignature": { - // GETCOUNT-NEXT: "returns": [ - // GETCOUNT-NEXT: { - // GETCOUNT-NEXT: "kind": "typeIdentifier", - // GETCOUNT-NEXT: "preciseIdentifier": "c:I", - // GETCOUNT-NEXT: "spelling": "int" - // GETCOUNT-NEXT: } - // GETCOUNT-NEXT: ] - // GETCOUNT-NEXT: }, - // GETCOUNT: "displayName": "Instance Method", - // GETCOUNT-NEXT: "identifier": "c++.method" - // GETCOUNT: "title": "getCount" - // GETCOUNT: "pathComponents": [ - // GETCOUNT-NEXT: "Foo", - // GETCOUNT-NEXT: "getCount" - // GETCOUNT-NEXT: ] - // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix SETL void setLength(int length) noexcept; - // SETL: "!testRelLabel": "memberOf $ c:@S@Foo@F@setLength#I# $ c:@S@Foo" - // SETL-LABEL: "!testLabel": "c:@S@Foo@F@setLength#I#" - // SETL: "declarationFragments": [ - // SETL-NEXT: { - // SETL-NEXT: "kind": "typeIdentifier", - // SETL-NEXT: "preciseIdentifier": "c:v", - // SETL-NEXT: "spelling": "void" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": " " - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "identifier", - // SETL-NEXT: "spelling": "setLength" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": "(" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "typeIdentifier", - // SETL-NEXT: "preciseIdentifier": "c:I", - // SETL-NEXT: "spelling": "int" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": " " - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "internalParam", - // SETL-NEXT: "spelling": "length" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": ")" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": " " - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "keyword", - // SETL-NEXT: "spelling": "noexcept" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": ";" - // SETL-NEXT: } - // SETL-NEXT: ], - // SETL: "functionSignature": { - // SETL-NEXT: "parameters": [ - // SETL-NEXT: { - // SETL-NEXT: "declarationFragments": [ - // SETL-NEXT: { - // SETL-NEXT: "kind": "typeIdentifier", - // SETL-NEXT: "preciseIdentifier": "c:I", - // SETL-NEXT: "spelling": "int" - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "text", - // SETL-NEXT: "spelling": " " - // SETL-NEXT: }, - // SETL-NEXT: { - // SETL-NEXT: "kind": "internalParam", - // SETL-NEXT: "spelling": "length" - // SETL-NEXT: } - // SETL-NEXT: ], - // SETL-NEXT: "name": "length" - // SETL-NEXT: } - // SETL-NEXT: ], - // SETL-NEXT: "returns": [ - // SETL-NEXT: { - // SETL-NEXT: "kind": "typeIdentifier", - // SETL-NEXT: "preciseIdentifier": "c:v", - // SETL-NEXT: "spelling": "void" - // SETL-NEXT: } - // SETL-NEXT: ] - // SETL-NEXT: }, public: - // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GETFOO static double getFoo(); - // GETFOO: "!testRelLabel": "memberOf $ c:@S@Foo@F@getFoo#S $ c:@S@Foo" - - // GETFOO-LABEL: "!testLabel": "c:@S@Foo@F@getFoo#S" - // GETFOO: "accessLevel": "public", - // GETFOO: "declarationFragments": [ - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "keyword", - // GETFOO-NEXT: "spelling": "static" - // GETFOO-NEXT: }, - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "text", - // GETFOO-NEXT: "spelling": " " - // GETFOO-NEXT: }, - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "typeIdentifier", - // GETFOO-NEXT: "preciseIdentifier": "c:d", - // GETFOO-NEXT: "spelling": "double" - // GETFOO-NEXT: }, - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "text", - // GETFOO-NEXT: "spelling": " " - // GETFOO-NEXT: }, - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "identifier", - // GETFOO-NEXT: "spelling": "getFoo" - // GETFOO-NEXT: }, - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "text", - // GETFOO-NEXT: "spelling": "();" - // GETFOO-NEXT: } - // GETFOO-NEXT: ], - // GETFOO: "functionSignature": { - // GETFOO-NEXT: "returns": [ - // GETFOO-NEXT: { - // GETFOO-NEXT: "kind": "typeIdentifier", - // GETFOO-NEXT: "preciseIdentifier": "c:d", - // GETFOO-NEXT: "spelling": "double" - // GETFOO-NEXT: } - // GETFOO-NEXT: ] - // GETFOO-NEXT: }, - // GETFOO: "kind": { - // GETFOO-NEXT: "displayName": "Static Method", - // GETFOO-NEXT: "identifier": "c++.type.method" - // GETFOO-NEXT: }, protected: - // RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GETBAR constexpr int getBar() const; - // GETBAR: "!testRelLabel": "memberOf $ c:@S@Foo@F@getBar#1 $ c:@S@Foo" - - // GETBAR-LABEL: "!testLabel": "c:@S@Foo@F@getBar#1" - // GETBAR: "accessLevel": "protected" - // GETBAR: "declarationFragments": [ - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "keyword", - // GETBAR-NEXT: "spelling": "constexpr" - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "text", - // GETBAR-NEXT: "spelling": " " - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "typeIdentifier", - // GETBAR-NEXT: "preciseIdentifier": "c:I", - // GETBAR-NEXT: "spelling": "int" - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "text", - // GETBAR-NEXT: "spelling": " " - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "identifier", - // GETBAR-NEXT: "spelling": "getBar" - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "text", - // GETBAR-NEXT: "spelling": "() " - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "keyword", - // GETBAR-NEXT: "spelling": "const" - // GETBAR-NEXT: }, - // GETBAR-NEXT: { - // GETBAR-NEXT: "kind": "text", - // GETBAR-NEXT: "spelling": ";" - // GETBAR-NEXT: } - // GETBAR-NEXT: ], }; +/// expected-no-diagnostics -// expected-no-diagnostics +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:@S@Foo@F@getCount#", + "target": "c:@S@Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:@S@Foo@F@setLength#I#", + "target": "c:@S@Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:@S@Foo@F@getBar#1", + "target": "c:@S@Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:@S@Foo@F@getFoo#S", + "target": "c:@S@Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo" + }, + "kind": { + "displayName": "Class", + "identifier": "c++.class" + }, + "location": { + "position": { + "character": 6, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "private", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "getCount" + }, + { + "kind": "text", + "spelling": "();" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@F@getCount#" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 6, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "getCount" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "getCount" + } + ], + "title": "getCount" + }, + "pathComponents": [ + "Foo", + "getCount" + ] + }, + { + "accessLevel": "private", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "setLength" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "length" + }, + { + "kind": "text", + "spelling": ")" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "noexcept" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "length" + } + ], + "name": "length" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@F@setLength#I#" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 7, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "setLength" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "setLength" + } + ], + "title": "setLength" + }, + "pathComponents": [ + "Foo", + "setLength" + ] + }, + { + "accessLevel": "protected", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "constexpr" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "getBar" + }, + { + "kind": "text", + "spelling": "() " + }, + { + "kind": "keyword", + "spelling": "const" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@F@getBar#1" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "c++.method" + }, + "location": { + "position": { + "character": 16, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "getBar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "getBar" + } + ], + "title": "getBar" + }, + "pathComponents": [ + "Foo", + "getBar" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "static" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:d", + "spelling": "double" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "getFoo" + }, + { + "kind": "text", + "spelling": "();" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:d", + "spelling": "double" + } + ] + }, + "identifier": { + "interfaceLanguage": "c++", + "precise": "c:@S@Foo@F@getFoo#S" + }, + "kind": { + "displayName": "Static Method", + "identifier": "c++.type.method" + }, + "location": { + "position": { + "character": 16, + "line": 6 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "getFoo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "getFoo" + } + ], + "title": "getFoo" + }, + "pathComponents": [ + "Foo", + "getFoo" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/multiple_inheritance.cpp b/clang/test/ExtractAPI/multiple_inheritance.cpp index 7d49cf4326465..a1f069be0de61 100644 --- a/clang/test/ExtractAPI/multiple_inheritance.cpp +++ b/clang/test/ExtractAPI/multiple_inheritance.cpp @@ -3,7 +3,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/namespace.cpp b/clang/test/ExtractAPI/namespace.cpp index 73e0728b9a441..e0c36dd3d60fe 100644 --- a/clang/test/ExtractAPI/namespace.cpp +++ b/clang/test/ExtractAPI/namespace.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -std=c++20 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/nested_namespaces.cpp b/clang/test/ExtractAPI/nested_namespaces.cpp index c6912cfb46312..bd13ef93807c0 100644 --- a/clang/test/ExtractAPI/nested_namespaces.cpp +++ b/clang/test/ExtractAPI/nested_namespaces.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -std=c++20 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/objc_block.m b/clang/test/ExtractAPI/objc_block.m index 4a4335ec09832..a7a4f5696333c 100644 --- a/clang/test/ExtractAPI/objc_block.m +++ b/clang/test/ExtractAPI/objc_block.m @@ -1,630 +1,965 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -fblocks -triple arm64-apple-macosx -x objective-c-header %s -o %t/output.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api -fblocks -triple arm64-apple-macosx \ +// RUN: -x objective-c-header %t/input.h -o %t/output.json -verify +// 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 + +//--- input.h @interface Foo -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix NOPARAM -(void)methodBlockNoParam:(void (^)())block; -// NOPARAM-LABEL: "!testLabel": "c:objc(cs)Foo(im)methodBlockNoParam:" -// NOPARAM: "declarationFragments": [ -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": "- (" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "typeIdentifier", -// NOPARAM-NEXT: "preciseIdentifier": "c:v", -// NOPARAM-NEXT: "spelling": "void" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": ") " -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "identifier", -// NOPARAM-NEXT: "spelling": "methodBlockNoParam:" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": "(" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "typeIdentifier", -// NOPARAM-NEXT: "preciseIdentifier": "c:v", -// NOPARAM-NEXT: "spelling": "void" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": " (^" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": ")()) " -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "internalParam", -// NOPARAM-NEXT: "spelling": "block" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": ";" -// NOPARAM-NEXT: } -// NOPARAM-NEXT: ], -// NOPARAM: "functionSignature": { -// NOPARAM-NEXT: "parameters": [ -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "declarationFragments": [ -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": "(" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "typeIdentifier", -// NOPARAM-NEXT: "preciseIdentifier": "c:v", -// NOPARAM-NEXT: "spelling": "void" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": " (^" -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "text", -// NOPARAM-NEXT: "spelling": ")()) " -// NOPARAM-NEXT: }, -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "internalParam", -// NOPARAM-NEXT: "spelling": "block" -// NOPARAM-NEXT: } -// NOPARAM-NEXT: ], -// NOPARAM-NEXT: "name": "block" -// NOPARAM-NEXT: } -// NOPARAM-NEXT: ], -// NOPARAM-NEXT: "returns": [ -// NOPARAM-NEXT: { -// NOPARAM-NEXT: "kind": "typeIdentifier", -// NOPARAM-NEXT: "preciseIdentifier": "c:v", -// NOPARAM-NEXT: "spelling": "void" -// NOPARAM-NEXT: } -// NOPARAM-NEXT: ] -// NOPARAM-NEXT: } - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix PARAM -(void)methodBlockWithParam:(int (^)(int foo))block; -// PARAM-LABEL: "!testLabel": "c:objc(cs)Foo(im)methodBlockWithParam:" -// PARAM: "declarationFragments": [ -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": "- (" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:v", -// PARAM-NEXT: "spelling": "void" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ") " -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "identifier", -// PARAM-NEXT: "spelling": "methodBlockWithParam:" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": "(" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:I", -// PARAM-NEXT: "spelling": "int" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": " (^" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ")(" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:I", -// PARAM-NEXT: "spelling": "int" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": " " -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "internalParam", -// PARAM-NEXT: "spelling": "foo" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ")) " -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "internalParam", -// PARAM-NEXT: "spelling": "block" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ";" -// PARAM-NEXT: } -// PARAM-NEXT: ], -// PARAM: "functionSignature": { -// PARAM-NEXT: "parameters": [ -// PARAM-NEXT: { -// PARAM-NEXT: "declarationFragments": [ -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": "(" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:I", -// PARAM-NEXT: "spelling": "int" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": " (^" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ")(" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:I", -// PARAM-NEXT: "spelling": "int" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": " " -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "internalParam", -// PARAM-NEXT: "spelling": "foo" -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "text", -// PARAM-NEXT: "spelling": ")) " -// PARAM-NEXT: }, -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "internalParam", -// PARAM-NEXT: "spelling": "block" -// PARAM-NEXT: } -// PARAM-NEXT: ], -// PARAM-NEXT: "name": "block" -// PARAM-NEXT: } -// PARAM-NEXT: ], -// PARAM-NEXT: "returns": [ -// PARAM-NEXT: { -// PARAM-NEXT: "kind": "typeIdentifier", -// PARAM-NEXT: "preciseIdentifier": "c:v", -// PARAM-NEXT: "spelling": "void" -// PARAM-NEXT: } -// PARAM-NEXT: ] -// PARAM-NEXT: } - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix MULTIPARAM -(void)methodBlockWithMultipleParam:(int (^)(int foo, unsigned baz))block; -// MULTIPARAM-LABEL: "!testLabel": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:" -// MULTIPARAM: "declarationFragments": [ -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": "- (" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:v", -// MULTIPARAM-NEXT: "spelling": "void" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ") " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "identifier", -// MULTIPARAM-NEXT: "spelling": "methodBlockWithMultipleParam:" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": "(" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:I", -// MULTIPARAM-NEXT: "spelling": "int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " (^" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ")(" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:I", -// MULTIPARAM-NEXT: "spelling": "int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "foo" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ", " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:i", -// MULTIPARAM-NEXT: "spelling": "unsigned int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "baz" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ")) " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "block" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ";" -// MULTIPARAM-NEXT: } -// MULTIPARAM-NEXT: ], -// MULTIPARAM: "functionSignature": { -// MULTIPARAM-NEXT: "parameters": [ -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "declarationFragments": [ -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": "(" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:I", -// MULTIPARAM-NEXT: "spelling": "int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " (^" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ")(" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:I", -// MULTIPARAM-NEXT: "spelling": "int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "foo" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ", " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:i", -// MULTIPARAM-NEXT: "spelling": "unsigned int" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": " " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "baz" -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "text", -// MULTIPARAM-NEXT: "spelling": ")) " -// MULTIPARAM-NEXT: }, -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "internalParam", -// MULTIPARAM-NEXT: "spelling": "block" -// MULTIPARAM-NEXT: } -// MULTIPARAM-NEXT: ], -// MULTIPARAM-NEXT: "name": "block" -// MULTIPARAM-NEXT: } -// MULTIPARAM-NEXT: ], -// MULTIPARAM-NEXT: "returns": [ -// MULTIPARAM-NEXT: { -// MULTIPARAM-NEXT: "kind": "typeIdentifier", -// MULTIPARAM-NEXT: "preciseIdentifier": "c:v", -// MULTIPARAM-NEXT: "spelling": "void" -// MULTIPARAM-NEXT: } -// MULTIPARAM-NEXT: ] -// MULTIPARAM-NEXT: }, - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix VARIADIC -(void)methodBlockVariadic:(int (^)(int foo, ...))block; -// VARIADIC-LABEL: "!testLabel": "c:objc(cs)Foo(im)methodBlockVariadic:" -// VARIADIC: "declarationFragments": [ -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": "- (" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:v", -// VARIADIC-NEXT: "spelling": "void" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ") " -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "identifier", -// VARIADIC-NEXT: "spelling": "methodBlockVariadic:" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": "(" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:I", -// VARIADIC-NEXT: "spelling": "int" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": " (^" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ")(" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:I", -// VARIADIC-NEXT: "spelling": "int" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": " " -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "internalParam", -// VARIADIC-NEXT: "spelling": "foo" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ", ...)) " -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "internalParam", -// VARIADIC-NEXT: "spelling": "block" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ";" -// VARIADIC-NEXT: } -// VARIADIC-NEXT: ], -// VARIADIC: "functionSignature": { -// VARIADIC-NEXT: "parameters": [ -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "declarationFragments": [ -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": "(" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:I", -// VARIADIC-NEXT: "spelling": "int" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": " (^" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ")(" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:I", -// VARIADIC-NEXT: "spelling": "int" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": " " -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "internalParam", -// VARIADIC-NEXT: "spelling": "foo" -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "text", -// VARIADIC-NEXT: "spelling": ", ...)) " -// VARIADIC-NEXT: }, -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "internalParam", -// VARIADIC-NEXT: "spelling": "block" -// VARIADIC-NEXT: } -// VARIADIC-NEXT: ], -// VARIADIC-NEXT: "name": "block" -// VARIADIC-NEXT: } -// VARIADIC-NEXT: ], -// VARIADIC-NEXT: "returns": [ -// VARIADIC-NEXT: { -// VARIADIC-NEXT: "kind": "typeIdentifier", -// VARIADIC-NEXT: "preciseIdentifier": "c:v", -// VARIADIC-NEXT: "spelling": "void" -// VARIADIC-NEXT: } -// VARIADIC-NEXT: ] -// VARIADIC-NEXT: }, @end -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix FUNC void func(int (^arg)(int foo)); -// FUNC-LABEL: "!testLabel": "c:@F@func" -// FUNC: "declarationFragments": [ -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:v", -// FUNC-NEXT: "spelling": "void" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": " " -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "identifier", -// FUNC-NEXT: "spelling": "func" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": "(" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:I", -// FUNC-NEXT: "spelling": "int" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": " (^" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "internalParam", -// FUNC-NEXT: "spelling": "arg" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": ")(" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:I", -// FUNC-NEXT: "spelling": "int" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": " " -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "internalParam", -// FUNC-NEXT: "spelling": "foo" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": "));" -// FUNC-NEXT: } -// FUNC-NEXT: ], -// FUNC: "functionSignature": { -// FUNC-NEXT: "parameters": [ -// FUNC-NEXT: { -// FUNC-NEXT: "declarationFragments": [ -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:I", -// FUNC-NEXT: "spelling": "int" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": " (^" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "internalParam", -// FUNC-NEXT: "spelling": "arg" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": ")(" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:I", -// FUNC-NEXT: "spelling": "int" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": " " -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "internalParam", -// FUNC-NEXT: "spelling": "foo" -// FUNC-NEXT: }, -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "text", -// FUNC-NEXT: "spelling": ")" -// FUNC-NEXT: } -// FUNC-NEXT: ], -// FUNC-NEXT: "name": "arg" -// FUNC-NEXT: } -// FUNC-NEXT: ], -// FUNC-NEXT: "returns": [ -// FUNC-NEXT: { -// FUNC-NEXT: "kind": "typeIdentifier", -// FUNC-NEXT: "preciseIdentifier": "c:v", -// FUNC-NEXT: "spelling": "void" -// FUNC-NEXT: } -// FUNC-NEXT: ] -// FUNC-NEXT: }, -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBAL int (^global)(int foo); -// GLOBAL-LABEL: "!testLabel": "c:@global" -// GLOBAL: "declarationFragments": [ -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "typeIdentifier", -// GLOBAL-NEXT: "preciseIdentifier": "c:I", -// GLOBAL-NEXT: "spelling": "int" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "text", -// GLOBAL-NEXT: "spelling": " (^" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "identifier", -// GLOBAL-NEXT: "spelling": "global" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "text", -// GLOBAL-NEXT: "spelling": ")(" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "typeIdentifier", -// GLOBAL-NEXT: "preciseIdentifier": "c:I", -// GLOBAL-NEXT: "spelling": "int" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "text", -// GLOBAL-NEXT: "spelling": " " -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "internalParam", -// GLOBAL-NEXT: "spelling": "foo" -// GLOBAL-NEXT: }, -// GLOBAL-NEXT: { -// GLOBAL-NEXT: "kind": "text", -// GLOBAL-NEXT: "spelling": ");" -// GLOBAL-NEXT: } -// GLOBAL-NEXT: ], ///expected-no-diagnostics + +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockNoParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockWithParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Foo(im)methodBlockVariadic:", + "target": "c:objc(cs)Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "identifier", + "spelling": "global" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@global" + }, + "kind": { + "displayName": "Global Variable", + "identifier": "objective-c.var" + }, + "location": { + "position": { + "character": 6, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "global" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "global" + } + ], + "title": "global" + }, + "pathComponents": [ + "global" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "func" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "internalParam", + "spelling": "arg" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": "));" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "internalParam", + "spelling": "arg" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "name": "arg" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@F@func" + }, + "kind": { + "displayName": "Function", + "identifier": "objective-c.func" + }, + "location": { + "position": { + "character": 5, + "line": 7 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "func" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "func" + } + ], + "title": "func" + }, + "pathComponents": [ + "func" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "methodBlockNoParam:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")()) " + }, + { + "kind": "internalParam", + "spelling": "block" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")()) " + }, + { + "kind": "internalParam", + "spelling": "block" + } + ], + "name": "block" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo(im)methodBlockNoParam:" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "methodBlockNoParam:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "methodBlockNoParam:" + } + ], + "title": "methodBlockNoParam:" + }, + "pathComponents": [ + "Foo", + "methodBlockNoParam:" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "methodBlockWithParam:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ")) " + }, + { + "kind": "internalParam", + "spelling": "block" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ")) " + }, + { + "kind": "internalParam", + "spelling": "block" + } + ], + "name": "block" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo(im)methodBlockWithParam:" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "methodBlockWithParam:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "methodBlockWithParam:" + } + ], + "title": "methodBlockWithParam:" + }, + "pathComponents": [ + "Foo", + "methodBlockWithParam:" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "methodBlockWithMultipleParam:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "baz" + }, + { + "kind": "text", + "spelling": ")) " + }, + { + "kind": "internalParam", + "spelling": "block" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "baz" + }, + { + "kind": "text", + "spelling": ")) " + }, + { + "kind": "internalParam", + "spelling": "block" + } + ], + "name": "block" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo(im)methodBlockWithMultipleParam:" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "methodBlockWithMultipleParam:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "methodBlockWithMultipleParam:" + } + ], + "title": "methodBlockWithMultipleParam:" + }, + "pathComponents": [ + "Foo", + "methodBlockWithMultipleParam:" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "methodBlockVariadic:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ", ...)) " + }, + { + "kind": "internalParam", + "spelling": "block" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " (^" + }, + { + "kind": "text", + "spelling": ")(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": ", ...)) " + }, + { + "kind": "internalParam", + "spelling": "block" + } + ], + "name": "block" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Foo(im)methodBlockVariadic:" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "methodBlockVariadic:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "methodBlockVariadic:" + } + ], + "title": "methodBlockVariadic:" + }, + "pathComponents": [ + "Foo", + "methodBlockVariadic:" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_category.m b/clang/test/ExtractAPI/objc_category.m index 9177d40b82644..34b0a9e31f553 100644 --- a/clang/test/ExtractAPI/objc_category.m +++ b/clang/test/ExtractAPI/objc_category.m @@ -1,21 +1,341 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -triple arm64-apple-macosx -x objective-c-header %s -o - -verify | FileCheck %s +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -x objective-c-header -target arm64-apple-macosx \ +// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s -@protocol Protocol -@end +// 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 +@protocol Protocol; @interface Interface @end @interface Interface (Category) -// CHECK-DAG: "!testRelLabel": "conformsTo $ c:objc(cs)Interface $ c:objc(pl)Protocol" @property int Property; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(py)Property $ c:objc(cs)Interface" - (void)InstanceMethod; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(im)InstanceMethod $ c:objc(cs)Interface" + (void)ClassMethod; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(cm)ClassMethod $ c:objc(cs)Interface" @end -// expected-no-diagnostics +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(im)InstanceMethod", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(cm)ClassMethod", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(py)Property", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "conformsTo", + "source": "c:objc(cs)Interface", + "target": "c:objc(pl)Protocol", + "targetFallback": "Protocol" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "title": "Interface" + }, + "pathComponents": [ + "Interface" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "InstanceMethod" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(im)InstanceMethod" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 7 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "InstanceMethod" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "InstanceMethod" + } + ], + "title": "InstanceMethod" + }, + "pathComponents": [ + "Interface", + "InstanceMethod" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "+ (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "ClassMethod" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(cm)ClassMethod" + }, + "kind": { + "displayName": "Type Method", + "identifier": "objective-c.type.method" + }, + "location": { + "position": { + "character": 0, + "line": 8 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "ClassMethod" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "+ " + }, + { + "kind": "identifier", + "spelling": "ClassMethod" + } + ], + "title": "ClassMethod" + }, + "pathComponents": [ + "Interface", + "ClassMethod" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Property" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(py)Property" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 14, + "line": 6 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Property" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Property" + } + ], + "title": "Property" + }, + "pathComponents": [ + "Interface", + "Property" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_external_category.m b/clang/test/ExtractAPI/objc_external_category.m deleted file mode 100644 index 47e699cb91c0e..0000000000000 --- a/clang/test/ExtractAPI/objc_external_category.m +++ /dev/null @@ -1,49 +0,0 @@ -// RUN: rm -rf %t -// RUN: split-file %s %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: --emit-extension-symbol-graphs --symbol-graph-dir=%t/symbols \ -// RUN: --product-name=Module -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules-cache \ -// RUN: -triple arm64-apple-macosx -x objective-c-header %t/input.h -verify - -//--- input.h -#include "ExternalModule.h" - -@interface ExtInterface (Category) -@property int Property; -- (void)InstanceMethod; -+ (void)ClassMethod; -@end - -@interface ModInterface -@end - -// expected-no-diagnostics - -//--- ExternalModule.h -@interface ExtInterface -@end - -//--- module.modulemap -module ExternalModule { - header "ExternalModule.h" -} - -// RUN: FileCheck %s --input-file %t/symbols/Module.symbols.json --check-prefix MOD -// MOD-NOT: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(py)Property $ c:objc(cs)ExtInterface" -// MOD-NOT: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(im)InstanceMethod $ c:objc(cs)ExtInterface" -// MOD-NOT: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(cm)ClassMethod $ c:objc(cs)ExtInterface" -// MOD-NOT: "!testLabel": "c:objc(cs)ExtInterface(py)Property" -// MOD-NOT: "!testLabel": "c:objc(cs)ExtInterface(im)InstanceMethod" -// MOD-NOT: "!testLabel": "c:objc(cs)ExtInterface(cm)ClassMethod" -// MOD-NOT: "!testLabel": "c:objc(cs)ExtInterface" -// MOD-DAG: "!testLabel": "c:objc(cs)ModInterface" - -// RUN: FileCheck %s --input-file %t/symbols/ExternalModule@Module.symbols.json --check-prefix EXT -// EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(py)Property $ c:objc(cs)ExtInterface" -// EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(im)InstanceMethod $ c:objc(cs)ExtInterface" -// EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(cm)ClassMethod $ c:objc(cs)ExtInterface" -// EXT-DAG: "!testLabel": "c:objc(cs)ExtInterface(py)Property" -// EXT-DAG: "!testLabel": "c:objc(cs)ExtInterface(im)InstanceMethod" -// EXT-DAG: "!testLabel": "c:objc(cs)ExtInterface(cm)ClassMethod" -// EXT-NOT: "!testLabel": "c:objc(cs)ExtInterface" -// EXT-NOT: "!testLabel": "c:objc(cs)ModInterface" diff --git a/clang/test/ExtractAPI/objc_id_protocol.m b/clang/test/ExtractAPI/objc_id_protocol.m index f2a03a9c57585..0b0f1b39d2bd6 100644 --- a/clang/test/ExtractAPI/objc_id_protocol.m +++ b/clang/test/ExtractAPI/objc_id_protocol.m @@ -1,56 +1,317 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -x objective-c-header -triple arm64-apple-macosx %s -o - -verify | FileCheck %s +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -x objective-c-header -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 @protocol MyProtocol @end @interface MyInterface @property(copy, readwrite) id obj1; -// CHECK-LABEL: "!testLabel": "c:objc(cs)MyInterface(py)obj1" -// CHECK: "declarationFragments": [ -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "keyword", -// CHECK-NEXT: "spelling": "@property" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "text", -// CHECK-NEXT: "spelling": " (" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "keyword", -// CHECK-NEXT: "spelling": "copy" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "text", -// CHECK-NEXT: "spelling": ", " -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "keyword", -// CHECK-NEXT: "spelling": "readwrite" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "text", -// CHECK-NEXT: "spelling": ") " -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "typeIdentifier", -// CHECK-NEXT: "preciseIdentifier": "c:Qoobjc(pl)MyProtocol", -// CHECK-NEXT: "spelling": "id" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "text", -// CHECK-NEXT: "spelling": " " -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "identifier", -// CHECK-NEXT: "spelling": "obj1" -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "kind": "text", -// CHECK-NEXT: "spelling": ";" -// CHECK-NEXT: } -// CHECK-NEXT: ], +@property(readwrite) id *obj2; @end - -// expected-no-diagnostics +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)MyInterface(py)obj1", + "target": "c:objc(cs)MyInterface", + "targetFallback": "MyInterface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)MyInterface(py)obj2", + "target": "c:objc(cs)MyInterface", + "targetFallback": "MyInterface" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyInterface" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyInterface" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyInterface" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyInterface" + } + ], + "title": "MyInterface" + }, + "pathComponents": [ + "MyInterface" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "copy" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "readwrite" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:Qoobjc(pl)MyProtocol", + "spelling": "id" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "obj1" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyInterface(py)obj1" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 42, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "obj1" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "obj1" + } + ], + "title": "obj1" + }, + "pathComponents": [ + "MyInterface", + "obj1" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "readwrite" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:Qoobjc(pl)MyProtocol", + "spelling": "id" + }, + { + "kind": "text", + "spelling": " * " + }, + { + "kind": "identifier", + "spelling": "obj2" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyInterface(py)obj2" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 37, + "line": 5 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "obj2" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "obj2" + } + ], + "title": "obj2" + }, + "pathComponents": [ + "MyInterface", + "obj2" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyProtocol" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(pl)MyProtocol" + }, + "kind": { + "displayName": "Protocol", + "identifier": "objective-c.protocol" + }, + "location": { + "position": { + "character": 10, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyProtocol" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyProtocol" + } + ], + "title": "MyProtocol" + }, + "pathComponents": [ + "MyProtocol" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_instancetype.m b/clang/test/ExtractAPI/objc_instancetype.m index 071ebe440918a..d9d259f2d5602 100644 --- a/clang/test/ExtractAPI/objc_instancetype.m +++ b/clang/test/ExtractAPI/objc_instancetype.m @@ -1,8 +1,8 @@ // RUN: rm -rf %t // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ -// RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx -x objective-c-header %t/input.h -o %t/output.json -verify + // RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx -x objective-c-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. // RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \ diff --git a/clang/test/ExtractAPI/objc_interface.m b/clang/test/ExtractAPI/objc_interface.m index 4abccddc3b5c8..ab1772a0c529b 100644 --- a/clang/test/ExtractAPI/objc_interface.m +++ b/clang/test/ExtractAPI/objc_interface.m @@ -1,360 +1,701 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -x objective-c-header -triple arm64-apple-macosx %s -o %t/output.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -x objective-c-header -target arm64-apple-macosx \ +// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s -@protocol Protocol -@end +// 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 -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix SUPER -@interface Super -// SUPER: "!testRelLabel": "conformsTo $ c:objc(cs)Super $ c:objc(pl)Protocol" -// SUPER-LABEL: "!testLabel": "c:objc(cs)Super" -// SUPER: "accessLevel": "public", -// SUPER: "declarationFragments": [ -// SUPER-NEXT: { -// SUPER-NEXT: "kind": "keyword", -// SUPER-NEXT: "spelling": "@interface" -// SUPER-NEXT: }, -// SUPER-NEXT: { -// SUPER-NEXT: "kind": "text", -// SUPER-NEXT: "spelling": " " -// SUPER-NEXT: }, -// SUPER-NEXT: { -// SUPER-NEXT: "kind": "identifier", -// SUPER-NEXT: "spelling": "Super" -// SUPER-NEXT: } -// SUPER-NEXT: ], -// SUPER: "kind": { -// SUPER-NEXT: "displayName": "Class", -// SUPER-NEXT: "identifier": "objective-c.class" -// SUPER-NEXT: }, -// SUPER: "title": "Super" -// SUPER: "pathComponents": [ -// SUPER-NEXT: "Super" -// SUPER-NEXT: ] +// CHECK-NOT: error: +// CHECK-NOT: warning: -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix PROP -@property(readonly, getter=getProperty) unsigned Property; -// PROP: "!testRelLabel": "memberOf $ c:objc(cs)Super(py)Property $ c:objc(cs)Super" -// PROP: "!testLabel": "c:objc(cs)Super(py)Property" -// PROP: "accessLevel": "public", -// PROP: "declarationFragments": [ -// PROP-NEXT: { -// PROP-NEXT: "kind": "keyword", -// PROP-NEXT: "spelling": "@property" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": " (" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "keyword", -// PROP-NEXT: "spelling": "readonly" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": ", " -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "keyword", -// PROP-NEXT: "spelling": "getter" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": "=" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "identifier", -// PROP-NEXT: "spelling": "getProperty" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": ") " -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "typeIdentifier", -// PROP-NEXT: "preciseIdentifier": "c:i", -// PROP-NEXT: "spelling": "unsigned int" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": " " -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "identifier", -// PROP-NEXT: "spelling": "Property" -// PROP-NEXT: }, -// PROP-NEXT: { -// PROP-NEXT: "kind": "text", -// PROP-NEXT: "spelling": ";" -// PROP-NEXT: } -// PROP-NEXT: ], -// PROP: "kind": { -// PROP-NEXT: "displayName": "Instance Property", -// PROP-NEXT: "identifier": "objective-c.property" -// PROP-NEXT: }, -// PROP: "title": "Property" -// PROP: "pathComponents": [ -// PROP-NEXT: "Super", -// PROP-NEXT: "Property" -// PROP-NEXT: ] +//--- input.h +@protocol Protocol; -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GET +@interface Super +@property(readonly, getter=getProperty) unsigned Property; + (id)getWithProperty:(unsigned) Property; -// GET: "!testRelLabel": "memberOf $ c:objc(cs)Super(cm)getWithProperty: $ c:objc(cs)Super" -// GET-LABEL: "!testLabel": "c:objc(cs)Super(cm)getWithProperty:" -// GET: "accessLevel": "public", -// GET: "declarationFragments": [ -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": "+ (" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "keyword", -// GET-NEXT: "spelling": "id" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": ") " -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "identifier", -// GET-NEXT: "spelling": "getWithProperty:" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": "(" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "typeIdentifier", -// GET-NEXT: "preciseIdentifier": "c:i", -// GET-NEXT: "spelling": "unsigned int" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": ") " -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "internalParam", -// GET-NEXT: "spelling": "Property" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": ";" -// GET-NEXT: } -// GET-NEXT: ], -// GET: "functionSignature": { -// GET-NEXT: "parameters": [ -// GET-NEXT: { -// GET-NEXT: "declarationFragments": [ -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": "(" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "typeIdentifier", -// GET-NEXT: "preciseIdentifier": "c:i", -// GET-NEXT: "spelling": "unsigned int" -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "text", -// GET-NEXT: "spelling": ") " -// GET-NEXT: }, -// GET-NEXT: { -// GET-NEXT: "kind": "internalParam", -// GET-NEXT: "spelling": "Property" -// GET-NEXT: } -// GET-NEXT: ], -// GET-NEXT: "name": "Property" -// GET-NEXT: } -// GET-NEXT: ], -// GET-NEXT: "returns": [ -// GET-NEXT: { -// GET-NEXT: "kind": "keyword", -// GET-NEXT: "spelling": "id" -// GET-NEXT: } -// GET-NEXT: ] -// GET-NEXT: }, -// GET: "kind": { -// GET-NEXT: "displayName": "Type Method", -// GET-NEXT: "identifier": "objective-c.type.method" -// GET-NEXT: }, -// GET: "title": "getWithProperty:" -// GET: "pathComponents": [ -// GET-NEXT: "Super", -// GET-NEXT: "getWithProperty:" -// GET-NEXT: ] - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix SET - (void)setProperty:(unsigned) Property andOtherThing: (unsigned) Thing; -// SET: "!testRelLabel": "memberOf $ c:objc(cs)Super(im)setProperty:andOtherThing: $ c:objc(cs)Super" -// SET-LABEL: "!testLabel": "c:objc(cs)Super(im)setProperty:andOtherThing:" -// SET: "accessLevel": "public", -// SET: "declarationFragments": [ -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": "- (" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:v", -// SET-NEXT: "spelling": "void" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ") " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "identifier", -// SET-NEXT: "spelling": "setProperty:" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": "(" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:i", -// SET-NEXT: "spelling": "unsigned int" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ") " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "internalParam", -// SET-NEXT: "spelling": "Property" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": " " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "identifier", -// SET-NEXT: "spelling": "andOtherThing:" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": "(" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:i", -// SET-NEXT: "spelling": "unsigned int" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ") " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "internalParam", -// SET-NEXT: "spelling": "Thing" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ";" -// SET-NEXT: } -// SET-NEXT: ], -// SET: "functionSignature": { -// SET-NEXT: "parameters": [ -// SET-NEXT: { -// SET-NEXT: "declarationFragments": [ -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": "(" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:i", -// SET-NEXT: "spelling": "unsigned int" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ") " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "internalParam", -// SET-NEXT: "spelling": "Property" -// SET-NEXT: } -// SET-NEXT: ], -// SET-NEXT: "name": "Property" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "declarationFragments": [ -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": "(" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:i", -// SET-NEXT: "spelling": "unsigned int" -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "text", -// SET-NEXT: "spelling": ") " -// SET-NEXT: }, -// SET-NEXT: { -// SET-NEXT: "kind": "internalParam", -// SET-NEXT: "spelling": "Thing" -// SET-NEXT: } -// SET-NEXT: ], -// SET-NEXT: "name": "Thing" -// SET-NEXT: } -// SET-NEXT: ], -// SET-NEXT: "returns": [ -// SET-NEXT: { -// SET-NEXT: "kind": "typeIdentifier", -// SET-NEXT: "preciseIdentifier": "c:v", -// SET-NEXT: "spelling": "void" -// SET-NEXT: } -// SET-NEXT: ] -// SET-NEXT: }, -// SET: "kind": { -// SET-NEXT: "displayName": "Instance Method", -// SET-NEXT: "identifier": "objective-c.method" -// SET-NEXT: }, -// SET: "title": "setProperty:andOtherThing:" @end -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix DERIVED @interface Derived : Super { -// DERIVED: "!testRelLabel": "inheritsFrom $ c:objc(cs)Derived $ c:objc(cs)Super" - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix IVAR char Ivar; -// IVAR: "!testRelLabel": "memberOf $ c:objc(cs)Derived@Ivar $ c:objc(cs)Derived" -// IVAR-LABEL: "!testLabel": "c:objc(cs)Derived@Ivar" -// IVAR: "accessLevel": "public", -// IVAR: "declarationFragments": [ -// IVAR-NEXT: { -// IVAR-NEXT: "kind": "typeIdentifier", -// IVAR-NEXT: "preciseIdentifier": "c:C", -// IVAR-NEXT: "spelling": "char" -// IVAR-NEXT: }, -// IVAR-NEXT: { -// IVAR-NEXT: "kind": "text", -// IVAR-NEXT: "spelling": " " -// IVAR-NEXT: }, -// IVAR-NEXT: { -// IVAR-NEXT: "kind": "identifier", -// IVAR-NEXT: "spelling": "Ivar" -// IVAR-NEXT: }, -// IVAR-NEXT: { -// IVAR-NEXT: "kind": "text", -// IVAR-NEXT: "spelling": ";" -// IVAR-NEXT: } -// IVAR-NEXT: ], -// IVAR: "kind": { -// IVAR-NEXT: "displayName": "Instance Variable", -// IVAR-NEXT: "identifier": "objective-c.ivar" -// IVAR-NEXT: }, -// IVAR: "title": "Ivar" -// IVAR: "pathComponents": [ -// IVAR-NEXT: "Derived", -// IVAR-NEXT: "Ivar" -// IVAR-NEXT: ] } +- (char)getIvar; @end -// expected-no-diagnostics +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)Super(cm)getWithProperty:", + "target": "c:objc(cs)Super", + "targetFallback": "Super" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Super(im)setProperty:andOtherThing:", + "target": "c:objc(cs)Super", + "targetFallback": "Super" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Super(py)Property", + "target": "c:objc(cs)Super", + "targetFallback": "Super" + }, + { + "kind": "conformsTo", + "source": "c:objc(cs)Super", + "target": "c:objc(pl)Protocol", + "targetFallback": "Protocol" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Derived@Ivar", + "target": "c:objc(cs)Derived", + "targetFallback": "Derived" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Derived(im)getIvar", + "target": "c:objc(cs)Derived", + "targetFallback": "Derived" + }, + { + "kind": "inheritsFrom", + "source": "c:objc(cs)Derived", + "target": "c:objc(cs)Super", + "targetFallback": "Super" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Super" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Super" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Super" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Super" + } + ], + "title": "Super" + }, + "pathComponents": [ + "Super" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "+ (" + }, + { + "kind": "keyword", + "spelling": "id" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "getWithProperty:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Property" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Property" + } + ], + "name": "Property" + } + ], + "returns": [ + { + "kind": "keyword", + "spelling": "id" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Super(cm)getWithProperty:" + }, + "kind": { + "displayName": "Type Method", + "identifier": "objective-c.type.method" + }, + "location": { + "position": { + "character": 0, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "getWithProperty:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "+ " + }, + { + "kind": "identifier", + "spelling": "getWithProperty:" + } + ], + "title": "getWithProperty:" + }, + "pathComponents": [ + "Super", + "getWithProperty:" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "setProperty:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Property" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "andOtherThing:" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Thing" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Property" + } + ], + "name": "Property" + }, + { + "declarationFragments": [ + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "internalParam", + "spelling": "Thing" + } + ], + "name": "Thing" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Super(im)setProperty:andOtherThing:" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 5 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "setProperty:andOtherThing:" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "setProperty:andOtherThing:" + } + ], + "title": "setProperty:andOtherThing:" + }, + "pathComponents": [ + "Super", + "setProperty:andOtherThing:" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "readonly" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "getter" + }, + { + "kind": "text", + "spelling": "=" + }, + { + "kind": "identifier", + "spelling": "getProperty" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Property" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Super(py)Property" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 49, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Property" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Property" + } + ], + "title": "Property" + }, + "pathComponents": [ + "Super", + "Property" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Derived" + }, + { + "kind": "text", + "spelling": " : " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)Super", + "spelling": "Super" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Derived" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 8 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Derived" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Derived" + } + ], + "title": "Derived" + }, + "pathComponents": [ + "Derived" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:C", + "spelling": "char" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Ivar" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Derived@Ivar" + }, + "kind": { + "displayName": "Instance Variable", + "identifier": "objective-c.ivar" + }, + "location": { + "position": { + "character": 7, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Ivar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Ivar" + } + ], + "title": "Ivar" + }, + "pathComponents": [ + "Derived", + "Ivar" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:C", + "spelling": "char" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "getIvar" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:C", + "spelling": "char" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Derived(im)getIvar" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 11 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "getIvar" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "getIvar" + } + ], + "title": "getIvar" + }, + "pathComponents": [ + "Derived", + "getIvar" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_module_category.m b/clang/test/ExtractAPI/objc_module_category.m new file mode 100644 index 0000000000000..708ed10be821d --- /dev/null +++ b/clang/test/ExtractAPI/objc_module_category.m @@ -0,0 +1,404 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -x objective-c-header \ +// RUN: -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 +#import "Foundation.h" + +/// Doc comment 1 +@interface NSString (Category1) +-(void)method1; +@end + +/// Doc comment 2 +@interface NSString (Category2) +-(void)method2; +@end + +//--- Foundation.h +@interface NSString +@end + +//--- 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" + } + }, + "relationships": [ + { + "kind": "extensionTo", + "source": "c:objc(cy)NSString@Category1", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)NSString(im)method1", + "target": "c:objc(cy)NSString@Category1", + "targetFallback": "Category1" + }, + { + "kind": "extensionTo", + "source": "c:objc(cy)NSString@Category2", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)NSString(im)method2", + "target": "c:objc(cy)NSString@Category2", + "targetFallback": "Category2" + } + ], + "symbols": [ + { + "accessLevel": "public", + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category1" + }, + "kind": { + "displayName": "Module Extension", + "identifier": "objective-c.module.extension" + } + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)NSString", + "spelling": "NSString" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "identifier", + "spelling": "Category1" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "docComment": { + "lines": [ + { + "range": { + "end": { + "character": 17, + "line": 2 + }, + "start": { + "character": 4, + "line": 2 + } + }, + "text": "Doc comment 1" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category1" + }, + "kind": { + "displayName": "Class Extension", + "identifier": "objective-c.class.extension" + }, + "location": { + "position": { + "character": 11, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Category1" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Category1" + } + ], + "title": "NSString (Category1)" + }, + "pathComponents": [ + "Category1" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "method1" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString(im)method1" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "method1" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "method1" + } + ], + "title": "method1" + }, + "pathComponents": [ + "Category1", + "method1" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)NSString", + "spelling": "NSString" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "identifier", + "spelling": "Category2" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "docComment": { + "lines": [ + { + "range": { + "end": { + "character": 17, + "line": 7 + }, + "start": { + "character": 4, + "line": 7 + } + }, + "text": "Doc comment 2" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category2" + }, + "kind": { + "displayName": "Class Extension", + "identifier": "objective-c.class.extension" + }, + "location": { + "position": { + "character": 11, + "line": 8 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "title": "NSString (Category2)" + }, + "pathComponents": [ + "Category2" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "method2" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString(im)method2" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "method2" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "method2" + } + ], + "title": "method2" + }, + "pathComponents": [ + "Category2", + "method2" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_property.m b/clang/test/ExtractAPI/objc_property.m index f05584c885d91..5712abc15393b 100644 --- a/clang/test/ExtractAPI/objc_property.m +++ b/clang/test/ExtractAPI/objc_property.m @@ -1,26 +1,608 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -triple arm64-apple-macosx -x objective-c-header %s -o - -verify | FileCheck %s +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx -x objective-c-header %t/input.h -o %t/output.json -verify +// 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 + +//--- input.h @protocol Protocol @property(class) int myProtocolTypeProp; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(pl)Protocol(cpy)myProtocolTypeProp $ c:objc(pl)Protocol" @property int myProtocolInstanceProp; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(pl)Protocol(py)myProtocolInstanceProp $ c:objc(pl)Protocol" @end @interface Interface @property(class) int myInterfaceTypeProp; -// CHECk-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(cpy)myInterfaceTypeProp $ c:objc(cs)Interface" @property int myInterfaceInstanceProp; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(py)myInterfaceInstanceProp $ c:objc(cs)Interface" @end @interface Interface (Category) @property(class) int myCategoryTypeProp; -// CHECK-DAG: "!testRelLabel": "memberOf $ c:objc(cs)Interface(cpy)myCategoryTypeProp $ c:objc(cs)Interface" @property int myCategoryInstanceProp; -// CHECK-DAG "!testRelLabel": "memberOf $ c:objc(cs)Interface(py)myCategoryInstanceProp $ c:objc(cs)Interface" @end - // expected-no-diagnostics + +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(cpy)myInterfaceTypeProp", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(py)myInterfaceInstanceProp", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(cpy)myCategoryTypeProp", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)Interface(py)myCategoryInstanceProp", + "target": "c:objc(cs)Interface", + "targetFallback": "Interface" + }, + { + "kind": "conformsTo", + "source": "c:objc(cs)Interface", + "target": "c:objc(pl)Protocol", + "targetFallback": "Protocol" + }, + { + "kind": "memberOf", + "source": "c:objc(pl)Protocol(cpy)myProtocolTypeProp", + "target": "c:objc(pl)Protocol", + "targetFallback": "Protocol" + }, + { + "kind": "memberOf", + "source": "c:objc(pl)Protocol(py)myProtocolInstanceProp", + "target": "c:objc(pl)Protocol", + "targetFallback": "Protocol" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 5 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Interface" + } + ], + "title": "Interface" + }, + "pathComponents": [ + "Interface" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myInterfaceTypeProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(cpy)myInterfaceTypeProp" + }, + "kind": { + "displayName": "Type Property", + "identifier": "objective-c.type.property" + }, + "location": { + "position": { + "character": 21, + "line": 6 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myInterfaceTypeProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myInterfaceTypeProp" + } + ], + "title": "myInterfaceTypeProp" + }, + "pathComponents": [ + "Interface", + "myInterfaceTypeProp" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myInterfaceInstanceProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(py)myInterfaceInstanceProp" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 14, + "line": 7 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myInterfaceInstanceProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myInterfaceInstanceProp" + } + ], + "title": "myInterfaceInstanceProp" + }, + "pathComponents": [ + "Interface", + "myInterfaceInstanceProp" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myCategoryTypeProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(cpy)myCategoryTypeProp" + }, + "kind": { + "displayName": "Type Property", + "identifier": "objective-c.type.property" + }, + "location": { + "position": { + "character": 21, + "line": 11 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myCategoryTypeProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myCategoryTypeProp" + } + ], + "title": "myCategoryTypeProp" + }, + "pathComponents": [ + "Interface", + "myCategoryTypeProp" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myCategoryInstanceProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)Interface(py)myCategoryInstanceProp" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 14, + "line": 12 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myCategoryInstanceProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myCategoryInstanceProp" + } + ], + "title": "myCategoryInstanceProp" + }, + "pathComponents": [ + "Interface", + "myCategoryInstanceProp" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Protocol" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(pl)Protocol" + }, + "kind": { + "displayName": "Protocol", + "identifier": "objective-c.protocol" + }, + "location": { + "position": { + "character": 10, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Protocol" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Protocol" + } + ], + "title": "Protocol" + }, + "pathComponents": [ + "Protocol" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myProtocolTypeProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(pl)Protocol(cpy)myProtocolTypeProp" + }, + "kind": { + "displayName": "Type Property", + "identifier": "objective-c.type.property" + }, + "location": { + "position": { + "character": 21, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myProtocolTypeProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myProtocolTypeProp" + } + ], + "title": "myProtocolTypeProp" + }, + "pathComponents": [ + "Protocol", + "myProtocolTypeProp" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@property" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "myProtocolInstanceProp" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(pl)Protocol(py)myProtocolInstanceProp" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "objective-c.property" + }, + "location": { + "position": { + "character": 14, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "myProtocolInstanceProp" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "myProtocolInstanceProp" + } + ], + "title": "myProtocolInstanceProp" + }, + "pathComponents": [ + "Protocol", + "myProtocolInstanceProp" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/objc_protocol.m b/clang/test/ExtractAPI/objc_protocol.m index 06f7ee3d20363..a04936fe04123 100644 --- a/clang/test/ExtractAPI/objc_protocol.m +++ b/clang/test/ExtractAPI/objc_protocol.m @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf -x objective-c-header -target arm64-apple-macosx \ +// RUN: %clang -extract-api -x objective-c-header -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. diff --git a/clang/test/ExtractAPI/objc_various_categories.m b/clang/test/ExtractAPI/objc_various_categories.m new file mode 100644 index 0000000000000..adaef5a7b31a9 --- /dev/null +++ b/clang/test/ExtractAPI/objc_various_categories.m @@ -0,0 +1,507 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -x objective-c-header \ +// RUN: -target arm64-apple-macosx \ +// RUN: %t/myclass_1.h \ +// 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 +#import "myclass_1.h" +#import "Foundation.h" + +@interface MyClass1 (MyCategory1) +- (int) SomeMethod; +@end + +@interface NSString (Category1) +-(void) StringMethod; +@end + +@interface NSString (Category2) +-(void) StringMethod2; +@end + +//--- myclass_1.h +@interface MyClass1 +@end + +//--- Foundation.h +@interface NSString +@end + +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:objc(cs)MyClass1(im)SomeMethod", + "target": "c:objc(cs)MyClass1", + "targetFallback": "MyClass1" + }, + { + "kind": "extensionTo", + "source": "c:objc(cy)NSString@Category1", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)NSString(im)StringMethod", + "target": "c:objc(cy)NSString@Category1", + "targetFallback": "Category1" + }, + { + "kind": "extensionTo", + "source": "c:objc(cy)NSString@Category2", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)NSString(im)StringMethod2", + "target": "c:objc(cy)NSString@Category2", + "targetFallback": "Category2" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyClass1" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyClass1" + }, + "kind": { + "displayName": "Class", + "identifier": "objective-c.class" + }, + "location": { + "position": { + "character": 11, + "line": 0 + }, + "uri": "file://INPUT_DIR/myclass_1.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyClass1" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyClass1" + } + ], + "title": "MyClass1" + }, + "pathComponents": [ + "MyClass1" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "SomeMethod" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyClass1(im)SomeMethod" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "SomeMethod" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "SomeMethod" + } + ], + "title": "SomeMethod" + }, + "pathComponents": [ + "MyClass1", + "SomeMethod" + ] + }, + { + "accessLevel": "public", + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category1" + }, + "kind": { + "displayName": "Module Extension", + "identifier": "objective-c.module.extension" + } + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)NSString", + "spelling": "NSString" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "identifier", + "spelling": "Category1" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category1" + }, + "kind": { + "displayName": "Class Extension", + "identifier": "objective-c.class.extension" + }, + "location": { + "position": { + "character": 11, + "line": 7 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Category1" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Category1" + } + ], + "title": "NSString (Category1)" + }, + "pathComponents": [ + "Category1" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "StringMethod" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString(im)StringMethod" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 8 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "StringMethod" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "StringMethod" + } + ], + "title": "StringMethod" + }, + "pathComponents": [ + "Category1", + "StringMethod" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)NSString", + "spelling": "NSString" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "identifier", + "spelling": "Category2" + }, + { + "kind": "text", + "spelling": ")" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cy)NSString@Category2" + }, + "kind": { + "displayName": "Class Extension", + "identifier": "objective-c.class.extension" + }, + "location": { + "position": { + "character": 11, + "line": 11 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "title": "NSString (Category2)" + }, + "pathComponents": [ + "Category2" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "StringMethod2" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString(im)StringMethod2" + }, + "kind": { + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 0, + "line": 12 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "StringMethod2" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "StringMethod2" + } + ], + "title": "StringMethod2" + }, + "pathComponents": [ + "Category2", + "StringMethod2" + ] + } + ] +} diff --git a/clang/test/ExtractAPI/operator_overload.cpp b/clang/test/ExtractAPI/operator_overload.cpp index 9430c58a991e1..511a5a7ae8fdf 100644 --- a/clang/test/ExtractAPI/operator_overload.cpp +++ b/clang/test/ExtractAPI/operator_overload.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/relative_include.m b/clang/test/ExtractAPI/relative_include.m index e5a02683cbd81..46cbdaeeb280c 100644 --- a/clang/test/ExtractAPI/relative_include.m +++ b/clang/test/ExtractAPI/relative_include.m @@ -15,7 +15,7 @@ // RUN: %hmaptool write %t/headermap.hmap.json %t/headermap.hmap // Input headers use paths to the framework root/DSTROOT -// RUN: %clang_cc1 -extract-api --pretty-sgf -v --product-name=MyFramework \ +// RUN: %clang_cc1 -extract-api -v --product-name=MyFramework \ // RUN: -triple arm64-apple-macosx \ // RUN: -iquote%t -I%t/headermap.hmap -F%t/Frameworks \ // RUN: -x objective-c-header \ diff --git a/clang/test/ExtractAPI/simple_inheritance.cpp b/clang/test/ExtractAPI/simple_inheritance.cpp index 58c3c4e1e5cb8..5fe99afe08763 100644 --- a/clang/test/ExtractAPI/simple_inheritance.cpp +++ b/clang/test/ExtractAPI/simple_inheritance.cpp @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx \ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ // RUN: -x c++-header %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/struct.c b/clang/test/ExtractAPI/struct.c index 1995a6aedbfd3..4284b734cd059 100644 --- a/clang/test/ExtractAPI/struct.c +++ b/clang/test/ExtractAPI/struct.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf -target arm64-apple-macosx \ +// 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. diff --git a/clang/test/ExtractAPI/typedef.c b/clang/test/ExtractAPI/typedef.c index a4c3619bfd210..c30e65549f2b7 100644 --- a/clang/test/ExtractAPI/typedef.c +++ b/clang/test/ExtractAPI/typedef.c @@ -1,93 +1,391 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -triple arm64-apple-macosx -x objective-c-header %s -o %t/output.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api --product-name=Typedef -target arm64-apple-macosx \ +// RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix MYINT +// 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 typedef int MyInt; -// MYINT-LABEL: "!testLabel": "c:typedef.c@T@MyInt" -// MYINT: "accessLevel": "public", -// MYINT: "declarationFragments": [ -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "keyword", -// MYINT-NEXT: "spelling": "typedef" -// MYINT-NEXT: }, -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "text", -// MYINT-NEXT: "spelling": " " -// MYINT-NEXT: }, -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "typeIdentifier", -// MYINT-NEXT: "preciseIdentifier": "c:I", -// MYINT-NEXT: "spelling": "int" -// MYINT-NEXT: }, -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "text", -// MYINT-NEXT: "spelling": " " -// MYINT-NEXT: }, -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "identifier", -// MYINT-NEXT: "spelling": "MyInt" -// MYINT-NEXT: }, -// MYINT-NEXT: { -// MYINT-NEXT: "kind": "text", -// MYINT-NEXT: "spelling": ";" -// MYINT-NEXT: } -// MYINT-NEXT: ], -// MYINT: "kind": { -// MYINT-NEXT: "displayName": "Type Alias", -// MYINT-NEXT: "identifier": "objective-c.typealias" -// MYINT-NEXT: }, -// MYINT: "title": "MyInt" -// MYINT: "pathComponents": [ -// MYINT-NEXT: "MyInt" -// MYINT-NEXT: ], -// MYINT: "type": "c:I" -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BARPTR typedef struct Bar *BarPtr; -// BARPTR-LABEL: "!testLabel": "c:typedef.c@T@BarPtr" -// BARPTR: "accessLevel": "public", -// BARPTR: "declarationFragments": [ -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "keyword", -// BARPTR-NEXT: "spelling": "typedef" -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "text", -// BARPTR-NEXT: "spelling": " " -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "keyword", -// BARPTR-NEXT: "spelling": "struct" -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "text", -// BARPTR-NEXT: "spelling": " " -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "typeIdentifier", -// BARPTR-NEXT: "preciseIdentifier": "c:@S@Bar", -// BARPTR-NEXT: "spelling": "Bar" -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "text", -// BARPTR-NEXT: "spelling": " * " -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "identifier", -// BARPTR-NEXT: "spelling": "BarPtr" -// BARPTR-NEXT: }, -// BARPTR-NEXT: { -// BARPTR-NEXT: "kind": "text", -// BARPTR-NEXT: "spelling": ";" -// BARPTR-NEXT: } -// BARPTR-NEXT: ], -// BARPTR: "type": "c:*$@S@Bar" -// RUN: FileCheck %s --input-file %t/output.symbols.json void foo(BarPtr value); void baz(BarPtr *value); -// CHECK-NOT: struct Bar * -// expected-no-diagnostics +//--- reference.output.json.in +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 5, + "patch": 3 + }, + "generator": "?" + }, + "module": { + "name": "Typedef", + "platform": { + "architecture": "arm64", + "operatingSystem": { + "minimumVersion": { + "major": 11, + "minor": 0, + "patch": 0 + }, + "name": "macosx" + }, + "vendor": "apple" + } + }, + "relationships": [], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "foo" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@BarPtr", + "spelling": "BarPtr" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "value" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@BarPtr", + "spelling": "BarPtr" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "internalParam", + "spelling": "value" + } + ], + "name": "value" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@F@foo" + }, + "kind": { + "displayName": "Function", + "identifier": "objective-c.func" + }, + "location": { + "position": { + "character": 5, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "foo" + } + ], + "title": "foo" + }, + "pathComponents": [ + "foo" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "baz" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@BarPtr", + "spelling": "BarPtr" + }, + { + "kind": "text", + "spelling": " * " + }, + { + "kind": "internalParam", + "spelling": "value" + }, + { + "kind": "text", + "spelling": ");" + } + ], + "functionSignature": { + "parameters": [ + { + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@BarPtr", + "spelling": "BarPtr" + }, + { + "kind": "text", + "spelling": " * " + }, + { + "kind": "internalParam", + "spelling": "value" + } + ], + "name": "value" + } + ], + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:@F@baz" + }, + "kind": { + "displayName": "Function", + "identifier": "objective-c.func" + }, + "location": { + "position": { + "character": 5, + "line": 6 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "baz" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "baz" + } + ], + "title": "baz" + }, + "pathComponents": [ + "baz" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyInt" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:input.h@T@MyInt" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "objective-c.typealias" + }, + "location": { + "position": { + "character": 12, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyInt" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyInt" + } + ], + "title": "MyInt" + }, + "pathComponents": [ + "MyInt" + ], + "type": "c:I" + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:@S@Bar", + "spelling": "Bar" + }, + { + "kind": "text", + "spelling": " * " + }, + { + "kind": "identifier", + "spelling": "BarPtr" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:input.h@T@BarPtr" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "objective-c.typealias" + }, + "location": { + "position": { + "character": 20, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "BarPtr" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "BarPtr" + } + ], + "title": "BarPtr" + }, + "pathComponents": [ + "BarPtr" + ], + "type": "c:*$@S@Bar" + } + ] +} diff --git a/clang/test/ExtractAPI/typedef_anonymous_record.c b/clang/test/ExtractAPI/typedef_anonymous_record.c index 9e00ff7525465..3e4c3e1dd60c4 100644 --- a/clang/test/ExtractAPI/typedef_anonymous_record.c +++ b/clang/test/ExtractAPI/typedef_anonymous_record.c @@ -1,158 +1,468 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang_cc1 -extract-api --product-name=TypedefChain -triple arm64-apple-macosx \ +// RUN: -x c-header %t/input.h -o %t/output.json -verify -// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCT -typedef struct { } MyStruct; -// MYSTRUCT-LABEL: "!testLabel": "c:@SA@MyStruct" -// MYSTRUCT: "accessLevel": "public", -// MYSTRUCT: "declarationFragments": [ -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "keyword", -// MYSTRUCT-NEXT: "spelling": "typedef" -// MYSTRUCT-NEXT: }, -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "text", -// MYSTRUCT-NEXT: "spelling": " " -// MYSTRUCT-NEXT: }, -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "keyword", -// MYSTRUCT-NEXT: "spelling": "struct" -// MYSTRUCT-NEXT: }, -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "text", -// MYSTRUCT-NEXT: "spelling": " " -// MYSTRUCT-NEXT: }, -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "identifier", -// MYSTRUCT-NEXT: "spelling": "MyStruct" -// MYSTRUCT-NEXT: }, -// MYSTRUCT-NEXT: { -// MYSTRUCT-NEXT: "kind": "text", -// MYSTRUCT-NEXT: "spelling": ";" -// MYSTRUCT-NEXT: } -// MYSTRUCT-NEXT: ] -// MYSTRUCT: "kind": { -// MYSTRUCT-NEXT: "displayName": "Structure", -// MYSTRUCT-NEXT: "identifier": "c.struct" -// MYSTRUCT: "title": "MyStruct" -// MYSTRUCT: "pathComponents": [ -// MYSTRUCT-NEXT: "MyStruct" -// MYSTRUCT-NEXT: ] +// 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 -// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCTSTRUCT +//--- input.h +typedef struct { } MyStruct; typedef MyStruct MyStructStruct; -// MYSTRUCTSTRUCT-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyStructStruct" -// MYSTRUCTSTRUCT: "accessLevel": "public", -// MYSTRUCTSTRUCT: "declarationFragments": [ -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "keyword", -// MYSTRUCTSTRUCT-NEXT: "spelling": "typedef" -// MYSTRUCTSTRUCT-NEXT: }, -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "text", -// MYSTRUCTSTRUCT-NEXT: "spelling": " " -// MYSTRUCTSTRUCT-NEXT: }, -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "typeIdentifier", -// MYSTRUCTSTRUCT-NEXT: "preciseIdentifier": "c:@SA@MyStruct", -// MYSTRUCTSTRUCT-NEXT: "spelling": "MyStruct" -// MYSTRUCTSTRUCT-NEXT: }, -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "text", -// MYSTRUCTSTRUCT-NEXT: "spelling": " " -// MYSTRUCTSTRUCT-NEXT: }, -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "identifier", -// MYSTRUCTSTRUCT-NEXT: "spelling": "MyStructStruct" -// MYSTRUCTSTRUCT-NEXT: }, -// MYSTRUCTSTRUCT-NEXT: { -// MYSTRUCTSTRUCT-NEXT: "kind": "text", -// MYSTRUCTSTRUCT-NEXT: "spelling": ";" -// MYSTRUCTSTRUCT-NEXT: } -// MYSTRUCTSTRUCT-NEXT:], -// MYSTRUCTSTRUCT: "kind": { -// MYSTRUCTSTRUCT-NEXT: "displayName": "Type Alias", -// MYSTRUCTSTRUCT-NEXT: "identifier": "c.typealias" - -// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUM -// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix CASE +typedef MyStructStruct MyStructStructStruct; typedef enum { Case } MyEnum; -// MYENUM: "source": "c:@EA@MyEnum@Case", -// MYENUM-NEXT: "target": "c:@EA@MyEnum", -// MYENUM-NEXT: "targetFallback": "MyEnum" -// MYENUM-LABEL: "!testLabel": "c:@EA@MyEnum" -// MYENUM: "declarationFragments": [ -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "keyword", -// MYENUM-NEXT: "spelling": "typedef" -// MYENUM-NEXT: }, -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "text", -// MYENUM-NEXT: "spelling": " " -// MYENUM-NEXT: }, -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "keyword", -// MYENUM-NEXT: "spelling": "enum" -// MYENUM-NEXT: }, -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "text", -// MYENUM-NEXT: "spelling": " " -// MYENUM-NEXT: }, -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "identifier", -// MYENUM-NEXT: "spelling": "MyEnum" -// MYENUM-NEXT: }, -// MYENUM-NEXT: { -// MYENUM-NEXT: "kind": "text", -// MYENUM-NEXT: "spelling": ";" -// MYENUM-NEXT: } -// MYENUM-NEXT:], -// MYENUM: "kind": { -// MYENUM-NEXT: "displayName": "Enumeration", -// MYENUM-NEXT: "identifier": "c.enum" -// MYENUM: "title": "MyEnum" - -// CASE-LABEL: "!testLabel": "c:@EA@MyEnum@Case" -// CASE: "pathComponents": [ -// CASE-NEXT: "MyEnum", -// CASE-NEXT: "Case" -// CASE-NEXT: ] - -// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUMENUM typedef MyEnum MyEnumEnum; -// MYENUMENUM-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyEnumEnum" -// MYENUMENUM: "declarationFragments": [ -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "keyword", -// MYENUMENUM-NEXT: "spelling": "typedef" -// MYENUMENUM-NEXT: }, -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "text", -// MYENUMENUM-NEXT: "spelling": " " -// MYENUMENUM-NEXT: }, -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "typeIdentifier", -// MYENUMENUM-NEXT: "preciseIdentifier": "c:@EA@MyEnum", -// MYENUMENUM-NEXT: "spelling": "MyEnum" -// MYENUMENUM-NEXT: }, -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "text", -// MYENUMENUM-NEXT: "spelling": " " -// MYENUMENUM-NEXT: }, -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "identifier", -// MYENUMENUM-NEXT: "spelling": "MyEnumEnum" -// MYENUMENUM-NEXT: }, -// MYENUMENUM-NEXT: { -// MYENUMENUM-NEXT: "kind": "text", -// MYENUMENUM-NEXT: "spelling": ";" -// MYENUMENUM-NEXT: } -// MYENUMENUM-NEXT: ], -// MYENUMENUM: "kind": { -// MYENUMENUM-NEXT: "displayName": "Type Alias", -// MYENUMENUM-NEXT: "identifier": "c.typealias" -// MYENUMENUM-NEXT: }, -// MYENUMENUM: "title": "MyEnumEnum" - +typedef MyEnumEnum MyEnumEnumEnum; // expected-no-diagnostics + +//--- reference.output.json.in +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 5, + "patch": 3 + }, + "generator": "?" + }, + "module": { + "name": "TypedefChain", + "platform": { + "architecture": "arm64", + "operatingSystem": { + "minimumVersion": { + "major": 11, + "minor": 0, + "patch": 0 + }, + "name": "macosx" + }, + "vendor": "apple" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:@EA@MyEnum@Case", + "target": "c:@EA@MyEnum", + "targetFallback": "MyEnum" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "enum" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyEnum" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@EA@MyEnum" + }, + "kind": { + "displayName": "Enumeration", + "identifier": "c.enum" + }, + "location": { + "position": { + "character": 8, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyEnum" + } + ], + "title": "MyEnum" + }, + "pathComponents": [ + "MyEnum" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "Case" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@EA@MyEnum@Case" + }, + "kind": { + "displayName": "Enumeration Case", + "identifier": "c.enum.case" + }, + "location": { + "position": { + "character": 15, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Case" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Case" + } + ], + "title": "Case" + }, + "pathComponents": [ + "MyEnum", + "Case" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyStruct" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@SA@MyStruct" + }, + "kind": { + "displayName": "Structure", + "identifier": "c.struct" + }, + "location": { + "position": { + "character": 8, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyStruct" + } + ], + "title": "MyStruct" + }, + "pathComponents": [ + "MyStruct" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:@SA@MyStruct", + "spelling": "MyStruct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyStructStruct" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@MyStructStruct" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 17, + "line": 1 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyStructStruct" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyStructStruct" + } + ], + "title": "MyStructStruct" + }, + "pathComponents": [ + "MyStructStruct" + ], + "type": "c:@SA@MyStruct" + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@MyStructStruct", + "spelling": "MyStructStruct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyStructStructStruct" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@MyStructStructStruct" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 23, + "line": 2 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyStructStructStruct" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyStructStructStruct" + } + ], + "title": "MyStructStructStruct" + }, + "pathComponents": [ + "MyStructStructStruct" + ], + "type": "c:input.h@T@MyStructStruct" + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:@EA@MyEnum", + "spelling": "MyEnum" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyEnumEnum" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@MyEnumEnum" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 15, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyEnumEnum" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyEnumEnum" + } + ], + "title": "MyEnumEnum" + }, + "pathComponents": [ + "MyEnumEnum" + ], + "type": "c:@EA@MyEnum" + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:input.h@T@MyEnumEnum", + "spelling": "MyEnumEnum" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyEnumEnumEnum" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@MyEnumEnumEnum" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 19, + "line": 5 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "MyEnumEnumEnum" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "MyEnumEnumEnum" + } + ], + "title": "MyEnumEnumEnum" + }, + "pathComponents": [ + "MyEnumEnumEnum" + ], + "type": "c:input.h@T@MyEnumEnum" + } + ] +} diff --git a/clang/test/ExtractAPI/typedef_chain.c b/clang/test/ExtractAPI/typedef_chain.c index 05d4eb52cef36..9e6151c8ebd90 100644 --- a/clang/test/ExtractAPI/typedef_chain.c +++ b/clang/test/ExtractAPI/typedef_chain.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang -extract-api --pretty-sgf --product-name=TypedefChain -target arm64-apple-macosx \ +// RUN: %clang -extract-api --product-name=TypedefChain -target arm64-apple-macosx \ // RUN: -x objective-c-header %t/input.h -o %t/output.json | FileCheck -allow-empty %s // Generator version is not consistent across test runs, normalize it. diff --git a/clang/test/ExtractAPI/typedef_struct_enum.c b/clang/test/ExtractAPI/typedef_struct_enum.c index fb6fbe987624f..15357d5b055fb 100644 --- a/clang/test/ExtractAPI/typedef_struct_enum.c +++ b/clang/test/ExtractAPI/typedef_struct_enum.c @@ -1,146 +1,445 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \ -// RUN: -x c-header %s -triple arm64-apple-macos -o %t/output.symbols.json -verify +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json +// RUN: %clang -extract-api -target arm64-apple-macosx \ +// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TEST +// 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 typedef struct Test { } Test; -// TEST-LABEL: "!testLabel": "c:@S@Test" -// TEST: "declarationFragments": [ -// TEST-NEXT: { -// TEST-NEXT: "kind": "keyword", -// TEST-NEXT: "spelling": "typedef" -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "text", -// TEST-NEXT: "spelling": " " -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "keyword", -// TEST-NEXT: "spelling": "struct" -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "text", -// TEST-NEXT: "spelling": " " -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "identifier", -// TEST-NEXT: "spelling": "Test" -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "text", -// TEST-NEXT: "spelling": " { ... } " -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "identifier", -// TEST-NEXT: "spelling": "Test" -// TEST-NEXT: }, -// TEST-NEXT: { -// TEST-NEXT: "kind": "text", -// TEST-NEXT: "spelling": ";" -// TEST-NEXT: } -// TEST-NEXT: ], -// TEST: "displayName": "Structure", -// TEST: "title": "Test" -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TEST2 typedef enum Test2 { simple } Test2; -// TEST2-LABEL: "!testLabel": "c:@E@Test2" -// TEST2: "declarationFragments": [ -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "keyword", -// TEST2-NEXT: "spelling": "typedef" -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "text", -// TEST2-NEXT: "spelling": " " -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "keyword", -// TEST2-NEXT: "spelling": "enum" -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "text", -// TEST2-NEXT: "spelling": " " -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "identifier", -// TEST2-NEXT: "spelling": "Test2" -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "text", -// TEST2-NEXT: "spelling": ": " -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "typeIdentifier", -// TEST2-NEXT: "preciseIdentifier": "c:i", -// TEST2-NEXT: "spelling": "unsigned int" -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "text", -// TEST2-NEXT: "spelling": " { ... } " -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "identifier", -// TEST2-NEXT: "spelling": "Test2" -// TEST2-NEXT: }, -// TEST2-NEXT: { -// TEST2-NEXT: "kind": "text", -// TEST2-NEXT: "spelling": ";" -// TEST2-NEXT: } -// TEST2-NEXT: ], -// TEST2: "displayName": "Enumeration", -// TEST2: "title": "Test2" - struct Foo; - -// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TYPEDEF typedef struct Foo TypedefedFoo; -// TYPEDEF-LABEL: "!testLabel": "c:typedef_struct_enum.c@T@TypedefedFoo" -// TYPEDEF: "declarationFragments": [ -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "keyword", -// TYPEDEF-NEXT: "spelling": "typedef" -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "text", -// TYPEDEF-NEXT: "spelling": " " -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "keyword", -// TYPEDEF-NEXT: "spelling": "struct" -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "text", -// TYPEDEF-NEXT: "spelling": " " -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "typeIdentifier", -// TYPEDEF-NEXT: "preciseIdentifier": "c:@S@Foo", -// TYPEDEF-NEXT: "spelling": "Foo" -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "text", -// TYPEDEF-NEXT: "spelling": " " -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "identifier", -// TYPEDEF-NEXT: "spelling": "TypedefedFoo" -// TYPEDEF-NEXT: }, -// TYPEDEF-NEXT: { -// TYPEDEF-NEXT: "kind": "text", -// TYPEDEF-NEXT: "spelling": ";" -// TYPEDEF-NEXT: } -// TYPEDEF-NEXT: ], -// TYPEDEF: "displayName": "Type Alias", -// TYPEDEF: "title": "TypedefedFoo" -// TYPEDEF: "type": "c:@S@Foo" - struct Foo { int bar; }; -// expected-no-diagnostics +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:@E@Test2@simple", + "target": "c:@E@Test2", + "targetFallback": "Test2" + }, + { + "kind": "memberOf", + "source": "c:@S@Foo@FI@bar", + "target": "c:@S@Foo", + "targetFallback": "Foo" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "enum" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Test2" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:i", + "spelling": "unsigned int" + }, + { + "kind": "text", + "spelling": " { ... } " + }, + { + "kind": "identifier", + "spelling": "Test2" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@E@Test2" + }, + "kind": { + "displayName": "Enumeration", + "identifier": "c.enum" + }, + "location": { + "position": { + "character": 13, + "line": 3 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Test2" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Test2" + } + ], + "title": "Test2" + }, + "pathComponents": [ + "Test2" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "simple" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@E@Test2@simple" + }, + "kind": { + "displayName": "Enumeration Case", + "identifier": "c.enum.case" + }, + "location": { + "position": { + "character": 2, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "simple" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "simple" + } + ], + "title": "simple" + }, + "pathComponents": [ + "Test2", + "simple" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Test" + }, + { + "kind": "text", + "spelling": " { ... } " + }, + { + "kind": "identifier", + "spelling": "Test" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@S@Test" + }, + "kind": { + "displayName": "Structure", + "identifier": "c.struct" + }, + "location": { + "position": { + "character": 15, + "line": 0 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Test" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Test" + } + ], + "title": "Test" + }, + "pathComponents": [ + "Test" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@S@Foo" + }, + "kind": { + "displayName": "Structure", + "identifier": "c.struct" + }, + "location": { + "position": { + "character": 7, + "line": 9 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Foo" + } + ], + "title": "Foo" + }, + "pathComponents": [ + "Foo" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "bar" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@S@Foo@FI@bar" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "c.property" + }, + "location": { + "position": { + "character": 8, + "line": 10 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "bar" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "bar" + } + ], + "title": "bar" + }, + "pathComponents": [ + "Foo", + "bar" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:@S@Foo", + "spelling": "Foo" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "TypedefedFoo" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@TypedefedFoo" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 19, + "line": 8 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "TypedefedFoo" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "TypedefedFoo" + } + ], + "title": "TypedefedFoo" + }, + "pathComponents": [ + "TypedefedFoo" + ], + "type": "c:@S@Foo" + } + ] +} diff --git a/clang/test/ExtractAPI/underscored.c b/clang/test/ExtractAPI/underscored.c index 204ec36f1fab1..30d2b63f763ef 100644 --- a/clang/test/ExtractAPI/underscored.c +++ b/clang/test/ExtractAPI/underscored.c @@ -1,5 +1,17 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ +// RUN: %t/reference.output.json.in >> %t/reference.output.json // RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \ -// RUN: -x c-header %s -o - -verify | FileCheck %s +// RUN: -x c-header %t/input.h -o %t/output.json -verify + +// 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 + +//--- input.h +// expected-no-diagnostics // Global record int _HiddenGlobal; @@ -7,22 +19,399 @@ int exposed_global; // Record type struct _HiddenRecord { - int HiddenRecordMember; + int a; }; struct ExposedRecord { - int ExposedRecordMember; + int a; }; +// Typedef +typedef struct {} _HiddenTypedef; +typedef int ExposedTypedef; +typedef _HiddenTypedef ExposedTypedefToHidden; + // Macros #define _HIDDEN_MACRO 5 #define EXPOSED_MACRO 5 -// expected-no-diagnostics - -// CHECK-NOT: _HiddenRecord -// CHECK-NOT: HiddenRecordMember -// CHECK: ExposedRecord -// CHECK: ExposedRecordMember -// CHECK-NOT: _HIDDEN_MACRO -// CHECK: EXPOSED_MACRO +// Symbols that start with '_' should not appear in the reference output +//--- 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" + } + }, + "relationships": [ + { + "kind": "memberOf", + "source": "c:@S@ExposedRecord@FI@a", + "target": "c:@S@ExposedRecord", + "targetFallback": "ExposedRecord" + } + ], + "symbols": [ + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "exposed_global" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@exposed_global" + }, + "kind": { + "displayName": "Global Variable", + "identifier": "c.var" + }, + "location": { + "position": { + "character": 4, + "line": 4 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "exposed_global" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "exposed_global" + } + ], + "title": "exposed_global" + }, + "pathComponents": [ + "exposed_global" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "struct" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "ExposedRecord" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@S@ExposedRecord" + }, + "kind": { + "displayName": "Structure", + "identifier": "c.struct" + }, + "location": { + "position": { + "character": 7, + "line": 11 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "ExposedRecord" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "ExposedRecord" + } + ], + "title": "ExposedRecord" + }, + "pathComponents": [ + "ExposedRecord" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "a" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:@S@ExposedRecord@FI@a" + }, + "kind": { + "displayName": "Instance Property", + "identifier": "c.property" + }, + "location": { + "position": { + "character": 6, + "line": 12 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "a" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "a" + } + ], + "title": "a" + }, + "pathComponents": [ + "ExposedRecord", + "a" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "#define" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "EXPOSED_MACRO" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@335@macro@EXPOSED_MACRO" + }, + "kind": { + "displayName": "Macro", + "identifier": "c.macro" + }, + "location": { + "position": { + "character": 8, + "line": 22 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "EXPOSED_MACRO" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "EXPOSED_MACRO" + } + ], + "title": "EXPOSED_MACRO" + }, + "pathComponents": [ + "EXPOSED_MACRO" + ] + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:I", + "spelling": "int" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "ExposedTypedef" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@ExposedTypedef" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 12, + "line": 17 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "ExposedTypedef" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "ExposedTypedef" + } + ], + "title": "ExposedTypedef" + }, + "pathComponents": [ + "ExposedTypedef" + ], + "type": "c:I" + }, + { + "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "typedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:@SA@_HiddenTypedef", + "spelling": "_HiddenTypedef" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "ExposedTypedefToHidden" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "identifier": { + "interfaceLanguage": "c", + "precise": "c:input.h@T@ExposedTypedefToHidden" + }, + "kind": { + "displayName": "Type Alias", + "identifier": "c.typealias" + }, + "location": { + "position": { + "character": 23, + "line": 18 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "ExposedTypedefToHidden" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "ExposedTypedefToHidden" + } + ], + "title": "ExposedTypedefToHidden" + }, + "pathComponents": [ + "ExposedTypedefToHidden" + ], + "type": "c:@SA@_HiddenTypedef" + } + ] +} diff --git a/clang/test/ExtractAPI/union.c b/clang/test/ExtractAPI/union.c index 8f8300b2c9a52..6ec9fd3ddf6e9 100644 --- a/clang/test/ExtractAPI/union.c +++ b/clang/test/ExtractAPI/union.c @@ -2,7 +2,7 @@ // RUN: split-file %s %t // RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \ // RUN: %t/reference.output.json.in >> %t/reference.output.json -// RUN: %clang_cc1 -extract-api --pretty-sgf -triple arm64-apple-macosx -x c-header\ +// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx -x c-header\ // RUN: %t/input.h -o %t/output.json -verify // Generator version is not consistent across test runs, normalize it. @@ -12,7 +12,7 @@ //--- input.h /// My Union -union Union { +union Union{ /// the a option int a; /// the b option diff --git a/clang/test/ExtractAPI/vfs_redirected_include.m b/clang/test/ExtractAPI/vfs_redirected_include.m index db0382052ba3e..9ba7e1dedb601 100644 --- a/clang/test/ExtractAPI/vfs_redirected_include.m +++ b/clang/test/ExtractAPI/vfs_redirected_include.m @@ -14,7 +14,7 @@ // RUN: %t/vfsoverlay.yaml.in >> %t/vfsoverlay.yaml // Input headers use paths to the framework root/DSTROOT -// RUN: %clang_cc1 -extract-api --pretty-sgf -v --product-name=MyFramework \ +// RUN: %clang_cc1 -extract-api -v --product-name=MyFramework \ // RUN: -triple arm64-apple-macosx \ // RUN: -iquote%t -ivfsoverlay %t/vfsoverlay.yaml -F%t/Frameworks \ // RUN: -x objective-c-header \ diff --git a/clang/test/Index/extract-api-cursor.m b/clang/test/Index/extract-api-cursor.m index 9d9d3a1e40f14..1b27b6f61437b 100644 --- a/clang/test/Index/extract-api-cursor.m +++ b/clang/test/Index/extract-api-cursor.m @@ -31,8 +31,6 @@ @implementation Derived - (void)derivedMethodWithValue:(id)value { int a = 5; } -/// Impl only docs -- (void)implOnlyMethod { } @end // RUN: c-index-test -single-symbol-sgf-at=%s:4:9 local %s | FileCheck -check-prefix=CHECK-FOO %s @@ -120,10 +118,3 @@ - (void)implOnlyMethod { } // CHECK-DERIVED-METHOD-IMPL: "text":"Derived method docs" // CHECK-DERIVED-METHOD-IMPL: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} // CHECK-DERIVED-METHOD-IMPL: "title":"derivedMethodWithValue:" - -// RUN: c-index-test -single-symbol-sgf-at=%s:35:11 local %s | FileCheck -check-prefix=CHECK-IMPL-ONLY %s -// CHECK-IMPL-ONLY: "relatedSymbols":[] -// CHECK-IMPL-ONLY: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)implOnlyMethod","target":"c:objc(cs)Derived" -// CHECK-IMPL-ONLY: "text":"Impl only docs" -// CHECK-IMPL-ONLY: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} -// CHECK-IMPL-ONLY: "title":"implOnlyMethod" diff --git a/clang/tools/libclang/CXExtractAPI.cpp b/clang/tools/libclang/CXExtractAPI.cpp index d74f3740406c5..05098c96829fc 100644 --- a/clang/tools/libclang/CXExtractAPI.cpp +++ b/clang/tools/libclang/CXExtractAPI.cpp @@ -18,7 +18,6 @@ #include "clang-c/Index.h" #include "clang-c/Platform.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/TargetInfo.h" #include "clang/ExtractAPI/API.h" @@ -55,20 +54,41 @@ struct LibClangExtractAPIVisitor if (!shouldDeclBeIncluded(Decl)) return true; - auto *Interface = Decl->getClassInterface(); + const ObjCInterfaceDecl *Interface = Decl->getClassInterface(); + StringRef Name = Interface->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + LinkageInfo Linkage = Decl->getLinkageAndVisibility(); + DocComment Comment; + if (auto *RawComment = fetchRawCommentForDecl(Interface)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading by generating them for the + // interface. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + // Collect super class information. + SymbolReference SuperClass; + if (const auto *SuperClassDecl = Decl->getSuperClass()) { + SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); + SuperClass.USR = API.recordUSR(SuperClassDecl); + } - if (!VisitObjCInterfaceDecl(Interface)) - return false; + ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( + Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, + Comment, Declaration, SubHeading, SuperClass, isInSystemHeader(Decl)); - SmallString<128> USR; - index::generateUSRForDecl(Interface, USR); + // Record all methods (selectors). This doesn't include automatically + // synthesized property methods. + recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); + recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); + recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); - if (auto *InterfaceRecord = dyn_cast_if_present( - API.findRecordForUSR(USR))) { - recordObjCMethods(InterfaceRecord, Decl->methods()); - recordObjCProperties(InterfaceRecord, Decl->properties()); - recordObjCInstanceVariables(InterfaceRecord, Decl->ivars()); - } return true; } }; @@ -76,14 +96,21 @@ struct LibClangExtractAPIVisitor DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet) -// Visits the Decl D and it's transitive DeclContexts recursively, starting from -// the outer-most context. This is guaranteed to visit every Decl we need in the -// right order to generate symbol graph information for D. static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, - Decl *D) { - if (auto *Parent = D->getDeclContext()) - WalkupFromMostDerivedType(Visitor, cast(Parent)); + Decl *D); +template +static bool WalkupParentContext(DeclContext *Parent, + LibClangExtractAPIVisitor &Visitor) { + if (auto *D = dyn_cast(Parent)) { + WalkupFromMostDerivedType(Visitor, D); + return true; + } + return false; +} + +static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, + Decl *D) { switch (D->getKind()) { #define ABSTRACT_DECL(DECL) #define DECL(CLASS, BASE) \ @@ -92,12 +119,20 @@ static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, break; #include "clang/AST/DeclNodes.inc" } + + for (auto *Parent = D->getDeclContext(); Parent != nullptr; + Parent = Parent->getParent()) { + if (WalkupParentContext(Parent, Visitor)) + return; + if (WalkupParentContext(Parent, Visitor)) + return; + } } static CXString GenerateCXStringFromSymbolGraphData(llvm::json::Object Obj) { llvm::SmallString<0> BackingString; llvm::raw_svector_ostream OS(BackingString); - OS << llvm::formatv("{0}", Value(std::move(Obj))); + OS << Value(std::move(Obj)); return cxstring::createDup(BackingString.str()); }