Viewing file: DeclarationFragments.h (16.9 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===- 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 <iterator> #include <utility> #include <vector>
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<Fragment>::iterator; using ConstFragmentIterator = std::vector<Fragment>::const_iterator;
const std::vector<Fragment> &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(); }
/// Prepend another DeclarationFragments to the beginning. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive operations. DeclarationFragments &prepend(DeclarationFragments Other) { return insert(begin(), std::move(Other)); }
/// Append another DeclarationFragments to the end. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive operations. DeclarationFragments &append(DeclarationFragments Other) { return insert(end(), std::move(Other)); }
/// Append a new Fragment to the end of the Fragments. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive operations. 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; }
/// Inserts another DeclarationFragments at \p It. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive operations. DeclarationFragments &insert(FragmentIterator It, DeclarationFragments Other) { if (Other.Fragments.empty()) return *this;
if (Fragments.empty()) { Fragments = std::move(Other.Fragments); return *this; }
const auto &OtherFrags = Other.Fragments; auto ToInsertBegin = std::make_move_iterator(Other.begin()); auto ToInsertEnd = std::make_move_iterator(Other.end());
// If we aren't inserting at the end let's make sure that we merge their // last fragment with It if both are text fragments. if (It != end() && It->Kind == FragmentKind::Text && OtherFrags.back().Kind == FragmentKind::Text) { auto &TheirBackSpelling = OtherFrags.back().Spelling; It->Spelling.reserve(It->Spelling.size() + TheirBackSpelling.size()); It->Spelling.insert(It->Spelling.begin(), TheirBackSpelling.begin(), TheirBackSpelling.end()); --ToInsertEnd; }
// If we aren't inserting at the beginning we want to merge their first // fragment with the fragment before It if both are text fragments. if (It != begin() && std::prev(It)->Kind == FragmentKind::Text && OtherFrags.front().Kind == FragmentKind::Text) { auto PrevIt = std::prev(It); auto &TheirFrontSpelling = OtherFrags.front().Spelling; PrevIt->Spelling.reserve(PrevIt->Spelling.size() + TheirFrontSpelling.size()); PrevIt->Spelling.append(TheirFrontSpelling); ++ToInsertBegin; }
Fragments.insert(It, ToInsertBegin, ToInsertEnd); 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 operations. DeclarationFragments &appendSpace();
/// Append a text Fragment of a semicolon character. /// /// \returns a reference to the DeclarationFragments object itself after /// appending to chain up consecutive operations. 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);
/// 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: DeclarationFragments &appendUnduplicatedTextCharacter(char Character); std::vector<Fragment> Fragments; };
class AccessControl { public: AccessControl(std::string Access) : Access(Access) {} AccessControl() : Access("public") {}
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<Parameter> &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<Parameter> 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 <typename FunctionT> 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/union record declaration /// RecordDecl. static DeclarationFragments getFragmentsForRecordDecl(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<NamedDecl *>);
static DeclarationFragments getFragmentsForTemplateArguments( const ArrayRef<TemplateArgument>, ASTContext &, const std::optional<ArrayRef<TemplateArgumentLoc>>);
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 <typename FunctionT> FunctionSignature DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { FunctionSignature Signature;
DeclarationFragments ReturnType, After; ReturnType = getFragmentsForType(Function->getReturnType(), Function->getASTContext(), After); if (isa<FunctionDecl>(Function) && dyn_cast<FunctionDecl>(Function)->getDescribedFunctionTemplate() && StringRef(ReturnType.begin()->Spelling).starts_with("type-parameter")) { std::string ProperArgName = Function->getReturnType().getAsString(); 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
|