Clang Project

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