//===- ExtractAPI/DeclarationFragments.h ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file defines the Declaration Fragments related classes. /// /// Declaration Fragments represent parts of a symbol declaration tagged with /// syntactic/semantic information. /// See https://github.com/apple/swift-docc-symbolkit /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H #define LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/StringRef.h" #include namespace clang { namespace extractapi { /// DeclarationFragments is a vector of tagged important parts of a symbol's /// declaration. /// /// The fragments sequence can be joined to form spans of declaration text, with /// attached information useful for purposes like syntax-highlighting etc. /// For example: /// \code /// const -> keyword "const" /// int -> type "int" /// pi; -> identifier "pi" /// \endcode class DeclarationFragments { public: DeclarationFragments() = default; /// The kind of a fragment. enum class FragmentKind { /// Unknown fragment kind. None, Keyword, Attribute, NumberLiteral, StringLiteral, Identifier, /// Identifier that refers to a type in the context. TypeIdentifier, /// Parameter that's used as generics in the context. For example template /// parameters. GenericParameter, /// External parameters in Objective-C methods. /// For example, \c forKey in /// \code{.m} /// - (void) setValue:(Value)value forKey(Key)key /// \endcode ExternalParam, /// Internal/local parameters in Objective-C methods. /// For example, \c key in /// \code{.m} /// - (void) setValue:(Value)value forKey(Key)key /// \endcode InternalParam, Text, }; /// Fragment holds information of a single fragment. struct Fragment { std::string Spelling; FragmentKind Kind; /// The USR of the fragment symbol, if applicable. std::string PreciseIdentifier; /// The associated declaration, if applicable. This is not intended to be /// used outside of libclang. const Decl *Declaration; Fragment(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier, const Decl *Declaration) : Spelling(Spelling), Kind(Kind), PreciseIdentifier(PreciseIdentifier), Declaration(Declaration) {} }; using FragmentIterator = std::vector::iterator; using ConstFragmentIterator = std::vector::const_iterator; const std::vector &getFragments() const { return Fragments; } FragmentIterator begin() { return Fragments.begin(); } FragmentIterator end() { return Fragments.end(); } ConstFragmentIterator cbegin() const { return Fragments.cbegin(); } ConstFragmentIterator cend() const { return Fragments.cend(); } // Add a new Fragment at an arbitrary offset. DeclarationFragments &insert(FragmentIterator It, StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier = "", const Decl *Declaration = nullptr) { Fragments.insert(It, Fragment(Spelling, Kind, PreciseIdentifier, Declaration)); return *this; } DeclarationFragments &insert(FragmentIterator It, DeclarationFragments &&Other) { Fragments.insert(It, std::make_move_iterator(Other.Fragments.begin()), std::make_move_iterator(Other.Fragments.end())); Other.Fragments.clear(); return *this; } /// Append a new Fragment to the end of the Fragments. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive appends. DeclarationFragments &append(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier = "", const Decl *Declaration = nullptr) { if (Kind == FragmentKind::Text && !Fragments.empty() && Fragments.back().Kind == FragmentKind::Text) { // If appending a text fragment, and the last fragment is also text, // merge into the last fragment. Fragments.back().Spelling.append(Spelling.data(), Spelling.size()); } else { Fragments.emplace_back(Spelling, Kind, PreciseIdentifier, Declaration); } return *this; } /// Append another DeclarationFragments to the end. /// /// Note: \p Other is moved from and cannot be used after a call to this /// method. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive appends. DeclarationFragments &append(DeclarationFragments &&Other) { Fragments.insert(Fragments.end(), std::make_move_iterator(Other.Fragments.begin()), std::make_move_iterator(Other.Fragments.end())); Other.Fragments.clear(); return *this; } /// Append a text Fragment of a space character. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive appends. DeclarationFragments &appendSpace(); /// Get the string description of a FragmentKind \p Kind. static StringRef getFragmentKindString(FragmentKind Kind); /// Get the corresponding FragmentKind from string \p S. static FragmentKind parseFragmentKindFromString(StringRef S); private: std::vector Fragments; }; /// Store function signature information with DeclarationFragments of the /// return type and parameters. class FunctionSignature { public: FunctionSignature() = default; /// Parameter holds the name and DeclarationFragments of a single parameter. struct Parameter { std::string Name; DeclarationFragments Fragments; Parameter(StringRef Name, DeclarationFragments Fragments) : Name(Name), Fragments(Fragments) {} }; const std::vector &getParameters() const { return Parameters; } const DeclarationFragments &getReturnType() const { return ReturnType; } FunctionSignature &addParameter(StringRef Name, DeclarationFragments Fragments) { Parameters.emplace_back(Name, Fragments); return *this; } void setReturnType(DeclarationFragments RT) { ReturnType = RT; } /// Determine if the FunctionSignature is empty. /// /// \returns true if the return type DeclarationFragments is empty and there /// is no parameter, otherwise false. bool empty() const { return Parameters.empty() && ReturnType.getFragments().empty(); } private: std::vector Parameters; DeclarationFragments ReturnType; }; /// A factory class to build DeclarationFragments for different kinds of Decl. class DeclarationFragmentsBuilder { public: /// Build DeclarationFragments for a variable declaration VarDecl. static DeclarationFragments getFragmentsForVar(const VarDecl *); /// Build DeclarationFragments for a function declaration FunctionDecl. static DeclarationFragments getFragmentsForFunction(const FunctionDecl *); /// Build DeclarationFragments for an enum constant declaration /// EnumConstantDecl. static DeclarationFragments getFragmentsForEnumConstant(const EnumConstantDecl *); /// Build DeclarationFragments for an enum declaration EnumDecl. static DeclarationFragments getFragmentsForEnum(const EnumDecl *); /// Build DeclarationFragments for a field declaration FieldDecl. static DeclarationFragments getFragmentsForField(const FieldDecl *); /// Build DeclarationFragments for a struct record declaration RecordDecl. static DeclarationFragments getFragmentsForStruct(const RecordDecl *); /// Build DeclarationFragments for an Objective-C category declaration /// ObjCCategoryDecl. static DeclarationFragments getFragmentsForObjCCategory(const ObjCCategoryDecl *); /// Build DeclarationFragments for an Objective-C interface declaration /// ObjCInterfaceDecl. static DeclarationFragments getFragmentsForObjCInterface(const ObjCInterfaceDecl *); /// Build DeclarationFragments for an Objective-C method declaration /// ObjCMethodDecl. static DeclarationFragments getFragmentsForObjCMethod(const ObjCMethodDecl *); /// Build DeclarationFragments for an Objective-C property declaration /// ObjCPropertyDecl. static DeclarationFragments getFragmentsForObjCProperty(const ObjCPropertyDecl *); /// Build DeclarationFragments for an Objective-C protocol declaration /// ObjCProtocolDecl. static DeclarationFragments getFragmentsForObjCProtocol(const ObjCProtocolDecl *); /// Build DeclarationFragments for a macro. /// /// \param Name name of the macro. /// \param MD the associated MacroDirective. static DeclarationFragments getFragmentsForMacro(StringRef Name, const MacroDirective *MD); /// Build DeclarationFragments for a typedef \p TypedefNameDecl. static DeclarationFragments getFragmentsForTypedef(const TypedefNameDecl *Decl); /// Build sub-heading fragments for a NamedDecl. static DeclarationFragments getSubHeading(const NamedDecl *); /// Build sub-heading fragments for an Objective-C method. static DeclarationFragments getSubHeading(const ObjCMethodDecl *); /// Build a sub-heading for macro \p Name. static DeclarationFragments getSubHeadingForMacro(StringRef Name); /// Build FunctionSignature for a function-like declaration \c FunctionT like /// FunctionDecl or ObjCMethodDecl. /// /// The logic and implementation of building a signature for a FunctionDecl /// and an ObjCMethodDecl are exactly the same, but they do not share a common /// base. This template helps reuse the code. template static FunctionSignature getFunctionSignature(const FunctionT *); private: DeclarationFragmentsBuilder() = delete; /// Build DeclarationFragments for a QualType. static DeclarationFragments getFragmentsForType(const QualType, ASTContext &, DeclarationFragments &); /// Build DeclarationFragments for a Type. static DeclarationFragments getFragmentsForType(const Type *, ASTContext &, DeclarationFragments &); /// Build DeclarationFragments for a NestedNameSpecifier. static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *, ASTContext &, DeclarationFragments &); /// Build DeclarationFragments for Qualifiers. static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals); /// Build DeclarationFragments for a parameter variable declaration /// ParmVarDecl. static DeclarationFragments getFragmentsForParam(const ParmVarDecl *); }; } // namespace extractapi } // namespace clang #endif // LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H