#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
#include <cassert>
#include <map>
return Preamble;
}
-private:
+ /// Data that allows us to tell if a file that was used in a preambule was
+ /// changed.
+ struct PreambleFileHash {
+ /// All files have size set.
+ off_t Size;
+
+ /// Modification time is set for files that are on disk. For memory
+ /// buffers it is zero.
+ time_t ModTime;
+
+ /// Memory buffers have MD5 instead of modification time. We don't
+ /// compute MD5 for on-disk files because we hope that modification time is
+ /// enough to tell if the file was changed.
+ llvm::MD5::MD5Result MD5;
+
+ static PreambleFileHash createForFile(off_t Size, time_t ModTime);
+ static PreambleFileHash
+ createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
+
+ friend bool operator==(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS);
+ friend bool operator!=(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS) {
+ return !(LHS == RHS);
+ }
+ };
+
+private:
/// \brief The contents of the preamble that has been precompiled to
/// \c PreambleFile.
PreambleData Preamble;
///
/// 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;
+ llvm::StringMap<PreambleFileHash> 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
return Result;
}
+ASTUnit::PreambleFileHash
+ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
+ PreambleFileHash Result;
+ Result.Size = Size;
+ Result.ModTime = ModTime;
+ memset(Result.MD5, 0, sizeof(Result.MD5[0]) * sizeof(Result.MD5));
+ return Result;
+}
+
+ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer(
+ const llvm::MemoryBuffer *Buffer) {
+ PreambleFileHash Result;
+ Result.Size = Buffer->getBufferSize();
+ Result.ModTime = 0;
+
+ llvm::MD5 MD5Ctx;
+ MD5Ctx.update(Buffer->getBuffer().data());
+ MD5Ctx.final(Result.MD5);
+
+ return Result;
+}
+
+namespace clang {
+bool operator==(const ASTUnit::PreambleFileHash &LHS,
+ const ASTUnit::PreambleFileHash &RHS) {
+ return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
+ memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5[0]) * sizeof(LHS.MD5)) == 0;
+}
+} // namespace clang
+
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
/// the source file.
///
// 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;
+ llvm::StringMap<PreambleFileHash> OverriddenFiles;
for (PreprocessorOptions::remapped_file_iterator
R = PreprocessorOpts.remapped_file_begin(),
REnd = PreprocessorOpts.remapped_file_end();
break;
}
- OverriddenFiles[R->first] = std::make_pair(
+ OverriddenFiles[R->first] = PreambleFileHash::createForFile(
Status.getSize(), Status.getLastModificationTime().toEpochTime());
}
for (PreprocessorOptions::remapped_file_buffer_iterator
++R) {
// FIXME: Should we actually compare the contents of file->buffer
// remappings?
- OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(),
- 0);
+ OverriddenFiles[R->first] =
+ PreambleFileHash::createForMemoryBuffer(R->second);
}
// Check whether anything has changed.
- for (llvm::StringMap<std::pair<off_t, time_t> >::iterator
+ for (llvm::StringMap<PreambleFileHash>::iterator
F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
!AnyFileChanged && F != FEnd;
++F) {
- llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+ llvm::StringMap<PreambleFileHash>::iterator Overridden
= OverriddenFiles.find(F->first());
if (Overridden != OverriddenFiles.end()) {
// This file was remapped; check whether the newly-mapped file
if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
// If we can't stat the file, assume that something horrible happened.
AnyFileChanged = true;
- } else if (Status.getSize() != uint64_t(F->second.first) ||
+ } else if (Status.getSize() != uint64_t(F->second.Size) ||
Status.getLastModificationTime().toEpochTime() !=
- uint64_t(F->second.second))
+ uint64_t(F->second.ModTime))
AnyFileChanged = true;
}
F != FEnd;
++F) {
const FileEntry *File = F->second->OrigEntry;
- if (!File || F->second->getRawBuffer() == MainFileBuffer)
+ if (!File)
continue;
-
- FilesInPreamble[File->getName()]
- = std::make_pair(F->second->getSize(), File->getModificationTime());
+ const llvm::MemoryBuffer *Buffer = F->second->getRawBuffer();
+ if (Buffer == MainFileBuffer)
+ continue;
+
+ if (time_t ModTime = File->getModificationTime()) {
+ FilesInPreamble[File->getName()] = PreambleFileHash::createForFile(
+ F->second->getSize(), ModTime);
+ } else {
+ assert(F->second->getSize() == Buffer->getBufferSize());
+ FilesInPreamble[File->getName()] =
+ PreambleFileHash::createForMemoryBuffer(Buffer);
+ }
}
PreambleRebuildCounter = 1;