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