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