clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
487 lines
17 KiB
C++
487 lines
17 KiB
C++
//===- ExtractAPI/DeclarationFragments.h ------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// 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
|