Home | History | Annotate | Download | only in Index
      1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
      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 "IndexingContext.h"
     11 #include "clang/Index/IndexDataConsumer.h"
     12 #include "clang/AST/ASTContext.h"
     13 #include "clang/AST/DeclTemplate.h"
     14 #include "clang/AST/DeclObjC.h"
     15 #include "clang/Basic/SourceManager.h"
     16 
     17 using namespace clang;
     18 using namespace index;
     19 
     20 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
     21   return IndexOpts.IndexFunctionLocals;
     22 }
     23 
     24 bool IndexingContext::handleDecl(const Decl *D,
     25                                  SymbolRoleSet Roles,
     26                                  ArrayRef<SymbolRelation> Relations) {
     27   return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false,
     28                               cast<Decl>(D->getDeclContext()), Roles, Relations,
     29                               nullptr, nullptr, D->getDeclContext());
     30 }
     31 
     32 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
     33                                  SymbolRoleSet Roles,
     34                                  ArrayRef<SymbolRelation> Relations,
     35                                  const DeclContext *DC) {
     36   if (!DC)
     37     DC = D->getDeclContext();
     38   return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
     39                               Roles, Relations,
     40                               nullptr, nullptr, DC);
     41 }
     42 
     43 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
     44                                       const NamedDecl *Parent,
     45                                       const DeclContext *DC,
     46                                       SymbolRoleSet Roles,
     47                                       ArrayRef<SymbolRelation> Relations,
     48                                       const Expr *RefE,
     49                                       const Decl *RefD) {
     50   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
     51     return true;
     52 
     53   if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
     54     return true;
     55 
     56   return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
     57                               RefE, RefD, DC);
     58 }
     59 
     60 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
     61   SourceLocation Loc;
     62   auto IdLocs = ImportD->getIdentifierLocs();
     63   if (!IdLocs.empty())
     64     Loc = IdLocs.front();
     65   else
     66     Loc = ImportD->getLocation();
     67   SourceManager &SM = Ctx->getSourceManager();
     68   Loc = SM.getFileLoc(Loc);
     69   if (Loc.isInvalid())
     70     return true;
     71 
     72   FileID FID;
     73   unsigned Offset;
     74   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
     75   if (FID.isInvalid())
     76     return true;
     77 
     78   bool Invalid = false;
     79   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
     80   if (Invalid || !SEntry.isFile())
     81     return true;
     82 
     83   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
     84     switch (IndexOpts.SystemSymbolFilter) {
     85     case IndexingOptions::SystemSymbolFilterKind::None:
     86       return true;
     87     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
     88     case IndexingOptions::SystemSymbolFilterKind::All:
     89       break;
     90     }
     91   }
     92 
     93   SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
     94   if (ImportD->isImplicit())
     95     Roles |= (unsigned)SymbolRole::Implicit;
     96 
     97   return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
     98 }
     99 
    100 bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
    101   assert(D);
    102 
    103   if (isa<TemplateTemplateParmDecl>(D))
    104     return true;
    105 
    106   if (isa<ObjCTypeParamDecl>(D))
    107     return true;
    108 
    109   if (!D->getParentFunctionOrMethod())
    110     return false;
    111 
    112   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
    113     switch (ND->getFormalLinkage()) {
    114     case NoLinkage:
    115     case VisibleNoLinkage:
    116     case InternalLinkage:
    117       return true;
    118     case UniqueExternalLinkage:
    119       llvm_unreachable("Not a sema linkage");
    120     case ExternalLinkage:
    121       return false;
    122     }
    123   }
    124 
    125   return true;
    126 }
    127 
    128 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
    129   TemplateSpecializationKind TKind = TSK_Undeclared;
    130   if (const ClassTemplateSpecializationDecl *
    131       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
    132     TKind = SD->getSpecializationKind();
    133   }
    134   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
    135     TKind = FD->getTemplateSpecializationKind();
    136   }
    137   switch (TKind) {
    138     case TSK_Undeclared:
    139     case TSK_ExplicitSpecialization:
    140       return false;
    141     case TSK_ImplicitInstantiation:
    142     case TSK_ExplicitInstantiationDeclaration:
    143     case TSK_ExplicitInstantiationDefinition:
    144       return true;
    145   }
    146   llvm_unreachable("invalid TemplateSpecializationKind");
    147 }
    148 
    149 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
    150   if (isa<ObjCInterfaceDecl>(D))
    151     return false;
    152   if (isa<ObjCCategoryDecl>(D))
    153     return false;
    154   if (isa<ObjCIvarDecl>(D))
    155     return false;
    156   if (isa<ObjCMethodDecl>(D))
    157     return false;
    158   if (isa<ImportDecl>(D))
    159     return false;
    160   return true;
    161 }
    162 
    163 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
    164   if (const ClassTemplateSpecializationDecl *
    165       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
    166     return SD->getTemplateInstantiationPattern();
    167   }
    168   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
    169     return FD->getTemplateInstantiationPattern();
    170   }
    171   return nullptr;
    172 }
    173 
    174 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
    175   if (auto VD = dyn_cast<VarDecl>(D))
    176     return VD->isThisDeclarationADefinition(Ctx);
    177 
    178   if (auto FD = dyn_cast<FunctionDecl>(D))
    179     return FD->isThisDeclarationADefinition();
    180 
    181   if (auto TD = dyn_cast<TagDecl>(D))
    182     return TD->isThisDeclarationADefinition();
    183 
    184   if (auto MD = dyn_cast<ObjCMethodDecl>(D))
    185     return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
    186 
    187   if (isa<TypedefNameDecl>(D) ||
    188       isa<EnumConstantDecl>(D) ||
    189       isa<FieldDecl>(D) ||
    190       isa<MSPropertyDecl>(D) ||
    191       isa<ObjCImplDecl>(D) ||
    192       isa<ObjCPropertyImplDecl>(D))
    193     return true;
    194 
    195   return false;
    196 }
    197 
    198 static const Decl *adjustParent(const Decl *Parent) {
    199   if (!Parent)
    200     return nullptr;
    201   for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
    202     if (isa<TranslationUnitDecl>(Parent))
    203       return nullptr;
    204     if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
    205       continue;
    206     if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
    207       if (NS->isAnonymousNamespace())
    208         continue;
    209     } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
    210       if (RD->isAnonymousStructOrUnion())
    211         continue;
    212     } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
    213       if (FD->getDeclName().isEmpty())
    214         continue;
    215     }
    216     return Parent;
    217   }
    218 }
    219 
    220 static const Decl *getCanonicalDecl(const Decl *D) {
    221   D = D->getCanonicalDecl();
    222   if (auto TD = dyn_cast<TemplateDecl>(D)) {
    223     D = TD->getTemplatedDecl();
    224     assert(D->isCanonicalDecl());
    225   }
    226 
    227   return D;
    228 }
    229 
    230 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
    231                                            bool IsRef, const Decl *Parent,
    232                                            SymbolRoleSet Roles,
    233                                            ArrayRef<SymbolRelation> Relations,
    234                                            const Expr *OrigE,
    235                                            const Decl *OrigD,
    236                                            const DeclContext *ContainerDC) {
    237   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
    238     return true;
    239   if (!isa<NamedDecl>(D) ||
    240       (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
    241        !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
    242     return true;
    243 
    244   SourceManager &SM = Ctx->getSourceManager();
    245   Loc = SM.getFileLoc(Loc);
    246   if (Loc.isInvalid())
    247     return true;
    248 
    249   FileID FID;
    250   unsigned Offset;
    251   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
    252   if (FID.isInvalid())
    253     return true;
    254 
    255   bool Invalid = false;
    256   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
    257   if (Invalid || !SEntry.isFile())
    258     return true;
    259 
    260   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
    261     switch (IndexOpts.SystemSymbolFilter) {
    262     case IndexingOptions::SystemSymbolFilterKind::None:
    263       return true;
    264     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
    265       if (IsRef)
    266         return true;
    267       break;
    268     case IndexingOptions::SystemSymbolFilterKind::All:
    269       break;
    270     }
    271   }
    272 
    273   if (isTemplateImplicitInstantiation(D)) {
    274     if (!IsRef)
    275       return true;
    276     D = adjustTemplateImplicitInstantiation(D);
    277     if (!D)
    278       return true;
    279     assert(!isTemplateImplicitInstantiation(D));
    280   }
    281 
    282   if (!OrigD)
    283     OrigD = D;
    284 
    285   if (IsRef)
    286     Roles |= (unsigned)SymbolRole::Reference;
    287   else if (isDeclADefinition(D, ContainerDC, *Ctx))
    288     Roles |= (unsigned)SymbolRole::Definition;
    289   else
    290     Roles |= (unsigned)SymbolRole::Declaration;
    291 
    292   D = getCanonicalDecl(D);
    293   if (D->isImplicit() && !isa<ObjCMethodDecl>(D) &&
    294       !(isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->getBuiltinID())) {
    295     // operator new declarations will link to the implicit one as canonical.
    296     return true;
    297   }
    298   Parent = adjustParent(Parent);
    299   if (Parent)
    300     Parent = getCanonicalDecl(Parent);
    301   assert((!Parent || !Parent->isImplicit() ||
    302           (isa<FunctionDecl>(Parent) &&
    303            cast<FunctionDecl>(Parent)->getBuiltinID()) ||
    304           isa<ObjCInterfaceDecl>(Parent) || isa<ObjCMethodDecl>(Parent)) &&
    305          "unexpected implicit parent!");
    306 
    307   SmallVector<SymbolRelation, 6> FinalRelations;
    308   FinalRelations.reserve(Relations.size()+1);
    309 
    310   auto addRelation = [&](SymbolRelation Rel) {
    311     auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
    312                 [&](SymbolRelation Elem)->bool {
    313                   return Elem.RelatedSymbol == Rel.RelatedSymbol;
    314                 });
    315     if (It != FinalRelations.end()) {
    316       It->Roles |= Rel.Roles;
    317     } else {
    318       FinalRelations.push_back(Rel);
    319     }
    320     Roles |= Rel.Roles;
    321   };
    322 
    323   if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) {
    324     addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent});
    325   }
    326   for (auto &Rel : Relations) {
    327     addRelation(SymbolRelation(Rel.Roles,
    328                                Rel.RelatedSymbol->getCanonicalDecl()));
    329   }
    330 
    331   IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
    332   return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
    333                                           Node);
    334 }
    335