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 SymbolInfo index::getSymbolInfo(const Decl *D) { 53 assert(D); 54 SymbolInfo Info; 55 Info.Kind = SymbolKind::Unknown; 56 Info.Properties = SymbolPropertySet(); 57 Info.Lang = SymbolLanguage::C; 58 59 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { 60 switch (TD->getTagKind()) { 61 case TTK_Struct: 62 Info.Kind = SymbolKind::Struct; break; 63 case TTK_Union: 64 Info.Kind = SymbolKind::Union; break; 65 case TTK_Class: 66 Info.Kind = SymbolKind::Class; 67 Info.Lang = SymbolLanguage::CXX; 68 break; 69 case TTK_Interface: 70 Info.Kind = SymbolKind::Protocol; 71 Info.Lang = SymbolLanguage::CXX; 72 break; 73 case TTK_Enum: 74 Info.Kind = SymbolKind::Enum; break; 75 } 76 77 if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) { 78 if (!CXXRec->isCLike()) { 79 Info.Lang = SymbolLanguage::CXX; 80 if (CXXRec->getDescribedClassTemplate()) { 81 Info.Properties |= (unsigned)SymbolProperty::Generic; 82 } 83 } 84 } 85 86 if (isa<ClassTemplatePartialSpecializationDecl>(D)) { 87 Info.Properties |= (unsigned)SymbolProperty::Generic; 88 Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; 89 } else if (isa<ClassTemplateSpecializationDecl>(D)) { 90 Info.Properties |= (unsigned)SymbolProperty::Generic; 91 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 92 } 93 94 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 95 Info.Kind = SymbolKind::Variable; 96 if (isa<CXXRecordDecl>(D->getDeclContext())) { 97 Info.Kind = SymbolKind::StaticProperty; 98 Info.Lang = SymbolLanguage::CXX; 99 } 100 if (isa<VarTemplatePartialSpecializationDecl>(D)) { 101 Info.Lang = SymbolLanguage::CXX; 102 Info.Properties |= (unsigned)SymbolProperty::Generic; 103 Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; 104 } else if (isa<VarTemplateSpecializationDecl>(D)) { 105 Info.Lang = SymbolLanguage::CXX; 106 Info.Properties |= (unsigned)SymbolProperty::Generic; 107 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 108 } else if (VD->getDescribedVarTemplate()) { 109 Info.Lang = SymbolLanguage::CXX; 110 Info.Properties |= (unsigned)SymbolProperty::Generic; 111 } 112 113 } else { 114 switch (D->getKind()) { 115 case Decl::Import: 116 Info.Kind = SymbolKind::Module; 117 break; 118 case Decl::Typedef: 119 Info.Kind = SymbolKind::TypeAlias; break; // Lang = C 120 case Decl::Function: 121 Info.Kind = SymbolKind::Function; 122 break; 123 case Decl::Field: 124 Info.Kind = SymbolKind::Field; 125 if (const CXXRecordDecl * 126 CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { 127 if (!CXXRec->isCLike()) 128 Info.Lang = SymbolLanguage::CXX; 129 } 130 break; 131 case Decl::EnumConstant: 132 Info.Kind = SymbolKind::EnumConstant; break; 133 case Decl::ObjCInterface: 134 case Decl::ObjCImplementation: { 135 Info.Kind = SymbolKind::Class; 136 Info.Lang = SymbolLanguage::ObjC; 137 const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D); 138 if (!ClsD) 139 ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface(); 140 if (isUnitTestCase(ClsD)) 141 Info.Properties |= (unsigned)SymbolProperty::UnitTest; 142 break; 143 } 144 case Decl::ObjCProtocol: 145 Info.Kind = SymbolKind::Protocol; 146 Info.Lang = SymbolLanguage::ObjC; 147 break; 148 case Decl::ObjCCategory: 149 case Decl::ObjCCategoryImpl: 150 Info.Kind = SymbolKind::Extension; 151 Info.Lang = SymbolLanguage::ObjC; 152 break; 153 case Decl::ObjCMethod: 154 if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) 155 Info.Kind = SymbolKind::InstanceMethod; 156 else 157 Info.Kind = SymbolKind::ClassMethod; 158 Info.Lang = SymbolLanguage::ObjC; 159 if (isUnitTest(cast<ObjCMethodDecl>(D))) 160 Info.Properties |= (unsigned)SymbolProperty::UnitTest; 161 if (D->hasAttr<IBActionAttr>()) 162 Info.Properties |= (unsigned)SymbolProperty::IBAnnotated; 163 break; 164 case Decl::ObjCProperty: 165 Info.Kind = SymbolKind::InstanceProperty; 166 Info.Lang = SymbolLanguage::ObjC; 167 checkForIBOutlets(D, Info.Properties); 168 if (auto *Annot = D->getAttr<AnnotateAttr>()) { 169 if (Annot->getAnnotation() == "gk_inspectable") 170 Info.Properties |= (unsigned)SymbolProperty::GKInspectable; 171 } 172 break; 173 case Decl::ObjCIvar: 174 Info.Kind = SymbolKind::Field; 175 Info.Lang = SymbolLanguage::ObjC; 176 checkForIBOutlets(D, Info.Properties); 177 break; 178 case Decl::Namespace: 179 Info.Kind = SymbolKind::Namespace; 180 Info.Lang = SymbolLanguage::CXX; 181 break; 182 case Decl::NamespaceAlias: 183 Info.Kind = SymbolKind::NamespaceAlias; 184 Info.Lang = SymbolLanguage::CXX; 185 break; 186 case Decl::CXXConstructor: 187 Info.Kind = SymbolKind::Constructor; 188 Info.Lang = SymbolLanguage::CXX; 189 break; 190 case Decl::CXXDestructor: 191 Info.Kind = SymbolKind::Destructor; 192 Info.Lang = SymbolLanguage::CXX; 193 break; 194 case Decl::CXXConversion: 195 Info.Kind = SymbolKind::ConversionFunction; 196 Info.Lang = SymbolLanguage::CXX; 197 break; 198 case Decl::CXXMethod: { 199 const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); 200 if (MD->isStatic()) 201 Info.Kind = SymbolKind::StaticMethod; 202 else 203 Info.Kind = SymbolKind::InstanceMethod; 204 Info.Lang = SymbolLanguage::CXX; 205 break; 206 } 207 case Decl::ClassTemplate: 208 Info.Kind = SymbolKind::Class; 209 Info.Properties |= (unsigned)SymbolProperty::Generic; 210 Info.Lang = SymbolLanguage::CXX; 211 break; 212 case Decl::FunctionTemplate: 213 Info.Kind = SymbolKind::Function; 214 Info.Properties |= (unsigned)SymbolProperty::Generic; 215 Info.Lang = SymbolLanguage::CXX; 216 if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( 217 cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { 218 if (isa<CXXConstructorDecl>(MD)) 219 Info.Kind = SymbolKind::Constructor; 220 else if (isa<CXXDestructorDecl>(MD)) 221 Info.Kind = SymbolKind::Destructor; 222 else if (isa<CXXConversionDecl>(MD)) 223 Info.Kind = SymbolKind::ConversionFunction; 224 else { 225 if (MD->isStatic()) 226 Info.Kind = SymbolKind::StaticMethod; 227 else 228 Info.Kind = SymbolKind::InstanceMethod; 229 } 230 } 231 break; 232 case Decl::TypeAliasTemplate: 233 Info.Kind = SymbolKind::TypeAlias; 234 Info.Lang = SymbolLanguage::CXX; 235 Info.Properties |= (unsigned)SymbolProperty::Generic; 236 break; 237 case Decl::TypeAlias: 238 Info.Kind = SymbolKind::TypeAlias; 239 Info.Lang = SymbolLanguage::CXX; 240 break; 241 default: 242 break; 243 } 244 } 245 246 if (Info.Kind == SymbolKind::Unknown) 247 return Info; 248 249 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 250 if (FD->getTemplatedKind() == 251 FunctionDecl::TK_FunctionTemplateSpecialization) { 252 Info.Properties |= (unsigned)SymbolProperty::Generic; 253 Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; 254 } 255 } 256 257 if (Info.Properties & (unsigned)SymbolProperty::Generic) 258 Info.Lang = SymbolLanguage::CXX; 259 260 return Info; 261 } 262 263 void index::applyForEachSymbolRole(SymbolRoleSet Roles, 264 llvm::function_ref<void(SymbolRole)> Fn) { 265 #define APPLY_FOR_ROLE(Role) \ 266 if (Roles & (unsigned)SymbolRole::Role) \ 267 Fn(SymbolRole::Role) 268 269 APPLY_FOR_ROLE(Declaration); 270 APPLY_FOR_ROLE(Definition); 271 APPLY_FOR_ROLE(Reference); 272 APPLY_FOR_ROLE(Read); 273 APPLY_FOR_ROLE(Write); 274 APPLY_FOR_ROLE(Call); 275 APPLY_FOR_ROLE(Dynamic); 276 APPLY_FOR_ROLE(AddressOf); 277 APPLY_FOR_ROLE(Implicit); 278 APPLY_FOR_ROLE(RelationChildOf); 279 APPLY_FOR_ROLE(RelationBaseOf); 280 APPLY_FOR_ROLE(RelationOverrideOf); 281 APPLY_FOR_ROLE(RelationReceivedBy); 282 APPLY_FOR_ROLE(RelationCalledBy); 283 APPLY_FOR_ROLE(RelationExtendedBy); 284 APPLY_FOR_ROLE(RelationAccessorOf); 285 286 #undef APPLY_FOR_ROLE 287 } 288 289 void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { 290 bool VisitedOnce = false; 291 applyForEachSymbolRole(Roles, [&](SymbolRole Role) { 292 if (VisitedOnce) 293 OS << ','; 294 else 295 VisitedOnce = true; 296 switch (Role) { 297 case SymbolRole::Declaration: OS << "Decl"; break; 298 case SymbolRole::Definition: OS << "Def"; break; 299 case SymbolRole::Reference: OS << "Ref"; break; 300 case SymbolRole::Read: OS << "Read"; break; 301 case SymbolRole::Write: OS << "Writ"; break; 302 case SymbolRole::Call: OS << "Call"; break; 303 case SymbolRole::Dynamic: OS << "Dyn"; break; 304 case SymbolRole::AddressOf: OS << "Addr"; break; 305 case SymbolRole::Implicit: OS << "Impl"; break; 306 case SymbolRole::RelationChildOf: OS << "RelChild"; break; 307 case SymbolRole::RelationBaseOf: OS << "RelBase"; break; 308 case SymbolRole::RelationOverrideOf: OS << "RelOver"; break; 309 case SymbolRole::RelationReceivedBy: OS << "RelRec"; break; 310 case SymbolRole::RelationCalledBy: OS << "RelCall"; break; 311 case SymbolRole::RelationExtendedBy: OS << "RelExt"; break; 312 case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; 313 } 314 }); 315 } 316 317 bool index::printSymbolName(const Decl *D, const LangOptions &LO, 318 raw_ostream &OS) { 319 if (auto *ND = dyn_cast<NamedDecl>(D)) { 320 PrintingPolicy Policy(LO); 321 // Forward references can have different template argument names. Suppress 322 // the template argument names in constructors to make their name more 323 // stable. 324 Policy.SuppressTemplateArgsInCXXConstructors = true; 325 DeclarationName DeclName = ND->getDeclName(); 326 if (DeclName.isEmpty()) 327 return true; 328 DeclName.print(OS, Policy); 329 return false; 330 } else { 331 return true; 332 } 333 } 334 335 StringRef index::getSymbolKindString(SymbolKind K) { 336 switch (K) { 337 case SymbolKind::Unknown: return "<unknown>"; 338 case SymbolKind::Module: return "module"; 339 case SymbolKind::Namespace: return "namespace"; 340 case SymbolKind::NamespaceAlias: return "namespace-alias"; 341 case SymbolKind::Macro: return "macro"; 342 case SymbolKind::Enum: return "enum"; 343 case SymbolKind::Struct: return "struct"; 344 case SymbolKind::Class: return "class"; 345 case SymbolKind::Protocol: return "protocol"; 346 case SymbolKind::Extension: return "extension"; 347 case SymbolKind::Union: return "union"; 348 case SymbolKind::TypeAlias: return "type-alias"; 349 case SymbolKind::Function: return "function"; 350 case SymbolKind::Variable: return "variable"; 351 case SymbolKind::Field: return "field"; 352 case SymbolKind::EnumConstant: return "enumerator"; 353 case SymbolKind::InstanceMethod: return "instance-method"; 354 case SymbolKind::ClassMethod: return "class-method"; 355 case SymbolKind::StaticMethod: return "static-method"; 356 case SymbolKind::InstanceProperty: return "instance-property"; 357 case SymbolKind::ClassProperty: return "class-property"; 358 case SymbolKind::StaticProperty: return "static-property"; 359 case SymbolKind::Constructor: return "constructor"; 360 case SymbolKind::Destructor: return "destructor"; 361 case SymbolKind::ConversionFunction: return "coversion-func"; 362 } 363 llvm_unreachable("invalid symbol kind"); 364 } 365 366 StringRef index::getSymbolLanguageString(SymbolLanguage K) { 367 switch (K) { 368 case SymbolLanguage::C: return "C"; 369 case SymbolLanguage::ObjC: return "ObjC"; 370 case SymbolLanguage::CXX: return "C++"; 371 } 372 llvm_unreachable("invalid symbol language kind"); 373 } 374 375 void index::applyForEachSymbolProperty(SymbolPropertySet Props, 376 llvm::function_ref<void(SymbolProperty)> Fn) { 377 #define APPLY_FOR_PROPERTY(K) \ 378 if (Props & (unsigned)SymbolProperty::K) \ 379 Fn(SymbolProperty::K) 380 381 APPLY_FOR_PROPERTY(Generic); 382 APPLY_FOR_PROPERTY(TemplatePartialSpecialization); 383 APPLY_FOR_PROPERTY(TemplateSpecialization); 384 APPLY_FOR_PROPERTY(UnitTest); 385 APPLY_FOR_PROPERTY(IBAnnotated); 386 APPLY_FOR_PROPERTY(IBOutletCollection); 387 APPLY_FOR_PROPERTY(GKInspectable); 388 389 #undef APPLY_FOR_PROPERTY 390 } 391 392 void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) { 393 bool VisitedOnce = false; 394 applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) { 395 if (VisitedOnce) 396 OS << ','; 397 else 398 VisitedOnce = true; 399 switch (Prop) { 400 case SymbolProperty::Generic: OS << "Gen"; break; 401 case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break; 402 case SymbolProperty::TemplateSpecialization: OS << "TS"; break; 403 case SymbolProperty::UnitTest: OS << "test"; break; 404 case SymbolProperty::IBAnnotated: OS << "IB"; break; 405 case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; 406 case SymbolProperty::GKInspectable: OS << "GKI"; break; 407 } 408 }); 409 } 410