/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/libclang/Indexing.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Indexing.cpp - Higher level API functions --------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "CIndexDiagnostic.h" |
10 | | #include "CIndexer.h" |
11 | | #include "CLog.h" |
12 | | #include "CXCursor.h" |
13 | | #include "CXIndexDataConsumer.h" |
14 | | #include "CXSourceLocation.h" |
15 | | #include "CXString.h" |
16 | | #include "CXTranslationUnit.h" |
17 | | #include "clang/AST/ASTConsumer.h" |
18 | | #include "clang/Frontend/ASTUnit.h" |
19 | | #include "clang/Frontend/CompilerInstance.h" |
20 | | #include "clang/Frontend/CompilerInvocation.h" |
21 | | #include "clang/Frontend/FrontendAction.h" |
22 | | #include "clang/Frontend/MultiplexConsumer.h" |
23 | | #include "clang/Frontend/Utils.h" |
24 | | #include "clang/Index/IndexingAction.h" |
25 | | #include "clang/Lex/HeaderSearch.h" |
26 | | #include "clang/Lex/PPCallbacks.h" |
27 | | #include "clang/Lex/PPConditionalDirectiveRecord.h" |
28 | | #include "clang/Lex/Preprocessor.h" |
29 | | #include "clang/Lex/PreprocessorOptions.h" |
30 | | #include "llvm/Support/CrashRecoveryContext.h" |
31 | | #include "llvm/Support/MemoryBuffer.h" |
32 | | #include <cstdio> |
33 | | #include <mutex> |
34 | | #include <utility> |
35 | | |
36 | | using namespace clang; |
37 | | using namespace clang::index; |
38 | | using namespace cxtu; |
39 | | using namespace cxindex; |
40 | | |
41 | | namespace { |
42 | | |
43 | | //===----------------------------------------------------------------------===// |
44 | | // Skip Parsed Bodies |
45 | | //===----------------------------------------------------------------------===// |
46 | | |
47 | | /// A "region" in source code identified by the file/offset of the |
48 | | /// preprocessor conditional directive that it belongs to. |
49 | | /// Multiple, non-consecutive ranges can be parts of the same region. |
50 | | /// |
51 | | /// As an example of different regions separated by preprocessor directives: |
52 | | /// |
53 | | /// \code |
54 | | /// #1 |
55 | | /// #ifdef BLAH |
56 | | /// #2 |
57 | | /// #ifdef CAKE |
58 | | /// #3 |
59 | | /// #endif |
60 | | /// #2 |
61 | | /// #endif |
62 | | /// #1 |
63 | | /// \endcode |
64 | | /// |
65 | | /// There are 3 regions, with non-consecutive parts: |
66 | | /// #1 is identified as the beginning of the file |
67 | | /// #2 is identified as the location of "#ifdef BLAH" |
68 | | /// #3 is identified as the location of "#ifdef CAKE" |
69 | | /// |
70 | | class PPRegion { |
71 | | llvm::sys::fs::UniqueID UniqueID; |
72 | | time_t ModTime; |
73 | | unsigned Offset; |
74 | | public: |
75 | 32 | PPRegion() : UniqueID(0, 0), ModTime(), Offset() {} |
76 | | PPRegion(llvm::sys::fs::UniqueID UniqueID, unsigned offset, time_t modTime) |
77 | 50 | : UniqueID(UniqueID), ModTime(modTime), Offset(offset) {} |
78 | | |
79 | 12 | const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } |
80 | 12 | unsigned getOffset() const { return Offset; } |
81 | 12 | time_t getModTime() const { return ModTime; } |
82 | | |
83 | 15 | bool isInvalid() const { return *this == PPRegion(); } |
84 | | |
85 | 278 | friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) { |
86 | 278 | return lhs.UniqueID == rhs.UniqueID && lhs.Offset == rhs.Offset207 && |
87 | 278 | lhs.ModTime == rhs.ModTime205 ; |
88 | 278 | } |
89 | | }; |
90 | | |
91 | | } // end anonymous namespace |
92 | | |
93 | | namespace llvm { |
94 | | |
95 | | template <> |
96 | | struct DenseMapInfo<PPRegion> { |
97 | 20 | static inline PPRegion getEmptyKey() { |
98 | 20 | return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-1), 0); |
99 | 20 | } |
100 | 15 | static inline PPRegion getTombstoneKey() { |
101 | 15 | return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-2), 0); |
102 | 15 | } |
103 | | |
104 | 12 | static unsigned getHashValue(const PPRegion &S) { |
105 | 12 | llvm::FoldingSetNodeID ID; |
106 | 12 | const llvm::sys::fs::UniqueID &UniqueID = S.getUniqueID(); |
107 | 12 | ID.AddInteger(UniqueID.getFile()); |
108 | 12 | ID.AddInteger(UniqueID.getDevice()); |
109 | 12 | ID.AddInteger(S.getOffset()); |
110 | 12 | ID.AddInteger(S.getModTime()); |
111 | 12 | return ID.ComputeHash(); |
112 | 12 | } |
113 | | |
114 | 248 | static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) { |
115 | 248 | return LHS == RHS; |
116 | 248 | } |
117 | | }; |
118 | | } |
119 | | |
120 | | namespace { |
121 | | |
122 | | /// Keeps track of function bodies that have already been parsed. |
123 | | /// |
124 | | /// Is thread-safe. |
125 | | class ThreadSafeParsedRegions { |
126 | | mutable std::mutex Mutex; |
127 | | llvm::DenseSet<PPRegion> ParsedRegions; |
128 | | |
129 | | public: |
130 | 46 | ~ThreadSafeParsedRegions() = default; |
131 | | |
132 | 17 | llvm::DenseSet<PPRegion> getParsedRegions() const { |
133 | 17 | std::lock_guard<std::mutex> MG(Mutex); |
134 | 17 | return ParsedRegions; |
135 | 17 | } |
136 | | |
137 | 17 | void addParsedRegions(ArrayRef<PPRegion> Regions) { |
138 | 17 | std::lock_guard<std::mutex> MG(Mutex); |
139 | 17 | ParsedRegions.insert(Regions.begin(), Regions.end()); |
140 | 17 | } |
141 | | }; |
142 | | |
143 | | /// Provides information whether source locations have already been parsed in |
144 | | /// another FrontendAction. |
145 | | /// |
146 | | /// Is NOT thread-safe. |
147 | | class ParsedSrcLocationsTracker { |
148 | | ThreadSafeParsedRegions &ParsedRegionsStorage; |
149 | | PPConditionalDirectiveRecord &PPRec; |
150 | | Preprocessor &PP; |
151 | | |
152 | | /// Snapshot of the shared state at the point when this instance was |
153 | | /// constructed. |
154 | | llvm::DenseSet<PPRegion> ParsedRegionsSnapshot; |
155 | | /// Regions that were queried during this instance lifetime. |
156 | | SmallVector<PPRegion, 32> NewParsedRegions; |
157 | | |
158 | | /// Caching the last queried region. |
159 | | PPRegion LastRegion; |
160 | | bool LastIsParsed; |
161 | | |
162 | | public: |
163 | | /// Creates snapshot of \p ParsedRegionsStorage. |
164 | | ParsedSrcLocationsTracker(ThreadSafeParsedRegions &ParsedRegionsStorage, |
165 | | PPConditionalDirectiveRecord &ppRec, |
166 | | Preprocessor &pp) |
167 | | : ParsedRegionsStorage(ParsedRegionsStorage), PPRec(ppRec), PP(pp), |
168 | 17 | ParsedRegionsSnapshot(ParsedRegionsStorage.getParsedRegions()) {} |
169 | | |
170 | | /// \returns true iff \p Loc has already been parsed. |
171 | | /// |
172 | | /// Can provide false-negative in case the location was parsed after this |
173 | | /// instance had been constructed. |
174 | | bool hasAlredyBeenParsed(SourceLocation Loc, FileID FID, |
175 | 15 | const FileEntry *FE) { |
176 | 15 | assert(FE); |
177 | 0 | PPRegion region = getRegion(Loc, FID, FE); |
178 | 15 | if (region.isInvalid()) |
179 | 0 | return false; |
180 | | |
181 | | // Check common case, consecutive functions in the same region. |
182 | 15 | if (LastRegion == region) |
183 | 6 | return LastIsParsed; |
184 | | |
185 | 9 | LastRegion = region; |
186 | | // Source locations can't be revisited during single TU parsing. |
187 | | // That means if we hit the same region again, it's a different location in |
188 | | // the same region and so the "is parsed" value from the snapshot is still |
189 | | // correct. |
190 | 9 | LastIsParsed = ParsedRegionsSnapshot.count(region); |
191 | 9 | if (!LastIsParsed) |
192 | 4 | NewParsedRegions.emplace_back(std::move(region)); |
193 | 9 | return LastIsParsed; |
194 | 15 | } |
195 | | |
196 | | /// Updates ParsedRegionsStorage with newly parsed regions. |
197 | 17 | void syncWithStorage() { |
198 | 17 | ParsedRegionsStorage.addParsedRegions(NewParsedRegions); |
199 | 17 | } |
200 | | |
201 | | private: |
202 | 15 | PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) { |
203 | 15 | assert(FE); |
204 | 4 | auto Bail = [this, FE]() { |
205 | 4 | if (isParsedOnceInclude(FE)) { |
206 | 4 | const llvm::sys::fs::UniqueID &ID = FE->getUniqueID(); |
207 | 4 | return PPRegion(ID, 0, FE->getModificationTime()); |
208 | 4 | } |
209 | 0 | return PPRegion(); |
210 | 4 | }; |
211 | | |
212 | 15 | SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc); |
213 | 15 | assert(RegionLoc.isFileID()); |
214 | 15 | if (RegionLoc.isInvalid()) |
215 | 4 | return Bail(); |
216 | | |
217 | 11 | FileID RegionFID; |
218 | 11 | unsigned RegionOffset; |
219 | 11 | std::tie(RegionFID, RegionOffset) = |
220 | 11 | PPRec.getSourceManager().getDecomposedLoc(RegionLoc); |
221 | | |
222 | 11 | if (RegionFID != FID) |
223 | 0 | return Bail(); |
224 | | |
225 | 11 | const llvm::sys::fs::UniqueID &ID = FE->getUniqueID(); |
226 | 11 | return PPRegion(ID, RegionOffset, FE->getModificationTime()); |
227 | 11 | } |
228 | | |
229 | 4 | bool isParsedOnceInclude(const FileEntry *FE) { |
230 | 4 | return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) || |
231 | 4 | PP.getHeaderSearchInfo().hasFileBeenImported(FE)2 ; |
232 | 4 | } |
233 | | }; |
234 | | |
235 | | //===----------------------------------------------------------------------===// |
236 | | // IndexPPCallbacks |
237 | | //===----------------------------------------------------------------------===// |
238 | | |
239 | | class IndexPPCallbacks : public PPCallbacks { |
240 | | Preprocessor &PP; |
241 | | CXIndexDataConsumer &DataConsumer; |
242 | | bool IsMainFileEntered; |
243 | | |
244 | | public: |
245 | | IndexPPCallbacks(Preprocessor &PP, CXIndexDataConsumer &dataConsumer) |
246 | 40 | : PP(PP), DataConsumer(dataConsumer), IsMainFileEntered(false) { } |
247 | | |
248 | | void FileChanged(SourceLocation Loc, FileChangeReason Reason, |
249 | 248 | SrcMgr::CharacteristicKind FileType, FileID PrevFID) override { |
250 | 248 | if (IsMainFileEntered) |
251 | 208 | return; |
252 | | |
253 | 40 | SourceManager &SM = PP.getSourceManager(); |
254 | 40 | SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID()); |
255 | | |
256 | 40 | if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) { |
257 | 40 | IsMainFileEntered = true; |
258 | 40 | DataConsumer.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID())); |
259 | 40 | } |
260 | 40 | } |
261 | | |
262 | | void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, |
263 | | StringRef FileName, bool IsAngled, |
264 | | CharSourceRange FilenameRange, |
265 | | Optional<FileEntryRef> File, StringRef SearchPath, |
266 | | StringRef RelativePath, const Module *Imported, |
267 | 19 | SrcMgr::CharacteristicKind FileType) override { |
268 | 19 | bool isImport = (IncludeTok.is(tok::identifier) && |
269 | 19 | IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import); |
270 | 19 | DataConsumer.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled, |
271 | 19 | Imported); |
272 | 19 | } |
273 | | |
274 | | /// MacroDefined - This hook is called whenever a macro definition is seen. |
275 | 14.6k | void MacroDefined(const Token &Id, const MacroDirective *MD) override {} |
276 | | |
277 | | /// MacroUndefined - This hook is called whenever a macro #undef is seen. |
278 | | /// MI is released immediately following this callback. |
279 | | void MacroUndefined(const Token &MacroNameTok, |
280 | | const MacroDefinition &MD, |
281 | 0 | const MacroDirective *UD) override {} |
282 | | |
283 | | /// MacroExpands - This is called by when a macro invocation is found. |
284 | | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
285 | 7 | SourceRange Range, const MacroArgs *Args) override {} |
286 | | |
287 | | /// SourceRangeSkipped - This hook is called when a source range is skipped. |
288 | | /// \param Range The SourceRange that was skipped. The range begins at the |
289 | | /// #if/#else directive and ends after the #endif/#else directive. |
290 | 5 | void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { |
291 | 5 | } |
292 | | }; |
293 | | |
294 | | //===----------------------------------------------------------------------===// |
295 | | // IndexingConsumer |
296 | | //===----------------------------------------------------------------------===// |
297 | | |
298 | | class IndexingConsumer : public ASTConsumer { |
299 | | CXIndexDataConsumer &DataConsumer; |
300 | | |
301 | | public: |
302 | | IndexingConsumer(CXIndexDataConsumer &dataConsumer, |
303 | | ParsedSrcLocationsTracker *parsedLocsTracker) |
304 | 40 | : DataConsumer(dataConsumer) {} |
305 | | |
306 | 40 | void Initialize(ASTContext &Context) override { |
307 | 40 | DataConsumer.setASTContext(Context); |
308 | 40 | DataConsumer.startedTranslationUnit(); |
309 | 40 | } |
310 | | |
311 | 178 | bool HandleTopLevelDecl(DeclGroupRef DG) override { |
312 | 178 | return !DataConsumer.shouldAbort(); |
313 | 178 | } |
314 | | }; |
315 | | |
316 | | //===----------------------------------------------------------------------===// |
317 | | // CaptureDiagnosticConsumer |
318 | | //===----------------------------------------------------------------------===// |
319 | | |
320 | | class CaptureDiagnosticConsumer : public DiagnosticConsumer { |
321 | | SmallVector<StoredDiagnostic, 4> Errors; |
322 | | public: |
323 | | |
324 | | void HandleDiagnostic(DiagnosticsEngine::Level level, |
325 | 5 | const Diagnostic &Info) override { |
326 | 5 | if (level >= DiagnosticsEngine::Error) |
327 | 1 | Errors.push_back(StoredDiagnostic(level, Info)); |
328 | 5 | } |
329 | | }; |
330 | | |
331 | | //===----------------------------------------------------------------------===// |
332 | | // IndexingFrontendAction |
333 | | //===----------------------------------------------------------------------===// |
334 | | |
335 | | class IndexingFrontendAction : public ASTFrontendAction { |
336 | | std::shared_ptr<CXIndexDataConsumer> DataConsumer; |
337 | | IndexingOptions Opts; |
338 | | |
339 | | ThreadSafeParsedRegions *SKData; |
340 | | std::unique_ptr<ParsedSrcLocationsTracker> ParsedLocsTracker; |
341 | | |
342 | | public: |
343 | | IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer, |
344 | | const IndexingOptions &Opts, |
345 | | ThreadSafeParsedRegions *skData) |
346 | 40 | : DataConsumer(std::move(dataConsumer)), Opts(Opts), SKData(skData) {} |
347 | | |
348 | | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, |
349 | 40 | StringRef InFile) override { |
350 | 40 | PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); |
351 | | |
352 | 40 | if (!PPOpts.ImplicitPCHInclude.empty()) { |
353 | 4 | auto File = CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude); |
354 | 4 | if (File) |
355 | 4 | DataConsumer->importedPCH(*File); |
356 | 4 | } |
357 | | |
358 | 40 | DataConsumer->setASTContext(CI.getASTContext()); |
359 | 40 | Preprocessor &PP = CI.getPreprocessor(); |
360 | 40 | PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP, *DataConsumer)); |
361 | 40 | DataConsumer->setPreprocessor(CI.getPreprocessorPtr()); |
362 | | |
363 | 40 | if (SKData) { |
364 | 17 | auto *PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager()); |
365 | 17 | PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); |
366 | 17 | ParsedLocsTracker = |
367 | 17 | std::make_unique<ParsedSrcLocationsTracker>(*SKData, *PPRec, PP); |
368 | 17 | } |
369 | | |
370 | 40 | std::vector<std::unique_ptr<ASTConsumer>> Consumers; |
371 | 40 | Consumers.push_back(std::make_unique<IndexingConsumer>( |
372 | 40 | *DataConsumer, ParsedLocsTracker.get())); |
373 | 40 | Consumers.push_back(createIndexingASTConsumer( |
374 | 40 | DataConsumer, Opts, CI.getPreprocessorPtr(), |
375 | 40 | [this](const Decl *D) { return this->shouldSkipFunctionBody(D); }32 )); |
376 | 40 | return std::make_unique<MultiplexConsumer>(std::move(Consumers)); |
377 | 40 | } |
378 | | |
379 | 32 | bool shouldSkipFunctionBody(const Decl *D) { |
380 | 32 | if (!ParsedLocsTracker) { |
381 | | // Always skip bodies. |
382 | 0 | return true; |
383 | 0 | } |
384 | | |
385 | 32 | const SourceManager &SM = D->getASTContext().getSourceManager(); |
386 | 32 | SourceLocation Loc = D->getLocation(); |
387 | 32 | if (Loc.isMacroID()) |
388 | 0 | return false; |
389 | 32 | if (SM.isInSystemHeader(Loc)) |
390 | 0 | return true; // always skip bodies from system headers. |
391 | | |
392 | 32 | FileID FID; |
393 | 32 | unsigned Offset; |
394 | 32 | std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); |
395 | | // Don't skip bodies from main files; this may be revisited. |
396 | 32 | if (SM.getMainFileID() == FID) |
397 | 17 | return false; |
398 | 15 | const FileEntry *FE = SM.getFileEntryForID(FID); |
399 | 15 | if (!FE) |
400 | 0 | return false; |
401 | | |
402 | 15 | return ParsedLocsTracker->hasAlredyBeenParsed(Loc, FID, FE); |
403 | 15 | } |
404 | | |
405 | 120 | TranslationUnitKind getTranslationUnitKind() override { |
406 | 120 | if (DataConsumer->shouldIndexImplicitTemplateInsts()) |
407 | 3 | return TU_Complete; |
408 | 117 | else |
409 | 117 | return TU_Prefix; |
410 | 120 | } |
411 | 40 | bool hasCodeCompletionSupport() const override { return false; } |
412 | | |
413 | 40 | void EndSourceFileAction() override { |
414 | 40 | if (ParsedLocsTracker) |
415 | 17 | ParsedLocsTracker->syncWithStorage(); |
416 | 40 | } |
417 | | }; |
418 | | |
419 | | //===----------------------------------------------------------------------===// |
420 | | // clang_indexSourceFileUnit Implementation |
421 | | //===----------------------------------------------------------------------===// |
422 | | |
423 | 49 | static IndexingOptions getIndexingOptionsFromCXOptions(unsigned index_options) { |
424 | 49 | IndexingOptions IdxOpts; |
425 | 49 | if (index_options & CXIndexOpt_IndexFunctionLocalSymbols) |
426 | 3 | IdxOpts.IndexFunctionLocals = true; |
427 | 49 | if (index_options & CXIndexOpt_IndexImplicitTemplateInstantiations) |
428 | 1 | IdxOpts.IndexImplicitInstantiation = true; |
429 | 49 | return IdxOpts; |
430 | 49 | } |
431 | | |
432 | | struct IndexSessionData { |
433 | | CXIndex CIdx; |
434 | | std::unique_ptr<ThreadSafeParsedRegions> SkipBodyData = |
435 | | std::make_unique<ThreadSafeParsedRegions>(); |
436 | | |
437 | 46 | explicit IndexSessionData(CXIndex cIdx) : CIdx(cIdx) {} |
438 | | }; |
439 | | |
440 | | } // anonymous namespace |
441 | | |
442 | | static CXErrorCode clang_indexSourceFile_Impl( |
443 | | CXIndexAction cxIdxAction, CXClientData client_data, |
444 | | IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, |
445 | | unsigned index_options, const char *source_filename, |
446 | | const char *const *command_line_args, int num_command_line_args, |
447 | | ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU, |
448 | 40 | unsigned TU_options) { |
449 | 40 | if (out_TU) |
450 | 0 | *out_TU = nullptr; |
451 | 40 | bool requestedToGetTU = (out_TU != nullptr); |
452 | | |
453 | 40 | if (!cxIdxAction) { |
454 | 0 | return CXError_InvalidArguments; |
455 | 0 | } |
456 | 40 | if (!client_index_callbacks || index_callbacks_size == 0) { |
457 | 0 | return CXError_InvalidArguments; |
458 | 0 | } |
459 | | |
460 | 40 | IndexerCallbacks CB; |
461 | 40 | memset(&CB, 0, sizeof(CB)); |
462 | 40 | unsigned ClientCBSize = index_callbacks_size < sizeof(CB) |
463 | 40 | ? index_callbacks_size0 : sizeof(CB); |
464 | 40 | memcpy(&CB, client_index_callbacks, ClientCBSize); |
465 | | |
466 | 40 | IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction); |
467 | 40 | CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx); |
468 | | |
469 | 40 | if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) |
470 | 0 | setThreadBackgroundPriority(); |
471 | | |
472 | 40 | CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All; |
473 | 40 | if (TU_options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles) |
474 | 0 | CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes; |
475 | 40 | if (Logger::isLoggingEnabled()) |
476 | 0 | CaptureDiagnostics = CaptureDiagsKind::None; |
477 | | |
478 | 40 | CaptureDiagnosticConsumer *CaptureDiag = nullptr; |
479 | 40 | if (CaptureDiagnostics != CaptureDiagsKind::None) |
480 | 40 | CaptureDiag = new CaptureDiagnosticConsumer(); |
481 | | |
482 | | // Configure the diagnostics. |
483 | 40 | IntrusiveRefCntPtr<DiagnosticsEngine> |
484 | 40 | Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, |
485 | 40 | CaptureDiag, |
486 | 40 | /*ShouldOwnClient=*/true)); |
487 | | |
488 | | // Recover resources if we crash before exiting this function. |
489 | 40 | llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, |
490 | 40 | llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > |
491 | 40 | DiagCleanup(Diags.get()); |
492 | | |
493 | 40 | std::unique_ptr<std::vector<const char *>> Args( |
494 | 40 | new std::vector<const char *>()); |
495 | | |
496 | | // Recover resources if we crash before exiting this method. |
497 | 40 | llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > |
498 | 40 | ArgsCleanup(Args.get()); |
499 | | |
500 | 40 | Args->insert(Args->end(), command_line_args, |
501 | 40 | command_line_args + num_command_line_args); |
502 | | |
503 | | // The 'source_filename' argument is optional. If the caller does not |
504 | | // specify it then it is assumed that the source file is specified |
505 | | // in the actual argument list. |
506 | | // Put the source file after command_line_args otherwise if '-x' flag is |
507 | | // present it will be unused. |
508 | 40 | if (source_filename) |
509 | 0 | Args->push_back(source_filename); |
510 | | |
511 | 40 | CreateInvocationOptions CIOpts; |
512 | 40 | CIOpts.Diags = Diags; |
513 | 40 | CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? |
514 | 40 | std::shared_ptr<CompilerInvocation> CInvok = |
515 | 40 | createInvocation(*Args, std::move(CIOpts)); |
516 | | |
517 | 40 | if (!CInvok) |
518 | 0 | return CXError_Failure; |
519 | | |
520 | | // Recover resources if we crash before exiting this function. |
521 | 40 | llvm::CrashRecoveryContextCleanupRegistrar< |
522 | 40 | std::shared_ptr<CompilerInvocation>, |
523 | 40 | llvm::CrashRecoveryContextDestructorCleanup< |
524 | 40 | std::shared_ptr<CompilerInvocation>>> |
525 | 40 | CInvokCleanup(&CInvok); |
526 | | |
527 | 40 | if (CInvok->getFrontendOpts().Inputs.empty()) |
528 | 0 | return CXError_Failure; |
529 | | |
530 | 40 | typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner; |
531 | 40 | std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner); |
532 | | |
533 | | // Recover resources if we crash before exiting this method. |
534 | 40 | llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup( |
535 | 40 | BufOwner.get()); |
536 | | |
537 | 40 | for (auto &UF : unsaved_files) { |
538 | 0 | std::unique_ptr<llvm::MemoryBuffer> MB = |
539 | 0 | llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); |
540 | 0 | CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get()); |
541 | 0 | BufOwner->push_back(std::move(MB)); |
542 | 0 | } |
543 | | |
544 | | // Since libclang is primarily used by batch tools dealing with |
545 | | // (often very broken) source code, where spell-checking can have a |
546 | | // significant negative impact on performance (particularly when |
547 | | // precompiled headers are involved), we disable it. |
548 | 40 | CInvok->getLangOpts()->SpellChecking = false; |
549 | | |
550 | 40 | if (index_options & CXIndexOpt_SuppressWarnings) |
551 | 0 | CInvok->getDiagnosticOpts().IgnoreWarnings = true; |
552 | | |
553 | | // Make sure to use the raw module format. |
554 | 40 | CInvok->getHeaderSearchOpts().ModuleFormat = std::string( |
555 | 40 | CXXIdx->getPCHContainerOperations()->getRawReader().getFormat()); |
556 | | |
557 | 40 | auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics, |
558 | 40 | /*UserFilesAreVolatile=*/true); |
559 | 40 | if (!Unit) |
560 | 0 | return CXError_InvalidArguments; |
561 | | |
562 | 40 | auto *UPtr = Unit.get(); |
563 | 40 | std::unique_ptr<CXTUOwner> CXTU( |
564 | 40 | new CXTUOwner(MakeCXTranslationUnit(CXXIdx, std::move(Unit)))); |
565 | | |
566 | | // Recover resources if we crash before exiting this method. |
567 | 40 | llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> |
568 | 40 | CXTUCleanup(CXTU.get()); |
569 | | |
570 | | // Enable the skip-parsed-bodies optimization only for C++; this may be |
571 | | // revisited. |
572 | 40 | bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) && |
573 | 40 | CInvok->getLangOpts()->CPlusPlus; |
574 | 40 | if (SkipBodies) |
575 | 17 | CInvok->getFrontendOpts().SkipFunctionBodies = true; |
576 | | |
577 | 40 | auto DataConsumer = |
578 | 40 | std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options, |
579 | 40 | CXTU->getTU()); |
580 | 40 | auto IndexAction = std::make_unique<IndexingFrontendAction>( |
581 | 40 | DataConsumer, getIndexingOptionsFromCXOptions(index_options), |
582 | 40 | SkipBodies ? IdxSession->SkipBodyData.get()17 : nullptr23 ); |
583 | | |
584 | | // Recover resources if we crash before exiting this method. |
585 | 40 | llvm::CrashRecoveryContextCleanupRegistrar<FrontendAction> |
586 | 40 | IndexActionCleanup(IndexAction.get()); |
587 | | |
588 | 40 | bool Persistent = requestedToGetTU; |
589 | 40 | bool OnlyLocalDecls = false; |
590 | 40 | bool PrecompilePreamble = false; |
591 | 40 | bool CreatePreambleOnFirstParse = false; |
592 | 40 | bool CacheCodeCompletionResults = false; |
593 | 40 | PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); |
594 | 40 | PPOpts.AllowPCHWithCompilerErrors = true; |
595 | | |
596 | 40 | if (requestedToGetTU) { |
597 | 0 | OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); |
598 | 0 | PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; |
599 | 0 | CreatePreambleOnFirstParse = |
600 | 0 | TU_options & CXTranslationUnit_CreatePreambleOnFirstParse; |
601 | | // FIXME: Add a flag for modules. |
602 | 0 | CacheCodeCompletionResults |
603 | 0 | = TU_options & CXTranslationUnit_CacheCompletionResults; |
604 | 0 | } |
605 | | |
606 | 40 | if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { |
607 | 40 | PPOpts.DetailedRecord = true; |
608 | 40 | } |
609 | | |
610 | 40 | if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) |
611 | 31 | PPOpts.DetailedRecord = false; |
612 | | |
613 | | // Unless the user specified that they want the preamble on the first parse |
614 | | // set it up to be created on the first reparse. This makes the first parse |
615 | | // faster, trading for a slower (first) reparse. |
616 | 40 | unsigned PrecompilePreambleAfterNParses = |
617 | 40 | !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse0 ; |
618 | 40 | DiagnosticErrorTrap DiagTrap(*Diags); |
619 | 40 | bool Success = ASTUnit::LoadFromCompilerInvocationAction( |
620 | 40 | std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags, |
621 | 40 | IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(), |
622 | 40 | OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses, |
623 | 40 | CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true); |
624 | 40 | if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()6 ) |
625 | 6 | printDiagsToStderr(UPtr); |
626 | | |
627 | 40 | if (isASTReadError(UPtr)) |
628 | 0 | return CXError_ASTReadError; |
629 | | |
630 | 40 | if (!Success) |
631 | 0 | return CXError_Failure; |
632 | | |
633 | 40 | if (out_TU) |
634 | 0 | *out_TU = CXTU->takeTU(); |
635 | | |
636 | 40 | return CXError_Success; |
637 | 40 | } |
638 | | |
639 | | //===----------------------------------------------------------------------===// |
640 | | // clang_indexTranslationUnit Implementation |
641 | | //===----------------------------------------------------------------------===// |
642 | | |
643 | 9 | static void indexPreprocessingRecord(ASTUnit &Unit, CXIndexDataConsumer &IdxCtx) { |
644 | 9 | Preprocessor &PP = Unit.getPreprocessor(); |
645 | 9 | if (!PP.getPreprocessingRecord()) |
646 | 0 | return; |
647 | | |
648 | | // FIXME: Only deserialize inclusion directives. |
649 | | |
650 | 9 | bool isModuleFile = Unit.isModuleFile(); |
651 | 3.60k | for (PreprocessedEntity *PPE : Unit.getLocalPreprocessingEntities()) { |
652 | 3.60k | if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { |
653 | 26 | SourceLocation Loc = ID->getSourceRange().getBegin(); |
654 | | // Modules have synthetic main files as input, give an invalid location |
655 | | // if the location points to such a file. |
656 | 26 | if (isModuleFile && Unit.isInMainFileID(Loc)25 ) |
657 | 18 | Loc = SourceLocation(); |
658 | 26 | IdxCtx.ppIncludedFile(Loc, ID->getFileName(), |
659 | 26 | ID->getFile(), |
660 | 26 | ID->getKind() == InclusionDirective::Import, |
661 | 26 | !ID->wasInQuotes(), ID->importedModule()); |
662 | 26 | } |
663 | 3.60k | } |
664 | 9 | } |
665 | | |
666 | | static CXErrorCode clang_indexTranslationUnit_Impl( |
667 | | CXIndexAction idxAction, CXClientData client_data, |
668 | | IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, |
669 | 9 | unsigned index_options, CXTranslationUnit TU) { |
670 | | // Check arguments. |
671 | 9 | if (isNotUsableTU(TU)) { |
672 | 0 | LOG_BAD_TU(TU); |
673 | 0 | return CXError_InvalidArguments; |
674 | 0 | } |
675 | 9 | if (!client_index_callbacks || index_callbacks_size == 0) { |
676 | 0 | return CXError_InvalidArguments; |
677 | 0 | } |
678 | | |
679 | 9 | CIndexer *CXXIdx = TU->CIdx; |
680 | 9 | if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) |
681 | 0 | setThreadBackgroundPriority(); |
682 | | |
683 | 9 | IndexerCallbacks CB; |
684 | 9 | memset(&CB, 0, sizeof(CB)); |
685 | 9 | unsigned ClientCBSize = index_callbacks_size < sizeof(CB) |
686 | 9 | ? index_callbacks_size0 : sizeof(CB); |
687 | 9 | memcpy(&CB, client_index_callbacks, ClientCBSize); |
688 | | |
689 | 9 | CXIndexDataConsumer DataConsumer(client_data, CB, index_options, TU); |
690 | | |
691 | 9 | ASTUnit *Unit = cxtu::getASTUnit(TU); |
692 | 9 | if (!Unit) |
693 | 0 | return CXError_Failure; |
694 | | |
695 | 9 | ASTUnit::ConcurrencyCheck Check(*Unit); |
696 | | |
697 | 9 | if (const FileEntry *PCHFile = Unit->getPCHFile()) |
698 | 0 | DataConsumer.importedPCH(PCHFile); |
699 | | |
700 | 9 | FileManager &FileMgr = Unit->getFileManager(); |
701 | | |
702 | 9 | if (Unit->getOriginalSourceFileName().empty()) |
703 | 6 | DataConsumer.enteredMainFile(nullptr); |
704 | 3 | else if (auto MainFile = FileMgr.getFile(Unit->getOriginalSourceFileName())) |
705 | 3 | DataConsumer.enteredMainFile(*MainFile); |
706 | 0 | else |
707 | 0 | DataConsumer.enteredMainFile(nullptr); |
708 | | |
709 | 9 | DataConsumer.setASTContext(Unit->getASTContext()); |
710 | 9 | DataConsumer.startedTranslationUnit(); |
711 | | |
712 | 9 | indexPreprocessingRecord(*Unit, DataConsumer); |
713 | 9 | indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options)); |
714 | 9 | DataConsumer.indexDiagnostics(); |
715 | | |
716 | 9 | return CXError_Success; |
717 | 9 | } |
718 | | |
719 | | //===----------------------------------------------------------------------===// |
720 | | // libclang public APIs. |
721 | | //===----------------------------------------------------------------------===// |
722 | | |
723 | 318 | int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) { |
724 | 318 | return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory188 ; |
725 | 318 | } |
726 | | |
727 | | const CXIdxObjCContainerDeclInfo * |
728 | 40 | clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) { |
729 | 40 | if (!DInfo) |
730 | 0 | return nullptr; |
731 | | |
732 | 40 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
733 | 40 | if (const ObjCContainerDeclInfo * |
734 | 40 | ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI)) |
735 | 40 | return &ContInfo->ObjCContDeclInfo; |
736 | | |
737 | 0 | return nullptr; |
738 | 40 | } |
739 | | |
740 | | const CXIdxObjCInterfaceDeclInfo * |
741 | 318 | clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) { |
742 | 318 | if (!DInfo) |
743 | 0 | return nullptr; |
744 | | |
745 | 318 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
746 | 318 | if (const ObjCInterfaceDeclInfo * |
747 | 318 | InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) |
748 | 21 | return &InterInfo->ObjCInterDeclInfo; |
749 | | |
750 | 297 | return nullptr; |
751 | 318 | } |
752 | | |
753 | | const CXIdxObjCCategoryDeclInfo * |
754 | 318 | clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){ |
755 | 318 | if (!DInfo) |
756 | 0 | return nullptr; |
757 | | |
758 | 318 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
759 | 318 | if (const ObjCCategoryDeclInfo * |
760 | 318 | CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) |
761 | 5 | return &CatInfo->ObjCCatDeclInfo; |
762 | | |
763 | 313 | return nullptr; |
764 | 318 | } |
765 | | |
766 | | const CXIdxObjCProtocolRefListInfo * |
767 | 318 | clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) { |
768 | 318 | if (!DInfo) |
769 | 0 | return nullptr; |
770 | | |
771 | 318 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
772 | | |
773 | 318 | if (const ObjCInterfaceDeclInfo * |
774 | 318 | InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) |
775 | 21 | return InterInfo->ObjCInterDeclInfo.protocols; |
776 | | |
777 | 297 | if (const ObjCProtocolDeclInfo * |
778 | 297 | ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI)) |
779 | 4 | return &ProtInfo->ObjCProtoRefListInfo; |
780 | | |
781 | 293 | if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) |
782 | 5 | return CatInfo->ObjCCatDeclInfo.protocols; |
783 | | |
784 | 288 | return nullptr; |
785 | 293 | } |
786 | | |
787 | | const CXIdxObjCPropertyDeclInfo * |
788 | 318 | clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) { |
789 | 318 | if (!DInfo) |
790 | 0 | return nullptr; |
791 | | |
792 | 318 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
793 | 318 | if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI)) |
794 | 8 | return &PropInfo->ObjCPropDeclInfo; |
795 | | |
796 | 310 | return nullptr; |
797 | 318 | } |
798 | | |
799 | | const CXIdxIBOutletCollectionAttrInfo * |
800 | 0 | clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) { |
801 | 0 | if (!AInfo) |
802 | 0 | return nullptr; |
803 | | |
804 | 0 | const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo); |
805 | 0 | if (const IBOutletCollectionInfo * |
806 | 0 | IBInfo = dyn_cast<IBOutletCollectionInfo>(DI)) |
807 | 0 | return &IBInfo->IBCollInfo; |
808 | | |
809 | 0 | return nullptr; |
810 | 0 | } |
811 | | |
812 | | const CXIdxCXXClassDeclInfo * |
813 | 318 | clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) { |
814 | 318 | if (!DInfo) |
815 | 0 | return nullptr; |
816 | | |
817 | 318 | const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); |
818 | 318 | if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI)) |
819 | 34 | return &ClassInfo->CXXClassInfo; |
820 | | |
821 | 284 | return nullptr; |
822 | 318 | } |
823 | | |
824 | | CXIdxClientContainer |
825 | 2.54k | clang_index_getClientContainer(const CXIdxContainerInfo *info) { |
826 | 2.54k | if (!info) |
827 | 0 | return nullptr; |
828 | 2.54k | const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); |
829 | 2.54k | return Container->IndexCtx->getClientContainerForDC(Container->DC); |
830 | 2.54k | } |
831 | | |
832 | | void clang_index_setClientContainer(const CXIdxContainerInfo *info, |
833 | 125 | CXIdxClientContainer client) { |
834 | 125 | if (!info) |
835 | 0 | return; |
836 | 125 | const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); |
837 | 125 | Container->IndexCtx->addContainerInMap(Container->DC, client); |
838 | 125 | } |
839 | | |
840 | 0 | CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) { |
841 | 0 | if (!info) |
842 | 0 | return nullptr; |
843 | 0 | const EntityInfo *Entity = static_cast<const EntityInfo *>(info); |
844 | 0 | return Entity->IndexCtx->getClientEntity(Entity->Dcl); |
845 | 0 | } |
846 | | |
847 | | void clang_index_setClientEntity(const CXIdxEntityInfo *info, |
848 | 0 | CXIdxClientEntity client) { |
849 | 0 | if (!info) |
850 | 0 | return; |
851 | 0 | const EntityInfo *Entity = static_cast<const EntityInfo *>(info); |
852 | 0 | Entity->IndexCtx->setClientEntity(Entity->Dcl, client); |
853 | 0 | } |
854 | | |
855 | 46 | CXIndexAction clang_IndexAction_create(CXIndex CIdx) { |
856 | 46 | return new IndexSessionData(CIdx); |
857 | 46 | } |
858 | | |
859 | 46 | void clang_IndexAction_dispose(CXIndexAction idxAction) { |
860 | 46 | if (idxAction) |
861 | 46 | delete static_cast<IndexSessionData *>(idxAction); |
862 | 46 | } |
863 | | |
864 | | int clang_indexSourceFile(CXIndexAction idxAction, |
865 | | CXClientData client_data, |
866 | | IndexerCallbacks *index_callbacks, |
867 | | unsigned index_callbacks_size, |
868 | | unsigned index_options, |
869 | | const char *source_filename, |
870 | | const char * const *command_line_args, |
871 | | int num_command_line_args, |
872 | | struct CXUnsavedFile *unsaved_files, |
873 | | unsigned num_unsaved_files, |
874 | | CXTranslationUnit *out_TU, |
875 | 40 | unsigned TU_options) { |
876 | 40 | SmallVector<const char *, 4> Args; |
877 | 40 | Args.push_back("clang"); |
878 | 40 | Args.append(command_line_args, command_line_args + num_command_line_args); |
879 | 40 | return clang_indexSourceFileFullArgv( |
880 | 40 | idxAction, client_data, index_callbacks, index_callbacks_size, |
881 | 40 | index_options, source_filename, Args.data(), Args.size(), unsaved_files, |
882 | 40 | num_unsaved_files, out_TU, TU_options); |
883 | 40 | } |
884 | | |
885 | | int clang_indexSourceFileFullArgv( |
886 | | CXIndexAction idxAction, CXClientData client_data, |
887 | | IndexerCallbacks *index_callbacks, unsigned index_callbacks_size, |
888 | | unsigned index_options, const char *source_filename, |
889 | | const char *const *command_line_args, int num_command_line_args, |
890 | | struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, |
891 | 40 | CXTranslationUnit *out_TU, unsigned TU_options) { |
892 | 40 | LOG_FUNC_SECTION { |
893 | 0 | *Log << source_filename << ": "; |
894 | 0 | for (int i = 0; i != num_command_line_args; ++i) |
895 | 0 | *Log << command_line_args[i] << " "; |
896 | 0 | } |
897 | | |
898 | 40 | if (num_unsaved_files && !unsaved_files0 ) |
899 | 0 | return CXError_InvalidArguments; |
900 | | |
901 | 40 | CXErrorCode result = CXError_Failure; |
902 | 40 | auto IndexSourceFileImpl = [=, &result]() { |
903 | 40 | result = clang_indexSourceFile_Impl( |
904 | 40 | idxAction, client_data, index_callbacks, index_callbacks_size, |
905 | 40 | index_options, source_filename, command_line_args, |
906 | 40 | num_command_line_args, |
907 | 40 | llvm::makeArrayRef(unsaved_files, num_unsaved_files), out_TU, |
908 | 40 | TU_options); |
909 | 40 | }; |
910 | | |
911 | 40 | llvm::CrashRecoveryContext CRC; |
912 | | |
913 | 40 | if (!RunSafely(CRC, IndexSourceFileImpl)) { |
914 | 0 | fprintf(stderr, "libclang: crash detected during indexing source file: {\n"); |
915 | 0 | fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); |
916 | 0 | fprintf(stderr, " 'command_line_args' : ["); |
917 | 0 | for (int i = 0; i != num_command_line_args; ++i) { |
918 | 0 | if (i) |
919 | 0 | fprintf(stderr, ", "); |
920 | 0 | fprintf(stderr, "'%s'", command_line_args[i]); |
921 | 0 | } |
922 | 0 | fprintf(stderr, "],\n"); |
923 | 0 | fprintf(stderr, " 'unsaved_files' : ["); |
924 | 0 | for (unsigned i = 0; i != num_unsaved_files; ++i) { |
925 | 0 | if (i) |
926 | 0 | fprintf(stderr, ", "); |
927 | 0 | fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, |
928 | 0 | unsaved_files[i].Length); |
929 | 0 | } |
930 | 0 | fprintf(stderr, "],\n"); |
931 | 0 | fprintf(stderr, " 'options' : %d,\n", TU_options); |
932 | 0 | fprintf(stderr, "}\n"); |
933 | | |
934 | 0 | return 1; |
935 | 40 | } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { |
936 | 0 | if (out_TU) |
937 | 0 | PrintLibclangResourceUsage(*out_TU); |
938 | 0 | } |
939 | | |
940 | 40 | return result; |
941 | 40 | } |
942 | | |
943 | | int clang_indexTranslationUnit(CXIndexAction idxAction, |
944 | | CXClientData client_data, |
945 | | IndexerCallbacks *index_callbacks, |
946 | | unsigned index_callbacks_size, |
947 | | unsigned index_options, |
948 | 9 | CXTranslationUnit TU) { |
949 | 9 | LOG_FUNC_SECTION { |
950 | 0 | *Log << TU; |
951 | 0 | } |
952 | | |
953 | 9 | CXErrorCode result; |
954 | 9 | auto IndexTranslationUnitImpl = [=, &result]() { |
955 | 9 | result = clang_indexTranslationUnit_Impl( |
956 | 9 | idxAction, client_data, index_callbacks, index_callbacks_size, |
957 | 9 | index_options, TU); |
958 | 9 | }; |
959 | | |
960 | 9 | llvm::CrashRecoveryContext CRC; |
961 | | |
962 | 9 | if (!RunSafely(CRC, IndexTranslationUnitImpl)) { |
963 | 0 | fprintf(stderr, "libclang: crash detected during indexing TU\n"); |
964 | | |
965 | 0 | return 1; |
966 | 0 | } |
967 | | |
968 | 9 | return result; |
969 | 9 | } |
970 | | |
971 | | void clang_indexLoc_getFileLocation(CXIdxLoc location, |
972 | | CXIdxClientFile *indexFile, |
973 | | CXFile *file, |
974 | | unsigned *line, |
975 | | unsigned *column, |
976 | 2.42k | unsigned *offset) { |
977 | 2.42k | if (indexFile) *indexFile = nullptr; |
978 | 2.42k | if (file) *file = nullptr0 ; |
979 | 2.42k | if (line) *line = 0; |
980 | 2.42k | if (column) *column = 0; |
981 | 2.42k | if (offset) *offset = 00 ; |
982 | | |
983 | 2.42k | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
984 | 2.42k | if (!location.ptr_data[0] || Loc.isInvalid()2.40k ) |
985 | 18 | return; |
986 | | |
987 | 2.40k | CXIndexDataConsumer &DataConsumer = |
988 | 2.40k | *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]); |
989 | 2.40k | DataConsumer.translateLoc(Loc, indexFile, file, line, column, offset); |
990 | 2.40k | } |
991 | | |
992 | 0 | CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) { |
993 | 0 | SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); |
994 | 0 | if (!location.ptr_data[0] || Loc.isInvalid()) |
995 | 0 | return clang_getNullLocation(); |
996 | | |
997 | 0 | CXIndexDataConsumer &DataConsumer = |
998 | 0 | *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]); |
999 | 0 | return cxloc::translateSourceLocation(DataConsumer.getASTContext(), Loc); |
1000 | 0 | } |