diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 9dbd9cfa21..50d997c986 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -33,6 +33,10 @@ def err_fe_expected_compiler_job : Error< "unable to handle compilation, expected exactly one compiler job in '%0'">; def err_fe_expected_clang_command : Error< "expected a clang compiler command">; +def err_fe_remap_missing_to_file : Error< + "could not remap file '%0' to the contents of file '%1'">, DefaultFatal; +def err_fe_remap_missing_from_file : Error< + "could not remap from missing file '%0'">, DefaultFatal; def err_verify_bogus_characters : Error< "bogus characters before '{{' in expected string">; diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index f0c1d3c2c3..c43a1feb8c 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringRef.h" #include #include +#include #include namespace clang { @@ -41,6 +42,21 @@ public: /// If given, a PTH cache file to use for speeding up header parsing. std::string TokenCache; + /// \brief The set of file remappings, which take existing files on + /// the system (the first part of each pair) and gives them the + /// contents of other files on the system (the second part of each + /// pair). + std::vector > RemappedFiles; + + typedef std::vector >::const_iterator + remapped_file_iterator; + remapped_file_iterator remapped_file_begin() const { + return RemappedFiles.begin(); + } + remapped_file_iterator remapped_file_end() const { + return RemappedFiles.end(); + } + public: PreprocessorOptions() : UsePredefines(true) {} @@ -50,6 +66,9 @@ public: void addMacroUndef(llvm::StringRef Name) { Macros.push_back(std::make_pair(Name, true)); } + void addRemappedFile(llvm::StringRef From, llvm::StringRef To) { + RemappedFiles.push_back(std::make_pair(From, To)); + } }; } // end namespace clang diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 2d58beead8..02b24b4976 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -190,6 +190,45 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, PP->setPTHManager(PTHMgr); } + // Remap files in the source manager. + for (PreprocessorOptions::remapped_file_iterator + Remap = PPOpts.remapped_file_begin(), + RemapEnd = PPOpts.remapped_file_end(); + Remap != RemapEnd; + ++Remap) { + // Find the file that we're mapping to. + const FileEntry *ToFile = FileMgr.getFile(Remap->second); + if (!ToFile) { + Diags.Report(diag::err_fe_remap_missing_to_file) + << Remap->first << Remap->second; + continue; + } + + // Find the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getFile(Remap->first); + if (!FromFile) { + // FIXME: We could actually recover from this, by faking a + // FileEntry based on the "ToFile". + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Load the contents of the file we're mapping to. + std::string ErrorStr; + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + if (!Buffer) { + Diags.Report(diag::err_fe_error_opening) + << Remap->second << ErrorStr; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Buffer); + } + InitializePreprocessor(*PP, PPOpts, HSOpts); // Handle generating dependencies, if requested. diff --git a/test/Misc/Inputs/remapped-file b/test/Misc/Inputs/remapped-file new file mode 100644 index 0000000000..657613ed14 --- /dev/null +++ b/test/Misc/Inputs/remapped-file @@ -0,0 +1 @@ +int *f(float *fp) { return fp; } diff --git a/test/Misc/remap-file.c b/test/Misc/remap-file.c new file mode 100644 index 0000000000..e8aa3e44cc --- /dev/null +++ b/test/Misc/remap-file.c @@ -0,0 +1,5 @@ +// RUN: clang-cc -remap-file="%s;%S/Inputs/remapped-file" -fsyntax-only %s 2>&1 | FileCheck %s + +// CHECK: remap-file.c:1:28: warning: incompatible pointer types + +int diff --git a/tools/clang-cc/Options.cpp b/tools/clang-cc/Options.cpp index a18598ef7c..c97d4ca8c9 100644 --- a/tools/clang-cc/Options.cpp +++ b/tools/clang-cc/Options.cpp @@ -673,6 +673,10 @@ static llvm::cl::opt UndefMacros("undef", llvm::cl::value_desc("macro"), llvm::cl::desc("undef all system defines")); +static llvm::cl::list +RemappedFiles("remap-file", llvm::cl::value_desc(";"), + llvm::cl::desc("replace the contents of the file with the contents of the file")); + } //===----------------------------------------------------------------------===// @@ -1071,6 +1075,20 @@ void clang::InitializePreprocessorOptions(PreprocessorOptions &Opts) { for (unsigned i = 0, e = OrderedPaths.size(); i != e; ++i) Opts.Includes.push_back(*OrderedPaths[i].second); + + // Handle file remapping. + for (unsigned i = 0, e = RemappedFiles.size(); i != e; ++i) { + std::string::size_type Semi = RemappedFiles[i].find(';'); + if (Semi == std::string::npos) { + // FIXME: Don't fail like this. + fprintf(stderr, + "error: -remap-file not of the form ;\n"); + continue; + } + + Opts.addRemappedFile(llvm::StringRef(RemappedFiles[i].c_str(), Semi), + llvm::StringRef(RemappedFiles[i].c_str() + Semi + 1)); + } } void clang::InitializeLangOptions(LangOptions &Options,