Home | History | Annotate | Download | only in Index
      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