IndexingContext.cpp revision 144b6c0c50b5523609cbac523f168b9e3cb01175
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 "CXTranslationUnit.h" 12#include "CIndexDiagnostic.h" 13 14#include "clang/Frontend/ASTUnit.h" 15#include "clang/AST/DeclObjC.h" 16 17using namespace clang; 18using namespace cxindex; 19using namespace cxcursor; 20 21IndexingContext::ObjCProtocolListInfo::ObjCProtocolListInfo( 22 const ObjCProtocolList &ProtList, 23 IndexingContext &IdxCtx, 24 StrAdapter &SA) { 25 ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); 26 for (ObjCInterfaceDecl::protocol_iterator 27 I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { 28 SourceLocation Loc = *LI; 29 ObjCProtocolDecl *PD = *I; 30 ProtEntities.push_back(CXIdxEntityInfo()); 31 IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA); 32 CXIdxObjCProtocolRefInfo ProtInfo = { 0, 33 MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU), 34 IdxCtx.getIndexLoc(Loc) }; 35 ProtInfos.push_back(ProtInfo); 36 } 37 38 for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) 39 ProtInfos[i].protocol = &ProtEntities[i]; 40 41 for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) 42 Prots.push_back(&ProtInfos[i]); 43} 44 45const char *IndexingContext::StrAdapter::toCStr(StringRef Str) { 46 if (Str.empty()) 47 return ""; 48 if (Str.data()[Str.size()] == '\0') 49 return Str.data(); 50 Scratch += Str; 51 Scratch.push_back('\0'); 52 return Scratch.data() + (Scratch.size() - Str.size() - 1); 53} 54 55void IndexingContext::setASTContext(ASTContext &ctx) { 56 Ctx = &ctx; 57 static_cast<ASTUnit*>(CXTU->TUData)->setASTContext(&ctx); 58} 59 60void IndexingContext::enteredMainFile(const FileEntry *File) { 61 if (File && CB.enteredMainFile) { 62 CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0); 63 FileMap[File] = idxFile; 64 } 65} 66 67void IndexingContext::ppIncludedFile(SourceLocation hashLoc, 68 StringRef filename, 69 const FileEntry *File, 70 bool isImport, bool isAngled) { 71 if (!CB.ppIncludedFile) 72 return; 73 74 StrAdapter SA(*this); 75 CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc), 76 SA.toCStr(filename), 77 (CXFile)File, 78 isImport, isAngled }; 79 CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info); 80 FileMap[File] = idxFile; 81} 82 83void IndexingContext::startedTranslationUnit() { 84 CXIdxClientContainer idxCont = 0; 85 if (CB.startedTranslationUnit) 86 idxCont = CB.startedTranslationUnit(ClientData, 0); 87 addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); 88} 89 90void IndexingContext::handleDiagnostic(const StoredDiagnostic &StoredDiag) { 91 if (!CB.diagnostic) 92 return; 93 94 CXStoredDiagnostic CXDiag(StoredDiag, Ctx->getLangOptions()); 95 CB.diagnostic(ClientData, &CXDiag, 0); 96} 97 98void IndexingContext::handleDiagnostic(CXDiagnostic CXDiag) { 99 if (!CB.diagnostic) 100 return; 101 102 CB.diagnostic(ClientData, CXDiag, 0); 103} 104 105void IndexingContext::handleDecl(const NamedDecl *D, 106 SourceLocation Loc, CXCursor Cursor, 107 DeclInfo &DInfo) { 108 if (!CB.indexDeclaration || !D) 109 return; 110 111 StrAdapter SA(*this); 112 getEntityInfo(D, DInfo.CXEntInfo, SA); 113 if (!DInfo.CXEntInfo.USR || Loc.isInvalid()) 114 return; 115 116 DInfo.entityInfo = &DInfo.CXEntInfo; 117 DInfo.cursor = Cursor; 118 DInfo.loc = getIndexLoc(Loc); 119 DInfo.container = getIndexContainer(D); 120 DInfo.isImplicit = D->isImplicit(); 121 122 CXIdxClientContainer clientCont = 0; 123 CXIdxDeclOut DeclOut = { DInfo.isContainer ? &clientCont : 0 }; 124 CB.indexDeclaration(ClientData, &DInfo, &DeclOut); 125 126 if (DInfo.isContainer) 127 addContainerInMap(cast<DeclContext>(D), clientCont); 128} 129 130void IndexingContext::handleObjCContainer(const ObjCContainerDecl *D, 131 SourceLocation Loc, CXCursor Cursor, 132 ObjCContainerDeclInfo &ContDInfo) { 133 ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo; 134 handleDecl(D, Loc, Cursor, ContDInfo); 135} 136 137void IndexingContext::handleFunction(const FunctionDecl *D) { 138 DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), 139 D->isThisDeclarationADefinition()); 140 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 141} 142 143void IndexingContext::handleVar(const VarDecl *D) { 144 DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), 145 /*isContainer=*/false); 146 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 147} 148 149void IndexingContext::handleField(const FieldDecl *D) { 150 DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, 151 /*isContainer=*/false); 152 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 153} 154 155void IndexingContext::handleEnumerator(const EnumConstantDecl *D) { 156 DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, 157 /*isContainer=*/false); 158 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 159} 160 161void IndexingContext::handleTagDecl(const TagDecl *D) { 162 DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), 163 D->isThisDeclarationADefinition()); 164 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 165} 166 167void IndexingContext::handleTypedef(const TypedefDecl *D) { 168 DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true, 169 /*isContainer=*/false); 170 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 171} 172 173void IndexingContext::handleObjCClass(const ObjCClassDecl *D) { 174 const ObjCClassDecl::ObjCClassRef *Ref = D->getForwardDecl(); 175 ObjCInterfaceDecl *IFaceD = Ref->getInterface(); 176 SourceLocation Loc = Ref->getLocation(); 177 bool isRedeclaration = IFaceD->getLocation() != Loc; 178 179 ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, 180 /*isImplementation=*/false); 181 handleObjCContainer(IFaceD, Loc, MakeCursorObjCClassRef(IFaceD, Loc, CXTU), 182 ContDInfo); 183} 184 185void IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) { 186 StrAdapter SA(*this); 187 188 CXIdxBaseClassInfo BaseClass; 189 CXIdxEntityInfo BaseEntity; 190 BaseClass.cursor = clang_getNullCursor(); 191 if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) { 192 getEntityInfo(SuperD, BaseEntity, SA); 193 SourceLocation SuperLoc = D->getSuperClassLoc(); 194 BaseClass.base = &BaseEntity; 195 BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU); 196 BaseClass.loc = getIndexLoc(SuperLoc); 197 } 198 199 ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA); 200 201 ObjCInterfaceDeclInfo InterInfo(D); 202 InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); 203 InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo; 204 InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass : 0; 205 InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo; 206 207 handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo); 208} 209 210void IndexingContext::handleObjCImplementation( 211 const ObjCImplementationDecl *D) { 212 ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, 213 /*isRedeclaration=*/true, 214 /*isImplementation=*/true); 215 handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo); 216} 217 218void IndexingContext::handleObjCForwardProtocol(const ObjCProtocolDecl *D, 219 SourceLocation Loc, 220 bool isRedeclaration) { 221 ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, 222 isRedeclaration, 223 /*isImplementation=*/false); 224 handleObjCContainer(D, Loc, MakeCursorObjCProtocolRef(D, Loc, CXTU), 225 ContDInfo); 226} 227 228void IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) { 229 StrAdapter SA(*this); 230 ObjCProtocolListInfo ProtListInfo(D->getReferencedProtocols(), *this, SA); 231 232 ObjCProtocolDeclInfo ProtInfo(D); 233 ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); 234 235 handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo); 236} 237 238void IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) { 239 ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); 240 CXIdxEntityInfo ClassEntity; 241 StrAdapter SA(*this); 242 const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); 243 SourceLocation ClassLoc = D->getLocation(); 244 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 245 getEntityInfo(IFaceD, ClassEntity, SA); 246 247 CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; 248 if (IFaceD) { 249 CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; 250 CatDInfo.ObjCCatDeclInfo.classCursor = 251 MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); 252 } else { 253 CatDInfo.ObjCCatDeclInfo.objcClass = 0; 254 CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); 255 } 256 CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); 257 handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); 258} 259 260void IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { 261 const ObjCCategoryDecl *CatD = D->getCategoryDecl(); 262 ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); 263 CXIdxEntityInfo ClassEntity; 264 StrAdapter SA(*this); 265 const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface(); 266 SourceLocation ClassLoc = D->getLocation(); 267 SourceLocation CategoryLoc = ClassLoc; //FIXME: D->getCategoryNameLoc(); 268 getEntityInfo(IFaceD, ClassEntity, SA); 269 270 CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; 271 if (IFaceD) { 272 CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; 273 CatDInfo.ObjCCatDeclInfo.classCursor = 274 MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); 275 } else { 276 CatDInfo.ObjCCatDeclInfo.objcClass = 0; 277 CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); 278 } 279 CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); 280 handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); 281} 282 283void IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) { 284 DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(), 285 D->isThisDeclarationADefinition()); 286 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 287} 288 289void IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) { 290 DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/false, 291 /*isContainer=*/false); 292 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 293} 294 295void IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, 296 const NamedDecl *Parent, 297 const DeclContext *DC, 298 const Expr *E, 299 CXIdxEntityRefKind Kind) { 300 if (!D) 301 return; 302 if (D->getParentFunctionOrMethod()) 303 return; 304 if (Loc.isInvalid()) 305 return; 306 if (!CB.indexEntityReference) 307 return; 308 if (isNotFromSourceFile(D->getLocation())) 309 return; 310 311 D = getEntityDecl(D); 312 313 StrAdapter SA(*this); 314 CXIdxEntityInfo RefEntity, ParentEntity; 315 getEntityInfo(D, RefEntity, SA); 316 if (!RefEntity.USR) 317 return; 318 319 getEntityInfo(Parent, ParentEntity, SA); 320 321 if (onlyOneRefPerFile()) { 322 SourceManager &SM = Ctx->getSourceManager(); 323 SourceLocation FileLoc = SM.getFileLoc(Loc); 324 325 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 326 FileID FID = LocInfo.first; 327 if (FID.isInvalid()) 328 return; 329 330 const FileEntry *FE = SM.getFileEntryForID(FID); 331 if (!FE) 332 return; 333 RefFileOccurence RefOccur(FE, D); 334 std::pair<llvm::DenseSet<RefFileOccurence>::iterator, bool> 335 res = RefFileOccurences.insert(RefOccur); 336 if (!res.second) 337 return; // already in map. 338 } 339 340 CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E), 341 const_cast<Decl*>(cast<Decl>(DC)), CXTU) 342 : getRefCursor(D, Loc); 343 CXIdxEntityRefInfo Info = { Cursor, 344 getIndexLoc(Loc), 345 &RefEntity, 346 Parent ? &ParentEntity : 0, 347 getIndexContainerForDC(DC), 348 Kind }; 349 CB.indexEntityReference(ClientData, &Info); 350} 351 352bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const { 353 if (Loc.isInvalid()) 354 return true; 355 SourceManager &SM = Ctx->getSourceManager(); 356 SourceLocation FileLoc = SM.getFileLoc(Loc); 357 FileID FID = SM.getFileID(FileLoc); 358 return SM.getFileEntryForID(FID) == 0; 359} 360 361void IndexingContext::addContainerInMap(const DeclContext *DC, 362 CXIdxClientContainer container) { 363 assert(getScopedContext(DC) == DC); 364 ContainerMapTy::iterator I = ContainerMap.find(DC); 365 if (I == ContainerMap.end()) { 366 if (container) 367 ContainerMap[DC] = container; 368 return; 369 } 370 // Allow changing the container of a previously seen DeclContext so we 371 // can handle invalid user code, like a function re-definition. 372 if (container) 373 I->second = container; 374 else 375 ContainerMap.erase(I); 376} 377 378const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { 379 assert(D); 380 D = cast<NamedDecl>(D->getCanonicalDecl()); 381 382 if (const ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(D)) { 383 if (Cat->IsClassExtension()) 384 return getEntityDecl(Cat->getClassInterface()); 385 386 } else if (const ObjCImplementationDecl * 387 ImplD = dyn_cast<ObjCImplementationDecl>(D)) { 388 return getEntityDecl(ImplD->getClassInterface()); 389 390 } else if (const ObjCCategoryImplDecl * 391 CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) { 392 return getEntityDecl(CatImplD->getCategoryDecl()); 393 } 394 395 return D; 396} 397 398const DeclContext * 399IndexingContext::getScopedContext(const DeclContext *DC) const { 400 // Local contexts are ignored for indexing. 401 const DeclContext *FuncCtx = cast<Decl>(DC)->getParentFunctionOrMethod(); 402 if (FuncCtx) 403 return FuncCtx; 404 405 // We consider enums always scoped for indexing. 406 if (isa<TagDecl>(DC)) 407 return DC; 408 409 if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { 410 if (NS->isAnonymousNamespace()) 411 return getScopedContext(NS->getParent()); 412 return NS; 413 } 414 415 return DC->getRedeclContext(); 416} 417 418CXIdxClientContainer 419IndexingContext::getIndexContainerForDC(const DeclContext *DC) const { 420 DC = getScopedContext(DC); 421 ContainerMapTy::const_iterator I = ContainerMap.find(DC); 422 if (I == ContainerMap.end()) 423 return 0; 424// assert(I != ContainerMap.end() && 425// "Failed to include a scoped context in the container map"); 426 return I->second; 427} 428 429CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) { 430 if (!File) 431 return 0; 432 433 FileMapTy::iterator FI = FileMap.find(File); 434 if (FI != FileMap.end()) 435 return FI->second; 436 437 return 0; 438} 439 440CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const { 441 CXIdxLoc idxLoc = { {0, 0}, 0 }; 442 if (Loc.isInvalid()) 443 return idxLoc; 444 445 idxLoc.ptr_data[0] = (void*)this; 446 idxLoc.int_data = Loc.getRawEncoding(); 447 return idxLoc; 448} 449 450void IndexingContext::translateLoc(SourceLocation Loc, 451 CXIdxClientFile *indexFile, CXFile *file, 452 unsigned *line, unsigned *column, 453 unsigned *offset) { 454 if (Loc.isInvalid()) 455 return; 456 457 SourceManager &SM = Ctx->getSourceManager(); 458 Loc = SM.getFileLoc(Loc); 459 460 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 461 FileID FID = LocInfo.first; 462 unsigned FileOffset = LocInfo.second; 463 464 if (FID.isInvalid()) 465 return; 466 467 const FileEntry *FE = SM.getFileEntryForID(FID); 468 if (indexFile) 469 *indexFile = getIndexFile(FE); 470 if (file) 471 *file = (void *)FE; 472 if (line) 473 *line = SM.getLineNumber(FID, FileOffset); 474 if (column) 475 *column = SM.getColumnNumber(FID, FileOffset); 476 if (offset) 477 *offset = FileOffset; 478} 479 480void IndexingContext::getEntityInfo(const NamedDecl *D, 481 CXIdxEntityInfo &EntityInfo, 482 StrAdapter &SA) { 483 if (!D) 484 return; 485 D = getEntityDecl(D); 486 EntityInfo.kind = CXIdxEntity_Unexposed; 487 488 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { 489 switch (TD->getTagKind()) { 490 case TTK_Struct: 491 EntityInfo.kind = CXIdxEntity_Struct; break; 492 case TTK_Union: 493 EntityInfo.kind = CXIdxEntity_Union; break; 494 case TTK_Class: 495 EntityInfo.kind = CXIdxEntity_CXXClass; break; 496 case TTK_Enum: 497 EntityInfo.kind = CXIdxEntity_Enum; break; 498 } 499 500 } else { 501 switch (D->getKind()) { 502 case Decl::Typedef: 503 EntityInfo.kind = CXIdxEntity_Typedef; break; 504 case Decl::Function: 505 EntityInfo.kind = CXIdxEntity_Function; break; 506 case Decl::Var: 507 EntityInfo.kind = CXIdxEntity_Variable; break; 508 case Decl::Field: 509 EntityInfo.kind = CXIdxEntity_Field; break; 510 case Decl::EnumConstant: 511 EntityInfo.kind = CXIdxEntity_EnumConstant; break; 512 case Decl::ObjCInterface: 513 EntityInfo.kind = CXIdxEntity_ObjCClass; break; 514 case Decl::ObjCProtocol: 515 EntityInfo.kind = CXIdxEntity_ObjCProtocol; break; 516 case Decl::ObjCCategory: 517 EntityInfo.kind = CXIdxEntity_ObjCCategory; break; 518 case Decl::ObjCMethod: 519 if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) 520 EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod; 521 else 522 EntityInfo.kind = CXIdxEntity_ObjCClassMethod; 523 break; 524 case Decl::ObjCProperty: 525 EntityInfo.kind = CXIdxEntity_ObjCProperty; break; 526 case Decl::ObjCIvar: 527 EntityInfo.kind = CXIdxEntity_ObjCIvar; break; 528 default: 529 break; 530 } 531 } 532 533 if (IdentifierInfo *II = D->getIdentifier()) { 534 EntityInfo.name = SA.toCStr(II->getName()); 535 536 } else if (isa<RecordDecl>(D) || isa<NamespaceDecl>(D)) { 537 EntityInfo.name = 0; // anonymous record/namespace. 538 539 } else { 540 unsigned Begin = SA.getCurSize(); 541 { 542 llvm::raw_svector_ostream OS(SA.getBuffer()); 543 D->printName(OS); 544 } 545 EntityInfo.name = SA.getCStr(Begin); 546 } 547 548 { 549 unsigned Begin = SA.getCurSize(); 550 bool Ignore = getDeclCursorUSR(D, SA.getBuffer()); 551 if (Ignore) { 552 EntityInfo.USR = 0; 553 } else { 554 EntityInfo.USR = SA.getCStr(Begin); 555 } 556 } 557} 558 559CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { 560 if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) 561 return MakeCursorTypeRef(TD, Loc, CXTU); 562 if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) 563 return MakeCursorObjCClassRef(ID, Loc, CXTU); 564 if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) 565 return MakeCursorObjCProtocolRef(PD, Loc, CXTU); 566 567 //assert(0 && "not yet"); 568 return clang_getNullCursor(); 569} 570