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