aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp1643
1 files changed, 1643 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp
new file mode 100644
index 000000000000..6b85c7db9034
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -0,0 +1,1643 @@
+//===- ExtractAPI/DeclarationFragments.cpp ----------------------*- 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 implements Declaration Fragments related classes.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/AST/ASTFwd.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+
+using namespace clang::extractapi;
+using namespace llvm;
+
+namespace {
+
+void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo,
+ clang::FunctionTypeLoc &Block,
+ clang::FunctionProtoTypeLoc &BlockProto) {
+ if (!TSInfo)
+ return;
+
+ clang::TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
+ while (true) {
+ // Look through qualified types
+ if (auto QualifiedTL = TL.getAs<clang::QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
+ continue;
+ }
+
+ if (auto AttrTL = TL.getAs<clang::AttributedTypeLoc>()) {
+ TL = AttrTL.getModifiedLoc();
+ continue;
+ }
+
+ // Try to get the function prototype behind the block pointer type,
+ // then we're done.
+ if (auto BlockPtr = TL.getAs<clang::BlockPointerTypeLoc>()) {
+ TL = BlockPtr.getPointeeLoc().IgnoreParens();
+ Block = TL.getAs<clang::FunctionTypeLoc>();
+ BlockProto = TL.getAs<clang::FunctionProtoTypeLoc>();
+ }
+ break;
+ }
+}
+
+} // namespace
+
+DeclarationFragments &
+DeclarationFragments::appendUnduplicatedTextCharacter(char Character) {
+ 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);
+ }
+ } else {
+ append("", FragmentKind::Text);
+ Fragments.back().Spelling.push_back(Character);
+ }
+ }
+
+ 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) {
+ case DeclarationFragments::FragmentKind::None:
+ return "none";
+ case DeclarationFragments::FragmentKind::Keyword:
+ return "keyword";
+ case DeclarationFragments::FragmentKind::Attribute:
+ return "attribute";
+ case DeclarationFragments::FragmentKind::NumberLiteral:
+ return "number";
+ case DeclarationFragments::FragmentKind::StringLiteral:
+ return "string";
+ case DeclarationFragments::FragmentKind::Identifier:
+ return "identifier";
+ case DeclarationFragments::FragmentKind::TypeIdentifier:
+ return "typeIdentifier";
+ case DeclarationFragments::FragmentKind::GenericParameter:
+ return "genericParameter";
+ case DeclarationFragments::FragmentKind::ExternalParam:
+ return "externalParam";
+ case DeclarationFragments::FragmentKind::InternalParam:
+ return "internalParam";
+ case DeclarationFragments::FragmentKind::Text:
+ return "text";
+ }
+
+ llvm_unreachable("Unhandled FragmentKind");
+}
+
+DeclarationFragments::FragmentKind
+DeclarationFragments::parseFragmentKindFromString(StringRef S) {
+ return llvm::StringSwitch<FragmentKind>(S)
+ .Case("keyword", DeclarationFragments::FragmentKind::Keyword)
+ .Case("attribute", DeclarationFragments::FragmentKind::Attribute)
+ .Case("number", DeclarationFragments::FragmentKind::NumberLiteral)
+ .Case("string", DeclarationFragments::FragmentKind::StringLiteral)
+ .Case("identifier", DeclarationFragments::FragmentKind::Identifier)
+ .Case("typeIdentifier",
+ DeclarationFragments::FragmentKind::TypeIdentifier)
+ .Case("genericParameter",
+ DeclarationFragments::FragmentKind::GenericParameter)
+ .Case("internalParam", DeclarationFragments::FragmentKind::InternalParam)
+ .Case("externalParam", DeclarationFragments::FragmentKind::ExternalParam)
+ .Case("text", DeclarationFragments::FragmentKind::Text)
+ .Default(DeclarationFragments::FragmentKind::None);
+}
+
+DeclarationFragments DeclarationFragments::getExceptionSpecificationString(
+ ExceptionSpecificationType ExceptionSpec) {
+ DeclarationFragments Fragments;
+ switch (ExceptionSpec) {
+ case ExceptionSpecificationType::EST_None:
+ return Fragments;
+ case ExceptionSpecificationType::EST_DynamicNone:
+ return Fragments.append(" ", DeclarationFragments::FragmentKind::Text)
+ .append("throw", DeclarationFragments::FragmentKind::Keyword)
+ .append("(", DeclarationFragments::FragmentKind::Text)
+ .append(")", DeclarationFragments::FragmentKind::Text);
+ case ExceptionSpecificationType::EST_Dynamic:
+ // FIXME: throw(int), get types of inner expression
+ return Fragments;
+ case ExceptionSpecificationType::EST_BasicNoexcept:
+ return Fragments.append(" ", DeclarationFragments::FragmentKind::Text)
+ .append("noexcept", DeclarationFragments::FragmentKind::Keyword);
+ case ExceptionSpecificationType::EST_DependentNoexcept:
+ // FIXME: throw(conditional-expression), get expression
+ break;
+ case ExceptionSpecificationType::EST_NoexceptFalse:
+ return Fragments.append(" ", DeclarationFragments::FragmentKind::Text)
+ .append("noexcept", DeclarationFragments::FragmentKind::Keyword)
+ .append("(", DeclarationFragments::FragmentKind::Text)
+ .append("false", DeclarationFragments::FragmentKind::Keyword)
+ .append(")", DeclarationFragments::FragmentKind::Text);
+ case ExceptionSpecificationType::EST_NoexceptTrue:
+ return Fragments.append(" ", DeclarationFragments::FragmentKind::Text)
+ .append("noexcept", DeclarationFragments::FragmentKind::Keyword)
+ .append("(", DeclarationFragments::FragmentKind::Text)
+ .append("true", DeclarationFragments::FragmentKind::Keyword)
+ .append(")", DeclarationFragments::FragmentKind::Text);
+ default:
+ return Fragments;
+ }
+
+ llvm_unreachable("Unhandled exception specification");
+}
+
+DeclarationFragments
+DeclarationFragments::getStructureTypeFragment(const RecordDecl *Record) {
+ DeclarationFragments Fragments;
+ if (Record->isStruct())
+ Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
+ else if (Record->isUnion())
+ Fragments.append("union", DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
+
+ return Fragments;
+}
+
+// NNS stores C++ nested name specifiers, which are prefixes to qualified names.
+// Build declaration fragments for NNS recursively so that we have the USR for
+// every part in a qualified name, and also leaves the actual underlying type
+// cleaner for its own fragment.
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS,
+ ASTContext &Context,
+ DeclarationFragments &After) {
+ DeclarationFragments Fragments;
+ if (NNS->getPrefix())
+ Fragments.append(getFragmentsForNNS(NNS->getPrefix(), Context, After));
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ Fragments.append(NNS->getAsIdentifier()->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+ break;
+
+ case NestedNameSpecifier::Namespace: {
+ const NamespaceDecl *NS = NNS->getAsNamespace();
+ if (NS->isAnonymousNamespace())
+ return Fragments;
+ SmallString<128> USR;
+ index::generateUSRForDecl(NS, USR);
+ Fragments.append(NS->getName(),
+ DeclarationFragments::FragmentKind::Identifier, USR, NS);
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ const NamespaceAliasDecl *Alias = NNS->getAsNamespaceAlias();
+ SmallString<128> USR;
+ index::generateUSRForDecl(Alias, USR);
+ Fragments.append(Alias->getName(),
+ DeclarationFragments::FragmentKind::Identifier, USR,
+ Alias);
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ // The global specifier `::` at the beginning. No stored value.
+ break;
+
+ case NestedNameSpecifier::Super:
+ // Microsoft's `__super` specifier.
+ Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword);
+ break;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // A type prefixed by the `template` keyword.
+ Fragments.append("template", DeclarationFragments::FragmentKind::Keyword);
+ Fragments.appendSpace();
+ // Fallthrough after adding the keyword to handle the actual type.
+ [[fallthrough]];
+
+ case NestedNameSpecifier::TypeSpec: {
+ const Type *T = NNS->getAsType();
+ // FIXME: Handle C++ template specialization type
+ Fragments.append(getFragmentsForType(T, Context, After));
+ break;
+ }
+ }
+
+ // Add the separator text `::` for this segment.
+ return Fragments.append("::", DeclarationFragments::FragmentKind::Text);
+}
+
+// Recursively build the declaration fragments for an underlying `Type` with
+// qualifiers removed.
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
+ const Type *T, ASTContext &Context, DeclarationFragments &After) {
+ assert(T && "invalid type");
+
+ DeclarationFragments Fragments;
+
+ // An ElaboratedType is a sugar for types that are referred to using an
+ // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a
+ // qualified name, e.g., `N::M::type`, or both.
+ if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
+ ElaboratedTypeKeyword Keyword = ET->getKeyword();
+ if (Keyword != ElaboratedTypeKeyword::None) {
+ Fragments
+ .append(ElaboratedType::getKeywordName(Keyword),
+ DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ }
+
+ if (const NestedNameSpecifier *NNS = ET->getQualifier())
+ Fragments.append(getFragmentsForNNS(NNS, Context, After));
+
+ // After handling the elaborated keyword or qualified name, build
+ // declaration fragments for the desugared underlying type.
+ return Fragments.append(getFragmentsForType(ET->desugar(), Context, After));
+ }
+
+ // If the type is a typedefed type, get the underlying TypedefNameDecl for a
+ // direct reference to the typedef instead of the wrapped type.
+
+ // 'id' type is a typedef for an ObjCObjectPointerType
+ // we treat it as a typedef
+ if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
+ const TypedefNameDecl *Decl = TypedefTy->getDecl();
+ TypedefUnderlyingTypeResolver TypedefResolver(Context);
+ std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
+
+ if (T->isObjCIdType()) {
+ return Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::Keyword);
+ }
+
+ return Fragments.append(
+ Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
+ }
+
+ // Declaration fragments of a pointer type is the declaration fragments of
+ // the pointee type followed by a `*`,
+ if (T->isPointerType() && !T->isFunctionPointerType())
+ return Fragments
+ .append(getFragmentsForType(T->getPointeeType(), Context, After))
+ .append(" *", DeclarationFragments::FragmentKind::Text);
+
+ // For Objective-C `id` and `Class` pointers
+ // we do not spell out the `*`.
+ if (T->isObjCObjectPointerType() &&
+ !T->getAs<ObjCObjectPointerType>()->isObjCIdOrClassType()) {
+
+ Fragments.append(getFragmentsForType(T->getPointeeType(), Context, After));
+
+ // id<protocol> is an qualified id type
+ // id<protocol>* is not an qualified id type
+ if (!T->getAs<ObjCObjectPointerType>()->isObjCQualifiedIdType()) {
+ Fragments.append(" *", DeclarationFragments::FragmentKind::Text);
+ }
+
+ return Fragments;
+ }
+
+ // Declaration fragments of a lvalue reference type is the declaration
+ // fragments of the underlying type followed by a `&`.
+ if (const LValueReferenceType *LRT = dyn_cast<LValueReferenceType>(T))
+ return Fragments
+ .append(
+ getFragmentsForType(LRT->getPointeeTypeAsWritten(), Context, After))
+ .append(" &", DeclarationFragments::FragmentKind::Text);
+
+ // Declaration fragments of a rvalue reference type is the declaration
+ // fragments of the underlying type followed by a `&&`.
+ if (const RValueReferenceType *RRT = dyn_cast<RValueReferenceType>(T))
+ return Fragments
+ .append(
+ getFragmentsForType(RRT->getPointeeTypeAsWritten(), Context, After))
+ .append(" &&", DeclarationFragments::FragmentKind::Text);
+
+ // Declaration fragments of an array-typed variable have two parts:
+ // 1. the element type of the array that appears before the variable name;
+ // 2. array brackets `[(0-9)?]` that appear after the variable name.
+ if (const ArrayType *AT = T->getAsArrayTypeUnsafe()) {
+ // Build the "after" part first because the inner element type might also
+ // be an array-type. For example `int matrix[3][4]` which has a type of
+ // "(array 3 of (array 4 of ints))."
+ // Push the array size part first to make sure they are in the right order.
+ After.append("[", DeclarationFragments::FragmentKind::Text);
+
+ switch (AT->getSizeModifier()) {
+ case ArraySizeModifier::Normal:
+ break;
+ case ArraySizeModifier::Static:
+ Fragments.append("static", DeclarationFragments::FragmentKind::Keyword);
+ break;
+ case ArraySizeModifier::Star:
+ Fragments.append("*", DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ // FIXME: right now this would evaluate any expressions/macros written in
+ // the original source to concrete values. For example
+ // `int nums[MAX]` -> `int nums[100]`
+ // `char *str[5 + 1]` -> `char *str[6]`
+ SmallString<128> Size;
+ CAT->getSize().toStringUnsigned(Size);
+ After.append(Size, DeclarationFragments::FragmentKind::NumberLiteral);
+ }
+
+ After.append("]", DeclarationFragments::FragmentKind::Text);
+
+ return Fragments.append(
+ getFragmentsForType(AT->getElementType(), Context, After));
+ }
+
+ if (const TemplateSpecializationType *TemplSpecTy =
+ dyn_cast<TemplateSpecializationType>(T)) {
+ const auto TemplName = TemplSpecTy->getTemplateName();
+ std::string Str;
+ raw_string_ostream Stream(Str);
+ TemplName.print(Stream, Context.getPrintingPolicy(),
+ TemplateName::Qualified::AsWritten);
+ SmallString<64> USR("");
+ if (const auto *TemplDecl = TemplName.getAsTemplateDecl())
+ index::generateUSRForDecl(TemplDecl, USR);
+
+ return Fragments
+ .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ TemplSpecTy->template_arguments(), Context, std::nullopt))
+ .append(">", DeclarationFragments::FragmentKind::Text);
+ }
+
+ // Everything we care about has been handled now, reduce to the canonical
+ // unqualified base type.
+ QualType Base = T->getCanonicalTypeUnqualified();
+
+ // If the base type is a TagType (struct/interface/union/class/enum), let's
+ // get the underlying Decl for better names and USRs.
+ if (const TagType *TagTy = dyn_cast<TagType>(Base)) {
+ const TagDecl *Decl = TagTy->getDecl();
+ // Anonymous decl, skip this fragment.
+ if (Decl->getName().empty())
+ return Fragments.append("{ ... }",
+ DeclarationFragments::FragmentKind::Text);
+ SmallString<128> TagUSR;
+ clang::index::generateUSRForDecl(Decl, TagUSR);
+ return Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier,
+ TagUSR, Decl);
+ }
+
+ // If the base type is an ObjCInterfaceType, use the underlying
+ // ObjCInterfaceDecl for the true USR.
+ if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) {
+ const auto *Decl = ObjCIT->getDecl();
+ SmallString<128> USR;
+ index::generateUSRForDecl(Decl, USR);
+ return Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR, Decl);
+ }
+
+ // Default fragment builder for other kinds of types (BuiltinType etc.)
+ SmallString<128> USR;
+ clang::index::generateUSRForType(Base, Context, USR);
+ Fragments.append(Base.getAsString(),
+ DeclarationFragments::FragmentKind::TypeIdentifier, USR);
+
+ return Fragments;
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForQualifiers(const Qualifiers Quals) {
+ DeclarationFragments Fragments;
+ if (Quals.hasConst())
+ Fragments.append("const", DeclarationFragments::FragmentKind::Keyword);
+ if (Quals.hasVolatile())
+ Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword);
+ if (Quals.hasRestrict())
+ Fragments.append("restrict", DeclarationFragments::FragmentKind::Keyword);
+
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
+ const QualType QT, ASTContext &Context, DeclarationFragments &After) {
+ assert(!QT.isNull() && "invalid type");
+
+ if (const ParenType *PT = dyn_cast<ParenType>(QT)) {
+ After.append(")", DeclarationFragments::FragmentKind::Text);
+ return getFragmentsForType(PT->getInnerType(), Context, After)
+ .append("(", DeclarationFragments::FragmentKind::Text);
+ }
+
+ const SplitQualType SQT = QT.split();
+ DeclarationFragments QualsFragments = getFragmentsForQualifiers(SQT.Quals),
+ TypeFragments =
+ getFragmentsForType(SQT.Ty, Context, After);
+ if (QT.getAsString() == "_Bool")
+ TypeFragments.replace("bool", 0);
+
+ if (QualsFragments.getFragments().empty())
+ return TypeFragments;
+
+ // Use east qualifier for pointer types
+ // For example:
+ // ```
+ // int * const
+ // ^---- ^----
+ // type qualifier
+ // ^-----------------
+ // const pointer to int
+ // ```
+ // should not be reconstructed as
+ // ```
+ // const int *
+ // ^---- ^--
+ // qualifier type
+ // ^---------------- ^
+ // pointer to const int
+ // ```
+ if (SQT.Ty->isAnyPointerType())
+ return TypeFragments.appendSpace().append(std::move(QualsFragments));
+
+ return QualsFragments.appendSpace().append(std::move(TypeFragments));
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace(
+ const NamespaceDecl *Decl) {
+ DeclarationFragments Fragments;
+ Fragments.append("namespace", DeclarationFragments::FragmentKind::Keyword);
+ if (!Decl->isAnonymousNamespace())
+ Fragments.appendSpace().append(
+ Decl->getName(), DeclarationFragments::FragmentKind::Identifier);
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
+ DeclarationFragments Fragments;
+ if (Var->isConstexpr())
+ Fragments.append("constexpr", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ StorageClass SC = Var->getStorageClass();
+ if (SC != SC_None)
+ Fragments
+ .append(VarDecl::getStorageClassSpecifierString(SC),
+ DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ // Capture potential fragments that needs to be placed after the variable name
+ // ```
+ // int nums[5];
+ // char (*ptr_to_array)[6];
+ // ```
+ DeclarationFragments After;
+ FunctionTypeLoc BlockLoc;
+ FunctionProtoTypeLoc BlockProtoLoc;
+ findTypeLocForBlockDecl(Var->getTypeSourceInfo(), BlockLoc, BlockProtoLoc);
+
+ if (!BlockLoc) {
+ QualType T = Var->getTypeSourceInfo()
+ ? Var->getTypeSourceInfo()->getType()
+ : Var->getASTContext().getUnqualifiedObjCPointerType(
+ Var->getType());
+
+ Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
+ .appendSpace();
+ } else {
+ Fragments.append(getFragmentsForBlock(Var, BlockLoc, BlockProtoLoc, After));
+ }
+
+ return Fragments
+ .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After))
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) {
+ DeclarationFragments Fragments;
+ if (Var->isConstexpr())
+ Fragments.append("constexpr", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ QualType T =
+ Var->getTypeSourceInfo()
+ ? Var->getTypeSourceInfo()->getType()
+ : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());
+
+ // Might be a member, so might be static.
+ if (Var->isStaticDataMember())
+ Fragments.append("static", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ DeclarationFragments After;
+ DeclarationFragments ArgumentFragment =
+ getFragmentsForType(T, Var->getASTContext(), After);
+ if (StringRef(ArgumentFragment.begin()->Spelling)
+ .starts_with("type-parameter")) {
+ std::string ProperArgName = T.getAsString();
+ ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+ }
+ Fragments.append(std::move(ArgumentFragment))
+ .appendSpace()
+ .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
+ .appendSemicolon();
+ return Fragments;
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
+ DeclarationFragments Fragments, After;
+
+ auto *TSInfo = Param->getTypeSourceInfo();
+
+ QualType T = TSInfo ? TSInfo->getType()
+ : Param->getASTContext().getUnqualifiedObjCPointerType(
+ Param->getType());
+
+ FunctionTypeLoc BlockLoc;
+ FunctionProtoTypeLoc BlockProtoLoc;
+ findTypeLocForBlockDecl(TSInfo, BlockLoc, BlockProtoLoc);
+
+ DeclarationFragments TypeFragments;
+ if (BlockLoc)
+ TypeFragments.append(
+ getFragmentsForBlock(Param, BlockLoc, BlockProtoLoc, After));
+ else
+ TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After));
+
+ if (StringRef(TypeFragments.begin()->Spelling)
+ .starts_with("type-parameter")) {
+ std::string ProperArgName = Param->getOriginalType().getAsString();
+ TypeFragments.begin()->Spelling.swap(ProperArgName);
+ }
+
+ if (Param->isObjCMethodParameter()) {
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text)
+ .append(std::move(TypeFragments))
+ .append(std::move(After))
+ .append(") ", DeclarationFragments::FragmentKind::Text)
+ .append(Param->getName(),
+ DeclarationFragments::FragmentKind::InternalParam);
+ } else {
+ Fragments.append(std::move(TypeFragments));
+ if (!T->isBlockPointerType())
+ Fragments.appendSpace();
+ Fragments
+ .append(Param->getName(),
+ DeclarationFragments::FragmentKind::InternalParam)
+ .append(std::move(After));
+ }
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock(
+ const NamedDecl *BlockDecl, FunctionTypeLoc &Block,
+ FunctionProtoTypeLoc &BlockProto, DeclarationFragments &After) {
+ DeclarationFragments Fragments;
+
+ DeclarationFragments RetTyAfter;
+ auto ReturnValueFragment = getFragmentsForType(
+ Block.getTypePtr()->getReturnType(), BlockDecl->getASTContext(), After);
+
+ Fragments.append(std::move(ReturnValueFragment))
+ .append(std::move(RetTyAfter))
+ .appendSpace()
+ .append("(^", DeclarationFragments::FragmentKind::Text);
+
+ After.append(")", DeclarationFragments::FragmentKind::Text);
+ unsigned NumParams = Block.getNumParams();
+
+ if (!BlockProto || NumParams == 0) {
+ if (BlockProto && BlockProto.getTypePtr()->isVariadic())
+ After.append("(...)", DeclarationFragments::FragmentKind::Text);
+ else
+ After.append("()", DeclarationFragments::FragmentKind::Text);
+ } else {
+ After.append("(", DeclarationFragments::FragmentKind::Text);
+ for (unsigned I = 0; I != NumParams; ++I) {
+ if (I)
+ After.append(", ", DeclarationFragments::FragmentKind::Text);
+ After.append(getFragmentsForParam(Block.getParam(I)));
+ if (I == NumParams - 1 && BlockProto.getTypePtr()->isVariadic())
+ After.append(", ...", DeclarationFragments::FragmentKind::Text);
+ }
+ After.append(")", DeclarationFragments::FragmentKind::Text);
+ }
+
+ return Fragments;
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
+ DeclarationFragments Fragments;
+ switch (Func->getStorageClass()) {
+ case SC_None:
+ case SC_PrivateExtern:
+ break;
+ case SC_Extern:
+ Fragments.append("extern", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ break;
+ case SC_Static:
+ Fragments.append("static", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ break;
+ case SC_Auto:
+ case SC_Register:
+ llvm_unreachable("invalid for functions");
+ }
+ if (Func->isConsteval()) // if consteval, it is also constexpr
+ Fragments.append("consteval", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ else if (Func->isConstexpr())
+ Fragments.append("constexpr", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ // FIXME: Is `after` actually needed here?
+ DeclarationFragments After;
+ auto ReturnValueFragment =
+ getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After);
+ if (StringRef(ReturnValueFragment.begin()->Spelling)
+ .starts_with("type-parameter")) {
+ std::string ProperArgName = Func->getReturnType().getAsString();
+ ReturnValueFragment.begin()->Spelling.swap(ProperArgName);
+ }
+
+ Fragments.append(std::move(ReturnValueFragment))
+ .appendSpace()
+ .append(Func->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ if (Func->getTemplateSpecializationInfo()) {
+ Fragments.append("<", DeclarationFragments::FragmentKind::Text);
+
+ for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(
+ getFragmentsForType(Func->getParamDecl(i)->getType(),
+ Func->getParamDecl(i)->getASTContext(), After));
+ }
+ Fragments.append(">", DeclarationFragments::FragmentKind::Text);
+ }
+ Fragments.append(std::move(After));
+
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+ unsigned NumParams = Func->getNumParams();
+ for (unsigned i = 0; i != NumParams; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
+ }
+
+ if (Func->isVariadic()) {
+ if (NumParams > 0)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+ Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+ Func->getExceptionSpecType()));
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant(
+ const EnumConstantDecl *EnumConstDecl) {
+ DeclarationFragments Fragments;
+ return Fragments.append(EnumConstDecl->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {
+ if (const auto *TypedefNameDecl = EnumDecl->getTypedefNameForAnonDecl())
+ return getFragmentsForTypedef(TypedefNameDecl);
+
+ DeclarationFragments Fragments, After;
+ Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword);
+
+ if (!EnumDecl->getName().empty())
+ Fragments.appendSpace().append(
+ EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+ QualType IntegerType = EnumDecl->getIntegerType();
+ if (!IntegerType.isNull())
+ Fragments.appendSpace()
+ .append(": ", DeclarationFragments::FragmentKind::Text)
+ .append(
+ getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After))
+ .append(std::move(After));
+
+ if (EnumDecl->getName().empty())
+ Fragments.appendSpace().append("{ ... }",
+ DeclarationFragments::FragmentKind::Text);
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
+ DeclarationFragments After;
+ DeclarationFragments Fragments;
+ if (Field->isMutable())
+ Fragments.append("mutable", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ return Fragments
+ .append(
+ getFragmentsForType(Field->getType(), Field->getASTContext(), After))
+ .appendSpace()
+ .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After))
+ .appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl(
+ const RecordDecl *Record) {
+ if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
+ return getFragmentsForTypedef(TypedefNameDecl);
+
+ DeclarationFragments Fragments;
+ if (Record->isUnion())
+ Fragments.append("union", DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
+
+ Fragments.appendSpace();
+ if (!Record->getName().empty())
+ Fragments.append(Record->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+ else
+ Fragments.append("{ ... }", DeclarationFragments::FragmentKind::Text);
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass(
+ const CXXRecordDecl *Record) {
+ if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
+ return getFragmentsForTypedef(TypedefNameDecl);
+
+ DeclarationFragments Fragments;
+ Fragments.append(DeclarationFragments::getStructureTypeFragment(Record));
+
+ if (!Record->getName().empty())
+ Fragments.appendSpace().append(
+ Record->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(
+ const CXXMethodDecl *Method) {
+ DeclarationFragments Fragments;
+ std::string Name;
+ if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(Method)) {
+ Name = Method->getNameAsString();
+ if (Constructor->isExplicit())
+ Fragments.append("explicit", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ } else if (isa<CXXDestructorDecl>(Method))
+ Name = Method->getNameAsString();
+
+ DeclarationFragments After;
+ Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After));
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+ for (unsigned i = 0, end = Method->getNumParams(); i != end; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(getFragmentsForParam(Method->getParamDecl(i)));
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+ Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+ Method->getExceptionSpecType()));
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod(
+ const CXXMethodDecl *Method) {
+ DeclarationFragments Fragments;
+ StringRef Name = Method->getName();
+ if (Method->isStatic())
+ Fragments.append("static", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ if (Method->isConstexpr())
+ Fragments.append("constexpr", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ if (Method->isVolatile())
+ Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ // Build return type
+ DeclarationFragments After;
+ Fragments
+ .append(getFragmentsForType(Method->getReturnType(),
+ Method->getASTContext(), After))
+ .appendSpace()
+ .append(Name, DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After));
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+ for (unsigned i = 0, end = Method->getNumParams(); i != end; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(getFragmentsForParam(Method->getParamDecl(i)));
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+ if (Method->isConst())
+ Fragments.appendSpace().append("const",
+ DeclarationFragments::FragmentKind::Keyword);
+
+ Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+ Method->getExceptionSpecType()));
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForConversionFunction(
+ const CXXConversionDecl *ConversionFunction) {
+ DeclarationFragments Fragments;
+
+ if (ConversionFunction->isExplicit())
+ Fragments.append("explicit", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ Fragments.append("operator", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+
+ Fragments
+ .append(ConversionFunction->getConversionType().getAsString(),
+ DeclarationFragments::FragmentKind::TypeIdentifier)
+ .append("(", DeclarationFragments::FragmentKind::Text);
+ for (unsigned i = 0, end = ConversionFunction->getNumParams(); i != end;
+ ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(getFragmentsForParam(ConversionFunction->getParamDecl(i)));
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+ if (ConversionFunction->isConst())
+ Fragments.appendSpace().append("const",
+ DeclarationFragments::FragmentKind::Keyword);
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(
+ const CXXMethodDecl *Method) {
+ DeclarationFragments Fragments;
+
+ // Build return type
+ DeclarationFragments After;
+ Fragments
+ .append(getFragmentsForType(Method->getReturnType(),
+ Method->getASTContext(), After))
+ .appendSpace()
+ .append(Method->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After));
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+ for (unsigned i = 0, end = Method->getNumParams(); i != end; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(getFragmentsForParam(Method->getParamDecl(i)));
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+ if (Method->isConst())
+ Fragments.appendSpace().append("const",
+ DeclarationFragments::FragmentKind::Keyword);
+
+ Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+ Method->getExceptionSpecType()));
+
+ return Fragments.appendSemicolon();
+}
+
+// Get fragments for template parameters, e.g. T in tempalte<typename T> ...
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
+ ArrayRef<NamedDecl *> ParameterArray) {
+ DeclarationFragments Fragments;
+ for (unsigned i = 0, end = ParameterArray.size(); i != end; ++i) {
+ if (i)
+ Fragments.append(",", DeclarationFragments::FragmentKind::Text)
+ .appendSpace();
+
+ if (const auto *TemplateParam =
+ dyn_cast<TemplateTypeParmDecl>(ParameterArray[i])) {
+ if (TemplateParam->hasTypeConstraint())
+ Fragments.append(TemplateParam->getTypeConstraint()
+ ->getNamedConcept()
+ ->getName()
+ .str(),
+ DeclarationFragments::FragmentKind::TypeIdentifier);
+ else if (TemplateParam->wasDeclaredWithTypename())
+ Fragments.append("typename",
+ DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
+
+ if (TemplateParam->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!TemplateParam->getName().empty())
+ Fragments.appendSpace().append(
+ TemplateParam->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+
+ if (TemplateParam->hasDefaultArgument()) {
+ const auto Default = TemplateParam->getDefaultArgument();
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ {Default.getArgument()}, TemplateParam->getASTContext(),
+ {Default}));
+ }
+ } else if (const auto *NTP =
+ dyn_cast<NonTypeTemplateParmDecl>(ParameterArray[i])) {
+ DeclarationFragments After;
+ const auto TyFragments =
+ getFragmentsForType(NTP->getType(), NTP->getASTContext(), After);
+ Fragments.append(std::move(TyFragments)).append(std::move(After));
+
+ if (NTP->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!NTP->getName().empty())
+ Fragments.appendSpace().append(
+ NTP->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+
+ if (NTP->hasDefaultArgument()) {
+ SmallString<8> ExprStr;
+ raw_svector_ostream Output(ExprStr);
+ NTP->getDefaultArgument().getArgument().print(
+ NTP->getASTContext().getPrintingPolicy(), Output,
+ /*IncludeType=*/false);
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(ExprStr, DeclarationFragments::FragmentKind::Text);
+ }
+ } else if (const auto *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(ParameterArray[i])) {
+ Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateParameters(
+ TTP->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(TTP->wasDeclaredWithTypename() ? "typename" : "class",
+ DeclarationFragments::FragmentKind::Keyword);
+
+ if (TTP->isParameterPack())
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+ if (!TTP->getName().empty())
+ Fragments.appendSpace().append(
+ TTP->getName(),
+ DeclarationFragments::FragmentKind::GenericParameter);
+ if (TTP->hasDefaultArgument()) {
+ const auto Default = TTP->getDefaultArgument();
+ Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ {Default.getArgument()}, TTP->getASTContext(), {Default}));
+ }
+ }
+ }
+ return Fragments;
+}
+
+// Get fragments for template arguments, e.g. int in template<typename T>
+// Foo<int>;
+//
+// Note: TemplateParameters is only necessary if the Decl is a
+// PartialSpecialization, where we need the parameters to deduce the name of the
+// generic arguments.
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForTemplateArguments(
+ const ArrayRef<TemplateArgument> TemplateArguments, ASTContext &Context,
+ const std::optional<ArrayRef<TemplateArgumentLoc>> TemplateArgumentLocs) {
+ DeclarationFragments Fragments;
+ for (unsigned i = 0, end = TemplateArguments.size(); i != end; ++i) {
+ if (i)
+ Fragments.append(",", DeclarationFragments::FragmentKind::Text)
+ .appendSpace();
+
+ const auto &CTA = TemplateArguments[i];
+ switch (CTA.getKind()) {
+ case TemplateArgument::Type: {
+ DeclarationFragments After;
+ DeclarationFragments ArgumentFragment =
+ getFragmentsForType(CTA.getAsType(), Context, After);
+
+ if (StringRef(ArgumentFragment.begin()->Spelling)
+ .starts_with("type-parameter")) {
+ if (TemplateArgumentLocs.has_value() &&
+ TemplateArgumentLocs->size() > i) {
+ std::string ProperArgName = TemplateArgumentLocs.value()[i]
+ .getTypeSourceInfo()
+ ->getType()
+ .getAsString();
+ ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+ } else {
+ auto &Spelling = ArgumentFragment.begin()->Spelling;
+ Spelling.clear();
+ raw_string_ostream OutStream(Spelling);
+ CTA.print(Context.getPrintingPolicy(), OutStream, false);
+ OutStream.flush();
+ }
+ }
+
+ Fragments.append(std::move(ArgumentFragment));
+ break;
+ }
+ case TemplateArgument::Declaration: {
+ const auto *VD = CTA.getAsDecl();
+ SmallString<128> USR;
+ index::generateUSRForDecl(VD, USR);
+ Fragments.append(VD->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier, USR);
+ break;
+ }
+ case TemplateArgument::NullPtr:
+ Fragments.append("nullptr", DeclarationFragments::FragmentKind::Keyword);
+ break;
+
+ case TemplateArgument::Integral: {
+ SmallString<4> Str;
+ CTA.getAsIntegral().toString(Str);
+ Fragments.append(Str, DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::StructuralValue: {
+ const auto SVTy = CTA.getStructuralValueType();
+ Fragments.append(CTA.getAsStructuralValue().getAsString(Context, SVTy),
+ DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Template: {
+ std::string Str;
+ raw_string_ostream Stream(Str);
+ CTA.getAsTemplate().print(Stream, Context.getPrintingPolicy());
+ SmallString<64> USR("");
+ if (const auto *TemplDecl =
+ CTA.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ index::generateUSRForDecl(TemplDecl, USR);
+ Fragments.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR);
+ if (CTA.getKind() == TemplateArgument::TemplateExpansion)
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ Fragments.append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(CTA.pack_elements(), Context,
+ {}))
+ .append(">", DeclarationFragments::FragmentKind::Text);
+ break;
+
+ case TemplateArgument::Expression: {
+ SmallString<8> ExprStr;
+ raw_svector_ostream Output(ExprStr);
+ CTA.getAsExpr()->printPretty(Output, nullptr,
+ Context.getPrintingPolicy());
+ Fragments.append(ExprStr, DeclarationFragments::FragmentKind::Text);
+ break;
+ }
+
+ case TemplateArgument::Null:
+ break;
+ }
+ }
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept(
+ const ConceptDecl *Concept) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateParameters(
+ Concept->getTemplateParameters()->asArray()))
+ .append("> ", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append("concept", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(Concept->getName().str(),
+ DeclarationFragments::FragmentKind::Identifier)
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
+ const RedeclarableTemplateDecl *RedeclarableTemplate) {
+ DeclarationFragments Fragments;
+ Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateParameters(
+ RedeclarableTemplate->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace();
+
+ if (isa<TypeAliasTemplateDecl>(RedeclarableTemplate))
+ Fragments.appendSpace()
+ .append("using", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(RedeclarableTemplate->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+ // the templated records will be resposbible for injecting their templates
+ return Fragments.appendSpace();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
+ const ClassTemplateSpecializationDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForCXXClass(
+ cast<CXXRecordDecl>(Decl)))
+ .pop_back() // there is an extra semicolon now
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ Decl->getTemplateArgs().asArray(), Decl->getASTContext(),
+ Decl->getTemplateArgsAsWritten()->arguments()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization(
+ const ClassTemplatePartialSpecializationDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateParameters(
+ Decl->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForCXXClass(
+ cast<CXXRecordDecl>(Decl)))
+ .pop_back() // there is an extra semicolon now
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ Decl->getTemplateArgs().asArray(), Decl->getASTContext(),
+ Decl->getTemplateArgsAsWritten()->arguments()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization(
+ const VarTemplateSpecializationDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(Decl))
+ .pop_back() // there is an extra semicolon now
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ Decl->getTemplateArgs().asArray(), Decl->getASTContext(),
+ Decl->getTemplateArgsAsWritten()->arguments()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization(
+ const VarTemplatePartialSpecializationDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ // Partial specs may have new params.
+ .append(getFragmentsForTemplateParameters(
+ Decl->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(Decl))
+ .pop_back() // there is an extra semicolon now
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForTemplateArguments(
+ Decl->getTemplateArgs().asArray(), Decl->getASTContext(),
+ Decl->getTemplateArgsAsWritten()->arguments()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSemicolon();
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
+ const FunctionTemplateDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<", DeclarationFragments::FragmentKind::Text)
+ // Partial specs may have new params.
+ .append(getFragmentsForTemplateParameters(
+ Decl->getTemplateParameters()->asArray()))
+ .append(">", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForFunction(
+ Decl->getAsFunction()));
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(
+ const FunctionDecl *Decl) {
+ DeclarationFragments Fragments;
+ return Fragments
+ .append("template", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append("<>", DeclarationFragments::FragmentKind::Text)
+ .appendSpace()
+ .append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl));
+}
+
+DeclarationFragments
+DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
+ const MacroDirective *MD) {
+ DeclarationFragments Fragments;
+ Fragments.append("#define", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace();
+ Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier);
+
+ auto *MI = MD->getMacroInfo();
+
+ if (MI->isFunctionLike()) {
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+ unsigned numParameters = MI->getNumParams();
+ if (MI->isC99Varargs())
+ --numParameters;
+ for (unsigned i = 0; i < numParameters; ++i) {
+ if (i)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append(MI->params()[i]->getName(),
+ DeclarationFragments::FragmentKind::InternalParam);
+ }
+ if (MI->isVariadic()) {
+ if (numParameters && MI->isC99Varargs())
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+ }
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+ }
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory(
+ const ObjCCategoryDecl *Category) {
+ DeclarationFragments Fragments;
+
+ auto *Interface = Category->getClassInterface();
+ SmallString<128> InterfaceUSR;
+ index::generateUSRForDecl(Interface, InterfaceUSR);
+
+ Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(Interface->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR,
+ Interface)
+ .append(" (", DeclarationFragments::FragmentKind::Text)
+ .append(Category->getName(),
+ DeclarationFragments::FragmentKind::Identifier)
+ .append(")", DeclarationFragments::FragmentKind::Text);
+
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
+ const ObjCInterfaceDecl *Interface) {
+ DeclarationFragments Fragments;
+ // Build the base of the Objective-C interface declaration.
+ Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(Interface->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ // Build the inheritance part of the declaration.
+ if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) {
+ SmallString<128> SuperUSR;
+ index::generateUSRForDecl(SuperClass, SuperUSR);
+ Fragments.append(" : ", DeclarationFragments::FragmentKind::Text)
+ .append(SuperClass->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR,
+ SuperClass);
+ }
+
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod(
+ const ObjCMethodDecl *Method) {
+ DeclarationFragments Fragments, After;
+ // Build the instance/class method indicator.
+ if (Method->isClassMethod())
+ Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
+ else if (Method->isInstanceMethod())
+ Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
+
+ // Build the return type.
+ Fragments.append("(", DeclarationFragments::FragmentKind::Text)
+ .append(getFragmentsForType(Method->getReturnType(),
+ Method->getASTContext(), After))
+ .append(std::move(After))
+ .append(")", DeclarationFragments::FragmentKind::Text);
+
+ // Build the selector part.
+ Selector Selector = Method->getSelector();
+ if (Selector.getNumArgs() == 0)
+ // For Objective-C methods that don't take arguments, the first (and only)
+ // slot of the selector is the method name.
+ Fragments.appendSpace().append(
+ Selector.getNameForSlot(0),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ // For Objective-C methods that take arguments, build the selector slots.
+ for (unsigned i = 0, end = Method->param_size(); i != end; ++i) {
+ // Objective-C method selector parts are considered as identifiers instead
+ // of "external parameters" as in Swift. This is because Objective-C method
+ // symbols are referenced with the entire selector, instead of just the
+ // method name in Swift.
+ SmallString<32> ParamID(Selector.getNameForSlot(i));
+ ParamID.append(":");
+ Fragments.appendSpace().append(
+ ParamID, DeclarationFragments::FragmentKind::Identifier);
+
+ // Build the internal parameter.
+ const ParmVarDecl *Param = Method->getParamDecl(i);
+ Fragments.append(getFragmentsForParam(Param));
+ }
+
+ return Fragments.appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
+ const ObjCPropertyDecl *Property) {
+ DeclarationFragments Fragments, After;
+
+ // Build the Objective-C property keyword.
+ Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword);
+
+ const auto Attributes = Property->getPropertyAttributesAsWritten();
+ // Build the attributes if there is any associated with the property.
+ if (Attributes != ObjCPropertyAttribute::kind_noattr) {
+ // No leading comma for the first attribute.
+ bool First = true;
+ Fragments.append(" (", DeclarationFragments::FragmentKind::Text);
+ // Helper function to render the attribute.
+ auto RenderAttribute =
+ [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling,
+ StringRef Arg = "",
+ DeclarationFragments::FragmentKind ArgKind =
+ DeclarationFragments::FragmentKind::Identifier) {
+ // Check if the `Kind` attribute is set for this property.
+ if ((Attributes & Kind) && !Spelling.empty()) {
+ // Add a leading comma if this is not the first attribute rendered.
+ if (!First)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ // Render the spelling of this attribute `Kind` as a keyword.
+ Fragments.append(Spelling,
+ DeclarationFragments::FragmentKind::Keyword);
+ // If this attribute takes in arguments (e.g. `getter=getterName`),
+ // render the arguments.
+ if (!Arg.empty())
+ Fragments.append("=", DeclarationFragments::FragmentKind::Text)
+ .append(Arg, ArgKind);
+ First = false;
+ }
+ };
+
+ // Go through all possible Objective-C property attributes and render set
+ // ones.
+ RenderAttribute(ObjCPropertyAttribute::kind_class, "class");
+ RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct");
+ RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic");
+ RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic");
+ RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign");
+ RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain");
+ RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong");
+ RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy");
+ RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak");
+ RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained,
+ "unsafe_unretained");
+ RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite");
+ RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly");
+ RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter",
+ Property->getGetterName().getAsString());
+ RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter",
+ Property->getSetterName().getAsString());
+
+ // Render nullability attributes.
+ if (Attributes & ObjCPropertyAttribute::kind_nullability) {
+ QualType Type = Property->getType();
+ if (const auto Nullability =
+ AttributedType::stripOuterNullability(Type)) {
+ if (!First)
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+ if (*Nullability == NullabilityKind::Unspecified &&
+ (Attributes & ObjCPropertyAttribute::kind_null_resettable))
+ Fragments.append("null_resettable",
+ DeclarationFragments::FragmentKind::Keyword);
+ else
+ Fragments.append(
+ getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true),
+ DeclarationFragments::FragmentKind::Keyword);
+ First = false;
+ }
+ }
+
+ Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+ }
+
+ Fragments.appendSpace();
+
+ FunctionTypeLoc BlockLoc;
+ FunctionProtoTypeLoc BlockProtoLoc;
+ findTypeLocForBlockDecl(Property->getTypeSourceInfo(), BlockLoc,
+ BlockProtoLoc);
+
+ auto PropType = Property->getType();
+ if (!BlockLoc)
+ Fragments
+ .append(getFragmentsForType(PropType, Property->getASTContext(), After))
+ .appendSpace();
+ else
+ Fragments.append(
+ getFragmentsForBlock(Property, BlockLoc, BlockProtoLoc, After));
+
+ return Fragments
+ .append(Property->getName(),
+ DeclarationFragments::FragmentKind::Identifier)
+ .append(std::move(After))
+ .appendSemicolon();
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(
+ const ObjCProtocolDecl *Protocol) {
+ DeclarationFragments Fragments;
+ // Build basic protocol declaration.
+ Fragments.append("@protocol", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(Protocol->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+
+ // If this protocol conforms to other protocols, build the conformance list.
+ if (!Protocol->protocols().empty()) {
+ Fragments.append(" <", DeclarationFragments::FragmentKind::Text);
+ for (ObjCProtocolDecl::protocol_iterator It = Protocol->protocol_begin();
+ It != Protocol->protocol_end(); It++) {
+ // Add a leading comma if this is not the first protocol rendered.
+ if (It != Protocol->protocol_begin())
+ Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+
+ SmallString<128> USR;
+ index::generateUSRForDecl(*It, USR);
+ Fragments.append((*It)->getName(),
+ DeclarationFragments::FragmentKind::TypeIdentifier, USR,
+ *It);
+ }
+ Fragments.append(">", DeclarationFragments::FragmentKind::Text);
+ }
+
+ return Fragments;
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef(
+ const TypedefNameDecl *Decl) {
+ DeclarationFragments Fragments, After;
+ Fragments.append("typedef", DeclarationFragments::FragmentKind::Keyword)
+ .appendSpace()
+ .append(getFragmentsForType(Decl->getUnderlyingType(),
+ Decl->getASTContext(), After))
+ .append(std::move(After))
+ .appendSpace()
+ .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+ return Fragments.appendSemicolon();
+}
+
+// Instantiate template for FunctionDecl.
+template FunctionSignature
+DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *);
+
+// Instantiate template for ObjCMethodDecl.
+template FunctionSignature
+DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *);
+
+// Subheading of a symbol defaults to its name.
+DeclarationFragments
+DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
+ DeclarationFragments Fragments;
+ if (isa<CXXConstructorDecl>(Decl) || isa<CXXDestructorDecl>(Decl))
+ Fragments.append(cast<CXXRecordDecl>(Decl->getDeclContext())->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+ else if (isa<CXXConversionDecl>(Decl)) {
+ Fragments.append(
+ cast<CXXConversionDecl>(Decl)->getConversionType().getAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+ } else if (isa<CXXMethodDecl>(Decl) &&
+ cast<CXXMethodDecl>(Decl)->isOverloadedOperator()) {
+ Fragments.append(Decl->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+ } else if (Decl->getIdentifier()) {
+ Fragments.append(Decl->getName(),
+ DeclarationFragments::FragmentKind::Identifier);
+ } else
+ Fragments.append(Decl->getDeclName().getAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+ return Fragments;
+}
+
+// Subheading of an Objective-C method is a `+` or `-` sign indicating whether
+// it's a class method or an instance method, followed by the selector name.
+DeclarationFragments
+DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) {
+ DeclarationFragments Fragments;
+ if (Method->isClassMethod())
+ Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
+ else if (Method->isInstanceMethod())
+ Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
+
+ return Fragments.append(Method->getNameAsString(),
+ DeclarationFragments::FragmentKind::Identifier);
+}
+
+// Subheading of a symbol defaults to its name.
+DeclarationFragments
+DeclarationFragmentsBuilder::getSubHeadingForMacro(StringRef Name) {
+ DeclarationFragments Fragments;
+ Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier);
+ return Fragments;
+}