Home | History | Annotate | Download | only in libclang
      1 //===- CIndexHigh.cpp - Higher level API functions ------------------------===//
      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/AST/DeclVisitor.h"
     12 
     13 using namespace clang;
     14 using namespace cxindex;
     15 
     16 namespace {
     17 
     18 class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
     19   IndexingContext &IndexCtx;
     20 
     21 public:
     22   explicit IndexingDeclVisitor(IndexingContext &indexCtx)
     23     : IndexCtx(indexCtx) { }
     24 
     25   /// \brief Returns true if the given method has been defined explicitly by the
     26   /// user.
     27   static bool hasUserDefined(const ObjCMethodDecl *D,
     28                              const ObjCImplDecl *Container) {
     29     const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(),
     30                                                     D->isInstanceMethod());
     31     return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
     32   }
     33 
     34   void handleDeclarator(const DeclaratorDecl *D,
     35                         const NamedDecl *Parent = nullptr) {
     36     if (!Parent) Parent = D;
     37 
     38     if (!IndexCtx.shouldIndexFunctionLocalSymbols()) {
     39       IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
     40       IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
     41     } else {
     42       if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
     43         IndexCtx.handleVar(Parm);
     44       } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     45         for (auto PI : FD->params()) {
     46           IndexCtx.handleVar(PI);
     47         }
     48       }
     49     }
     50   }
     51 
     52   void handleObjCMethod(const ObjCMethodDecl *D) {
     53     IndexCtx.handleObjCMethod(D);
     54     if (D->isImplicit())
     55       return;
     56 
     57     IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
     58     for (const auto *I : D->params())
     59       handleDeclarator(I, D);
     60 
     61     if (D->isThisDeclarationADefinition()) {
     62       const Stmt *Body = D->getBody();
     63       if (Body) {
     64         IndexCtx.indexBody(Body, D, D);
     65       }
     66     }
     67   }
     68 
     69   bool VisitFunctionDecl(const FunctionDecl *D) {
     70     IndexCtx.handleFunction(D);
     71     handleDeclarator(D);
     72 
     73     if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
     74       // Constructor initializers.
     75       for (const auto *Init : Ctor->inits()) {
     76         if (Init->isWritten()) {
     77           IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
     78           if (const FieldDecl *Member = Init->getAnyMember())
     79             IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D);
     80           IndexCtx.indexBody(Init->getInit(), D, D);
     81         }
     82       }
     83     }
     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 VisitVarDecl(const VarDecl *D) {
     95     IndexCtx.handleVar(D);
     96     handleDeclarator(D);
     97     IndexCtx.indexBody(D->getInit(), D);
     98     return true;
     99   }
    100 
    101   bool VisitFieldDecl(const FieldDecl *D) {
    102     IndexCtx.handleField(D);
    103     handleDeclarator(D);
    104     if (D->isBitField())
    105       IndexCtx.indexBody(D->getBitWidth(), D);
    106     else if (D->hasInClassInitializer())
    107       IndexCtx.indexBody(D->getInClassInitializer(), D);
    108     return true;
    109   }
    110 
    111   bool VisitMSPropertyDecl(const MSPropertyDecl *D) {
    112     handleDeclarator(D);
    113     return true;
    114   }
    115 
    116   bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
    117     IndexCtx.handleEnumerator(D);
    118     IndexCtx.indexBody(D->getInitExpr(), D);
    119     return true;
    120   }
    121 
    122   bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
    123     IndexCtx.handleTypedefName(D);
    124     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
    125     return true;
    126   }
    127 
    128   bool VisitTagDecl(const TagDecl *D) {
    129     // Non-free standing tags are handled in indexTypeSourceInfo.
    130     if (D->isFreeStanding())
    131       IndexCtx.indexTagDecl(D);
    132     return true;
    133   }
    134 
    135   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
    136     IndexCtx.handleObjCInterface(D);
    137 
    138     if (D->isThisDeclarationADefinition()) {
    139       IndexCtx.indexTUDeclsInObjCContainer();
    140       IndexCtx.indexDeclContext(D);
    141     }
    142     return true;
    143   }
    144 
    145   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
    146     IndexCtx.handleObjCProtocol(D);
    147 
    148     if (D->isThisDeclarationADefinition()) {
    149       IndexCtx.indexTUDeclsInObjCContainer();
    150       IndexCtx.indexDeclContext(D);
    151     }
    152     return true;
    153   }
    154 
    155   bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
    156     const ObjCInterfaceDecl *Class = D->getClassInterface();
    157     if (!Class)
    158       return true;
    159 
    160     if (Class->isImplicitInterfaceDecl())
    161       IndexCtx.handleObjCInterface(Class);
    162 
    163     IndexCtx.handleObjCImplementation(D);
    164 
    165     IndexCtx.indexTUDeclsInObjCContainer();
    166 
    167     // Index the ivars first to make sure the synthesized ivars are indexed
    168     // before indexing the methods that can reference them.
    169     for (const auto *IvarI : D->ivars())
    170       IndexCtx.indexDecl(IvarI);
    171     for (const auto *I : D->decls()) {
    172       if (!isa<ObjCIvarDecl>(I))
    173         IndexCtx.indexDecl(I);
    174     }
    175 
    176     return true;
    177   }
    178 
    179   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
    180     IndexCtx.handleObjCCategory(D);
    181 
    182     IndexCtx.indexTUDeclsInObjCContainer();
    183     IndexCtx.indexDeclContext(D);
    184     return true;
    185   }
    186 
    187   bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
    188     const ObjCCategoryDecl *Cat = D->getCategoryDecl();
    189     if (!Cat)
    190       return true;
    191 
    192     IndexCtx.handleObjCCategoryImpl(D);
    193 
    194     IndexCtx.indexTUDeclsInObjCContainer();
    195     IndexCtx.indexDeclContext(D);
    196     return true;
    197   }
    198 
    199   bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
    200     // Methods associated with a property, even user-declared ones, are
    201     // handled when we handle the property.
    202     if (D->isPropertyAccessor())
    203       return true;
    204 
    205     handleObjCMethod(D);
    206     return true;
    207   }
    208 
    209   bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
    210     if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
    211       if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
    212         handleObjCMethod(MD);
    213     if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
    214       if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
    215         handleObjCMethod(MD);
    216     IndexCtx.handleObjCProperty(D);
    217     IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
    218     return true;
    219   }
    220 
    221   bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
    222     ObjCPropertyDecl *PD = D->getPropertyDecl();
    223     IndexCtx.handleSynthesizedObjCProperty(D);
    224 
    225     if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
    226       return true;
    227     assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
    228 
    229     if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
    230       if (!IvarD->getSynthesize())
    231         IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
    232                                  D->getDeclContext());
    233     }
    234 
    235     if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
    236       if (MD->isPropertyAccessor() &&
    237           !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
    238         IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
    239                                              D->getLexicalDeclContext());
    240     }
    241     if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
    242       if (MD->isPropertyAccessor() &&
    243           !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext())))
    244         IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
    245                                              D->getLexicalDeclContext());
    246     }
    247     return true;
    248   }
    249 
    250   bool VisitNamespaceDecl(const NamespaceDecl *D) {
    251     IndexCtx.handleNamespace(D);
    252     IndexCtx.indexDeclContext(D);
    253     return true;
    254   }
    255 
    256   bool VisitUsingDecl(const UsingDecl *D) {
    257     // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
    258     // we should do better.
    259 
    260     IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
    261     for (const auto *I : D->shadows())
    262       IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), D,
    263                                D->getLexicalDeclContext());
    264     return true;
    265   }
    266 
    267   bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
    268     // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
    269     // we should do better.
    270 
    271     IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
    272     IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
    273                              D->getLocation(), D, D->getLexicalDeclContext());
    274     return true;
    275   }
    276 
    277   bool VisitClassTemplateDecl(const ClassTemplateDecl *D) {
    278     IndexCtx.handleClassTemplate(D);
    279     if (D->isThisDeclarationADefinition())
    280       IndexCtx.indexDeclContext(D->getTemplatedDecl());
    281     return true;
    282   }
    283 
    284   bool VisitClassTemplateSpecializationDecl(const
    285                                            ClassTemplateSpecializationDecl *D) {
    286     // FIXME: Notify subsequent callbacks if info comes from implicit
    287     // instantiation.
    288     if (D->isThisDeclarationADefinition() &&
    289         (IndexCtx.shouldIndexImplicitTemplateInsts() ||
    290          !IndexCtx.isTemplateImplicitInstantiation(D)))
    291       IndexCtx.indexTagDecl(D);
    292     return true;
    293   }
    294 
    295   bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
    296     IndexCtx.handleFunctionTemplate(D);
    297     FunctionDecl *FD = D->getTemplatedDecl();
    298     handleDeclarator(FD, D);
    299     if (FD->isThisDeclarationADefinition()) {
    300       const Stmt *Body = FD->getBody();
    301       if (Body) {
    302         IndexCtx.indexBody(Body, D, FD);
    303       }
    304     }
    305     return true;
    306   }
    307 
    308   bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
    309     IndexCtx.handleTypeAliasTemplate(D);
    310     IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
    311     return true;
    312   }
    313 
    314   bool VisitImportDecl(const ImportDecl *D) {
    315     IndexCtx.importedModule(D);
    316     return true;
    317   }
    318 };
    319 
    320 } // anonymous namespace
    321 
    322 void IndexingContext::indexDecl(const Decl *D) {
    323   if (D->isImplicit() && shouldIgnoreIfImplicit(D))
    324     return;
    325 
    326   bool Handled = IndexingDeclVisitor(*this).Visit(D);
    327   if (!Handled && isa<DeclContext>(D))
    328     indexDeclContext(cast<DeclContext>(D));
    329 }
    330 
    331 void IndexingContext::indexDeclContext(const DeclContext *DC) {
    332   for (const auto *I : DC->decls())
    333     indexDecl(I);
    334 }
    335 
    336 void IndexingContext::indexTopLevelDecl(const Decl *D) {
    337   if (isNotFromSourceFile(D->getLocation()))
    338     return;
    339 
    340   if (isa<ObjCMethodDecl>(D))
    341     return; // Wait for the objc container.
    342 
    343   indexDecl(D);
    344 }
    345 
    346 void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
    347   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
    348     indexTopLevelDecl(*I);
    349 }
    350 
    351 void IndexingContext::indexTUDeclsInObjCContainer() {
    352   while (!TUDeclsInObjCContainer.empty()) {
    353     DeclGroupRef DG = TUDeclsInObjCContainer.front();
    354     TUDeclsInObjCContainer.pop_front();
    355     indexDeclGroupRef(DG);
    356   }
    357 }
    358