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