IndexingContext.cpp revision 21ee5707e6e59d982d2f2ae28e079c7ff46dc519
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 const ObjCInterfaceDecl *Class = D->getClassInterface(); 210 ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, 211 /*isRedeclaration=*/!Class->isImplicitInterfaceDecl(), 212 /*isImplementation=*/true); 213 handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo); 214} 215 216void IndexingContext::handleObjCForwardProtocol(const ObjCProtocolDecl *D, 217 SourceLocation Loc, 218 bool isRedeclaration) { 219 ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, 220 isRedeclaration, 221 /*isImplementation=*/false); 222 handleObjCContainer(D, Loc, MakeCursorObjCProtocolRef(D, Loc, CXTU), 223 ContDInfo); 224} 225 226void IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) { 227 StrAdapter SA(*this); 228 ObjCProtocolListInfo ProtListInfo(D->getReferencedProtocols(), *this, SA); 229 230 ObjCProtocolDeclInfo ProtInfo(D); 231 ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); 232 233 handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo); 234} 235 236void IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) { 237 ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); 238 CXIdxEntityInfo ClassEntity; 239 StrAdapter SA(*this); 240 const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); 241 SourceLocation ClassLoc = D->getLocation(); 242 SourceLocation CategoryLoc = D->getCategoryNameLoc(); 243 getEntityInfo(D->getClassInterface(), ClassEntity, SA); 244 245 CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; 246 CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; 247 CatDInfo.ObjCCatDeclInfo.classCursor = 248 MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); 249 CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); 250 handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); 251} 252 253void IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { 254 const ObjCCategoryDecl *CatD = D->getCategoryDecl(); 255 ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); 256 CXIdxEntityInfo ClassEntity; 257 StrAdapter SA(*this); 258 getEntityInfo(CatD->getClassInterface(), ClassEntity, SA); 259 260 CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; 261 CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; 262 handleObjCContainer(D, D->getLocation(), getCursor(D), CatDInfo); 263} 264 265void IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) { 266 DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(), 267 D->isThisDeclarationADefinition()); 268 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 269} 270 271void IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) { 272 DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/false, 273 /*isContainer=*/false); 274 handleDecl(D, D->getLocation(), getCursor(D), DInfo); 275} 276 277void IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, 278 const NamedDecl *Parent, 279 const DeclContext *DC, 280 const Expr *E, 281 CXIdxEntityRefKind Kind) { 282 if (Loc.isInvalid()) 283 return; 284 if (!CB.indexEntityReference) 285 return; 286 if (isNotFromSourceFile(D->getLocation())) 287 return; 288 289 StrAdapter SA(*this); 290 CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E), 291 const_cast<Decl*>(cast<Decl>(DC)), CXTU) 292 : getRefCursor(D, Loc); 293 294 CXIdxEntityInfo RefEntity, ParentEntity; 295 getEntityInfo(D, RefEntity, SA); 296 getEntityInfo(Parent, ParentEntity, SA); 297 CXIdxEntityRefInfo Info = { Cursor, 298 getIndexLoc(Loc), 299 &RefEntity, 300 &ParentEntity, 301 getIndexContainerForDC(DC), 302 Kind }; 303 CB.indexEntityReference(ClientData, &Info); 304} 305 306bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const { 307 if (Loc.isInvalid()) 308 return true; 309 SourceManager &SM = Ctx->getSourceManager(); 310 SourceLocation FileLoc = SM.getFileLoc(Loc); 311 FileID FID = SM.getFileID(FileLoc); 312 return SM.getFileEntryForID(FID) == 0; 313} 314 315void IndexingContext::addContainerInMap(const DeclContext *DC, 316 CXIdxClientContainer container) { 317 assert(getScopedContext(DC) == DC); 318 ContainerMapTy::iterator I = ContainerMap.find(DC); 319 if (I == ContainerMap.end()) { 320 if (container) 321 ContainerMap[DC] = container; 322 return; 323 } 324 // Allow changing the container of a previously seen DeclContext so we 325 // can handle invalid user code, like a function re-definition. 326 if (container) 327 I->second = container; 328 else 329 ContainerMap.erase(I); 330} 331 332const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { 333 assert(D); 334 D = cast<NamedDecl>(D->getCanonicalDecl()); 335 336 if (const ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(D)) { 337 if (Cat->IsClassExtension()) 338 return getEntityDecl(Cat->getClassInterface()); 339 340 } else if (const ObjCImplementationDecl * 341 ImplD = dyn_cast<ObjCImplementationDecl>(D)) { 342 return getEntityDecl(ImplD->getClassInterface()); 343 344 } else if (const ObjCCategoryImplDecl * 345 CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) { 346 return getEntityDecl(CatImplD->getCategoryDecl()); 347 } 348 349 return D; 350} 351 352const DeclContext * 353IndexingContext::getScopedContext(const DeclContext *DC) const { 354 // Local contexts are ignored for indexing. 355 const DeclContext *FuncCtx = cast<Decl>(DC)->getParentFunctionOrMethod(); 356 if (FuncCtx) 357 return FuncCtx; 358 359 // We consider enums always scoped for indexing. 360 if (isa<TagDecl>(DC)) 361 return DC; 362 363 if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { 364 if (NS->isAnonymousNamespace()) 365 return getScopedContext(NS->getParent()); 366 return NS; 367 } 368 369 return DC->getRedeclContext(); 370} 371 372CXIdxClientContainer 373IndexingContext::getIndexContainerForDC(const DeclContext *DC) const { 374 DC = getScopedContext(DC); 375 ContainerMapTy::const_iterator I = ContainerMap.find(DC); 376// assert(I != ContainerMap.end() && 377// "Failed to include a scoped context in the container map"); 378 return I->second; 379} 380 381CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) { 382 if (!File) 383 return 0; 384 385 FileMapTy::iterator FI = FileMap.find(File); 386 if (FI != FileMap.end()) 387 return FI->second; 388 389 return 0; 390} 391 392CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const { 393 CXIdxLoc idxLoc = { {0, 0}, 0 }; 394 if (Loc.isInvalid()) 395 return idxLoc; 396 397 idxLoc.ptr_data[0] = (void*)this; 398 idxLoc.int_data = Loc.getRawEncoding(); 399 return idxLoc; 400} 401 402void IndexingContext::translateLoc(SourceLocation Loc, 403 CXIdxClientFile *indexFile, CXFile *file, 404 unsigned *line, unsigned *column, 405 unsigned *offset) { 406 if (Loc.isInvalid()) 407 return; 408 409 SourceManager &SM = Ctx->getSourceManager(); 410 Loc = SM.getFileLoc(Loc); 411 412 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 413 FileID FID = LocInfo.first; 414 unsigned FileOffset = LocInfo.second; 415 416 if (FID.isInvalid()) 417 return; 418 419 const FileEntry *FE = SM.getFileEntryForID(FID); 420 if (indexFile) 421 *indexFile = getIndexFile(FE); 422 if (file) 423 *file = (void *)FE; 424 if (line) 425 *line = SM.getLineNumber(FID, FileOffset); 426 if (column) 427 *column = SM.getColumnNumber(FID, FileOffset); 428 if (offset) 429 *offset = FileOffset; 430} 431 432void IndexingContext::getEntityInfo(const NamedDecl *D, 433 CXIdxEntityInfo &EntityInfo, 434 StrAdapter &SA) { 435 D = getEntityDecl(D); 436 EntityInfo.kind = CXIdxEntity_Unexposed; 437 438 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { 439 switch (TD->getTagKind()) { 440 case TTK_Struct: 441 EntityInfo.kind = CXIdxEntity_Struct; break; 442 case TTK_Union: 443 EntityInfo.kind = CXIdxEntity_Union; break; 444 case TTK_Class: 445 EntityInfo.kind = CXIdxEntity_CXXClass; break; 446 case TTK_Enum: 447 EntityInfo.kind = CXIdxEntity_Enum; break; 448 } 449 450 } else { 451 switch (D->getKind()) { 452 case Decl::Typedef: 453 EntityInfo.kind = CXIdxEntity_Typedef; break; 454 case Decl::Function: 455 EntityInfo.kind = CXIdxEntity_Function; break; 456 case Decl::Var: 457 EntityInfo.kind = CXIdxEntity_Variable; break; 458 case Decl::Field: 459 EntityInfo.kind = CXIdxEntity_Field; break; 460 case Decl::EnumConstant: 461 EntityInfo.kind = CXIdxEntity_EnumConstant; break; 462 case Decl::ObjCInterface: 463 EntityInfo.kind = CXIdxEntity_ObjCClass; break; 464 case Decl::ObjCProtocol: 465 EntityInfo.kind = CXIdxEntity_ObjCProtocol; break; 466 case Decl::ObjCCategory: 467 EntityInfo.kind = CXIdxEntity_ObjCCategory; break; 468 case Decl::ObjCMethod: 469 if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) 470 EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod; 471 else 472 EntityInfo.kind = CXIdxEntity_ObjCClassMethod; 473 break; 474 case Decl::ObjCProperty: 475 EntityInfo.kind = CXIdxEntity_ObjCProperty; break; 476 case Decl::ObjCIvar: 477 EntityInfo.kind = CXIdxEntity_ObjCIvar; break; 478 default: 479 break; 480 } 481 } 482 483 if (IdentifierInfo *II = D->getIdentifier()) { 484 EntityInfo.name = SA.toCStr(II->getName()); 485 486 } else if (isa<RecordDecl>(D) || isa<NamespaceDecl>(D)) { 487 EntityInfo.name = 0; // anonymous record/namespace. 488 489 } else { 490 unsigned Begin = SA.getCurSize(); 491 { 492 llvm::raw_svector_ostream OS(SA.getBuffer()); 493 D->printName(OS); 494 } 495 EntityInfo.name = SA.getCStr(Begin); 496 } 497 498 { 499 unsigned Begin = SA.getCurSize(); 500 bool Ignore = getDeclCursorUSR(D, SA.getBuffer()); 501 if (Ignore) { 502 EntityInfo.USR = ""; 503 } else { 504 EntityInfo.USR = SA.getCStr(Begin); 505 } 506 } 507} 508 509CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { 510 if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) 511 return MakeCursorTypeRef(TD, Loc, CXTU); 512 if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) 513 return MakeCursorObjCClassRef(ID, Loc, CXTU); 514 if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) 515 return MakeCursorObjCProtocolRef(PD, Loc, CXTU); 516 517 //assert(0 && "not yet"); 518 return clang_getNullCursor(); 519} 520