Home | History | Annotate | Download | only in Index
      1 //===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===//
      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/RecursiveASTVisitor.h"
     12 
     13 using namespace clang;
     14 using namespace index;
     15 
     16 namespace {
     17 
     18 class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
     19   IndexingContext &IndexCtx;
     20   const NamedDecl *Parent;
     21   const DeclContext *ParentDC;
     22   bool IsBase;
     23   SmallVector<SymbolRelation, 3> Relations;
     24 
     25   typedef RecursiveASTVisitor<TypeIndexer> base;
     26 
     27 public:
     28   TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,
     29               const DeclContext *DC, bool isBase)
     30     : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) {
     31     if (IsBase) {
     32       assert(Parent);
     33       Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent);
     34     }
     35   }
     36 
     37   bool shouldWalkTypesOfTypeLocs() const { return false; }
     38 
     39   bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
     40     return IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
     41                                     Parent, ParentDC, SymbolRoleSet(),
     42                                     Relations);
     43   }
     44 
     45 #define TRY_TO(CALL_EXPR)                                                      \
     46   do {                                                                         \
     47     if (!CALL_EXPR)                                                            \
     48       return false;                                                            \
     49   } while (0)
     50 
     51   bool traverseParamVarHelper(ParmVarDecl *D) {
     52     TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
     53     if (D->getTypeSourceInfo())
     54       TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
     55     return true;
     56   }
     57 
     58   bool TraverseParmVarDecl(ParmVarDecl *D) {
     59     // Avoid visiting default arguments from the definition that were already
     60     // visited in the declaration.
     61     // FIXME: A free function definition can have default arguments.
     62     // Avoiding double visitaiton of default arguments should be handled by the
     63     // visitor probably with a bit in the AST to indicate if the attached
     64     // default argument was 'inherited' or written in source.
     65     if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {
     66       if (FD->isThisDeclarationADefinition()) {
     67         return traverseParamVarHelper(D);
     68       }
     69     }
     70 
     71     return base::TraverseParmVarDecl(D);
     72   }
     73 
     74   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
     75     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
     76     return true;
     77   }
     78 
     79   bool VisitTagTypeLoc(TagTypeLoc TL) {
     80     TagDecl *D = TL.getDecl();
     81     if (D->getParentFunctionOrMethod())
     82       return true;
     83 
     84     if (TL.isDefinition()) {
     85       IndexCtx.indexTagDecl(D);
     86       return true;
     87     }
     88 
     89     return IndexCtx.handleReference(D, TL.getNameLoc(),
     90                                     Parent, ParentDC, SymbolRoleSet(),
     91                                     Relations);
     92   }
     93 
     94   bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
     95     return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
     96                                     Parent, ParentDC, SymbolRoleSet());
     97   }
     98 
     99   bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
    100     for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
    101       IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
    102                                Parent, ParentDC, SymbolRoleSet());
    103     }
    104     return true;
    105   }
    106 
    107   bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
    108     if (const TemplateSpecializationType *T = TL.getTypePtr()) {
    109       if (IndexCtx.shouldIndexImplicitTemplateInsts()) {
    110         if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
    111           IndexCtx.handleReference(RD, TL.getTemplateNameLoc(),
    112                                    Parent, ParentDC, SymbolRoleSet(), Relations);
    113       } else {
    114         if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl())
    115           IndexCtx.handleReference(D, TL.getTemplateNameLoc(),
    116                                    Parent, ParentDC, SymbolRoleSet(), Relations);
    117       }
    118     }
    119     return true;
    120   }
    121 
    122   bool TraverseStmt(Stmt *S) {
    123     IndexCtx.indexBody(S, Parent, ParentDC);
    124     return true;
    125   }
    126 };
    127 
    128 } // anonymous namespace
    129 
    130 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
    131                                           const NamedDecl *Parent,
    132                                           const DeclContext *DC,
    133                                           bool isBase) {
    134   if (!TInfo || TInfo->getTypeLoc().isNull())
    135     return;
    136 
    137   indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase);
    138 }
    139 
    140 void IndexingContext::indexTypeLoc(TypeLoc TL,
    141                                    const NamedDecl *Parent,
    142                                    const DeclContext *DC,
    143                                    bool isBase) {
    144   if (TL.isNull())
    145     return;
    146 
    147   if (!DC)
    148     DC = Parent->getLexicalDeclContext();
    149   TypeIndexer(*this, Parent, DC, isBase).TraverseTypeLoc(TL);
    150 }
    151 
    152 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
    153                                                   const NamedDecl *Parent,
    154                                                   const DeclContext *DC) {
    155   if (!NNS)
    156     return;
    157 
    158   if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
    159     indexNestedNameSpecifierLoc(Prefix, Parent, DC);
    160 
    161   if (!DC)
    162     DC = Parent->getLexicalDeclContext();
    163   SourceLocation Loc = NNS.getSourceRange().getBegin();
    164 
    165   switch (NNS.getNestedNameSpecifier()->getKind()) {
    166   case NestedNameSpecifier::Identifier:
    167   case NestedNameSpecifier::Global:
    168   case NestedNameSpecifier::Super:
    169     break;
    170 
    171   case NestedNameSpecifier::Namespace:
    172     handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
    173                     Loc, Parent, DC, SymbolRoleSet());
    174     break;
    175   case NestedNameSpecifier::NamespaceAlias:
    176     handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
    177                     Loc, Parent, DC, SymbolRoleSet());
    178     break;
    179 
    180   case NestedNameSpecifier::TypeSpec:
    181   case NestedNameSpecifier::TypeSpecWithTemplate:
    182     indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
    183     break;
    184   }
    185 }
    186 
    187 void IndexingContext::indexTagDecl(const TagDecl *D) {
    188   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
    189     return;
    190 
    191   if (handleDecl(D)) {
    192     if (D->isThisDeclarationADefinition()) {
    193       indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
    194       if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
    195         for (const auto &I : CXXRD->bases()) {
    196           indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);
    197         }
    198       }
    199       indexDeclContext(D);
    200     }
    201   }
    202 }
    203