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