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