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