//===- 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/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/SmallVector.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; } DeclarationFragments &pop_back() { Fragments.pop_back(); return *this; } DeclarationFragments &replace(std::string NewSpelling, unsigned Position) { Fragments.at(Position).Spelling = NewSpelling; 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); static DeclarationFragments getExceptionSpecificationString(ExceptionSpecificationType ExceptionSpec); static DeclarationFragments getStructureTypeFragment(const RecordDecl *Decl); private: std::vector Fragments; }; class AccessControl { public: AccessControl(std::string Access) : Access(Access) {} const std::string &getAccess() const { return Access; } bool empty() const { return Access.empty(); } private: std::string Access; }; /// 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 FunctionSignature for a function-like declaration \c FunctionT like /// FunctionDecl, ObjCMethodDecl, or CXXMethodDecl. /// /// The logic and implementation of building a signature for a FunctionDecl, /// CXXMethodDecl, and 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 *Function); static AccessControl getAccessControl(const Decl *Decl) { switch (Decl->getAccess()) { case AS_public: case AS_none: return AccessControl("public"); case AS_private: return AccessControl("private"); case AS_protected: return AccessControl("protected"); } llvm_unreachable("Unhandled access control"); } static DeclarationFragments getFragmentsForNamespace(const NamespaceDecl *Decl); /// Build DeclarationFragments for a variable declaration VarDecl. static DeclarationFragments getFragmentsForVar(const VarDecl *); static DeclarationFragments getFragmentsForVarTemplate(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 *); static DeclarationFragments getFragmentsForCXXClass(const CXXRecordDecl *); static DeclarationFragments getFragmentsForSpecialCXXMethod(const CXXMethodDecl *); static DeclarationFragments getFragmentsForCXXMethod(const CXXMethodDecl *); static DeclarationFragments getFragmentsForConversionFunction(const CXXConversionDecl *); static DeclarationFragments getFragmentsForOverloadedOperator(const CXXMethodDecl *); static DeclarationFragments getFragmentsForTemplateParameters(ArrayRef); static std::string getNameForTemplateArgument(const ArrayRef, std::string); static DeclarationFragments getFragmentsForTemplateArguments(const ArrayRef, ASTContext &, const std::optional>); static DeclarationFragments getFragmentsForConcept(const ConceptDecl *); static DeclarationFragments getFragmentsForRedeclarableTemplate(const RedeclarableTemplateDecl *); static DeclarationFragments getFragmentsForClassTemplateSpecialization( const ClassTemplateSpecializationDecl *); static DeclarationFragments getFragmentsForClassTemplatePartialSpecialization( const ClassTemplatePartialSpecializationDecl *); static DeclarationFragments getFragmentsForVarTemplateSpecialization( const VarTemplateSpecializationDecl *); static DeclarationFragments getFragmentsForVarTemplatePartialSpecialization( const VarTemplatePartialSpecializationDecl *); static DeclarationFragments getFragmentsForFunctionTemplate(const FunctionTemplateDecl *Decl); static DeclarationFragments getFragmentsForFunctionTemplateSpecialization(const FunctionDecl *Decl); /// 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); 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 *); static DeclarationFragments getFragmentsForBlock(const NamedDecl *BlockDecl, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After); }; template FunctionSignature DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { FunctionSignature Signature; DeclarationFragments ReturnType, After; ReturnType = getFragmentsForType(Function->getReturnType(), Function->getASTContext(), After); if (isa(Function) && dyn_cast(Function)->getDescribedFunctionTemplate() && ReturnType.begin()->Spelling.substr(0, 14).compare("type-parameter") == 0) { std::string ProperArgName = getNameForTemplateArgument(dyn_cast(Function) ->getDescribedFunctionTemplate() ->getTemplateParameters() ->asArray(), ReturnType.begin()->Spelling); ReturnType.begin()->Spelling.swap(ProperArgName); } ReturnType.append(std::move(After)); Signature.setReturnType(ReturnType); for (const auto *Param : Function->parameters()) Signature.addParameter(Param->getName(), getFragmentsForParam(Param)); return Signature; } } // namespace extractapi } // namespace clang #endif // LLVM_CLANG_EXTRACTAPI_DECLARATION_FRAGMENTS_H