Home | History | Annotate | Download | only in libclang
      1 //===- CXIndexDataConsumer.h - Index data consumer for libclang--*- C++ -*-===//
      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 #ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H
     11 #define LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H
     12 
     13 #include "CXCursor.h"
     14 #include "Index_Internal.h"
     15 #include "clang/Index/IndexDataConsumer.h"
     16 #include "clang/AST/DeclGroup.h"
     17 #include "clang/AST/DeclObjC.h"
     18 #include "llvm/ADT/DenseSet.h"
     19 #include <deque>
     20 
     21 namespace clang {
     22   class FileEntry;
     23   class MSPropertyDecl;
     24   class ObjCPropertyDecl;
     25   class ClassTemplateDecl;
     26   class FunctionTemplateDecl;
     27   class TypeAliasTemplateDecl;
     28   class ClassTemplateSpecializationDecl;
     29 
     30 namespace cxindex {
     31   class CXIndexDataConsumer;
     32   class AttrListInfo;
     33 
     34 class ScratchAlloc {
     35   CXIndexDataConsumer &IdxCtx;
     36 
     37 public:
     38   explicit ScratchAlloc(CXIndexDataConsumer &indexCtx);
     39   ScratchAlloc(const ScratchAlloc &SA);
     40 
     41   ~ScratchAlloc();
     42 
     43   const char *toCStr(StringRef Str);
     44   const char *copyCStr(StringRef Str);
     45 
     46   template <typename T>
     47   T *allocate();
     48 };
     49 
     50 struct EntityInfo : public CXIdxEntityInfo {
     51   const NamedDecl *Dcl;
     52   CXIndexDataConsumer *IndexCtx;
     53   IntrusiveRefCntPtr<AttrListInfo> AttrList;
     54 
     55   EntityInfo() {
     56     name = USR = nullptr;
     57     attributes = nullptr;
     58     numAttributes = 0;
     59   }
     60 };
     61 
     62 struct ContainerInfo : public CXIdxContainerInfo {
     63   const DeclContext *DC;
     64   CXIndexDataConsumer *IndexCtx;
     65 };
     66 
     67 struct DeclInfo : public CXIdxDeclInfo {
     68   enum DInfoKind {
     69     Info_Decl,
     70 
     71     Info_ObjCContainer,
     72       Info_ObjCInterface,
     73       Info_ObjCProtocol,
     74       Info_ObjCCategory,
     75 
     76     Info_ObjCProperty,
     77 
     78     Info_CXXClass
     79   };
     80 
     81   DInfoKind Kind;
     82 
     83   EntityInfo EntInfo;
     84   ContainerInfo SemanticContainer;
     85   ContainerInfo LexicalContainer;
     86   ContainerInfo DeclAsContainer;
     87 
     88   DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer)
     89     : Kind(Info_Decl) {
     90     this->isRedeclaration = isRedeclaration;
     91     this->isDefinition = isDefinition;
     92     this->isContainer = isContainer;
     93     attributes = nullptr;
     94     numAttributes = 0;
     95     declAsContainer = semanticContainer = lexicalContainer = nullptr;
     96     flags = 0;
     97   }
     98   DeclInfo(DInfoKind K,
     99            bool isRedeclaration, bool isDefinition, bool isContainer)
    100     : Kind(K) {
    101     this->isRedeclaration = isRedeclaration;
    102     this->isDefinition = isDefinition;
    103     this->isContainer = isContainer;
    104     attributes = nullptr;
    105     numAttributes = 0;
    106     declAsContainer = semanticContainer = lexicalContainer = nullptr;
    107     flags = 0;
    108   }
    109 };
    110 
    111 struct ObjCContainerDeclInfo : public DeclInfo {
    112   CXIdxObjCContainerDeclInfo ObjCContDeclInfo;
    113 
    114   ObjCContainerDeclInfo(bool isForwardRef,
    115                         bool isRedeclaration,
    116                         bool isImplementation)
    117     : DeclInfo(Info_ObjCContainer, isRedeclaration,
    118                /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) {
    119     init(isForwardRef, isImplementation);
    120   }
    121   ObjCContainerDeclInfo(DInfoKind K,
    122                         bool isForwardRef,
    123                         bool isRedeclaration,
    124                         bool isImplementation)
    125     : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef,
    126                /*isContainer=*/!isForwardRef) {
    127     init(isForwardRef, isImplementation);
    128   }
    129 
    130   static bool classof(const DeclInfo *D) {
    131     return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
    132   }
    133 
    134 private:
    135   void init(bool isForwardRef, bool isImplementation) {
    136     if (isForwardRef)
    137       ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef;
    138     else if (isImplementation)
    139       ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation;
    140     else
    141       ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface;
    142   }
    143 };
    144 
    145 struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
    146   CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo;
    147   CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
    148 
    149   ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D)
    150     : ObjCContainerDeclInfo(Info_ObjCInterface,
    151                             /*isForwardRef=*/false,
    152                             /*isRedeclaration=*/D->getPreviousDecl() != nullptr,
    153                             /*isImplementation=*/false) { }
    154 
    155   static bool classof(const DeclInfo *D) {
    156     return D->Kind == Info_ObjCInterface;
    157   }
    158 };
    159 
    160 struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
    161   CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo;
    162 
    163   ObjCProtocolDeclInfo(const ObjCProtocolDecl *D)
    164     : ObjCContainerDeclInfo(Info_ObjCProtocol,
    165                             /*isForwardRef=*/false,
    166                             /*isRedeclaration=*/D->getPreviousDecl(),
    167                             /*isImplementation=*/false) { }
    168 
    169   static bool classof(const DeclInfo *D) {
    170     return D->Kind == Info_ObjCProtocol;
    171   }
    172 };
    173 
    174 struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
    175   CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo;
    176   CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
    177 
    178   explicit ObjCCategoryDeclInfo(bool isImplementation)
    179     : ObjCContainerDeclInfo(Info_ObjCCategory,
    180                             /*isForwardRef=*/false,
    181                             /*isRedeclaration=*/isImplementation,
    182                             /*isImplementation=*/isImplementation) { }
    183 
    184   static bool classof(const DeclInfo *D) {
    185     return D->Kind == Info_ObjCCategory;
    186   }
    187 };
    188 
    189 struct ObjCPropertyDeclInfo : public DeclInfo {
    190   CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo;
    191 
    192   ObjCPropertyDeclInfo()
    193     : DeclInfo(Info_ObjCProperty,
    194                /*isRedeclaration=*/false, /*isDefinition=*/false,
    195                /*isContainer=*/false) { }
    196 
    197   static bool classof(const DeclInfo *D) {
    198     return D->Kind == Info_ObjCProperty;
    199   }
    200 };
    201 
    202 struct CXXClassDeclInfo : public DeclInfo {
    203   CXIdxCXXClassDeclInfo CXXClassInfo;
    204 
    205   CXXClassDeclInfo(bool isRedeclaration, bool isDefinition)
    206     : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { }
    207 
    208   static bool classof(const DeclInfo *D) {
    209     return D->Kind == Info_CXXClass;
    210   }
    211 };
    212 
    213 struct AttrInfo : public CXIdxAttrInfo {
    214   const Attr *A;
    215 
    216   AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) {
    217     kind = Kind;
    218     cursor = C;
    219     loc = Loc;
    220     this->A = A;
    221   }
    222 };
    223 
    224 struct IBOutletCollectionInfo : public AttrInfo {
    225   EntityInfo ClassInfo;
    226   CXIdxIBOutletCollectionAttrInfo IBCollInfo;
    227 
    228   IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) :
    229     AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) {
    230     assert(C.kind == CXCursor_IBOutletCollectionAttr);
    231     IBCollInfo.objcClass = nullptr;
    232   }
    233 
    234   IBOutletCollectionInfo(const IBOutletCollectionInfo &other);
    235 
    236   static bool classof(const AttrInfo *A) {
    237     return A->kind == CXIdxAttr_IBOutletCollection;
    238   }
    239 };
    240 
    241 class AttrListInfo {
    242   ScratchAlloc SA;
    243 
    244   SmallVector<AttrInfo, 2> Attrs;
    245   SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs;
    246   SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
    247   unsigned ref_cnt;
    248 
    249   AttrListInfo(const AttrListInfo &) = delete;
    250   void operator=(const AttrListInfo &) = delete;
    251 public:
    252   AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx);
    253 
    254   static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D,
    255                                                  CXIndexDataConsumer &IdxCtx);
    256 
    257   const CXIdxAttrInfo *const *getAttrs() const {
    258     if (CXAttrs.empty())
    259       return nullptr;
    260     return CXAttrs.data();
    261   }
    262   unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); }
    263 
    264   /// \brief Retain/Release only useful when we allocate a AttrListInfo from the
    265   /// BumpPtrAllocator, and not from the stack; so that we keep a pointer
    266   // in the EntityInfo
    267   void Retain() { ++ref_cnt; }
    268   void Release() {
    269     assert (ref_cnt > 0 && "Reference count is already zero.");
    270     if (--ref_cnt == 0) {
    271       // Memory is allocated from a BumpPtrAllocator, no need to delete it.
    272       this->~AttrListInfo();
    273     }
    274   }
    275 };
    276 
    277 class CXIndexDataConsumer : public index::IndexDataConsumer {
    278   ASTContext *Ctx;
    279   CXClientData ClientData;
    280   IndexerCallbacks &CB;
    281   unsigned IndexOptions;
    282   CXTranslationUnit CXTU;
    283 
    284   typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy;
    285   typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer>
    286     ContainerMapTy;
    287   typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy;
    288 
    289   FileMapTy FileMap;
    290   ContainerMapTy ContainerMap;
    291   EntityMapTy EntityMap;
    292 
    293   typedef std::pair<const FileEntry *, const Decl *> RefFileOccurrence;
    294   llvm::DenseSet<RefFileOccurrence> RefFileOccurrences;
    295 
    296   llvm::BumpPtrAllocator StrScratch;
    297   unsigned StrAdapterCount;
    298   friend class ScratchAlloc;
    299 
    300   struct ObjCProtocolListInfo {
    301     SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos;
    302     SmallVector<EntityInfo, 4> ProtEntities;
    303     SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots;
    304 
    305     CXIdxObjCProtocolRefListInfo getListInfo() const {
    306       CXIdxObjCProtocolRefListInfo Info = { Prots.data(),
    307                                             (unsigned)Prots.size() };
    308       return Info;
    309     }
    310 
    311     ObjCProtocolListInfo(const ObjCProtocolList &ProtList,
    312                          CXIndexDataConsumer &IdxCtx,
    313                          ScratchAlloc &SA);
    314   };
    315 
    316   struct CXXBasesListInfo {
    317     SmallVector<CXIdxBaseClassInfo, 4> BaseInfos;
    318     SmallVector<EntityInfo, 4> BaseEntities;
    319     SmallVector<CXIdxBaseClassInfo *, 4> CXBases;
    320 
    321     const CXIdxBaseClassInfo *const *getBases() const {
    322       return CXBases.data();
    323     }
    324     unsigned getNumBases() const { return (unsigned)CXBases.size(); }
    325 
    326     CXXBasesListInfo(const CXXRecordDecl *D,
    327                      CXIndexDataConsumer &IdxCtx, ScratchAlloc &SA);
    328 
    329   private:
    330     SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const;
    331   };
    332 
    333   friend class AttrListInfo;
    334 
    335 public:
    336   CXIndexDataConsumer(CXClientData clientData, IndexerCallbacks &indexCallbacks,
    337                   unsigned indexOptions, CXTranslationUnit cxTU)
    338     : Ctx(nullptr), ClientData(clientData), CB(indexCallbacks),
    339       IndexOptions(indexOptions), CXTU(cxTU),
    340       StrScratch(), StrAdapterCount(0) { }
    341 
    342   ASTContext &getASTContext() const { return *Ctx; }
    343   CXTranslationUnit getCXTU() const { return CXTU; }
    344 
    345   void setASTContext(ASTContext &ctx);
    346   void setPreprocessor(Preprocessor &PP);
    347 
    348   bool shouldSuppressRefs() const {
    349     return IndexOptions & CXIndexOpt_SuppressRedundantRefs;
    350   }
    351 
    352   bool shouldIndexFunctionLocalSymbols() const {
    353     return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols;
    354   }
    355 
    356   bool shouldIndexImplicitTemplateInsts() const {
    357     return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
    358   }
    359 
    360   static bool isFunctionLocalDecl(const Decl *D);
    361 
    362   bool shouldAbort();
    363 
    364   bool hasDiagnosticCallback() const { return CB.diagnostic; }
    365 
    366   void enteredMainFile(const FileEntry *File);
    367 
    368   void ppIncludedFile(SourceLocation hashLoc,
    369                       StringRef filename, const FileEntry *File,
    370                       bool isImport, bool isAngled, bool isModuleImport);
    371 
    372   void importedModule(const ImportDecl *ImportD);
    373   void importedPCH(const FileEntry *File);
    374 
    375   void startedTranslationUnit();
    376 
    377   void indexDecl(const Decl *D);
    378 
    379   void indexTagDecl(const TagDecl *D);
    380 
    381   void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
    382                            const DeclContext *DC = nullptr);
    383 
    384   void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent,
    385                     const DeclContext *DC = nullptr);
    386 
    387   void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
    388                                    const NamedDecl *Parent,
    389                                    const DeclContext *DC = nullptr);
    390 
    391   void indexDeclContext(const DeclContext *DC);
    392 
    393   void indexBody(const Stmt *S, const NamedDecl *Parent,
    394                  const DeclContext *DC = nullptr);
    395 
    396   void indexDiagnostics();
    397 
    398   void handleDiagnosticSet(CXDiagnosticSet CXDiagSet);
    399 
    400   bool handleFunction(const FunctionDecl *FD);
    401 
    402   bool handleVar(const VarDecl *D);
    403 
    404   bool handleField(const FieldDecl *D);
    405 
    406   bool handleMSProperty(const MSPropertyDecl *D);
    407 
    408   bool handleEnumerator(const EnumConstantDecl *D);
    409 
    410   bool handleTagDecl(const TagDecl *D);
    411 
    412   bool handleTypedefName(const TypedefNameDecl *D);
    413 
    414   bool handleObjCInterface(const ObjCInterfaceDecl *D);
    415   bool handleObjCImplementation(const ObjCImplementationDecl *D);
    416 
    417   bool handleObjCProtocol(const ObjCProtocolDecl *D);
    418 
    419   bool handleObjCCategory(const ObjCCategoryDecl *D);
    420   bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D);
    421 
    422   bool handleObjCMethod(const ObjCMethodDecl *D);
    423 
    424   bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D);
    425   bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc,
    426                                    const DeclContext *LexicalDC);
    427 
    428   bool handleObjCProperty(const ObjCPropertyDecl *D);
    429 
    430   bool handleNamespace(const NamespaceDecl *D);
    431 
    432   bool handleClassTemplate(const ClassTemplateDecl *D);
    433   bool handleFunctionTemplate(const FunctionTemplateDecl *D);
    434   bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
    435 
    436   bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
    437                        const NamedDecl *Parent,
    438                        const DeclContext *DC,
    439                        const Expr *E = nullptr,
    440                        CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
    441 
    442   bool handleReference(const NamedDecl *D, SourceLocation Loc,
    443                        const NamedDecl *Parent,
    444                        const DeclContext *DC,
    445                        const Expr *E = nullptr,
    446                        CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
    447 
    448   bool isNotFromSourceFile(SourceLocation Loc) const;
    449 
    450   void indexTopLevelDecl(const Decl *D);
    451   void indexDeclGroupRef(DeclGroupRef DG);
    452 
    453   void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file,
    454                     unsigned *line, unsigned *column, unsigned *offset);
    455 
    456   CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const;
    457   void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container);
    458 
    459   CXIdxClientEntity getClientEntity(const Decl *D) const;
    460   void setClientEntity(const Decl *D, CXIdxClientEntity client);
    461 
    462   static bool isTemplateImplicitInstantiation(const Decl *D);
    463 
    464 private:
    465   bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
    466                            ArrayRef<index::SymbolRelation> Relations,
    467                            FileID FID, unsigned Offset,
    468                            ASTNodeInfo ASTNode) override;
    469 
    470   bool handleModuleOccurence(const ImportDecl *ImportD,
    471                              index::SymbolRoleSet Roles,
    472                              FileID FID, unsigned Offset) override;
    473 
    474   void finish() override;
    475 
    476   bool handleDecl(const NamedDecl *D,
    477                   SourceLocation Loc, CXCursor Cursor,
    478                   DeclInfo &DInfo,
    479                   const DeclContext *LexicalDC = nullptr,
    480                   const DeclContext *SemaDC = nullptr);
    481 
    482   bool handleObjCContainer(const ObjCContainerDecl *D,
    483                            SourceLocation Loc, CXCursor Cursor,
    484                            ObjCContainerDeclInfo &ContDInfo);
    485 
    486   bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD);
    487 
    488   bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc);
    489 
    490   const NamedDecl *getEntityDecl(const NamedDecl *D) const;
    491 
    492   const DeclContext *getEntityContainer(const Decl *D) const;
    493 
    494   CXIdxClientFile getIndexFile(const FileEntry *File);
    495 
    496   CXIdxLoc getIndexLoc(SourceLocation Loc) const;
    497 
    498   void getEntityInfo(const NamedDecl *D,
    499                      EntityInfo &EntityInfo,
    500                      ScratchAlloc &SA);
    501 
    502   void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
    503 
    504   CXCursor getCursor(const Decl *D) {
    505     return cxcursor::MakeCXCursor(D, CXTU);
    506   }
    507 
    508   CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
    509 
    510   static bool shouldIgnoreIfImplicit(const Decl *D);
    511 };
    512 
    513 inline ScratchAlloc::ScratchAlloc(CXIndexDataConsumer &idxCtx) : IdxCtx(idxCtx) {
    514   ++IdxCtx.StrAdapterCount;
    515 }
    516 inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) {
    517   ++IdxCtx.StrAdapterCount;
    518 }
    519 
    520 inline ScratchAlloc::~ScratchAlloc() {
    521   --IdxCtx.StrAdapterCount;
    522   if (IdxCtx.StrAdapterCount == 0)
    523     IdxCtx.StrScratch.Reset();
    524 }
    525 
    526 template <typename T>
    527 inline T *ScratchAlloc::allocate() {
    528   return IdxCtx.StrScratch.Allocate<T>();
    529 }
    530 
    531 }} // end clang::cxindex
    532 
    533 #endif
    534