aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend/ASTUnit.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-07-31 00:40:00 +0000
committerDouglas Gregor <dgregor@apple.com>2010-07-31 00:40:00 +0000
commitcc5888d833caf90ebda37f24da40d2cd06b4d820 (patch)
tree6dc571d547e7b6116db03fa68d26420f3fdb2aa2 /lib/Frontend/ASTUnit.cpp
parent036cdf05ef011f564fdec3cf949fbcec41a71a77 (diff)
Implement dependency analysis for the precompiled preamble. If any of
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
Diffstat (limited to 'lib/Frontend/ASTUnit.cpp')
-rw-r--r--lib/Frontend/ASTUnit.cpp105
1 files changed, 91 insertions, 14 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 7f42fa949e..d7597bcf5b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -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)