diff options
-rw-r--r-- | clang/include/clang/Frontend/ASTUnit.h | 32 | ||||
-rw-r--r-- | clang/lib/Frontend/ASTUnit.cpp | 63 |
2 files changed, 81 insertions, 14 deletions
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 1b54fdf0a9e..4971cac208d 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -30,6 +30,7 @@ #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> @@ -205,8 +206,35 @@ public: 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; @@ -226,7 +254,7 @@ private: /// /// 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 diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 9862e2d87df..350ed73068f 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1359,6 +1359,36 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, 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. /// @@ -1428,7 +1458,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // 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(); @@ -1442,7 +1472,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( break; } - OverriddenFiles[R->first] = std::make_pair( + OverriddenFiles[R->first] = PreambleFileHash::createForFile( Status.getSize(), Status.getLastModificationTime().toEpochTime()); } for (PreprocessorOptions::remapped_file_buffer_iterator @@ -1452,16 +1482,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( ++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 @@ -1476,9 +1506,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( 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; } @@ -1678,11 +1708,20 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( 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; |