diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp | 822 | 
1 files changed, 822 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..1e52f221c798 --- /dev/null +++ b/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -0,0 +1,822 @@ +//===- 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/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include "clang/Index/USRGeneration.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang::extractapi; +using namespace llvm; + +DeclarationFragments &DeclarationFragments::appendSpace() { +  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() != ' ') { // avoid extra trailing spaces. +        Last.Spelling.push_back(' '); +      } +    } else { +      append(" ", FragmentKind::Text); +    } +  } + +  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); +} + +// 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; + +  // Declaration fragments of a pointer type is the declaration fragments of +  // the pointee type followed by a `*`, +  if (T->isPointerType()) +    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 ArrayType::Normal: +      break; +    case ArrayType::Static: +      Fragments.append("static", DeclarationFragments::FragmentKind::Keyword); +      break; +    case ArrayType::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)); +  } + +  // 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 != ETK_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))); +  } + +  // 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; +    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 (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::getFragmentsForVar(const VarDecl *Var) { +  DeclarationFragments Fragments; +  StorageClass SC = Var->getStorageClass(); +  if (SC != SC_None) +    Fragments +        .append(VarDecl::getStorageClassSpecifierString(SC), +                DeclarationFragments::FragmentKind::Keyword) +        .appendSpace(); +  QualType T = +      Var->getTypeSourceInfo() +          ? Var->getTypeSourceInfo()->getType() +          : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); + +  // Capture potential fragments that needs to be placed after the variable name +  // ``` +  // int nums[5]; +  // char (*ptr_to_array)[6]; +  // ``` +  DeclarationFragments After; +  return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) +      .appendSpace() +      .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) +      .append(std::move(After)); +} + +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { +  DeclarationFragments Fragments, After; + +  QualType T = Param->getTypeSourceInfo() +                   ? Param->getTypeSourceInfo()->getType() +                   : Param->getASTContext().getUnqualifiedObjCPointerType( +                         Param->getType()); + +  DeclarationFragments TypeFragments = +      getFragmentsForType(T, Param->getASTContext(), After); + +  if (Param->isObjCMethodParameter()) +    Fragments.append("(", DeclarationFragments::FragmentKind::Text) +        .append(std::move(TypeFragments)) +        .append(") ", DeclarationFragments::FragmentKind::Text); +  else +    Fragments.append(std::move(TypeFragments)).appendSpace(); + +  return Fragments +      .append(Param->getName(), +              DeclarationFragments::FragmentKind::InternalParam) +      .append(std::move(After)); +} + +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { +  DeclarationFragments Fragments; +  // FIXME: Handle template specialization +  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"); +  } +  // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc. + +  // FIXME: Is `after` actually needed here? +  DeclarationFragments After; +  Fragments +      .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(), +                                  After)) +      .appendSpace() +      .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier) +      .append(std::move(After)); + +  Fragments.append("(", DeclarationFragments::FragmentKind::Text); +  for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) { +    if (i) +      Fragments.append(", ", DeclarationFragments::FragmentKind::Text); +    Fragments.append(getFragmentsForParam(Func->getParamDecl(i))); +  } +  Fragments.append(")", DeclarationFragments::FragmentKind::Text); + +  // FIXME: Handle exception specifiers: throw, noexcept +  return Fragments.append(";", DeclarationFragments::FragmentKind::Text); +} + +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.append(": ", DeclarationFragments::FragmentKind::Text) +        .append( +            getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) +        .append(std::move(After)); + +  return Fragments.append(";", DeclarationFragments::FragmentKind::Text); +} + +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { +  DeclarationFragments After; +  return getFragmentsForType(Field->getType(), Field->getASTContext(), After) +      .appendSpace() +      .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) +      .append(std::move(After)); +} + +DeclarationFragments +DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) { +  if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl()) +    return getFragmentsForTypedef(TypedefNameDecl); + +  DeclarationFragments Fragments; +  Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword); + +  if (!Record->getName().empty()) +    Fragments.appendSpace().append( +        Record->getName(), DeclarationFragments::FragmentKind::Identifier); + +  return Fragments.append(";", DeclarationFragments::FragmentKind::Text); +} + +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(Category->getClassInterface()->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.append(";", DeclarationFragments::FragmentKind::Text); +} + +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); +  } + +  // Build the property type and name, and return the completed fragments. +  return Fragments.appendSpace() +      .append(getFragmentsForType(Property->getType(), +                                  Property->getASTContext(), After)) +      .appendSpace() +      .append(Property->getName(), +              DeclarationFragments::FragmentKind::Identifier) +      .append(std::move(After)); +} + +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.append(";", DeclarationFragments::FragmentKind::Text); +} + +template <typename FunctionT> +FunctionSignature +DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { +  FunctionSignature Signature; + +  DeclarationFragments ReturnType, After; +  ReturnType +      .append(getFragmentsForType(Function->getReturnType(), +                                  Function->getASTContext(), After)) +      .append(std::move(After)); +  Signature.setReturnType(ReturnType); + +  for (const auto *Param : Function->parameters()) +    Signature.addParameter(Param->getName(), getFragmentsForParam(Param)); + +  return Signature; +} + +// 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 (!Decl->getName().empty()) +    Fragments.append(Decl->getName(), +                     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; +}  | 
