r212060 - Consider module depedencies when checking a preamble in libclang

Nico Weber thakis at chromium.org
Wed Jul 16 10:01:23 PDT 2014


I agree that it looks strange :-) I filed PR20325 for it. If I run this
without lldb, the stack is

0  libclangTests            0x0000000104bfea6e
llvm::sys::PrintStackTrace(__sFILE*) + 46
1  libclangTests            0x0000000104bfed7b
PrintStackTraceSignalHandler(void*) + 27
2  libclangTests            0x0000000104bff10c SignalHandler(int) + 412
3  libsystem_platform.dylib 0x00007fff8e6bf5aa _sigtramp + 26
4  libsystem_platform.dylib 0x5a5a5a5a5a5a5a5a _sigtramp + 3421398218

I think the crash recovery relies on threads somehow (see also PR11974),
but I don't know the details.


On Wed, Jul 16, 2014 at 9:56 AM, Ben Langmuir <blangmuir at apple.com> wrote:

>
> On Jul 16, 2014, at 9:34 AM, Nico Weber <thakis at chromium.org> wrote:
>
> …with this stack:
>
>
> That looks pretty bizarre. I’m assuming that means the
>  CrashRecoveryContext (this at the location you’re showing) is null? Maybe
> I’m reading the code wrong, but if the context is null, I would expect
> cleanup to be null as well and we would hit the early return.
>
> Here, we are returning what will be in “cleanup”, and context must be
> non-null.
>
>     if (x) {
>       if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent
> ())
>         return new DERIVED(context, x);
>     }
>     return 0;
>
> Ben
>
>
> (lldb) run
> Process 23113 launched:
> './tools/clang/unittests/libclang/Debug+Asserts/libclangTests' (x86_64)
> Note: Google Test filter = LibclangReparseTest.ReparseWithModule
> [==========] Running 1 test from 1 test case.
> [----------] Global test environment set-up.
> [----------] 1 test from LibclangReparseTest
> [ RUN      ] LibclangReparseTest.ReparseWithModule
> Process 23113 stopped
> * thread #1: tid = 0x710632, 0x000000010142308b
> libclang.dylib`llvm::CrashRecoveryContext::registerCleanup(this=0xc000000000000000,
> cleanup=0x000000010300ddc0) + 43 at CrashRecoveryContext.cpp:111, queue =
> 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
>     frame #0: 0x000000010142308b
> libclang.dylib`llvm::CrashRecoveryContext::registerCleanup(this=0xc000000000000000,
> cleanup=0x000000010300ddc0) + 43 at CrashRecoveryContext.cpp:111
>    108 {
>    109   if (!cleanup)
>    110     return;
> -> 111   if (head)
>    112     head->prev = cleanup;
>    113   cleanup->next = head;
>    114   head = cleanup;
> (lldb) bt
> * thread #1: tid = 0x710632, 0x000000010142308b
> libclang.dylib`llvm::CrashRecoveryContext::registerCleanup(this=0xc000000000000000,
> cleanup=0x000000010300ddc0) + 43 at CrashRecoveryContext.cpp:111, queue =
> 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
>   * frame #0: 0x000000010142308b
> libclang.dylib`llvm::CrashRecoveryContext::registerCleanup(this=0xc000000000000000,
> cleanup=0x000000010300ddc0) + 43 at CrashRecoveryContext.cpp:111
>     frame #1: 0x000000010039ef10
> libclang.dylib`CrashRecoveryContextCleanupRegistrar(this=0x00007fff5fbfd5d0,
> x=0x000000010300eb60) + 80 at CrashRecoveryContext.h:196
>     frame #2: 0x0000000100395c7d
> libclang.dylib`CrashRecoveryContextCleanupRegistrar(this=0x00007fff5fbfd5d0,
> x=0x000000010300eb60) + 29 at CrashRecoveryContext.h:197
>     frame #3: 0x000000010037e1cd
> libclang.dylib`clang::ASTUnit::Parse(this=0x0000000103802800,
> OverrideMainBuffer=0x0000000103021720) + 477 at ASTUnit.cpp:1048
>     frame #4: 0x000000010038c126
> libclang.dylib`clang::ASTUnit::Reparse(this=0x0000000103802800,
> RemappedFiles=ArrayRef<std::__1::pair<std::__1::basic_string<char>,
> llvm::MemoryBuffer *> > at 0x00007fff5fbfdf60) + 1414 at ASTUnit.cpp:2076
>     frame #5: 0x00000001001b3957
> libclang.dylib`clang_reparseTranslationUnit_Impl(UserData=0x00007fff5fbfe910)
> + 2487 at CIndex.cpp:3094
>     frame #6: 0x00000001001f684f
> libclang.dylib`operator(this=0x00007fff5fbfe840) + 31 at
> CrashRecoveryContext.h:96
>     frame #7: 0x00000001001f6825 libclang.dylib`void
> llvm::function_ref<void
> (callable=140734799800384)>::callback_fn<llvm::CrashRecoveryContext::RunSafelyOnThread(void
> (*)(void*), void*, unsigned int)::'lambda'()>(long) + 21 at STLExtras.h:75
>     frame #8: 0x0000000101423bf9 libclang.dylib`llvm::function_ref<void
> (this=0x00007fff5fbfe808)>::operator()() const + 25 at STLExtras.h:85
>     frame #9: 0x0000000101423c75 libclang.dylib`void
> llvm::function_ref<void
> (callable=140734799800328)>::callback_fn<llvm::function_ref<void ()>
> >(long) + 21 at STLExtras.h:75
>     frame #10: 0x0000000101423bf9 libclang.dylib`llvm::function_ref<void
> (this=0x00007fff5fbfe7e0)>::operator()() const + 25 at STLExtras.h:85
>     frame #11: 0x0000000101423c75 libclang.dylib`void
> llvm::function_ref<void
> (callable=140734799800288)>::callback_fn<llvm::function_ref<void ()>
> >(long) + 21 at STLExtras.h:75
>     frame #12: 0x0000000101423bf9 libclang.dylib`llvm::function_ref<void
> (this=0x00007fff5fbfe730)>::operator()() const + 25 at STLExtras.h:85
>     frame #13: 0x000000010142351d
> libclang.dylib`llvm::CrashRecoveryContext::RunSafely(this=0x00007fff5fbfe900,
> Fn=function_ref<void ()> at 0x00007fff5fbfe730)>) + 237 at
> CrashRecoveryContext.cpp:318
>     frame #14: 0x00000001014237c1
> libclang.dylib`RunSafelyOnThread_Dispatch(UserData=0x00007fff5fbfe7e0) + 81
> at CrashRecoveryContext.cpp:366
>     frame #15: 0x0000000101465f9d
> libclang.dylib`llvm::llvm_execute_on_thread(Fn=0x0000000101423770,
> UserData=0x00007fff5fbfe7e0, RequestedStackSize=8388608)(void*), void*,
> unsigned int) + 29 at Threading.cpp:109
>     frame #16: 0x0000000101423702
> libclang.dylib`llvm::CrashRecoveryContext::RunSafelyOnThread(this=0x00007fff5fbfe900,
> Fn=function_ref<void ()> at 0x00007fff5fbfe808,
> RequestedStackSize=8388608)>, unsigned int) + 98 at
> CrashRecoveryContext.cpp:372
>     frame #17: 0x00000001001dd926
> libclang.dylib`llvm::CrashRecoveryContext::RunSafelyOnThread(this=0x00007fff5fbfe900,
> Fn=0x00000001001b2fa0, UserData=0x00007fff5fbfe910,
> RequestedStackSize=8388608)(void*), void*, unsigned int) + 86 at
> CrashRecoveryContext.h:96
>     frame #18: 0x00000001001b054d
> libclang.dylib`clang::RunSafely(CRC=0x00007fff5fbfe900,
> Fn=0x00000001001b2fa0, UserData=0x00007fff5fbfe910, Size=8388608)(void*),
> void*, unsigned int) + 77 at CIndex.cpp:6809
>     frame #19: 0x00000001001b2f03
> libclang.dylib`clang_reparseTranslationUnit(TU=0x00000001030056a0,
> num_unsaved_files=0, unsaved_files=0x0000000000000000, options=0) + 339 at
> CIndex.cpp:3123
>     frame #20: 0x0000000100005d6f
> libclangTests`LibclangReparseTest::ReparseTU(this=0x0000000103004ad0,
> num_unsaved_files=0, unsaved_files=0x0000000000000000) + 79 at
> LibclangTest.cpp:385
>     frame #21: 0x0000000100004179
> libclangTests`LibclangReparseTest_ReparseWithModule_Test::TestBody(this=0x0000000103004ad0)
> + 5257 at LibclangTest.cpp:455
>     frame #22: 0x0000000100041f83 libclangTests`void
> testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,
> void>(object=0x0000000103004ad0, method=21 00 00 00 00 00 00 00,
> location=0x00000001000b80bf)(), char const*) + 131 at gtest.cc:2090
>     frame #23: 0x0000000100030d8e libclangTests`void
> testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,
> void>(object=0x0000000103004ad0, method=21 00 00 00 00 00 00 00,
> location=0x00000001000b80bf)(), char const*) + 110 at gtest.cc:2142
>     frame #24: 0x000000010001bd35
> libclangTests`testing::Test::Run(this=0x0000000103004ad0) + 197 at
> gtest.cc:2161
>     frame #25: 0x000000010001c94b
> libclangTests`testing::TestInfo::Run(this=0x0000000103004a00) + 219 at
> gtest.cc:2309
>     frame #26: 0x000000010001d477
> libclangTests`testing::TestCase::Run(this=0x0000000103004990) + 231 at
> gtest.cc:2416
>     frame #27: 0x000000010002352e
> libclangTests`testing::internal::UnitTestImpl::RunAllTests(this=0x0000000103003bd0)
> + 926 at gtest.cc:4205
>     frame #28: 0x000000010003ebf3 libclangTests`bool
> testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,
> bool>(object=0x0000000103003bd0, method=90 31 02 00 01 00 00 00,
> location=0x00000001000b8770)(), char const*) + 131 at gtest.cc:2090
>     frame #29: 0x0000000100032ffe libclangTests`bool
> testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,
> bool>(object=0x0000000103003bd0, method=90 31 02 00 01 00 00 00,
> location=0x00000001000b8770)(), char const*) + 110 at gtest.cc:2142
>     frame #30: 0x0000000100023174
> libclangTests`testing::UnitTest::Run(this=0x00000001000c2cf0) + 100 at
> gtest.cc:3839
>     frame #31: 0x000000010004a369 libclangTests`main(argc=1,
> argv=0x00007fff5fbff9e0) + 89 at TestMain.cpp:48
>
>
>
> On Wed, Jul 16, 2014 at 8:59 AM, Nico Weber <thakis at chromium.org> wrote:
>
>> LibclangReparseTest.ReparseWithModule fails for me. (With `./configure
>> --enable-optimized --enable-targets=host-only --enable-libedit=no
>> --disable-threads --disable-pthreads --without-llvmgcc --without-llvmgxx`)
>>
>>
>>
>> On Mon, Jun 30, 2014 at 1:04 PM, Ben Langmuir <blangmuir at apple.com>
>> wrote:
>>
>>> Author: benlangmuir
>>> Date: Mon Jun 30 15:04:14 2014
>>> New Revision: 212060
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=212060&view=rev
>>> Log:
>>> Consider module depedencies when checking a preamble in libclang
>>>
>>> Add module dependencies (header files, module map files) to the list of
>>> files to check when deciding whether to rebuild a preamble. That fixes
>>> using preambles with module imports so long as they are in
>>> non-overridden files.
>>>
>>> My intent is to use to unify the existing dependency collectors to the
>>> new “DependencyCollectory” interface from this commit, starting with the
>>> DependencyFileGenerator.
>>>
>>> Modified:
>>>     cfe/trunk/include/clang/Frontend/CompilerInstance.h
>>>     cfe/trunk/include/clang/Frontend/Utils.h
>>>     cfe/trunk/lib/Frontend/ASTUnit.cpp
>>>     cfe/trunk/lib/Frontend/CompilerInstance.cpp
>>>     cfe/trunk/lib/Frontend/DependencyFile.cpp
>>>     cfe/trunk/unittests/libclang/LibclangTest.cpp
>>>
>>> Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original)
>>> +++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Mon Jun 30
>>> 15:04:14 2014
>>> @@ -111,6 +111,8 @@ class CompilerInstance : public ModuleLo
>>>    /// \brief The dependency file generator.
>>>    std::unique_ptr<DependencyFileGenerator> TheDependencyFileGenerator;
>>>
>>> +  std::vector<std::shared_ptr<DependencyCollector>>
>>> DependencyCollectors;
>>> +
>>>    /// \brief The set of top-level modules that has already been loaded,
>>>    /// along with the module map
>>>    llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
>>> @@ -711,6 +713,10 @@ public:
>>>    GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
>>> override;
>>>
>>>    bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc)
>>> override;
>>> +
>>> +  void addDependencyCollector(std::shared_ptr<DependencyCollector>
>>> Listener) {
>>> +    DependencyCollectors.push_back(std::move(Listener));
>>> +  }
>>>  };
>>>
>>>  } // end namespace clang
>>>
>>> Modified: cfe/trunk/include/clang/Frontend/Utils.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/Utils.h?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Frontend/Utils.h (original)
>>> +++ cfe/trunk/include/clang/Frontend/Utils.h Mon Jun 30 15:04:14 2014
>>> @@ -69,6 +69,39 @@ void InitializePreprocessor(Preprocessor
>>>  void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS,
>>>                                const PreprocessorOutputOptions &Opts);
>>>
>>> +/// An interface for collecting the dependencies of a compilation.
>>> Users should
>>> +/// use \c attachToPreprocessor and \c attachToASTReader to get all of
>>> the
>>> +/// dependencies.
>>> +// FIXME: Migrate DependencyFileGen, DependencyGraphGen,
>>> ModuleDepCollectory to
>>> +// use this interface.
>>> +class DependencyCollector {
>>> +public:
>>> +  void attachToPreprocessor(Preprocessor &PP);
>>> +  void attachToASTReader(ASTReader &R);
>>> +  llvm::ArrayRef<std::string> getDependencies() const { return
>>> Dependencies; }
>>> +
>>> +  /// Called when a new file is seen. Return true if \p Filename should
>>> be added
>>> +  /// to the list of dependencies.
>>> +  ///
>>> +  /// The default implementation ignores <built-in> and system files.
>>> +  virtual bool sawDependency(StringRef Filename, bool FromModule,
>>> +                             bool IsSystem, bool IsModuleFile, bool
>>> IsMissing);
>>> +  /// Called when the end of the main file is reached.
>>> +  virtual void finishedMainFile() { }
>>> +  /// Return true if system files should be passed to sawDependency().
>>> +  virtual bool needSystemDependencies() { return false; }
>>> +  virtual ~DependencyCollector();
>>> +
>>> +public: // implementation detail
>>> +  /// Add a dependency \p Filename if it has not been seen before and
>>> +  /// sawDependency() returns true.
>>> +  void maybeAddDependency(StringRef Filename, bool FromModule, bool
>>> IsSystem,
>>> +                          bool IsModuleFile, bool IsMissing);
>>> +private:
>>> +  llvm::StringSet<> Seen;
>>> +  std::vector<std::string> Dependencies;
>>> +};
>>> +
>>>  /// Builds a depdenency file when attached to a Preprocessor (for
>>> includes) and
>>>  /// ASTReader (for module imports), and writes it out at the end of
>>> processing
>>>  /// a source file.  Users should attach to the ast reader whenever a
>>> module is
>>>
>>> Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
>>> +++ cfe/trunk/lib/Frontend/ASTUnit.cpp Mon Jun 30 15:04:14 2014
>>> @@ -1609,6 +1609,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBuff
>>>    Clang->setSourceManager(new SourceManager(getDiagnostics(),
>>>                                              Clang->getFileManager()));
>>>
>>> +  auto PreambleDepCollector = std::make_shared<DependencyCollector>();
>>> +  Clang->addDependencyCollector(PreambleDepCollector);
>>> +
>>>    std::unique_ptr<PrecompilePreambleAction> Act;
>>>    Act.reset(new PrecompilePreambleAction(*this));
>>>    if (!Act->BeginSourceFile(*Clang.get(),
>>> Clang->getFrontendOpts().Inputs[0])) {
>>> @@ -1657,29 +1660,20 @@ llvm::MemoryBuffer *ASTUnit::getMainBuff
>>>    // so we can verify whether they have changed or not.
>>>    FilesInPreamble.clear();
>>>    SourceManager &SourceMgr = Clang->getSourceManager();
>>> -  const llvm::MemoryBuffer *MainFileBuffer
>>> -    = SourceMgr.getBuffer(SourceMgr.getMainFileID());
>>> -  for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
>>> -                                     FEnd = SourceMgr.fileinfo_end();
>>> -       F != FEnd;
>>> -       ++F) {
>>> -    const FileEntry *File = F->second->OrigEntry;
>>> -    if (!File)
>>> -      continue;
>>> -    const llvm::MemoryBuffer *Buffer = F->second->getRawBuffer();
>>> -    if (Buffer == MainFileBuffer)
>>> +  for (auto &Filename : PreambleDepCollector->getDependencies()) {
>>> +    const FileEntry *File = Clang->getFileManager().getFile(Filename);
>>> +    if (!File || File ==
>>> SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
>>>        continue;
>>> -
>>>      if (time_t ModTime = File->getModificationTime()) {
>>>        FilesInPreamble[File->getName()] =
>>> PreambleFileHash::createForFile(
>>> -          F->second->getSize(), ModTime);
>>> +          File->getSize(), ModTime);
>>>      } else {
>>> -      assert(F->second->getSize() == Buffer->getBufferSize());
>>> +      llvm::MemoryBuffer *Buffer =
>>> SourceMgr.getMemoryBufferForFile(File);
>>>        FilesInPreamble[File->getName()] =
>>>            PreambleFileHash::createForMemoryBuffer(Buffer);
>>>      }
>>>    }
>>> -
>>> +
>>>    PreambleRebuildCounter = 1;
>>>    PreprocessorOpts.eraseRemappedFile(
>>>
>>> PreprocessorOpts.remapped_file_buffer_end() - 1);
>>>
>>> Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
>>> +++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Mon Jun 30 15:04:14 2014
>>> @@ -288,6 +288,9 @@ void CompilerInstance::createPreprocesso
>>>      AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
>>>                               getHeaderSearchOpts().Sysroot);
>>>
>>> +  for (auto &Listener : DependencyCollectors)
>>> +    Listener->attachToPreprocessor(*PP);
>>> +
>>>    // If we don't have a collector, but we are collecting module
>>> dependencies,
>>>    // then we're the top level compiler instance and need to create one.
>>>    if (!ModuleDepCollector && !DepOpts.ModuleDependencyOutputDir.empty())
>>> @@ -1233,6 +1236,9 @@ CompilerInstance::loadModule(SourceLocat
>>>      if (ModuleDepCollector)
>>>        ModuleDepCollector->attachToASTReader(*ModuleManager);
>>>
>>> +    for (auto &Listener : DependencyCollectors)
>>> +      Listener->attachToASTReader(*ModuleManager);
>>> +
>>>      // Try to load the module file.
>>>      unsigned ARRFlags = ASTReader::ARR_OutOfDate |
>>> ASTReader::ARR_Missing;
>>>      switch (ModuleManager->ReadAST(ModuleFileName,
>>> serialization::MK_Module,
>>>
>>> Modified: cfe/trunk/lib/Frontend/DependencyFile.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/DependencyFile.cpp?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Frontend/DependencyFile.cpp (original)
>>> +++ cfe/trunk/lib/Frontend/DependencyFile.cpp Mon Jun 30 15:04:14 2014
>>> @@ -29,6 +29,105 @@
>>>  using namespace clang;
>>>
>>>  namespace {
>>> +struct DepCollectorPPCallbacks : public PPCallbacks {
>>> +  DependencyCollector &DepCollector;
>>> +  SourceManager &SM;
>>> +  DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
>>> +      : DepCollector(L), SM(SM) { }
>>> +
>>> +  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
>>> +                   SrcMgr::CharacteristicKind FileType,
>>> +                   FileID PrevFID) override {
>>> +    if (Reason != PPCallbacks::EnterFile)
>>> +      return;
>>> +
>>> +    // Dependency generation really does want to go all the way to the
>>> +    // file entry for a source location to find out what is depended on.
>>> +    // We do not want #line markers to affect dependency generation!
>>> +    const FileEntry *FE =
>>> +        SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
>>> +    if (!FE)
>>> +      return;
>>> +
>>> +    StringRef Filename = FE->getName();
>>> +
>>> +    // Remove leading "./" (or ".//" or "././" etc.)
>>> +    while (Filename.size() > 2 && Filename[0] == '.' &&
>>> +           llvm::sys::path::is_separator(Filename[1])) {
>>> +      Filename = Filename.substr(1);
>>> +      while (llvm::sys::path::is_separator(Filename[0]))
>>> +        Filename = Filename.substr(1);
>>> +    }
>>> +
>>> +    DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
>>> +                                   FileType != SrcMgr::C_User,
>>> +                                   /*IsModuleFile*/false,
>>> /*IsMissing*/false);
>>> +  }
>>> +
>>> +  void InclusionDirective(SourceLocation HashLoc, const Token
>>> &IncludeTok,
>>> +                          StringRef FileName, bool IsAngled,
>>> +                          CharSourceRange FilenameRange, const
>>> FileEntry *File,
>>> +                          StringRef SearchPath, StringRef RelativePath,
>>> +                          const Module *Imported) override {
>>> +    if (!File)
>>> +      DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
>>> +                                     /*IsSystem*/false,
>>> /*IsModuleFile*/false,
>>> +                                     /*IsMissing*/true);
>>> +    // Files that actually exist are handled by FileChanged.
>>> +  }
>>> +
>>> +  void EndOfMainFile() override {
>>> +    DepCollector.finishedMainFile();
>>> +  }
>>> +};
>>> +
>>> +struct DepCollectorASTListener : public ASTReaderListener {
>>> +  DependencyCollector &DepCollector;
>>> +  DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
>>> +  bool needsInputFileVisitation() override { return true; }
>>> +  bool needsSystemInputFileVisitation() override {
>>> +    return DepCollector.needSystemDependencies();
>>> +  }
>>> +  void visitModuleFile(StringRef Filename) override {
>>> +    DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
>>> +                                   /*IsSystem*/false,
>>> /*IsModuleFile*/true,
>>> +                                   /*IsMissing*/false);
>>> +  }
>>> +  bool visitInputFile(StringRef Filename, bool IsSystem,
>>> +                      bool IsOverridden) override {
>>> +    if (IsOverridden)
>>> +      return true;
>>> +
>>> +    DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
>>> IsSystem,
>>> +                                   /*IsModuleFile*/false,
>>> /*IsMissing*/false);
>>> +    return true;
>>> +  }
>>> +};
>>> +} // end anonymous namespace
>>> +
>>> +void DependencyCollector::maybeAddDependency(StringRef Filename, bool
>>> FromModule,
>>> +                                            bool IsSystem, bool
>>> IsModuleFile,
>>> +                                            bool IsMissing) {
>>> +  if (Seen.insert(Filename) &&
>>> +      sawDependency(Filename, FromModule, IsSystem, IsModuleFile,
>>> IsMissing))
>>> +    Dependencies.push_back(Filename);
>>> +}
>>> +
>>> +bool DependencyCollector::sawDependency(StringRef Filename, bool
>>> FromModule,
>>> +                                       bool IsSystem, bool IsModuleFile,
>>> +                                       bool IsMissing) {
>>> +  return Filename != "<built-in>" && (needSystemDependencies() ||
>>> !IsSystem);
>>> +}
>>> +
>>> +DependencyCollector::~DependencyCollector() { }
>>> +void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
>>> +  PP.addPPCallbacks(new DepCollectorPPCallbacks(*this,
>>> PP.getSourceManager()));
>>> +}
>>> +void DependencyCollector::attachToASTReader(ASTReader &R) {
>>> +  R.addListener(new DepCollectorASTListener(*this));
>>> +}
>>> +
>>> +namespace {
>>>  /// Private implementation for DependencyFileGenerator
>>>  class DFGImpl : public PPCallbacks {
>>>    std::vector<std::string> Files;
>>>
>>> Modified: cfe/trunk/unittests/libclang/LibclangTest.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/libclang/LibclangTest.cpp?rev=212060&r1=212059&r2=212060&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/unittests/libclang/LibclangTest.cpp (original)
>>> +++ cfe/trunk/unittests/libclang/LibclangTest.cpp Mon Jun 30 15:04:14
>>> 2014
>>> @@ -340,9 +340,9 @@ TEST(libclang, ModuleMapDescriptor) {
>>>  }
>>>
>>>  class LibclangReparseTest : public ::testing::Test {
>>> -  std::string TestDir;
>>>    std::set<std::string> Files;
>>>  public:
>>> +  std::string TestDir;
>>>    CXIndex Index;
>>>    CXTranslationUnit ClangTU;
>>>    unsigned TUFlags;
>>> @@ -407,6 +407,39 @@ TEST_F(LibclangReparseTest, Reparse) {
>>>                                         nullptr, 0, TUFlags);
>>>    EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
>>>    DisplayDiagnostics();
>>> +
>>> +  // Immedaitely reparse.
>>> +  ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
>>> +  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
>>> +
>>> +  std::string NewHeaderContents =
>>> +      std::string(HeaderTop) + "int baz;" + HeaderBottom;
>>> +  WriteFile(HeaderName, NewHeaderContents);
>>> +
>>> +  // Reparse after fix.
>>> +  ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
>>> +  EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
>>> +}
>>> +
>>> +TEST_F(LibclangReparseTest, ReparseWithModule) {
>>> +  const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
>>> +  const char *HeaderBottom = "\n};\n#endif\n";
>>> +  const char *MFile = "#include \"HeaderFile.h\"\nint main() {"
>>> +                         " struct Foo foo; foo.bar = 7; foo.baz = 8;
>>> }\n";
>>> +  const char *ModFile = "module A { header \"HeaderFile.h\" }\n";
>>> +  std::string HeaderName = "HeaderFile.h";
>>> +  std::string MName = "MFile.m";
>>> +  std::string ModName = "module.modulemap";
>>> +  WriteFile(MName, MFile);
>>> +  WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);
>>> +  WriteFile(ModName, ModFile);
>>> +
>>> +  const char *Args[] = { "-fmodules", "-I", TestDir.c_str() };
>>> +  int NumArgs = sizeof(Args) / sizeof(Args[0]);
>>> +  ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args,
>>> NumArgs,
>>> +                                       nullptr, 0, TUFlags);
>>> +  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
>>> +  DisplayDiagnostics();
>>>
>>>    // Immedaitely reparse.
>>>    ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140716/21afd00a/attachment.html>


More information about the cfe-commits mailing list