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