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