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