1 //===- ExtractAPI/DeclarationFragments.cpp ----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements Declaration Fragments related classes. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/ExtractAPI/DeclarationFragments.h" 15 #include "clang/Index/USRGeneration.h" 16 #include "llvm/ADT/StringSwitch.h" 17 18 using namespace clang::extractapi; 19 using namespace llvm; 20 21 DeclarationFragments &DeclarationFragments::appendSpace() { 22 if (!Fragments.empty()) { 23 Fragment Last = Fragments.back(); 24 if (Last.Kind == FragmentKind::Text) { 25 // Merge the extra space into the last fragment if the last fragment is 26 // also text. 27 if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. 28 Last.Spelling.push_back(' '); 29 } 30 } else { 31 append(" ", FragmentKind::Text); 32 } 33 } 34 35 return *this; 36 } 37 38 StringRef DeclarationFragments::getFragmentKindString( 39 DeclarationFragments::FragmentKind Kind) { 40 switch (Kind) { 41 case DeclarationFragments::FragmentKind::None: 42 return "none"; 43 case DeclarationFragments::FragmentKind::Keyword: 44 return "keyword"; 45 case DeclarationFragments::FragmentKind::Attribute: 46 return "attribute"; 47 case DeclarationFragments::FragmentKind::NumberLiteral: 48 return "number"; 49 case DeclarationFragments::FragmentKind::StringLiteral: 50 return "string"; 51 case DeclarationFragments::FragmentKind::Identifier: 52 return "identifier"; 53 case DeclarationFragments::FragmentKind::TypeIdentifier: 54 return "typeIdentifier"; 55 case DeclarationFragments::FragmentKind::GenericParameter: 56 return "genericParameter"; 57 case DeclarationFragments::FragmentKind::ExternalParam: 58 return "externalParam"; 59 case DeclarationFragments::FragmentKind::InternalParam: 60 return "internalParam"; 61 case DeclarationFragments::FragmentKind::Text: 62 return "text"; 63 } 64 65 llvm_unreachable("Unhandled FragmentKind"); 66 } 67 68 DeclarationFragments::FragmentKind 69 DeclarationFragments::parseFragmentKindFromString(StringRef S) { 70 return llvm::StringSwitch<FragmentKind>(S) 71 .Case("keyword", DeclarationFragments::FragmentKind::Keyword) 72 .Case("attribute", DeclarationFragments::FragmentKind::Attribute) 73 .Case("number", DeclarationFragments::FragmentKind::NumberLiteral) 74 .Case("string", DeclarationFragments::FragmentKind::StringLiteral) 75 .Case("identifier", DeclarationFragments::FragmentKind::Identifier) 76 .Case("typeIdentifier", 77 DeclarationFragments::FragmentKind::TypeIdentifier) 78 .Case("genericParameter", 79 DeclarationFragments::FragmentKind::GenericParameter) 80 .Case("internalParam", DeclarationFragments::FragmentKind::InternalParam) 81 .Case("externalParam", DeclarationFragments::FragmentKind::ExternalParam) 82 .Case("text", DeclarationFragments::FragmentKind::Text) 83 .Default(DeclarationFragments::FragmentKind::None); 84 } 85 86 // NNS stores C++ nested name specifiers, which are prefixes to qualified names. 87 // Build declaration fragments for NNS recursively so that we have the USR for 88 // every part in a qualified name, and also leaves the actual underlying type 89 // cleaner for its own fragment. 90 DeclarationFragments 91 DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS, 92 ASTContext &Context, 93 DeclarationFragments &After) { 94 DeclarationFragments Fragments; 95 if (NNS->getPrefix()) 96 Fragments.append(getFragmentsForNNS(NNS->getPrefix(), Context, After)); 97 98 switch (NNS->getKind()) { 99 case NestedNameSpecifier::Identifier: 100 Fragments.append(NNS->getAsIdentifier()->getName(), 101 DeclarationFragments::FragmentKind::Identifier); 102 break; 103 104 case NestedNameSpecifier::Namespace: { 105 const NamespaceDecl *NS = NNS->getAsNamespace(); 106 if (NS->isAnonymousNamespace()) 107 return Fragments; 108 SmallString<128> USR; 109 index::generateUSRForDecl(NS, USR); 110 Fragments.append(NS->getName(), 111 DeclarationFragments::FragmentKind::Identifier, USR); 112 break; 113 } 114 115 case NestedNameSpecifier::NamespaceAlias: { 116 const NamespaceAliasDecl *Alias = NNS->getAsNamespaceAlias(); 117 SmallString<128> USR; 118 index::generateUSRForDecl(Alias, USR); 119 Fragments.append(Alias->getName(), 120 DeclarationFragments::FragmentKind::Identifier, USR); 121 break; 122 } 123 124 case NestedNameSpecifier::Global: 125 // The global specifier `::` at the beginning. No stored value. 126 break; 127 128 case NestedNameSpecifier::Super: 129 // Microsoft's `__super` specifier. 130 Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword); 131 break; 132 133 case NestedNameSpecifier::TypeSpecWithTemplate: 134 // A type prefixed by the `template` keyword. 135 Fragments.append("template", DeclarationFragments::FragmentKind::Keyword); 136 Fragments.appendSpace(); 137 // Fallthrough after adding the keyword to handle the actual type. 138 LLVM_FALLTHROUGH; 139 140 case NestedNameSpecifier::TypeSpec: { 141 const Type *T = NNS->getAsType(); 142 // FIXME: Handle C++ template specialization type 143 Fragments.append(getFragmentsForType(T, Context, After)); 144 break; 145 } 146 } 147 148 // Add the separator text `::` for this segment. 149 return Fragments.append("::", DeclarationFragments::FragmentKind::Text); 150 } 151 152 // Recursively build the declaration fragments for an underlying `Type` with 153 // qualifiers removed. 154 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( 155 const Type *T, ASTContext &Context, DeclarationFragments &After) { 156 assert(T && "invalid type"); 157 158 DeclarationFragments Fragments; 159 160 // Declaration fragments of a pointer type is the declaration fragments of 161 // the pointee type followed by a `*`, except for Objective-C `id` and `Class` 162 // pointers, where we do not spell out the `*`. 163 if (T->isPointerType() || 164 (T->isObjCObjectPointerType() && 165 !T->getAs<ObjCObjectPointerType>()->isObjCIdOrClassType())) { 166 return Fragments 167 .append(getFragmentsForType(T->getPointeeType(), Context, After)) 168 .append(" *", DeclarationFragments::FragmentKind::Text); 169 } 170 171 // Declaration fragments of a lvalue reference type is the declaration 172 // fragments of the underlying type followed by a `&`. 173 if (const LValueReferenceType *LRT = dyn_cast<LValueReferenceType>(T)) 174 return Fragments 175 .append( 176 getFragmentsForType(LRT->getPointeeTypeAsWritten(), Context, After)) 177 .append(" &", DeclarationFragments::FragmentKind::Text); 178 179 // Declaration fragments of a rvalue reference type is the declaration 180 // fragments of the underlying type followed by a `&&`. 181 if (const RValueReferenceType *RRT = dyn_cast<RValueReferenceType>(T)) 182 return Fragments 183 .append( 184 getFragmentsForType(RRT->getPointeeTypeAsWritten(), Context, After)) 185 .append(" &&", DeclarationFragments::FragmentKind::Text); 186 187 // Declaration fragments of an array-typed variable have two parts: 188 // 1. the element type of the array that appears before the variable name; 189 // 2. array brackets `[(0-9)?]` that appear after the variable name. 190 if (const ArrayType *AT = T->getAsArrayTypeUnsafe()) { 191 // Build the "after" part first because the inner element type might also 192 // be an array-type. For example `int matrix[3][4]` which has a type of 193 // "(array 3 of (array 4 of ints))." 194 // Push the array size part first to make sure they are in the right order. 195 After.append("[", DeclarationFragments::FragmentKind::Text); 196 197 switch (AT->getSizeModifier()) { 198 case ArrayType::Normal: 199 break; 200 case ArrayType::Static: 201 Fragments.append("static", DeclarationFragments::FragmentKind::Keyword); 202 break; 203 case ArrayType::Star: 204 Fragments.append("*", DeclarationFragments::FragmentKind::Text); 205 break; 206 } 207 208 if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { 209 // FIXME: right now this would evaluate any expressions/macros written in 210 // the original source to concrete values. For example 211 // `int nums[MAX]` -> `int nums[100]` 212 // `char *str[5 + 1]` -> `char *str[6]` 213 SmallString<128> Size; 214 CAT->getSize().toStringUnsigned(Size); 215 After.append(Size, DeclarationFragments::FragmentKind::NumberLiteral); 216 } 217 218 After.append("]", DeclarationFragments::FragmentKind::Text); 219 220 return Fragments.append( 221 getFragmentsForType(AT->getElementType(), Context, After)); 222 } 223 224 // An ElaboratedType is a sugar for types that are referred to using an 225 // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a 226 // qualified name, e.g., `N::M::type`, or both. 227 if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) { 228 ElaboratedTypeKeyword Keyword = ET->getKeyword(); 229 if (Keyword != ETK_None) { 230 Fragments 231 .append(ElaboratedType::getKeywordName(Keyword), 232 DeclarationFragments::FragmentKind::Keyword) 233 .appendSpace(); 234 } 235 236 if (const NestedNameSpecifier *NNS = ET->getQualifier()) 237 Fragments.append(getFragmentsForNNS(NNS, Context, After)); 238 239 // After handling the elaborated keyword or qualified name, build 240 // declaration fragments for the desugared underlying type. 241 return Fragments.append(getFragmentsForType(ET->desugar(), Context, After)); 242 } 243 244 // Everything we care about has been handled now, reduce to the canonical 245 // unqualified base type. 246 QualType Base = T->getCanonicalTypeUnqualified(); 247 248 // Render Objective-C `id`/`instancetype` as keywords. 249 if (T->isObjCIdType()) 250 return Fragments.append(Base.getAsString(), 251 DeclarationFragments::FragmentKind::Keyword); 252 253 // If the base type is an ObjCInterfaceType, use the underlying 254 // ObjCInterfaceDecl for the true USR. 255 if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) { 256 const auto *Decl = ObjCIT->getDecl(); 257 SmallString<128> USR; 258 index::generateUSRForDecl(Decl, USR); 259 return Fragments.append(Decl->getName(), 260 DeclarationFragments::FragmentKind::TypeIdentifier, 261 USR); 262 } 263 264 // Default fragment builder for other kinds of types (BuiltinType etc.) 265 SmallString<128> USR; 266 clang::index::generateUSRForType(Base, Context, USR); 267 Fragments.append(Base.getAsString(), 268 DeclarationFragments::FragmentKind::TypeIdentifier, USR); 269 270 return Fragments; 271 } 272 273 DeclarationFragments 274 DeclarationFragmentsBuilder::getFragmentsForQualifiers(const Qualifiers Quals) { 275 DeclarationFragments Fragments; 276 if (Quals.hasConst()) 277 Fragments.append("const", DeclarationFragments::FragmentKind::Keyword); 278 if (Quals.hasVolatile()) 279 Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword); 280 if (Quals.hasRestrict()) 281 Fragments.append("restrict", DeclarationFragments::FragmentKind::Keyword); 282 283 return Fragments; 284 } 285 286 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( 287 const QualType QT, ASTContext &Context, DeclarationFragments &After) { 288 assert(!QT.isNull() && "invalid type"); 289 290 if (const ParenType *PT = dyn_cast<ParenType>(QT)) { 291 After.append(")", DeclarationFragments::FragmentKind::Text); 292 return getFragmentsForType(PT->getInnerType(), Context, After) 293 .append("(", DeclarationFragments::FragmentKind::Text); 294 } 295 296 const SplitQualType SQT = QT.split(); 297 DeclarationFragments QualsFragments = getFragmentsForQualifiers(SQT.Quals), 298 TypeFragments = 299 getFragmentsForType(SQT.Ty, Context, After); 300 if (QualsFragments.getFragments().empty()) 301 return TypeFragments; 302 303 // Use east qualifier for pointer types 304 // For example: 305 // ``` 306 // int * const 307 // ^---- ^---- 308 // type qualifier 309 // ^----------------- 310 // const pointer to int 311 // ``` 312 // should not be reconstructed as 313 // ``` 314 // const int * 315 // ^---- ^-- 316 // qualifier type 317 // ^---------------- ^ 318 // pointer to const int 319 // ``` 320 if (SQT.Ty->isAnyPointerType()) 321 return TypeFragments.appendSpace().append(std::move(QualsFragments)); 322 323 return QualsFragments.appendSpace().append(std::move(TypeFragments)); 324 } 325 326 DeclarationFragments 327 DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { 328 DeclarationFragments Fragments; 329 StorageClass SC = Var->getStorageClass(); 330 if (SC != SC_None) 331 Fragments 332 .append(VarDecl::getStorageClassSpecifierString(SC), 333 DeclarationFragments::FragmentKind::Keyword) 334 .appendSpace(); 335 QualType T = 336 Var->getTypeSourceInfo() 337 ? Var->getTypeSourceInfo()->getType() 338 : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); 339 340 // Capture potential fragments that needs to be placed after the variable name 341 // ``` 342 // int nums[5]; 343 // char (*ptr_to_array)[6]; 344 // ``` 345 DeclarationFragments After; 346 return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) 347 .appendSpace() 348 .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) 349 .append(std::move(After)); 350 } 351 352 DeclarationFragments 353 DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { 354 DeclarationFragments Fragments, After; 355 356 QualType T = Param->getTypeSourceInfo() 357 ? Param->getTypeSourceInfo()->getType() 358 : Param->getASTContext().getUnqualifiedObjCPointerType( 359 Param->getType()); 360 361 DeclarationFragments TypeFragments = 362 getFragmentsForType(T, Param->getASTContext(), After); 363 364 if (Param->isObjCMethodParameter()) 365 Fragments.append("(", DeclarationFragments::FragmentKind::Text) 366 .append(std::move(TypeFragments)) 367 .append(")", DeclarationFragments::FragmentKind::Text); 368 else 369 Fragments.append(std::move(TypeFragments)).appendSpace(); 370 371 return Fragments 372 .append(Param->getName(), 373 DeclarationFragments::FragmentKind::InternalParam) 374 .append(std::move(After)); 375 } 376 377 DeclarationFragments 378 DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { 379 DeclarationFragments Fragments; 380 // FIXME: Handle template specialization 381 switch (Func->getStorageClass()) { 382 case SC_None: 383 case SC_PrivateExtern: 384 break; 385 case SC_Extern: 386 Fragments.append("extern", DeclarationFragments::FragmentKind::Keyword) 387 .appendSpace(); 388 break; 389 case SC_Static: 390 Fragments.append("static", DeclarationFragments::FragmentKind::Keyword) 391 .appendSpace(); 392 break; 393 case SC_Auto: 394 case SC_Register: 395 llvm_unreachable("invalid for functions"); 396 } 397 // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc. 398 399 // FIXME: Is `after` actually needed here? 400 DeclarationFragments After; 401 Fragments 402 .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(), 403 After)) 404 .appendSpace() 405 .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier) 406 .append(std::move(After)); 407 408 Fragments.append("(", DeclarationFragments::FragmentKind::Text); 409 for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) { 410 if (i) 411 Fragments.append(", ", DeclarationFragments::FragmentKind::Text); 412 Fragments.append(getFragmentsForParam(Func->getParamDecl(i))); 413 } 414 Fragments.append(")", DeclarationFragments::FragmentKind::Text); 415 416 // FIXME: Handle exception specifiers: throw, noexcept 417 return Fragments; 418 } 419 420 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( 421 const EnumConstantDecl *EnumConstDecl) { 422 DeclarationFragments Fragments; 423 return Fragments.append(EnumConstDecl->getName(), 424 DeclarationFragments::FragmentKind::Identifier); 425 } 426 427 DeclarationFragments 428 DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { 429 // TODO: After we support typedef records, if there's a typedef for this enum 430 // just use the declaration fragments of the typedef decl. 431 432 DeclarationFragments Fragments, After; 433 Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword); 434 435 if (!EnumDecl->getName().empty()) 436 Fragments.appendSpace().append( 437 EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier); 438 439 QualType IntegerType = EnumDecl->getIntegerType(); 440 if (!IntegerType.isNull()) 441 Fragments.append(": ", DeclarationFragments::FragmentKind::Text) 442 .append( 443 getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) 444 .append(std::move(After)); 445 446 return Fragments; 447 } 448 449 DeclarationFragments 450 DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { 451 DeclarationFragments After; 452 return getFragmentsForType(Field->getType(), Field->getASTContext(), After) 453 .appendSpace() 454 .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) 455 .append(std::move(After)); 456 } 457 458 DeclarationFragments 459 DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) { 460 // TODO: After we support typedef records, if there's a typedef for this 461 // struct just use the declaration fragments of the typedef decl. 462 463 DeclarationFragments Fragments; 464 Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword); 465 466 if (!Record->getName().empty()) 467 Fragments.appendSpace().append( 468 Record->getName(), DeclarationFragments::FragmentKind::Identifier); 469 470 return Fragments; 471 } 472 473 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface( 474 const ObjCInterfaceDecl *Interface) { 475 DeclarationFragments Fragments; 476 // Build the base of the Objective-C interface declaration. 477 Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) 478 .appendSpace() 479 .append(Interface->getName(), 480 DeclarationFragments::FragmentKind::Identifier); 481 482 // Build the inheritance part of the declaration. 483 if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) { 484 SmallString<128> SuperUSR; 485 index::generateUSRForDecl(SuperClass, SuperUSR); 486 Fragments.append(" : ", DeclarationFragments::FragmentKind::Text) 487 .append(SuperClass->getName(), 488 DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR); 489 } 490 491 return Fragments; 492 } 493 494 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( 495 const ObjCMethodDecl *Method) { 496 DeclarationFragments Fragments, After; 497 // Build the instance/class method indicator. 498 if (Method->isClassMethod()) 499 Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); 500 else if (Method->isInstanceMethod()) 501 Fragments.append("- ", DeclarationFragments::FragmentKind::Text); 502 503 // Build the return type. 504 Fragments.append("(", DeclarationFragments::FragmentKind::Text) 505 .append(getFragmentsForType(Method->getReturnType(), 506 Method->getASTContext(), After)) 507 .append(std::move(After)) 508 .append(")", DeclarationFragments::FragmentKind::Text); 509 510 // Build the selector part. 511 Selector Selector = Method->getSelector(); 512 if (Selector.getNumArgs() == 0) 513 // For Objective-C methods that don't take arguments, the first (and only) 514 // slot of the selector is the method name. 515 Fragments.appendSpace().append( 516 Selector.getNameForSlot(0), 517 DeclarationFragments::FragmentKind::Identifier); 518 519 // For Objective-C methods that take arguments, build the selector slots. 520 for (unsigned i = 0, end = Method->param_size(); i != end; ++i) { 521 Fragments.appendSpace() 522 .append(Selector.getNameForSlot(i), 523 // The first slot is the name of the method, record as an 524 // identifier, otherwise as exteranl parameters. 525 i == 0 ? DeclarationFragments::FragmentKind::Identifier 526 : DeclarationFragments::FragmentKind::ExternalParam) 527 .append(":", DeclarationFragments::FragmentKind::Text); 528 529 // Build the internal parameter. 530 const ParmVarDecl *Param = Method->getParamDecl(i); 531 Fragments.append(getFragmentsForParam(Param)); 532 } 533 534 return Fragments; 535 } 536 537 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( 538 const ObjCPropertyDecl *Property) { 539 DeclarationFragments Fragments, After; 540 541 // Build the Objective-C property keyword. 542 Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword); 543 544 const auto Attributes = Property->getPropertyAttributes(); 545 // Build the attributes if there is any associated with the property. 546 if (Attributes != ObjCPropertyAttribute::kind_noattr) { 547 // No leading comma for the first attribute. 548 bool First = true; 549 Fragments.append(" (", DeclarationFragments::FragmentKind::Text); 550 // Helper function to render the attribute. 551 auto RenderAttribute = 552 [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling, 553 StringRef Arg = "", 554 DeclarationFragments::FragmentKind ArgKind = 555 DeclarationFragments::FragmentKind::Identifier) { 556 // Check if the `Kind` attribute is set for this property. 557 if ((Attributes & Kind) && !Spelling.empty()) { 558 // Add a leading comma if this is not the first attribute rendered. 559 if (!First) 560 Fragments.append(", ", DeclarationFragments::FragmentKind::Text); 561 // Render the spelling of this attribute `Kind` as a keyword. 562 Fragments.append(Spelling, 563 DeclarationFragments::FragmentKind::Keyword); 564 // If this attribute takes in arguments (e.g. `getter=getterName`), 565 // render the arguments. 566 if (!Arg.empty()) 567 Fragments.append("=", DeclarationFragments::FragmentKind::Text) 568 .append(Arg, ArgKind); 569 First = false; 570 } 571 }; 572 573 // Go through all possible Objective-C property attributes and render set 574 // ones. 575 RenderAttribute(ObjCPropertyAttribute::kind_class, "class"); 576 RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct"); 577 RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic"); 578 RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic"); 579 RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign"); 580 RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain"); 581 RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong"); 582 RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy"); 583 RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak"); 584 RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained, 585 "unsafe_unretained"); 586 RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite"); 587 RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly"); 588 RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter", 589 Property->getGetterName().getAsString()); 590 RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter", 591 Property->getSetterName().getAsString()); 592 593 // Render nullability attributes. 594 if (Attributes & ObjCPropertyAttribute::kind_nullability) { 595 QualType Type = Property->getType(); 596 if (const auto Nullability = 597 AttributedType::stripOuterNullability(Type)) { 598 if (!First) 599 Fragments.append(", ", DeclarationFragments::FragmentKind::Text); 600 if (*Nullability == NullabilityKind::Unspecified && 601 (Attributes & ObjCPropertyAttribute::kind_null_resettable)) 602 Fragments.append("null_resettable", 603 DeclarationFragments::FragmentKind::Keyword); 604 else 605 Fragments.append( 606 getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true), 607 DeclarationFragments::FragmentKind::Keyword); 608 First = false; 609 } 610 } 611 612 Fragments.append(")", DeclarationFragments::FragmentKind::Text); 613 } 614 615 // Build the property type and name, and return the completed fragments. 616 return Fragments.appendSpace() 617 .append(getFragmentsForType(Property->getType(), 618 Property->getASTContext(), After)) 619 .append(Property->getName(), 620 DeclarationFragments::FragmentKind::Identifier) 621 .append(std::move(After)); 622 } 623 624 DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( 625 const ObjCProtocolDecl *Protocol) { 626 DeclarationFragments Fragments; 627 // Build basic protocol declaration. 628 Fragments.append("@protocol", DeclarationFragments::FragmentKind::Keyword) 629 .appendSpace() 630 .append(Protocol->getName(), 631 DeclarationFragments::FragmentKind::Identifier); 632 633 // If this protocol conforms to other protocols, build the conformance list. 634 if (!Protocol->protocols().empty()) { 635 Fragments.append(" <", DeclarationFragments::FragmentKind::Text); 636 for (ObjCProtocolDecl::protocol_iterator It = Protocol->protocol_begin(); 637 It != Protocol->protocol_end(); It++) { 638 // Add a leading comma if this is not the first protocol rendered. 639 if (It != Protocol->protocol_begin()) 640 Fragments.append(", ", DeclarationFragments::FragmentKind::Text); 641 642 SmallString<128> USR; 643 index::generateUSRForDecl(*It, USR); 644 Fragments.append((*It)->getName(), 645 DeclarationFragments::FragmentKind::TypeIdentifier, USR); 646 } 647 Fragments.append(">", DeclarationFragments::FragmentKind::Text); 648 } 649 650 return Fragments; 651 } 652 653 template <typename FunctionT> 654 FunctionSignature 655 DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { 656 FunctionSignature Signature; 657 658 DeclarationFragments ReturnType, After; 659 ReturnType 660 .append(getFragmentsForType(Function->getReturnType(), 661 Function->getASTContext(), After)) 662 .append(std::move(After)); 663 Signature.setReturnType(ReturnType); 664 665 for (const auto *Param : Function->parameters()) 666 Signature.addParameter(Param->getName(), getFragmentsForParam(Param)); 667 668 return Signature; 669 } 670 671 // Instantiate template for FunctionDecl. 672 template FunctionSignature 673 DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *); 674 675 // Instantiate template for ObjCMethodDecl. 676 template FunctionSignature 677 DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *); 678 679 // Subheading of a symbol defaults to its name. 680 DeclarationFragments 681 DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) { 682 DeclarationFragments Fragments; 683 if (!Decl->getName().empty()) 684 Fragments.append(Decl->getName(), 685 DeclarationFragments::FragmentKind::Identifier); 686 return Fragments; 687 } 688 689 // Subheading of an Objective-C method is a `+` or `-` sign indicating whether 690 // it's a class method or an instance method, followed by the selector name. 691 DeclarationFragments 692 DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) { 693 DeclarationFragments Fragments; 694 if (Method->isClassMethod()) 695 Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); 696 else if (Method->isInstanceMethod()) 697 Fragments.append("- ", DeclarationFragments::FragmentKind::Text); 698 699 return Fragments.append(Method->getNameAsString(), 700 DeclarationFragments::FragmentKind::Identifier); 701 } 702