1 //===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "clang/Index/IndexSymbol.h" 11 #include "clang/AST/DeclCXX.h" 12 #include "clang/AST/DeclObjC.h" 13 #include "clang/AST/DeclTemplate.h" 14 #include "clang/AST/PrettyPrinter.h" 15 16 using namespace clang; 17 using namespace clang::index; 18 19 /// \returns true if \c D is a subclass of 'XCTestCase'. 20 static bool isUnitTestCase(const ObjCInterfaceDecl *D) { 21 if (!D) 22 return false; 23 while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) { 24 if (SuperD->getName() == "XCTestCase") 25 return true; 26 D = SuperD; 27 } 28 return false; 29 } 30 31 /// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has 32 /// no parameters, and its name starts with 'test'. 33 static bool isUnitTest(const ObjCMethodDecl *D) { 34 if (!D->parameters().empty()) 35 return false; 36 if (!D->getReturnType()->isVoidType()) 37 return false; 38 if (!D->getSelector().getNameForSlot(0).startswith("test")) 39 return false; 40 return isUnitTestCase(D->getClassInterface()); 41 } 42 43 static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) { 44 if (D->hasAttr<IBOutletAttr>()) { 45 PropSet |= (unsigned)SymbolProperty::IBAnnotated; 46 } else if (D->hasAttr<IBOutletCollectionAttr>()) { 47 PropSet |= (unsigned)SymbolProperty::IBAnnotated; 48 PropSet |= (unsigned)SymbolProperty::IBOutletCollection; 49 } 50 } 51 52 bool index::isFunctionLocalSymbol(const Decl *D) { 53 assert(D); 54 55 if (isa<ParmVarDecl>(D)) 56 return true; 57 58 if (isa<TemplateTemplateParmDecl>(D)) 59 return true; 60 61 if (isa<ObjCTypeParamDecl>(D)) 62 return true; 63 64 if (!D->getParentFunctionOrMethod()) 65 return false; 66 67 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { 68 switch (ND->getFormalLinkage()) { 69 case NoLinkage: 70 case VisibleNoLinkage: 71 case InternalLinkage: 72 return true; 73 case UniqueExternalLinkage: 74 llvm_unreachable("Not a sema linkage"); 75 case ExternalLinkage: 76 return false; 77 } 78 } 79 80 return true; 81 } 82 83 SymbolInfo index::getSymbolInfo(const Decl *D) { 84 assert(D); 85 SymbolInfo Info; 86 Info.Kind = SymbolKind::Unknown; 87 Info.SubKind = SymbolSubKind::None; 88 Info.Properties = SymbolPropertySet(); 89 Info.Lang = SymbolLanguage::C; 90 91 if (isFunctionLocalSymbol(D)) { 92 Info.Properties |= (unsigned)SymbolProperty::Local; 93 } 94 95 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { 96 switch (TD->getTagKind()) { 97 case TTK_Struct: 98 Info.Kind = SymbolKind::Struct; break; 99 case TTK_Union: 100 Info.Kind = SymbolKind::Union; break; 101 case TTK_Class: 102 Info.Kind = SymbolKind::Class; 103 Info.Lang = SymbolLanguage::CXX; 104 break; 105 case TTK_Interface: 106 Info.Kind = SymbolKind::Protocol; 107 Info.Lang = SymbolLanguage::CXX; 108 break; 109 case TTK_Enum: 110 Info.Kind = SymbolKind::Enum; break; 111 } 112 113 if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) { 114 if (!CXXRec->isCLike()) { 115 Info.Lang = SymbolLanguage::CXX; 116 if (CXXRec->getDescribedClassTemplate()) { 117 Info.Properties |= (unsigned)SymbolProperty::Generic; 118 } 119 } 120 } 121 122 if (isa<ClassTemplatePartialSpecializationDecl>(D)) { 123 Info.Properties |= (unsigned)SymbolProperty::Generic; 124 Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; 125 } else if (isa<ClassTemplateSpecializationDecl>(D)) { 126 Info.Properties |= (unsigned)SymbolProperty::Generic; 127 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 128 } 129 130 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 131 Info.Kind = SymbolKind::Variable; 132 if (isa<ParmVarDecl>(D)) { 133 Info.Kind = SymbolKind::Parameter; 134 } else if (isa<CXXRecordDecl>(D->getDeclContext())) { 135 Info.Kind = SymbolKind::StaticProperty; 136 Info.Lang = SymbolLanguage::CXX; 137 } 138 139 if (isa<VarTemplatePartialSpecializationDecl>(D)) { 140 Info.Lang = SymbolLanguage::CXX; 141 Info.Properties |= (unsigned)SymbolProperty::Generic; 142 Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; 143 } else if (isa<VarTemplateSpecializationDecl>(D)) { 144 Info.Lang = SymbolLanguage::CXX; 145 Info.Properties |= (unsigned)SymbolProperty::Generic; 146 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 147 } else if (VD->getDescribedVarTemplate()) { 148 Info.Lang = SymbolLanguage::CXX; 149 Info.Properties |= (unsigned)SymbolProperty::Generic; 150 } 151 152 } else { 153 switch (D->getKind()) { 154 case Decl::Import: 155 Info.Kind = SymbolKind::Module; 156 break; 157 case Decl::Typedef: 158 Info.Kind = SymbolKind::TypeAlias; break; // Lang = C 159 case Decl::Function: 160 Info.Kind = SymbolKind::Function; 161 break; 162 case Decl::Field: 163 Info.Kind = SymbolKind::Field; 164 if (const CXXRecordDecl * 165 CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { 166 if (!CXXRec->isCLike()) 167 Info.Lang = SymbolLanguage::CXX; 168 } 169 break; 170 case Decl::EnumConstant: 171 Info.Kind = SymbolKind::EnumConstant; break; 172 case Decl::ObjCInterface: 173 case Decl::ObjCImplementation: { 174 Info.Kind = SymbolKind::Class; 175 Info.Lang = SymbolLanguage::ObjC; 176 const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D); 177 if (!ClsD) 178 ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface(); 179 if (isUnitTestCase(ClsD)) 180 Info.Properties |= (unsigned)SymbolProperty::UnitTest; 181 break; 182 } 183 case Decl::ObjCProtocol: 184 Info.Kind = SymbolKind::Protocol; 185 Info.Lang = SymbolLanguage::ObjC; 186 break; 187 case Decl::ObjCCategory: 188 case Decl::ObjCCategoryImpl: { 189 Info.Kind = SymbolKind::Extension; 190 Info.Lang = SymbolLanguage::ObjC; 191 const ObjCInterfaceDecl *ClsD = nullptr; 192 if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D)) 193 ClsD = CatD->getClassInterface(); 194 else 195 ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface(); 196 if (isUnitTestCase(ClsD)) 197 Info.Properties |= (unsigned)SymbolProperty::UnitTest; 198 break; 199 } 200 case Decl::ObjCMethod: 201 if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) { 202 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); 203 Info.Kind = SymbolKind::InstanceMethod; 204 if (MD->isPropertyAccessor()) { 205 if (MD->param_size()) 206 Info.SubKind = SymbolSubKind::AccessorSetter; 207 else 208 Info.SubKind = SymbolSubKind::AccessorGetter; 209 } 210 } else { 211 Info.Kind = SymbolKind::ClassMethod; 212 } 213 Info.Lang = SymbolLanguage::ObjC; 214 if (isUnitTest(cast<ObjCMethodDecl>(D))) 215 Info.Properties |= (unsigned)SymbolProperty::UnitTest; 216 if (D->hasAttr<IBActionAttr>()) 217 Info.Properties |= (unsigned)SymbolProperty::IBAnnotated; 218 break; 219 case Decl::ObjCProperty: 220 Info.Kind = SymbolKind::InstanceProperty; 221 Info.Lang = SymbolLanguage::ObjC; 222 checkForIBOutlets(D, Info.Properties); 223 if (auto *Annot = D->getAttr<AnnotateAttr>()) { 224 if (Annot->getAnnotation() == "gk_inspectable") 225 Info.Properties |= (unsigned)SymbolProperty::GKInspectable; 226 } 227 break; 228 case Decl::ObjCIvar: 229 Info.Kind = SymbolKind::Field; 230 Info.Lang = SymbolLanguage::ObjC; 231 checkForIBOutlets(D, Info.Properties); 232 break; 233 case Decl::Namespace: 234 Info.Kind = SymbolKind::Namespace; 235 Info.Lang = SymbolLanguage::CXX; 236 break; 237 case Decl::NamespaceAlias: 238 Info.Kind = SymbolKind::NamespaceAlias; 239 Info.Lang = SymbolLanguage::CXX; 240 break; 241 case Decl::CXXConstructor: { 242 Info.Kind = SymbolKind::Constructor; 243 Info.Lang = SymbolLanguage::CXX; 244 auto *CD = cast<CXXConstructorDecl>(D); 245 if (CD->isCopyConstructor()) 246 Info.SubKind = SymbolSubKind::CXXCopyConstructor; 247 else if (CD->isMoveConstructor()) 248 Info.SubKind = SymbolSubKind::CXXMoveConstructor; 249 break; 250 } 251 case Decl::CXXDestructor: 252 Info.Kind = SymbolKind::Destructor; 253 Info.Lang = SymbolLanguage::CXX; 254 break; 255 case Decl::CXXConversion: 256 Info.Kind = SymbolKind::ConversionFunction; 257 Info.Lang = SymbolLanguage::CXX; 258 break; 259 case Decl::CXXMethod: { 260 const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); 261 if (MD->isStatic()) 262 Info.Kind = SymbolKind::StaticMethod; 263 else 264 Info.Kind = SymbolKind::InstanceMethod; 265 Info.Lang = SymbolLanguage::CXX; 266 break; 267 } 268 case Decl::ClassTemplate: 269 Info.Kind = SymbolKind::Class; 270 Info.Properties |= (unsigned)SymbolProperty::Generic; 271 Info.Lang = SymbolLanguage::CXX; 272 break; 273 case Decl::FunctionTemplate: 274 Info.Kind = SymbolKind::Function; 275 Info.Properties |= (unsigned)SymbolProperty::Generic; 276 Info.Lang = SymbolLanguage::CXX; 277 if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( 278 cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { 279 if (isa<CXXConstructorDecl>(MD)) 280 Info.Kind = SymbolKind::Constructor; 281 else if (isa<CXXDestructorDecl>(MD)) 282 Info.Kind = SymbolKind::Destructor; 283 else if (isa<CXXConversionDecl>(MD)) 284 Info.Kind = SymbolKind::ConversionFunction; 285 else { 286 if (MD->isStatic()) 287 Info.Kind = SymbolKind::StaticMethod; 288 else 289 Info.Kind = SymbolKind::InstanceMethod; 290 } 291 } 292 break; 293 case Decl::TypeAliasTemplate: 294 Info.Kind = SymbolKind::TypeAlias; 295 Info.Lang = SymbolLanguage::CXX; 296 Info.Properties |= (unsigned)SymbolProperty::Generic; 297 break; 298 case Decl::TypeAlias: 299 Info.Kind = SymbolKind::TypeAlias; 300 Info.Lang = SymbolLanguage::CXX; 301 break; 302 default: 303 break; 304 } 305 } 306 307 if (Info.Kind == SymbolKind::Unknown) 308 return Info; 309 310 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 311 if (FD->getTemplatedKind() == 312 FunctionDecl::TK_FunctionTemplateSpecialization) { 313 Info.Properties |= (unsigned)SymbolProperty::Generic; 314 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 315 } 316 } 317 318 if (Info.Properties & (unsigned)SymbolProperty::Generic) 319 Info.Lang = SymbolLanguage::CXX; 320 321 return Info; 322 } 323 324 bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, 325 llvm::function_ref<bool(SymbolRole)> Fn) { 326 #define APPLY_FOR_ROLE(Role) \ 327 if (Roles & (unsigned)SymbolRole::Role) \ 328 if (!Fn(SymbolRole::Role)) \ 329 return false; 330 331 APPLY_FOR_ROLE(Declaration); 332 APPLY_FOR_ROLE(Definition); 333 APPLY_FOR_ROLE(Reference); 334 APPLY_FOR_ROLE(Read); 335 APPLY_FOR_ROLE(Write); 336 APPLY_FOR_ROLE(Call); 337 APPLY_FOR_ROLE(Dynamic); 338 APPLY_FOR_ROLE(AddressOf); 339 APPLY_FOR_ROLE(Implicit); 340 APPLY_FOR_ROLE(RelationChildOf); 341 APPLY_FOR_ROLE(RelationBaseOf); 342 APPLY_FOR_ROLE(RelationOverrideOf); 343 APPLY_FOR_ROLE(RelationReceivedBy); 344 APPLY_FOR_ROLE(RelationCalledBy); 345 APPLY_FOR_ROLE(RelationExtendedBy); 346 APPLY_FOR_ROLE(RelationAccessorOf); 347 APPLY_FOR_ROLE(RelationContainedBy); 348 APPLY_FOR_ROLE(RelationIBTypeOf); 349 APPLY_FOR_ROLE(RelationSpecializationOf); 350 351 #undef APPLY_FOR_ROLE 352 353 return true; 354 } 355 356 void index::applyForEachSymbolRole(SymbolRoleSet Roles, 357 llvm::function_ref<void(SymbolRole)> Fn) { 358 applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool { 359 Fn(r); 360 return true; 361 }); 362 } 363 364 void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { 365 bool VisitedOnce = false; 366 applyForEachSymbolRole(Roles, [&](SymbolRole Role) { 367 if (VisitedOnce) 368 OS << ','; 369 else 370 VisitedOnce = true; 371 switch (Role) { 372 case SymbolRole::Declaration: OS << "Decl"; break; 373 case SymbolRole::Definition: OS << "Def"; break; 374 case SymbolRole::Reference: OS << "Ref"; break; 375 case SymbolRole::Read: OS << "Read"; break; 376 case SymbolRole::Write: OS << "Writ"; break; 377 case SymbolRole::Call: OS << "Call"; break; 378 case SymbolRole::Dynamic: OS << "Dyn"; break; 379 case SymbolRole::AddressOf: OS << "Addr"; break; 380 case SymbolRole::Implicit: OS << "Impl"; break; 381 case SymbolRole::RelationChildOf: OS << "RelChild"; break; 382 case SymbolRole::RelationBaseOf: OS << "RelBase"; break; 383 case SymbolRole::RelationOverrideOf: OS << "RelOver"; break; 384 case SymbolRole::RelationReceivedBy: OS << "RelRec"; break; 385 case SymbolRole::RelationCalledBy: OS << "RelCall"; break; 386 case SymbolRole::RelationExtendedBy: OS << "RelExt"; break; 387 case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; 388 case SymbolRole::RelationContainedBy: OS << "RelCont"; break; 389 case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break; 390 case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break; 391 } 392 }); 393 } 394 395 bool index::printSymbolName(const Decl *D, const LangOptions &LO, 396 raw_ostream &OS) { 397 if (auto *ND = dyn_cast<NamedDecl>(D)) { 398 PrintingPolicy Policy(LO); 399 // Forward references can have different template argument names. Suppress 400 // the template argument names in constructors to make their name more 401 // stable. 402 Policy.SuppressTemplateArgsInCXXConstructors = true; 403 DeclarationName DeclName = ND->getDeclName(); 404 if (DeclName.isEmpty()) 405 return true; 406 DeclName.print(OS, Policy); 407 return false; 408 } else { 409 return true; 410 } 411 } 412 413 StringRef index::getSymbolKindString(SymbolKind K) { 414 switch (K) { 415 case SymbolKind::Unknown: return "<unknown>"; 416 case SymbolKind::Module: return "module"; 417 case SymbolKind::Namespace: return "namespace"; 418 case SymbolKind::NamespaceAlias: return "namespace-alias"; 419 case SymbolKind::Macro: return "macro"; 420 case SymbolKind::Enum: return "enum"; 421 case SymbolKind::Struct: return "struct"; 422 case SymbolKind::Class: return "class"; 423 case SymbolKind::Protocol: return "protocol"; 424 case SymbolKind::Extension: return "extension"; 425 case SymbolKind::Union: return "union"; 426 case SymbolKind::TypeAlias: return "type-alias"; 427 case SymbolKind::Function: return "function"; 428 case SymbolKind::Variable: return "variable"; 429 case SymbolKind::Field: return "field"; 430 case SymbolKind::EnumConstant: return "enumerator"; 431 case SymbolKind::InstanceMethod: return "instance-method"; 432 case SymbolKind::ClassMethod: return "class-method"; 433 case SymbolKind::StaticMethod: return "static-method"; 434 case SymbolKind::InstanceProperty: return "instance-property"; 435 case SymbolKind::ClassProperty: return "class-property"; 436 case SymbolKind::StaticProperty: return "static-property"; 437 case SymbolKind::Constructor: return "constructor"; 438 case SymbolKind::Destructor: return "destructor"; 439 case SymbolKind::ConversionFunction: return "coversion-func"; 440 case SymbolKind::Parameter: return "param"; 441 } 442 llvm_unreachable("invalid symbol kind"); 443 } 444 445 StringRef index::getSymbolSubKindString(SymbolSubKind K) { 446 switch (K) { 447 case SymbolSubKind::None: return "<none>"; 448 case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor"; 449 case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; 450 case SymbolSubKind::AccessorGetter: return "acc-get"; 451 case SymbolSubKind::AccessorSetter: return "acc-set"; 452 } 453 llvm_unreachable("invalid symbol subkind"); 454 } 455 456 StringRef index::getSymbolLanguageString(SymbolLanguage K) { 457 switch (K) { 458 case SymbolLanguage::C: return "C"; 459 case SymbolLanguage::ObjC: return "ObjC"; 460 case SymbolLanguage::CXX: return "C++"; 461 } 462 llvm_unreachable("invalid symbol language kind"); 463 } 464 465 void index::applyForEachSymbolProperty(SymbolPropertySet Props, 466 llvm::function_ref<void(SymbolProperty)> Fn) { 467 #define APPLY_FOR_PROPERTY(K) \ 468 if (Props & (unsigned)SymbolProperty::K) \ 469 Fn(SymbolProperty::K) 470 471 APPLY_FOR_PROPERTY(Generic); 472 APPLY_FOR_PROPERTY(TemplatePartialSpecialization); 473 APPLY_FOR_PROPERTY(TemplateSpecialization); 474 APPLY_FOR_PROPERTY(UnitTest); 475 APPLY_FOR_PROPERTY(IBAnnotated); 476 APPLY_FOR_PROPERTY(IBOutletCollection); 477 APPLY_FOR_PROPERTY(GKInspectable); 478 APPLY_FOR_PROPERTY(Local); 479 480 #undef APPLY_FOR_PROPERTY 481 } 482 483 void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) { 484 bool VisitedOnce = false; 485 applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) { 486 if (VisitedOnce) 487 OS << ','; 488 else 489 VisitedOnce = true; 490 switch (Prop) { 491 case SymbolProperty::Generic: OS << "Gen"; break; 492 case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break; 493 case SymbolProperty::TemplateSpecialization: OS << "TS"; break; 494 case SymbolProperty::UnitTest: OS << "test"; break; 495 case SymbolProperty::IBAnnotated: OS << "IB"; break; 496 case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; 497 case SymbolProperty::GKInspectable: OS << "GKI"; break; 498 case SymbolProperty::Local: OS << "local"; break; 499 } 500 }); 501 } 502