]> granicus.if.org Git - clang/commitdiff
Implement dependency analysis for the precompiled preamble. If any of
authorDouglas Gregor <dgregor@apple.com>
Sat, 31 Jul 2010 00:40:00 +0000 (00:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 31 Jul 2010 00:40:00 +0000 (00:40 +0000)
the files in the precompiled preamble have changed since it was build,
force the preamble to be rebuilt.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109937 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/SourceManager.h
include/clang/Frontend/ASTUnit.h
lib/Basic/Diagnostic.cpp
lib/Frontend/ASTUnit.cpp

index b6a1ac4492eb421bfdf285ddf2c5e41b7ad785b9..dc314f1f072675ff4828b3bd5329d56b48857130 100644 (file)
@@ -110,6 +110,12 @@ namespace SrcMgr {
       Buffer.setPointer(B);
       Buffer.setInt(false);
     }
+    
+    /// \brief Get the underlying buffer, returning NULL if the buffer is not
+    /// yet available.
+    const llvm::MemoryBuffer *getRawBuffer() const {
+      return Buffer.getPointer();
+    }
 
     /// \brief Replace the existing buffer (which will be deleted)
     /// with the given buffer.
index 56e73d9be4b50b881894611857d1c7ae5ebb721f..b9db4beafd46c991754bb9e91c7ecaa0fa87418e 100644 (file)
@@ -21,6 +21,7 @@
 #include "clang/Basic/FileManager.h"
 #include "clang/Index/ASTLocation.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/System/Path.h"
 #include "llvm/Support/Timer.h"
 #include <map>
@@ -28,6 +29,7 @@
 #include <vector>
 #include <cassert>
 #include <utility>
+#include <sys/types.h>
 
 namespace llvm {
   class MemoryBuffer;
@@ -135,14 +137,21 @@ private:
   /// \brief The size of the source buffer that we've reserved for the main 
   /// file within the precompiled preamble.
   unsigned PreambleReservedSize;
-  
+
+  /// \brief Keeps track of the files that were used when computing the 
+  /// preamble, with both their buffer size and their modification time.
+  ///
+  /// If any of the files have changed from one compile to the next,
+  /// the preamble must be thrown away.
+  llvm::StringMap<std::pair<off_t, time_t> > FilesInPreamble;
+
   /// \brief When non-NULL, this is the buffer used to store the contents of
   /// the main file when it has been padded for use with the precompiled
   /// preamble.
   llvm::MemoryBuffer *SavedMainFileBuffer;
   
   /// \brief The group of timers associated with this translation unit.
-  llvm::OwningPtr<llvm::TimerGroup> TimerGroup;
+  llvm::OwningPtr<llvm::TimerGroup> TimerGroup;  
   
   /// \brief The timers we've created from the various parses, reparses, etc.
   /// involved in this translation unit.
index 74937910d93be77ca7b54cfcd173c54cb8bc980a..0dc57e4ecbf4a2ce9cfe0c9d04950d67215c1ad4 100644 (file)
@@ -251,6 +251,23 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
   ArgToStringFn = DummyArgToStringFn;
   ArgToStringCookie = 0;
 
+  AllExtensionsSilenced = 0;
+  IgnoreAllWarnings = false;
+  WarningsAsErrors = false;
+  ErrorsAsFatal = false;
+  SuppressSystemWarnings = false;
+  SuppressAllDiagnostics = false;
+  ShowOverloads = Ovl_All;
+  ExtBehavior = Ext_Ignore;
+
+  ErrorLimit = 0;
+  TemplateBacktraceLimit = 0;
+  CustomDiagInfo = 0;
+
+  // Set all mappings to 'unset'.
+  DiagMappingsStack.clear();
+  DiagMappingsStack.push_back(DiagMappings());
+
   Reset();
 }
 
@@ -315,31 +332,15 @@ bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID,
 }
 
 void Diagnostic::Reset() {
-  AllExtensionsSilenced = 0;
-  IgnoreAllWarnings = false;
-  WarningsAsErrors = false;
-  ErrorsAsFatal = false;
-  SuppressSystemWarnings = false;
-  SuppressAllDiagnostics = false;
-  ShowOverloads = Ovl_All;
-  ExtBehavior = Ext_Ignore;
-  
   ErrorOccurred = false;
   FatalErrorOccurred = false;
-  ErrorLimit = 0;
-  TemplateBacktraceLimit = 0;
   
   NumWarnings = 0;
   NumErrors = 0;
   NumErrorsSuppressed = 0;
-  CustomDiagInfo = 0;
   CurDiagID = ~0U;
   LastDiagLevel = Ignored;
   DelayedDiagID = 0;
-
-  // Set all mappings to 'unset'.
-  DiagMappingsStack.clear();
-  DiagMappingsStack.push_back(DiagMappings());
 }
 
 /// getDescription - Given a diagnostic ID, return a description of the
