blob: c4fba968492fc34db80f1d24785a81e59730fa10 [file] [log] [blame]
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +00001//===- 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 "CXCursor.h"
12#include "CXSourceLocation.h"
13#include "CXTranslationUnit.h"
14#include "CXString.h"
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +000015#include "CIndexDiagnostic.h"
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000016#include "CIndexer.h"
17
18#include "clang/Frontend/ASTUnit.h"
19#include "clang/Frontend/CompilerInvocation.h"
20#include "clang/Frontend/CompilerInstance.h"
Douglas Gregor1f6b2b52012-01-20 16:28:04 +000021#include "clang/Frontend/FrontendAction.h"
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000022#include "clang/Frontend/Utils.h"
23#include "clang/Sema/SemaConsumer.h"
24#include "clang/AST/ASTConsumer.h"
25#include "clang/AST/DeclVisitor.h"
26#include "clang/Lex/Preprocessor.h"
27#include "clang/Lex/PPCallbacks.h"
28#include "llvm/Support/MemoryBuffer.h"
29#include "llvm/Support/CrashRecoveryContext.h"
30
31using namespace clang;
32using namespace cxstring;
33using namespace cxtu;
34using namespace cxindex;
35
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +000036static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx);
37
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000038namespace {
39
40//===----------------------------------------------------------------------===//
41// IndexPPCallbacks
42//===----------------------------------------------------------------------===//
43
44class IndexPPCallbacks : public PPCallbacks {
45 Preprocessor &PP;
46 IndexingContext &IndexCtx;
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +000047 bool IsMainFileEntered;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000048
49public:
50 IndexPPCallbacks(Preprocessor &PP, IndexingContext &indexCtx)
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +000051 : PP(PP), IndexCtx(indexCtx), IsMainFileEntered(false) { }
52
53 virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
54 SrcMgr::CharacteristicKind FileType, FileID PrevFID) {
55 if (IsMainFileEntered)
56 return;
57
58 SourceManager &SM = PP.getSourceManager();
59 SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID());
60
61 if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) {
62 IsMainFileEntered = true;
63 IndexCtx.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID()));
64 }
65 }
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000066
67 virtual void InclusionDirective(SourceLocation HashLoc,
68 const Token &IncludeTok,
69 StringRef FileName,
70 bool IsAngled,
Argyrios Kyrtzidisda313592012-09-27 01:42:07 +000071 CharSourceRange FilenameRange,
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000072 const FileEntry *File,
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000073 StringRef SearchPath,
Argyrios Kyrtzidisf8afcff2012-09-29 01:06:10 +000074 StringRef RelativePath,
75 const Module *Imported) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000076 bool isImport = (IncludeTok.is(tok::identifier) &&
77 IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
78 IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled);
79 }
80
81 /// MacroDefined - This hook is called whenever a macro definition is seen.
82 virtual void MacroDefined(const Token &Id, const MacroInfo *MI) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000083 }
84
85 /// MacroUndefined - This hook is called whenever a macro #undef is seen.
86 /// MI is released immediately following this callback.
87 virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000088 }
89
90 /// MacroExpands - This is called by when a macro invocation is found.
91 virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
92 SourceRange Range) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +000093 }
94
95 /// SourceRangeSkipped - This hook is called when a source range is skipped.
96 /// \param Range The SourceRange that was skipped. The range begins at the
97 /// #if/#else directive and ends after the #endif/#else directive.
98 virtual void SourceRangeSkipped(SourceRange Range) {
99 }
100};
101
102//===----------------------------------------------------------------------===//
103// IndexingConsumer
104//===----------------------------------------------------------------------===//
105
106class IndexingConsumer : public ASTConsumer {
107 IndexingContext &IndexCtx;
108
109public:
110 explicit IndexingConsumer(IndexingContext &indexCtx)
111 : IndexCtx(indexCtx) { }
112
113 // ASTConsumer Implementation
114
115 virtual void Initialize(ASTContext &Context) {
116 IndexCtx.setASTContext(Context);
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000117 IndexCtx.startedTranslationUnit();
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000118 }
119
120 virtual void HandleTranslationUnit(ASTContext &Ctx) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000121 }
122
Argyrios Kyrtzidis88c25962011-11-18 00:26:59 +0000123 virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000124 IndexCtx.indexDeclGroupRef(DG);
Argyrios Kyrtzidis88c25962011-11-18 00:26:59 +0000125 return !IndexCtx.shouldAbort();
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000126 }
127
128 /// \brief Handle the specified top-level declaration that occurred inside
129 /// and ObjC container.
130 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
131 // They will be handled after the interface is seen first.
132 IndexCtx.addTUDeclInObjCContainer(D);
133 }
134
135 /// \brief This is called by the AST reader when deserializing things.
136 /// The default implementation forwards to HandleTopLevelDecl but we don't
137 /// care about them when indexing, so have an empty definition.
138 virtual void HandleInterestingDecl(DeclGroupRef D) {}
Argyrios Kyrtzidis6d968362012-02-10 20:10:44 +0000139
140 virtual void HandleTagDeclDefinition(TagDecl *D) {
Argyrios Kyrtzidis58d2dbe2012-02-14 22:23:11 +0000141 if (!IndexCtx.shouldIndexImplicitTemplateInsts())
142 return;
143
Argyrios Kyrtzidis6d968362012-02-10 20:10:44 +0000144 if (IndexCtx.isTemplateImplicitInstantiation(D))
145 IndexCtx.indexDecl(D);
146 }
147
148 virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
Argyrios Kyrtzidis58d2dbe2012-02-14 22:23:11 +0000149 if (!IndexCtx.shouldIndexImplicitTemplateInsts())
150 return;
151
Argyrios Kyrtzidis6d968362012-02-10 20:10:44 +0000152 IndexCtx.indexDecl(D);
153 }
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000154};
155
156//===----------------------------------------------------------------------===//
Argyrios Kyrtzidisb395c632011-11-18 00:26:51 +0000157// CaptureDiagnosticConsumer
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000158//===----------------------------------------------------------------------===//
159
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000160class CaptureDiagnosticConsumer : public DiagnosticConsumer {
161 SmallVector<StoredDiagnostic, 4> Errors;
162public:
163
164 virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
165 const Diagnostic &Info) {
166 if (level >= DiagnosticsEngine::Error)
167 Errors.push_back(StoredDiagnostic(level, Info));
168 }
169
170 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
171 return new IgnoringDiagConsumer();
172 }
173};
174
175//===----------------------------------------------------------------------===//
176// IndexingFrontendAction
177//===----------------------------------------------------------------------===//
178
179class IndexingFrontendAction : public ASTFrontendAction {
180 IndexingContext IndexCtx;
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +0000181 CXTranslationUnit CXTU;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000182
183public:
184 IndexingFrontendAction(CXClientData clientData,
185 IndexerCallbacks &indexCallbacks,
186 unsigned indexOptions,
187 CXTranslationUnit cxTU)
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +0000188 : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
189 CXTU(cxTU) { }
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000190
191 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
192 StringRef InFile) {
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000193 IndexCtx.setASTContext(CI.getASTContext());
194 Preprocessor &PP = CI.getPreprocessor();
195 PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
Argyrios Kyrtzidis7fe90f32012-01-17 18:48:07 +0000196 IndexCtx.setPreprocessor(PP);
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000197 return new IndexingConsumer(IndexCtx);
198 }
199
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +0000200 virtual void EndSourceFileAction() {
201 indexDiagnostics(CXTU, IndexCtx);
202 }
203
Argyrios Kyrtzidis58d2dbe2012-02-14 22:23:11 +0000204 virtual TranslationUnitKind getTranslationUnitKind() {
205 if (IndexCtx.shouldIndexImplicitTemplateInsts())
206 return TU_Complete;
207 else
208 return TU_Prefix;
209 }
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000210 virtual bool hasCodeCompletionSupport() const { return false; }
211};
212
213//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000214// clang_indexSourceFileUnit Implementation
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000215//===----------------------------------------------------------------------===//
216
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000217struct IndexSourceFileInfo {
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000218 CXIndexAction idxAction;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000219 CXClientData client_data;
220 IndexerCallbacks *index_callbacks;
221 unsigned index_callbacks_size;
222 unsigned index_options;
223 const char *source_filename;
224 const char *const *command_line_args;
225 int num_command_line_args;
226 struct CXUnsavedFile *unsaved_files;
227 unsigned num_unsaved_files;
228 CXTranslationUnit *out_TU;
229 unsigned TU_options;
230 int result;
231};
232
233struct MemBufferOwner {
234 SmallVector<const llvm::MemoryBuffer *, 8> Buffers;
235
236 ~MemBufferOwner() {
237 for (SmallVectorImpl<const llvm::MemoryBuffer *>::iterator
238 I = Buffers.begin(), E = Buffers.end(); I != E; ++I)
239 delete *I;
240 }
241};
242
243} // anonymous namespace
244
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000245static void clang_indexSourceFile_Impl(void *UserData) {
246 IndexSourceFileInfo *ITUI =
247 static_cast<IndexSourceFileInfo*>(UserData);
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000248 CXIndex CIdx = (CXIndex)ITUI->idxAction;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000249 CXClientData client_data = ITUI->client_data;
250 IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
251 unsigned index_callbacks_size = ITUI->index_callbacks_size;
252 unsigned index_options = ITUI->index_options;
253 const char *source_filename = ITUI->source_filename;
254 const char * const *command_line_args = ITUI->command_line_args;
255 int num_command_line_args = ITUI->num_command_line_args;
256 struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files;
257 unsigned num_unsaved_files = ITUI->num_unsaved_files;
258 CXTranslationUnit *out_TU = ITUI->out_TU;
259 unsigned TU_options = ITUI->TU_options;
260 ITUI->result = 1; // init as error.
261
262 if (out_TU)
263 *out_TU = 0;
264 bool requestedToGetTU = (out_TU != 0);
265
266 if (!CIdx)
267 return;
268 if (!client_index_callbacks || index_callbacks_size == 0)
269 return;
270
271 IndexerCallbacks CB;
272 memset(&CB, 0, sizeof(CB));
273 unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
274 ? index_callbacks_size : sizeof(CB);
275 memcpy(&CB, client_index_callbacks, ClientCBSize);
276
277 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
278
Argyrios Kyrtzidisfdc17952012-03-28 02:18:05 +0000279 if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
Argyrios Kyrtzidis81b5ac32012-03-28 02:49:54 +0000280 setThreadBackgroundPriority();
Argyrios Kyrtzidisfdc17952012-03-28 02:18:05 +0000281
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000282 CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
283
284 // Configure the diagnostics.
285 DiagnosticOptions DiagOpts;
Dylan Noblesmithc93dc782012-02-20 14:00:23 +0000286 IntrusiveRefCntPtr<DiagnosticsEngine>
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000287 Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
288 command_line_args,
289 CaptureDiag,
Argyrios Kyrtzidis73835502011-11-29 08:14:50 +0000290 /*ShouldOwnClient=*/true,
291 /*ShouldCloneClient=*/false));
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000292
293 // Recover resources if we crash before exiting this function.
294 llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
295 llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
296 DiagCleanup(Diags.getPtr());
297
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000298 OwningPtr<std::vector<const char *> >
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000299 Args(new std::vector<const char*>());
300
301 // Recover resources if we crash before exiting this method.
302 llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
303 ArgsCleanup(Args.get());
304
305 Args->insert(Args->end(), command_line_args,
306 command_line_args + num_command_line_args);
307
308 // The 'source_filename' argument is optional. If the caller does not
309 // specify it then it is assumed that the source file is specified
310 // in the actual argument list.
311 // Put the source file after command_line_args otherwise if '-x' flag is
312 // present it will be unused.
313 if (source_filename)
314 Args->push_back(source_filename);
315
Dylan Noblesmithc93dc782012-02-20 14:00:23 +0000316 IntrusiveRefCntPtr<CompilerInvocation>
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000317 CInvok(createInvocationFromCommandLine(*Args, Diags));
318
319 if (!CInvok)
320 return;
321
322 // Recover resources if we crash before exiting this function.
323 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
324 llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
325 CInvokCleanup(CInvok.getPtr());
326
327 if (CInvok->getFrontendOpts().Inputs.empty())
328 return;
329
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000330 OwningPtr<MemBufferOwner> BufOwner(new MemBufferOwner());
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000331
332 // Recover resources if we crash before exiting this method.
333 llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner>
334 BufOwnerCleanup(BufOwner.get());
335
336 for (unsigned I = 0; I != num_unsaved_files; ++I) {
337 StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
338 const llvm::MemoryBuffer *Buffer
339 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
340 CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer);
341 BufOwner->Buffers.push_back(Buffer);
342 }
343
344 // Since libclang is primarily used by batch tools dealing with
345 // (often very broken) source code, where spell-checking can have a
346 // significant negative impact on performance (particularly when
347 // precompiled headers are involved), we disable it.
Ted Kremenekd3b74d92011-11-17 23:01:24 +0000348 CInvok->getLangOpts()->SpellChecking = false;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000349
350 if (!requestedToGetTU)
351 CInvok->getPreprocessorOpts().DetailedRecord = false;
352
Argyrios Kyrtzidisb49a29f2012-03-27 21:38:03 +0000353 if (index_options & CXIndexOpt_SuppressWarnings)
354 CInvok->getDiagnosticOpts().IgnoreWarnings = true;
355
Argyrios Kyrtzidis991bf492011-11-28 04:55:55 +0000356 ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
Argyrios Kyrtzidisff398962012-07-11 20:59:04 +0000357 /*CaptureDiagnostics=*/true,
358 /*UserFilesAreVolatile=*/true);
Argyrios Kyrtzidisfdc17952012-03-28 02:18:05 +0000359 OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000360
361 // Recover resources if we crash before exiting this method.
362 llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
363 CXTUCleanup(CXTU.get());
364
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000365 OwningPtr<IndexingFrontendAction> IndexAction;
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000366 IndexAction.reset(new IndexingFrontendAction(client_data, CB,
367 index_options, CXTU->getTU()));
368
369 // Recover resources if we crash before exiting this method.
370 llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction>
371 IndexActionCleanup(IndexAction.get());
372
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000373 bool Persistent = requestedToGetTU;
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000374 bool OnlyLocalDecls = false;
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000375 bool PrecompilePreamble = false;
376 bool CacheCodeCompletionResults = false;
377 PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
378 PPOpts.DetailedRecord = false;
Argyrios Kyrtzidisbef35c92012-03-07 01:51:17 +0000379 PPOpts.AllowPCHWithCompilerErrors = true;
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000380
381 if (requestedToGetTU) {
382 OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
383 PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
384 // FIXME: Add a flag for modules.
385 CacheCodeCompletionResults
386 = TU_options & CXTranslationUnit_CacheCompletionResults;
387 if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
388 PPOpts.DetailedRecord = true;
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000389 }
390 }
391
Argyrios Kyrtzidise722ed62012-04-11 02:11:16 +0000392 DiagnosticErrorTrap DiagTrap(*Diags);
393 bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags,
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000394 IndexAction.get(),
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000395 Unit,
396 Persistent,
Argyrios Kyrtzidis37918142012-06-28 21:03:08 +0000397 CXXIdx->getClangResourcesPath(),
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000398 OnlyLocalDecls,
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +0000399 /*CaptureDiagnostics=*/true,
Argyrios Kyrtzidis6f3ce972011-11-28 04:56:00 +0000400 PrecompilePreamble,
Argyrios Kyrtzidisff398962012-07-11 20:59:04 +0000401 CacheCodeCompletionResults,
402 /*IncludeBriefCommentsInCodeCompletion=*/false,
403 /*UserFilesAreVolatile=*/true);
Argyrios Kyrtzidise722ed62012-04-11 02:11:16 +0000404 if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
405 printDiagsToStderr(Unit);
406
407 if (!Success)
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000408 return;
409
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000410 if (out_TU)
411 *out_TU = CXTU->takeTU();
412
413 ITUI->result = 0; // success.
414}
415
416//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000417// clang_indexTranslationUnit Implementation
418//===----------------------------------------------------------------------===//
419
420namespace {
421
422struct IndexTranslationUnitInfo {
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000423 CXIndexAction idxAction;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000424 CXClientData client_data;
425 IndexerCallbacks *index_callbacks;
426 unsigned index_callbacks_size;
427 unsigned index_options;
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000428 CXTranslationUnit TU;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000429 int result;
430};
431
432} // anonymous namespace
433
434static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) {
435 Preprocessor &PP = Unit.getPreprocessor();
436 if (!PP.getPreprocessingRecord())
437 return;
438
439 PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
440
441 // FIXME: Only deserialize inclusion directives.
442 // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
443 // that it depends on.
444
445 bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
446 PreprocessingRecord::iterator I, E;
447 if (OnlyLocal) {
448 I = PPRec.local_begin();
449 E = PPRec.local_end();
450 } else {
451 I = PPRec.begin();
452 E = PPRec.end();
453 }
454
455 for (; I != E; ++I) {
456 PreprocessedEntity *PPE = *I;
457
458 if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
459 IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(),
460 ID->getFile(), ID->getKind() == InclusionDirective::Import,
461 !ID->wasInQuotes());
462 }
463 }
464}
465
466static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
467 // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
468 // that it depends on.
469
470 bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
471
472 if (OnlyLocal) {
473 for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(),
474 TLEnd = Unit.top_level_end();
475 TL != TLEnd; ++TL) {
476 IdxCtx.indexTopLevelDecl(*TL);
Argyrios Kyrtzidisb395c632011-11-18 00:26:51 +0000477 if (IdxCtx.shouldAbort())
478 return;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000479 }
480
481 } else {
482 TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl();
483 for (TranslationUnitDecl::decl_iterator
484 I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) {
485 IdxCtx.indexTopLevelDecl(*I);
Argyrios Kyrtzidisb395c632011-11-18 00:26:51 +0000486 if (IdxCtx.shouldAbort())
487 return;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000488 }
489 }
490}
491
492static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) {
Argyrios Kyrtzidis996e6e52011-12-01 02:42:50 +0000493 if (!IdxCtx.hasDiagnosticCallback())
494 return;
495
496 CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU);
497 IdxCtx.handleDiagnosticSet(DiagSet);
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000498}
499
500static void clang_indexTranslationUnit_Impl(void *UserData) {
501 IndexTranslationUnitInfo *ITUI =
502 static_cast<IndexTranslationUnitInfo*>(UserData);
503 CXTranslationUnit TU = ITUI->TU;
504 CXClientData client_data = ITUI->client_data;
505 IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
506 unsigned index_callbacks_size = ITUI->index_callbacks_size;
507 unsigned index_options = ITUI->index_options;
508 ITUI->result = 1; // init as error.
509
510 if (!TU)
511 return;
512 if (!client_index_callbacks || index_callbacks_size == 0)
513 return;
514
Argyrios Kyrtzidisfdc17952012-03-28 02:18:05 +0000515 CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
516 if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
Argyrios Kyrtzidis81b5ac32012-03-28 02:49:54 +0000517 setThreadBackgroundPriority();
Argyrios Kyrtzidisfdc17952012-03-28 02:18:05 +0000518
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000519 IndexerCallbacks CB;
520 memset(&CB, 0, sizeof(CB));
521 unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
522 ? index_callbacks_size : sizeof(CB);
523 memcpy(&CB, client_index_callbacks, ClientCBSize);
524
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000525 OwningPtr<IndexingContext> IndexCtx;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000526 IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU));
527
528 // Recover resources if we crash before exiting this method.
529 llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext>
530 IndexCtxCleanup(IndexCtx.get());
531
Dylan Noblesmith1e4c01b2012-02-13 12:32:21 +0000532 OwningPtr<IndexingConsumer> IndexConsumer;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000533 IndexConsumer.reset(new IndexingConsumer(*IndexCtx));
534
535 // Recover resources if we crash before exiting this method.
536 llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer>
537 IndexConsumerCleanup(IndexConsumer.get());
538
539 ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
540 if (!Unit)
541 return;
542
Argyrios Kyrtzidis162884d2012-09-25 19:29:50 +0000543 ASTUnit::ConcurrencyCheck Check(*Unit);
544
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000545 FileManager &FileMgr = Unit->getFileManager();
546
547 if (Unit->getOriginalSourceFileName().empty())
548 IndexCtx->enteredMainFile(0);
549 else
550 IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName()));
551
552 IndexConsumer->Initialize(Unit->getASTContext());
553
554 indexPreprocessingRecord(*Unit, *IndexCtx);
555 indexTranslationUnit(*Unit, *IndexCtx);
556 indexDiagnostics(TU, *IndexCtx);
557
558 ITUI->result = 0;
559}
560
561//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000562// libclang public APIs.
563//===----------------------------------------------------------------------===//
564
565extern "C" {
566
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +0000567int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
568 return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
569}
570
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000571const CXIdxObjCContainerDeclInfo *
572clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) {
573 if (!DInfo)
574 return 0;
575
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000576 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
577 if (const ObjCContainerDeclInfo *
578 ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI))
579 return &ContInfo->ObjCContDeclInfo;
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +0000580
581 return 0;
582}
583
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000584const CXIdxObjCInterfaceDeclInfo *
585clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) {
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000586 if (!DInfo)
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000587 return 0;
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +0000588
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000589 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
590 if (const ObjCInterfaceDeclInfo *
591 InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
592 return &InterInfo->ObjCInterDeclInfo;
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000593
594 return 0;
595}
596
597const CXIdxObjCCategoryDeclInfo *
598clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000599 if (!DInfo)
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000600 return 0;
601
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000602 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
603 if (const ObjCCategoryDeclInfo *
604 CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
605 return &CatInfo->ObjCCatDeclInfo;
606
607 return 0;
608}
609
610const CXIdxObjCProtocolRefListInfo *
611clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) {
612 if (!DInfo)
613 return 0;
614
615 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
616
617 if (const ObjCInterfaceDeclInfo *
618 InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
619 return InterInfo->ObjCInterDeclInfo.protocols;
620
621 if (const ObjCProtocolDeclInfo *
622 ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI))
623 return &ProtInfo->ObjCProtoRefListInfo;
624
Argyrios Kyrtzidisc10a4c82011-12-13 18:47:45 +0000625 if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
626 return CatInfo->ObjCCatDeclInfo.protocols;
627
Argyrios Kyrtzidisc71d5542011-11-14 22:39:19 +0000628 return 0;
Argyrios Kyrtzidis6ec43ad2011-11-12 02:16:30 +0000629}
630
Argyrios Kyrtzidis792db262012-02-28 17:50:33 +0000631const CXIdxObjCPropertyDeclInfo *
632clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) {
633 if (!DInfo)
634 return 0;
635
636 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
637 if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI))
638 return &PropInfo->ObjCPropDeclInfo;
639
640 return 0;
641}
642
Argyrios Kyrtzidisb395c632011-11-18 00:26:51 +0000643const CXIdxIBOutletCollectionAttrInfo *
644clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) {
645 if (!AInfo)
646 return 0;
647
648 const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo);
649 if (const IBOutletCollectionInfo *
650 IBInfo = dyn_cast<IBOutletCollectionInfo>(DI))
651 return &IBInfo->IBCollInfo;
652
653 return 0;
654}
655
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000656const CXIdxCXXClassDeclInfo *
657clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) {
658 if (!DInfo)
659 return 0;
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000660
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000661 const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
662 if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI))
663 return &ClassInfo->CXXClassInfo;
664
665 return 0;
666}
667
668CXIdxClientContainer
669clang_index_getClientContainer(const CXIdxContainerInfo *info) {
670 if (!info)
671 return 0;
Benjamin Kramer3267e112011-11-29 12:31:20 +0000672 const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000673 return Container->IndexCtx->getClientContainerForDC(Container->DC);
674}
675
676void clang_index_setClientContainer(const CXIdxContainerInfo *info,
677 CXIdxClientContainer client) {
678 if (!info)
679 return;
Benjamin Kramer3267e112011-11-29 12:31:20 +0000680 const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000681 Container->IndexCtx->addContainerInMap(Container->DC, client);
682}
683
684CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) {
685 if (!info)
686 return 0;
Benjamin Kramer3267e112011-11-29 12:31:20 +0000687 const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000688 return Entity->IndexCtx->getClientEntity(Entity->Dcl);
689}
690
691void clang_index_setClientEntity(const CXIdxEntityInfo *info,
692 CXIdxClientEntity client) {
693 if (!info)
694 return;
Benjamin Kramer3267e112011-11-29 12:31:20 +0000695 const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000696 Entity->IndexCtx->setClientEntity(Entity->Dcl, client);
697}
698
699CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
700 // For now, CXIndexAction is featureless.
701 return CIdx;
702}
703
704void clang_IndexAction_dispose(CXIndexAction idxAction) {
705 // For now, CXIndexAction is featureless.
706}
707
708int clang_indexSourceFile(CXIndexAction idxAction,
709 CXClientData client_data,
710 IndexerCallbacks *index_callbacks,
711 unsigned index_callbacks_size,
712 unsigned index_options,
713 const char *source_filename,
714 const char * const *command_line_args,
715 int num_command_line_args,
716 struct CXUnsavedFile *unsaved_files,
717 unsigned num_unsaved_files,
718 CXTranslationUnit *out_TU,
719 unsigned TU_options) {
720
721 IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks,
722 index_callbacks_size, index_options,
723 source_filename, command_line_args,
724 num_command_line_args, unsaved_files,
725 num_unsaved_files, out_TU, TU_options, 0 };
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000726
Argyrios Kyrtzidise7de9b42011-10-29 19:32:39 +0000727 if (getenv("LIBCLANG_NOTHREADS")) {
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000728 clang_indexSourceFile_Impl(&ITUI);
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000729 return ITUI.result;
730 }
731
732 llvm::CrashRecoveryContext CRC;
733
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000734 if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) {
735 fprintf(stderr, "libclang: crash detected during indexing source file: {\n");
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000736 fprintf(stderr, " 'source_filename' : '%s'\n", source_filename);
737 fprintf(stderr, " 'command_line_args' : [");
738 for (int i = 0; i != num_command_line_args; ++i) {
739 if (i)
740 fprintf(stderr, ", ");
741 fprintf(stderr, "'%s'", command_line_args[i]);
742 }
743 fprintf(stderr, "],\n");
744 fprintf(stderr, " 'unsaved_files' : [");
745 for (unsigned i = 0; i != num_unsaved_files; ++i) {
746 if (i)
747 fprintf(stderr, ", ");
748 fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename,
749 unsaved_files[i].Length);
750 }
751 fprintf(stderr, "],\n");
752 fprintf(stderr, " 'options' : %d,\n", TU_options);
753 fprintf(stderr, "}\n");
754
755 return 1;
756 } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
757 if (out_TU)
758 PrintLibclangResourceUsage(*out_TU);
759 }
760
761 return ITUI.result;
762}
763
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000764int clang_indexTranslationUnit(CXIndexAction idxAction,
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000765 CXClientData client_data,
766 IndexerCallbacks *index_callbacks,
767 unsigned index_callbacks_size,
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000768 unsigned index_options,
769 CXTranslationUnit TU) {
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000770
Argyrios Kyrtzidis2957e6f2011-11-22 07:24:51 +0000771 IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks,
772 index_callbacks_size, index_options, TU,
773 0 };
Argyrios Kyrtzidis21ee5702011-11-15 06:20:16 +0000774
775 if (getenv("LIBCLANG_NOTHREADS")) {
776 clang_indexTranslationUnit_Impl(&ITUI);
777 return ITUI.result;
778 }
779
780 llvm::CrashRecoveryContext CRC;
781
782 if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) {
783 fprintf(stderr, "libclang: crash detected during indexing TU\n");
784
785 return 1;
786 }
787
788 return ITUI.result;
789}
790
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000791void clang_indexLoc_getFileLocation(CXIdxLoc location,
Argyrios Kyrtzidisdd93c592011-11-11 00:23:36 +0000792 CXIdxClientFile *indexFile,
Argyrios Kyrtzidis4e7064f2011-10-17 19:48:19 +0000793 CXFile *file,
794 unsigned *line,
795 unsigned *column,
796 unsigned *offset) {
797 if (indexFile) *indexFile = 0;
798 if (file) *file = 0;
799 if (line) *line = 0;
800 if (column) *column = 0;
801 if (offset) *offset = 0;
802
803 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
804 if (!location.ptr_data[0] || Loc.isInvalid())
805 return;
806
807 IndexingContext &IndexCtx =
808 *static_cast<IndexingContext*>(location.ptr_data[0]);
809 IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset);
810}
811
812CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
813 SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
814 if (!location.ptr_data[0] || Loc.isInvalid())
815 return clang_getNullLocation();
816
817 IndexingContext &IndexCtx =
818 *static_cast<IndexingContext*>(location.ptr_data[0]);
819 return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc);
820}
821
822} // end: extern "C"
823