123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805 |
- //===- 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 "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 `*`, except for Objective-C `id` and `Class`
- // pointers, where we do not spell out the `*`.
- if (T->isPointerType() ||
- (T->isObjCObjectPointerType() &&
- !T->getAs<ObjCObjectPointerType>()->isObjCIdOrClassType())) {
- return Fragments
- .append(getFragmentsForType(T->getPointeeType(), Context, After))
- .append(" *", DeclarationFragments::FragmentKind::Text);
- }
- // 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));
- }
- // Everything we care about has been handled now, reduce to the canonical
- // unqualified base type.
- QualType Base = T->getCanonicalTypeUnqualified();
- // Render Objective-C `id`/`instancetype` as keywords.
- if (T->isObjCIdType())
- return Fragments.append(Base.getAsString(),
- DeclarationFragments::FragmentKind::Keyword);
- // If the type is a typedefed type, get the underlying TypedefNameDecl for a
- // direct reference to the typedef instead of the wrapped type.
- if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
- const TypedefNameDecl *Decl = TypedefTy->getDecl();
- TypedefUnderlyingTypeResolver TypedefResolver(Context);
- std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
- return Fragments.append(
- Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
- USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
- }
- // 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;
- }
- 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;
- }
- 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;
- }
- 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->getPropertyAttributes();
- // 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;
- }
- 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;
- }
|