index 7f42fa949e5bb2a3ef7e5a1b168685f441fa39d2..d7597bcf5b182e9968b6c57de97f6f9893444d29 100644 (file)
@@ -36,6 +36,7 @@
 #include "llvm/Support/Timer.h"
 #include <cstdlib>
 #include <cstdio>
+#include <sys/stat.h>
 using namespace clang;
 
 ASTUnit::ASTUnit(bool _MainFileIsAST)
@@ -626,14 +627,72 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
                NewPreamble.second.first) == 0) {
       // The preamble has not changed. We may be able to re-use the precompiled
       // preamble.
-      // FIXME: Check that none of the files used by the preamble have changed.
           
+      // Check that none of the files used by the preamble have changed.
+      bool AnyFileChanged = false;
+          
+      // First, make a record of those files that have been overridden via
+      // remapping or unsaved_files.
+      llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
+      for (PreprocessorOptions::remapped_file_iterator
+                R = PreprocessorOpts.remapped_file_begin(),
+             REnd = PreprocessorOpts.remapped_file_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        struct stat StatBuf;
+        if (stat(R->second.c_str(), &StatBuf)) {
+          // If we can't stat the file we're remapping to, assume that something
+          // horrible happened.
+          AnyFileChanged = true;
+          break;
+        }
         
-      // Okay! Re-use the precompiled preamble.
-      return CreatePaddedMainFileBuffer(NewPreamble.first, 
-                                        CreatedPreambleBuffer,
-                                        PreambleReservedSize,
-                                        FrontendOpts.Inputs[0].second);
+        OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size, 
+                                                   StatBuf.st_mtime);
+      }
+      for (PreprocessorOptions::remapped_file_buffer_iterator
+                R = PreprocessorOpts.remapped_file_buffer_begin(),
+             REnd = PreprocessorOpts.remapped_file_buffer_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        // FIXME: Should we actually compare the contents of file->buffer
+        // remappings?
+        OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(), 
+                                                   0);
+      }
+       
+      // Check whether anything has changed.
+      for (llvm::StringMap<std::pair<off_t, time_t> >::iterator 
+             F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
+           !AnyFileChanged && F != FEnd; 
+           ++F) {
+        llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+          = OverriddenFiles.find(F->first());
+        if (Overridden != OverriddenFiles.end()) {
+          // This file was remapped; check whether the newly-mapped file 
+          // matches up with the previous mapping.
+          if (Overridden->second != F->second)
+            AnyFileChanged = true;
+          continue;
+        }
+        
+        // The file was not remapped; check whether it has changed on disk.
+        struct stat StatBuf;
+        if (stat(F->first(), &StatBuf)) {
+          // If we can't stat the file, assume that something horrible happened.
+          AnyFileChanged = true;
+        } else if (StatBuf.st_size != F->second.first || 
+                   StatBuf.st_mtime != F->second.second)
+          AnyFileChanged = true;
+      }
+          
+      if (!AnyFileChanged) {
+        // Okay! Re-use the precompiled preamble.
+        return CreatePaddedMainFileBuffer(NewPreamble.first, 
+                                          CreatedPreambleBuffer,
+                                          PreambleReservedSize,
+                                          FrontendOpts.Inputs[0].second);
+      }
     }
     
     // We can't reuse the previously-computed preamble. Build a new one.
@@ -768,14 +827,31 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
       delete NewPreamble.first;
     if (PreambleTimer)
       PreambleTimer->stopTimer();
-    if (PreambleTimer)
-      PreambleTimer->stopTimer();
 
     return 0;
   }
   
   // Keep track of the preamble we precompiled.
   PreambleFile = FrontendOpts.OutputFile;
+  
+  // Keep track of all of the files that the source manager knows about,
+  // 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->Entry;
+    if (!File || F->second->getRawBuffer() == MainFileBuffer)
+      continue;
+    
+    FilesInPreamble[File->getName()]
+      = std::make_pair(F->second->getSize(), File->getModificationTime());
+  }
+  
   if (PreambleTimer)
     PreambleTimer->stopTimer();
   
@@ -913,6 +989,13 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
     Timers.push_back(ReparsingTimer);
   }
   
+  // Remap files.
+  // FIXME: Do we want to remove old mappings for these files?
+  Invocation->getPreprocessorOpts().clearRemappedFiles();
+  for (unsigned I = 0; I != NumRemappedFiles; ++I)
+    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+                                                      RemappedFiles[I].second);
+  
   // If we have a preamble file lying around, build or reuse the precompiled
   // preamble.
   llvm::MemoryBuffer *OverrideMainBuffer = 0;
@@ -922,12 +1005,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
   // Clear out the diagnostics state.
   getDiagnostics().Reset();
   
-  // Remap files.
-  Invocation->getPreprocessorOpts().clearRemappedFiles();
-  for (unsigned I = 0; I != NumRemappedFiles; ++I)
-    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
-                                                      RemappedFiles[I].second);
-
   // Parse the sources
   bool Result = Parse(OverrideMainBuffer);  
   if (ReparsingTimer)