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