Home | History | Annotate | Download | only in Index
      1 //===- IndexDecl.cpp - Indexing declarations ------------------------------===//
      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/DeclVisitor.h"
     13 
     14 using namespace clang;
     15 using namespace index;
     16 
     17 #define TRY_TO(CALL_EXPR)                                                      \
     18   do {                                                                         \
     19     if (!CALL_EXPR)                                                            \
     20       return false;                                                            \
     21   } while (0)
     22 
     23 namespace {
     24 
     25 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
     26   IndexingContext &IndexCtx;
     27 
     28 public:
     29   explicit IndexingDeclVisitor(IndexingContext &indexCtx)
     30     : IndexCtx(indexCtx) { }
     31 
     32   bool Handled = true;
     33 
     34   bool VisitDecl(const Decl *D) {
     35     Handled = false;
     36     return true;
     37   }
     38 
     39   /// \brief Returns true if the given method has been defined explicitly by the
     40   /// user.
     41   static bool hasUserDefined(const ObjCMethodDecl *D,
     42                              const ObjCImplDecl *Container) {
     43     const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
     44                                                     D->isInstanceMethod());
     45     return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
     46   }
     47 
     48   void handleDeclarator(const DeclaratorDecl *D,
     49                         const NamedDecl *Parent = nullptr) {
     50     if (!Parent) Parent = D;
     51 
     52     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
     53     IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
     54     if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
     55       // Only index parameters in definitions, parameters in declarations are
     56       // not useful.
     57       if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
     58         auto *DC = Parm->getDeclContext();
     59         if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
     60           if (FD->isThisDeclarationADefinition())
     61             IndexCtx.handleDecl(Parm);
     62         } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) {
     63           if (MD->isThisDeclarationADefinition())
     64             IndexCtx.handleDecl(Parm);
     65         } else {
     66           IndexCtx.handleDecl(Parm);
     67         }
     68       } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     69         if (FD->isThisDeclarationADefinition()) {
     70           for (auto PI : FD->parameters()) {
     71             IndexCtx.handleDecl(PI);
     72           }
     73         }
     74       }
     75     }
     76   }
     77 
     78   bool handleObjCMethod(const ObjCMethodDecl *D) {
     79     if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic))
     80       return false;
     81     IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
     82     for (const auto *I : D->parameters())
     83       handleDeclarator(I, D);
     84 
     85     if (D->isThisDeclarationADefinition()) {
     86       const Stmt *Body = D->getBody();
     87       if (Body) {
     88         IndexCtx.indexBody(Body, D, D);
     89       }
     90     }
     91     return true;
     92   }
     93 
     94   bool VisitFunctionDecl(const FunctionDecl *D) {
     95     if (D->isDeleted())
     96       return true;
     97 
     98     SymbolRoleSet Roles{};
     99     SmallVector<SymbolRelation, 4> Relations;
    100     if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
    101       if (CXXMD->isVirtual())
    102         Roles |= (unsigned)SymbolRole::Dynamic;
    103       for (auto I = CXXMD->begin_overridden_methods(),
    104            E = CXXMD->end_overridden_methods(); I != E; ++I) {
    105         Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
    106       }
    107     }
    108 
    109     if (!IndexCtx.handleDecl(D, Roles, Relations))
    110       return false;
    111     handleDeclarator(D);
    112 
    113     if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
    114       // Constructor initializers.
    115       for (const auto *Init : Ctor->inits()) {
    116         if (Init->isWritten()) {
    117           IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
    118           if (const FieldDecl *Member = Init->getAnyMember())
    119             IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D,
    120                                      (unsigned)SymbolRole::Write);
    121           IndexCtx.indexBody(Init->getInit(), D, D);
    122         }
    123       }
    124     }
    125 
    126     if (D->isThisDeclarationADefinition()) {
    127       const Stmt *Body = D->getBody();
    128       if (Body) {
    129         IndexCtx.indexBody(Body, D, D);
    130       }
    131     }
    132     return true;
    133   }
    134 
    135   bool VisitVarDecl(const VarDecl *D) {
    136     if (!IndexCtx.handleDecl(D))
    137       return false;
    138     handleDeclarator(D);
    139     IndexCtx.indexBody(D->getInit(), D);
    140     return true;
    141   }
    142 
    143   bool VisitFieldDecl(const FieldDecl *D) {
    144     if (!IndexCtx.handleDecl(D))
    145       return false;
    146     handleDeclarator(D);
    147     if (D->isBitField())
    148       IndexCtx.indexBody(D->getBitWidth(), D);
    149     else if (D->hasInClassInitializer())
    150       IndexCtx.indexBody(D->getInClassInitializer(), D);
    151     return true;
    152   }
    153 
    154   bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
    155     if (D->getSynthesize()) {
    156       // For synthesized ivars, use the location of the ObjC implementation,
    157       // not the location of the property.
    158       // Otherwise the header file containing the @interface will have different
    159       // indexing contents based on whether the @implementation was present or
    160       // not in the translation unit.
    161       return IndexCtx.handleDecl(D,
    162                                  cast<Decl>(D->getDeclContext())->getLocation(),
    163                                  (unsigned)SymbolRole::Implicit);
    164     }
    165     if (!IndexCtx.handleDecl(D))
    166       return false;
    167     handleDeclarator(D);
    168     return true;
    169   }
    170 
    171   bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
    172     handleDeclarator(D);
    173     return true;
    174   }
    175 
    176   bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
    177     if (!IndexCtx.handleDecl(D))
    178       return false;
    179     IndexCtx.indexBody(D->getInitExpr(), D);
    180     return true;
    181   }
    182 
    183   bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
    184     if (!IndexCtx.handleDecl(D))
    185       return false;
    186     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
    187     return true;
    188   }
    189 
    190   bool VisitTagDecl(const TagDecl *D) {
    191     // Non-free standing tags are handled in indexTypeSourceInfo.
    192     if (D->isFreeStanding()) {
    193       if (D->isThisDeclarationADefinition()) {
    194         IndexCtx.indexTagDecl(D);
    195       } else {
    196         auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
    197         return IndexCtx.handleReference(D, D->getLocation(), Parent,
    198                                         D->getLexicalDeclContext(),
    199                                         SymbolRoleSet());
    200       }
    201     }
    202     return true;
    203   }
    204 
    205   bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
    206                                  const ObjCContainerDecl *ContD) {
    207     ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
    208     for (ObjCInterfaceDecl::protocol_iterator
    209          I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
    210       SourceLocation Loc = *LI;
    211       ObjCProtocolDecl *PD = *I;
    212       TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD,
    213           SymbolRoleSet(),
    214           SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
    215     }
    216     return true;
    217   }
    218 
    219   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
    220     if (D->isThisDeclarationADefinition()) {
    221       TRY_TO(IndexCtx.handleDecl(D));
    222       if (auto *SuperD = D->getSuperClass()) {
    223         TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D,
    224             SymbolRoleSet(),
    225             SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
    226       }
    227       TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
    228       TRY_TO(IndexCtx.indexDeclContext(D));
    229     } else {
    230       return IndexCtx.handleReference(D, D->getLocation(), nullptr,
    231                                       D->getDeclContext(), SymbolRoleSet());
    232     }
    233     return true;
    234   }
    235 
    236   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
    237     if (D->isThisDeclarationADefinition()) {
    238       TRY_TO(IndexCtx.handleDecl(D));
    239       TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
    240       TRY_TO(IndexCtx.indexDeclContext(D));
    241     } else {
    242       return IndexCtx.handleReference(D, D->getLocation(), nullptr,
    243                                       D->getDeclContext(), SymbolRoleSet());
    244     }
    245     return true;
    246   }
    247 
    248   bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
    249     const ObjCInterfaceDecl *Class = D->getClassInterface();
    250     if (!Class)
    251       return true;
    252 
    253     if (Class->isImplicitInterfaceDecl())
    254       IndexCtx.handleDecl(Class);
    255 
    256     if (!IndexCtx.handleDecl(D))
    257       return false;
    258 
    259     // Index the ivars first to make sure the synthesized ivars are indexed
    260     // before indexing the methods that can reference them.
    261     for (const auto *IvarI : D->ivars())
    262       IndexCtx.indexDecl(IvarI);
    263     for (const auto *I : D->decls()) {
    264       if (!isa<ObjCIvarDecl>(I))
    265         IndexCtx.indexDecl(I);
    266     }
    267 
    268     return true;
    269   }
    270 
    271   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
    272     if (!IndexCtx.handleDecl(D))
    273       return false;
    274     IndexCtx.indexDeclContext(D);
    275     return true;
    276   }
    277 
    278   bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
    279     const ObjCCategoryDecl *Cat = D->getCategoryDecl();
    280     if (!Cat)
    281       return true;
    282 
    283     if (!IndexCtx.handleDecl(D))
    284       return false;
    285     IndexCtx.indexDeclContext(D);
    286     return true;
    287   }
    288 
    289   bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
    290     // Methods associated with a property, even user-declared ones, are
    291     // handled when we handle the property.
    292     if (D->isPropertyAccessor())
    293       return true;
    294 
    295     handleObjCMethod(D);
    296     return true;
    297   }
    298 
    299   bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
    300     if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
    301       if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
    302         handleObjCMethod(MD);
    303     if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
    304       if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
    305         handleObjCMethod(MD);
    306     if (!IndexCtx.handleDecl(D))
    307       return false;
    308     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
    309     return true;
    310   }
    311 
    312   bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
    313     ObjCPropertyDecl *PD = D->getPropertyDecl();
    314     if (!IndexCtx.handleReference(PD, D->getLocation(),
    315                              /*Parent=*/cast<NamedDecl>(D->getDeclContext()),
    316                              D->getDeclContext(), SymbolRoleSet(), {},
    317                              /*RefE=*/nullptr, D))
    318       return false;
    319 
    320     if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
    321       return true;
    322     assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
    323 
    324     if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
    325       if (!IvarD->getSynthesize())
    326         IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
    327                                  D->getDeclContext(), SymbolRoleSet());
    328     }
    329 
    330     auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext());
    331     if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
    332       if (MD->isPropertyAccessor() &&
    333           !hasUserDefined(MD, ImplD))
    334         IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
    335     }
    336     if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
    337       if (MD->isPropertyAccessor() &&
    338           !hasUserDefined(MD, ImplD))
    339         IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
    340     }
    341     return true;
    342   }
    343 
    344   bool VisitNamespaceDecl(const NamespaceDecl *D) {
    345     if (!IndexCtx.handleDecl(D))
    346       return false;
    347     IndexCtx.indexDeclContext(D);
    348     return true;
    349   }
    350 
    351   bool VisitUsingDecl(const UsingDecl *D) {
    352     const DeclContext *DC = D->getDeclContext()->getRedeclContext();
    353     const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
    354 
    355     IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
    356                                          D->getLexicalDeclContext());
    357     for (const auto *I : D->shadows())
    358       IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent,
    359                                D->getLexicalDeclContext(), SymbolRoleSet());
    360     return true;
    361   }
    362 
    363   bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
    364     const DeclContext *DC = D->getDeclContext()->getRedeclContext();
    365     const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
    366 
    367     IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
    368                                          D->getLexicalDeclContext());
    369     return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
    370                                     D->getLocation(), Parent,
    371                                     D->getLexicalDeclContext(),
    372                                     SymbolRoleSet());
    373   }
    374 
    375   bool VisitClassTemplateSpecializationDecl(const
    376                                            ClassTemplateSpecializationDecl *D) {
    377     // FIXME: Notify subsequent callbacks if info comes from implicit
    378     // instantiation.
    379     if (D->isThisDeclarationADefinition())
    380       IndexCtx.indexTagDecl(D);
    381     return true;
    382   }
    383 
    384   bool VisitTemplateDecl(const TemplateDecl *D) {
    385     // FIXME: Template parameters.
    386     return Visit(D->getTemplatedDecl());
    387   }
    388 
    389   bool VisitFriendDecl(const FriendDecl *D) {
    390     if (auto ND = D->getFriendDecl()) {
    391       // FIXME: Ignore a class template in a dependent context, these are not
    392       // linked properly with their redeclarations, ending up with duplicate
    393       // USRs.
    394       // See comment "Friend templates are visible in fairly strange ways." in
    395       // SemaTemplate.cpp which precedes code that prevents the friend template
    396       // from becoming visible from the enclosing context.
    397       if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext())
    398         return true;
    399       return Visit(ND);
    400     }
    401     if (auto Ty = D->getFriendType()) {
    402       IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext()));
    403     }
    404     return true;
    405   }
    406 
    407   bool VisitImportDecl(const ImportDecl *D) {
    408     return IndexCtx.importedModule(D);
    409   }
    410 };
    411 
    412 } // anonymous namespace
    413 
    414 bool IndexingContext::indexDecl(const Decl *D) {
    415   if (D->isImplicit() && shouldIgnoreIfImplicit(D))
    416     return true;
    417 
    418   if (isTemplateImplicitInstantiation(D))
    419     return true;
    420 
    421   IndexingDeclVisitor Visitor(*this);
    422   bool ShouldContinue = Visitor.Visit(D);
    423   if (!ShouldContinue)
    424     return false;
    425 
    426   if (!Visitor.Handled && isa<DeclContext>(D))
    427     return indexDeclContext(cast<DeclContext>(D));
    428 
    429   return true;
    430 }
    431 
    432 bool IndexingContext::indexDeclContext(const DeclContext *DC) {
    433   for (const auto *I : DC->decls())
    434     if (!indexDecl(I))
    435       return false;
    436   return true;
    437 }
    438 
    439 bool IndexingContext::indexTopLevelDecl(const Decl *D) {
    440   if (D->getLocation().isInvalid())
    441     return true;
    442 
    443   if (isa<ObjCMethodDecl>(D))
    444     return true; // Wait for the objc container.
    445 
    446   return indexDecl(D);
    447 }
    448 
    449 bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
    450   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
    451     if (!indexTopLevelDecl(*I))
    452       return false;
    453   return true;
    454 }
    455