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