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