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