diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-01-23 00:14:00 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-01-23 00:14:00 +0000 |
commit | 4db64a461cb3442934afe43c83ed3f17f7c11c1d (patch) | |
tree | c9de870e2fa2e16f082b9e5124e32ac324b070c3 | |
parent | e4fb82839a762e632f63e195058015e2f1ca27a8 (diff) |
Extend clang_createTranslationUnitFromSourceFile() to support creating
translation units that include unsaved files.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94258 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang-c/Index.h | 18 | ||||
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 17 | ||||
-rw-r--r-- | include/clang/Frontend/PreprocessorOptions.h | 22 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 32 | ||||
-rw-r--r-- | lib/Frontend/InitPreprocessor.cpp | 41 | ||||
-rw-r--r-- | test/Index/Inputs/remap-load-to.c | 3 | ||||
-rw-r--r-- | test/Index/remap-cursor-at.c | 5 | ||||
-rw-r--r-- | test/Index/remap-load.c | 13 | ||||
-rw-r--r-- | tools/CIndex/CIndex.cpp | 41 | ||||
-rw-r--r-- | tools/CIndex/CIndexCodeCompletion.cpp | 31 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.cpp | 37 | ||||
-rw-r--r-- | tools/CIndex/CIndexer.h | 14 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 214 |
13 files changed, 334 insertions, 154 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 2a9dd0f5a1..ef17ed1ca8 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -222,13 +222,21 @@ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); * * \param source_filename - The name of the source file to load, or NULL if the * source file is included in clang_command_line_args. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for code completion, including the contents of + * those files. */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( - CXIndex CIdx, - const char *source_filename, - int num_clang_command_line_args, - const char **clang_command_line_args -); + CXIndex CIdx, + const char *source_filename, + int num_clang_command_line_args, + const char **clang_command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files); /** * \defgroup CINDEX_FILES File manipulation routines diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index f18972ab34..2659dbb2a3 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -21,6 +21,11 @@ #include <string> #include <vector> #include <cassert> +#include <utility> + +namespace llvm { + class MemoryBuffer; +} namespace clang { class ASTContext; @@ -111,6 +116,10 @@ public: return TopLevelDecls; } + /// \brief A mapping from a file name to the memory buffer that stores the + /// remapped contents of that file. + typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile; + /// \brief Create a ASTUnit from a PCH file. /// /// \param Filename - The PCH file to load. @@ -122,7 +131,9 @@ public: static ASTUnit *LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false); + bool UseBumpAllocator = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0); /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. @@ -158,7 +169,9 @@ public: Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls = false, - bool UseBumpAllocator = false); + bool UseBumpAllocator = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0); }; } // namespace clang diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index c43a1feb8c..7ba7c5c38d 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -16,6 +16,10 @@ #include <utility> #include <vector> +namespace llvm { + class MemoryBuffer; +} + namespace clang { class Preprocessor; @@ -48,6 +52,12 @@ public: /// pair). std::vector<std::pair<std::string, std::string> > RemappedFiles; + /// \brief The set of file-to-buffer remappings, which take existing files + /// on the system (the first part of each pair) and gives them the contents + /// of the specified memory buffer (the second part of each pair). + std::vector<std::pair<std::string, const llvm::MemoryBuffer *> > + RemappedFileBuffers; + typedef std::vector<std::pair<std::string, std::string> >::const_iterator remapped_file_iterator; remapped_file_iterator remapped_file_begin() const { @@ -57,6 +67,15 @@ public: return RemappedFiles.end(); } + typedef std::vector<std::pair<std::string, const llvm::MemoryBuffer *> >:: + const_iterator remapped_file_buffer_iterator; + remapped_file_buffer_iterator remapped_file_buffer_begin() const { + return RemappedFileBuffers.begin(); + } + remapped_file_buffer_iterator remapped_file_buffer_end() const { + return RemappedFileBuffers.end(); + } + public: PreprocessorOptions() : UsePredefines(true) {} @@ -69,6 +88,9 @@ public: void addRemappedFile(llvm::StringRef From, llvm::StringRef To) { RemappedFiles.push_back(std::make_pair(From, To)); } + void addRemappedFile(llvm::StringRef From, const llvm::MemoryBuffer * To) { + RemappedFileBuffers.push_back(std::make_pair(From, To)); + } }; } // end namespace clang diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 48296c7289..2fb47cbd8a 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; @@ -103,11 +104,31 @@ const std::string &ASTUnit::getPCHFileName() { ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + RemappedFiles[I].second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, + RemappedFiles[I].second); + } + // Gather Info for preprocessor construction later on. LangOptions LangInfo; @@ -289,7 +310,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgBegin, ArgEnd); @@ -327,6 +350,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, (const char**) CCArgs.data()+CCArgs.size(), Diags); + // Override any files that need remapping + for (unsigned I = 0; I != NumRemappedFiles; ++I) + CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + // Override the resources path. CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 32363eed20..9aaf132034 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -424,40 +424,61 @@ static void InitializeFileRemapping(Diagnostic &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { - // Remap files in the source manager. + // Remap files in the source manager (with buffers). + for (PreprocessorOptions::remapped_file_buffer_iterator + Remap = InitOpts.remapped_file_buffer_begin(), + RemapEnd = InitOpts.remapped_file_buffer_end(); + Remap != RemapEnd; + ++Remap) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + Remap->second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Remap->second); + } + + // Remap files in the source manager (with other files). for (PreprocessorOptions::remapped_file_iterator - Remap = InitOpts.remapped_file_begin(), - RemapEnd = InitOpts.remapped_file_end(); + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.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; + << Remap->first << Remap->second; continue; } - + // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) - << Remap->first; + << 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); + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) - << Remap->second << ErrorStr; + << Remap->second << ErrorStr; continue; } - + // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, Buffer); diff --git a/test/Index/Inputs/remap-load-to.c b/test/Index/Inputs/remap-load-to.c new file mode 100644 index 0000000000..8f9e1eba47 --- /dev/null +++ b/test/Index/Inputs/remap-load-to.c @@ -0,0 +1,3 @@ +int foo(int parm1, float parm2) { + return parm1 + parm2; +} diff --git a/test/Index/remap-cursor-at.c b/test/Index/remap-cursor-at.c new file mode 100644 index 0000000000..f7bcf79b75 --- /dev/null +++ b/test/Index/remap-cursor-at.c @@ -0,0 +1,5 @@ +// RUN: c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s +// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s + +// CHECK: ParmDecl=parm1:1:13 (Definition) +// CHECK: DeclRefExpr=parm2:1:26 diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c new file mode 100644 index 0000000000..84e45bcda4 --- /dev/null +++ b/test/Index/remap-load.c @@ -0,0 +1,13 @@ +// RUN: c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s +// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s + +// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) [Extent=1:5:3:1] +// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) [Extent=1:9:1:17] +// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) [Extent=1:20:1:30] +// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=1:33:3:1] +// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=2:3:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22] +// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 [Extent=2:10:2:14] +// CHECK: remap-load.c:2:10: DeclRefExpr=parm1:1:13 [Extent=2:10:2:14] +// CHECK: remap-load.c:2:18: DeclRefExpr=parm2:1:26 [Extent=2:18:2:22] diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index ddbdf531d0..6cd545f53f 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -873,10 +873,22 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args) { + const char **command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files) { assert(CIdx && "Passed null CXIndex"); CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, + unsaved_files[I].Contents + unsaved_files[I].Length, + unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + if (!CXXIdx->getUseExternalASTGeneration()) { llvm::SmallVector<const char *, 16> Args; @@ -899,7 +911,9 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getDiags(), CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), - /* UseBumpAllocator = */ true)); + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size())); // FIXME: Until we have broader testing, just drop the entire AST if we // encountered an error. @@ -930,6 +944,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, char astTmpFile[L_tmpnam]; argv.push_back(tmpnam(astTmpFile)); + // Remap any unsaved files to temporary files. + std::vector<llvm::sys::Path> TemporaryFiles; + std::vector<std::string> RemapArgs; + if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) + return 0; + + // The pointers into the elements of RemapArgs are stable because we + // won't be adding anything to RemapArgs after this point. + for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) + argv.push_back(RemapArgs[i].c_str()); + // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. for (int i = 0; i < num_command_line_args; ++i) if (const char *arg = command_line_args[i]) { @@ -970,11 +995,17 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, llvm::errs() << '\n'; } - // Finally, we create the translation unit from the ast file. - ASTUnit *ATU = static_cast<ASTUnit *>( - clang_createTranslationUnit(CIdx, astTmpFile)); + ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(), + CXXIdx->getOnlyLocalDecls(), + /* UseBumpAllocator = */ true, + RemappedFiles.data(), + RemappedFiles.size()); if (ATU) ATU->unlinkTemporaryFile(); + + for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) + TemporaryFiles[i].eraseFromDisk(); + return ATU; } diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index f70479b5e8..f3b60dc8b0 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -221,35 +221,10 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, argv.push_back("-Xclang"); argv.push_back("-code-completion-macros"); + // Remap any unsaved files to temporary files. std::vector<std::string> RemapArgs; - for (unsigned i = 0; i != num_unsaved_files; ++i) { - char tmpFile[L_tmpnam]; - char *tmpFileName = tmpnam(tmpFile); - - // Write the contents of this unsaved file into the temporary file. - llvm::sys::Path SavedFile(tmpFileName); - std::string ErrorInfo; - llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); - if (!ErrorInfo.empty()) - continue; - - OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); - OS.close(); - if (OS.has_error()) { - SavedFile.eraseFromDisk(); - continue; - } - - // Remap the file. - std::string RemapArg = unsaved_files[i].Filename; - RemapArg += ';'; - RemapArg += tmpFileName; - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back("-remap-file"); - RemapArgs.push_back("-Xclang"); - RemapArgs.push_back(RemapArg); - TemporaryFiles.push_back(SavedFile); - } + if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) + return 0; // The pointers into the elements of RemapArgs are stable because we // won't be adding anything to RemapArgs after this point. diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp index f26c8ce813..53636a4ff3 100644 --- a/tools/CIndex/CIndexer.cpp +++ b/tools/CIndex/CIndexer.cpp @@ -94,3 +94,40 @@ std::string CIndexer::getClangResourcesPath() { return P.str(); } + +bool clang::RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles) { + for (unsigned i = 0; i != num_unsaved_files; ++i) { + char tmpFile[L_tmpnam]; + char *tmpFileName = tmpnam(tmpFile); + + // Write the contents of this unsaved file into the temporary file. + llvm::sys::Path SavedFile(tmpFileName); + std::string ErrorInfo; + llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + return true; + + OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); + OS.close(); + if (OS.has_error()) { + SavedFile.eraseFromDisk(); + return true; + } + + // Remap the file. + std::string RemapArg = unsaved_files[i].Filename; + RemapArg += ';'; + RemapArg += tmpFileName; + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back("-remap-file"); + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back(RemapArg); + TemporaryFiles.push_back(SavedFile); + } + + return false; +} + diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h index 1a4e4b7b8f..d01454f9dc 100644 --- a/tools/CIndex/CIndexer.h +++ b/tools/CIndex/CIndexer.h @@ -19,6 +19,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/ASTUnit.h" #include "llvm/System/Path.h" +#include <vector> using namespace clang; @@ -77,4 +78,17 @@ public: static CXString createCXString(const char *String, bool DupString = false); }; +namespace clang { + /** + * \brief Given a set of "unsaved" files, create temporary files and + * construct the clang -cc1 argument list needed to perform the remapping. + * + * \returns true if an error occurred. + */ + bool RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles); +} + #endif diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 98ed772ec6..4ef3904139 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -39,6 +39,99 @@ static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, return 1; } +void free_remapped_files(struct CXUnsavedFile *unsaved_files, + int num_unsaved_files) { + int i; + for (i = 0; i != num_unsaved_files; ++i) { + free((char *)unsaved_files[i].Filename); + free((char *)unsaved_files[i].Contents); + } +} + +int parse_remapped_files(int argc, const char **argv, int start_arg, + struct CXUnsavedFile **unsaved_files, + int *num_unsaved_files) { + int i; + int arg; + int prefix_len = strlen("-remap-file="); + *unsaved_files = 0; + *num_unsaved_files = 0; + + /* Count the number of remapped files. */ + for (arg = start_arg; arg < argc; ++arg) { + if (strncmp(argv[arg], "-remap-file=", prefix_len)) + break; + + ++*num_unsaved_files; + } + + if (*num_unsaved_files == 0) + return 0; + + *unsaved_files + = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * + *num_unsaved_files); + for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { + struct CXUnsavedFile *unsaved = *unsaved_files + i; + const char *arg_string = argv[arg] + prefix_len; + int filename_len; + char *filename; + char *contents; + FILE *to_file; + const char *semi = strchr(arg_string, ';'); + if (!semi) { + fprintf(stderr, + "error: -remap-file=from;to argument is missing semicolon\n"); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + + /* Open the file that we're remapping to. */ + to_file = fopen(semi + 1, "r"); + if (!to_file) { + fprintf(stderr, "error: cannot open file %s that we are remapping to\n", + semi + 1); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + + /* Determine the length of the file we're remapping to. */ + fseek(to_file, 0, SEEK_END); + unsaved->Length = ftell(to_file); + fseek(to_file, 0, SEEK_SET); + + /* Read the contents of the file we're remapping to. */ + contents = (char *)malloc(unsaved->Length + 1); + if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { + fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", + (feof(to_file) ? "EOF" : "error"), semi + 1); + fclose(to_file); + free_remapped_files(*unsaved_files, i); + *unsaved_files = 0; + *num_unsaved_files = 0; + return -1; + } + contents[unsaved->Length] = 0; + unsaved->Contents = contents; + + /* Close the file. */ + fclose(to_file); + + /* Copy the file name that we're remapping from. */ + filename_len = semi - arg_string; + filename = (char *)malloc(filename_len + 1); + memcpy(filename, arg_string, filename_len); + filename[filename_len] = 0; + unsaved->Filename = filename; + } + + return 0; +} + /******************************************************************************/ /* Pretty-printing. */ /******************************************************************************/ @@ -258,6 +351,10 @@ int perform_test_load_source(int argc, const char **argv, const char *filter, getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); CXIndex Idx; CXTranslationUnit TU; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + int result; + Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, /* displayDiagnostics */ 1); @@ -265,13 +362,22 @@ int perform_test_load_source(int argc, const char **argv, const char *filter, if (UseExternalASTs && strlen(UseExternalASTs)) clang_setUseExternalASTGeneration(Idx, 1); - TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv); + if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) + return -1; + + TU = clang_createTranslationUnitFromSourceFile(Idx, 0, + argc - num_unsaved_files, + argv + num_unsaved_files, + num_unsaved_files, + unsaved_files); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); return 1; } - return perform_test_load(Idx, TU, filter, NULL, Visitor); + result = perform_test_load(Idx, TU, filter, NULL, Visitor); + free_remapped_files(unsaved_files, num_unsaved_files); + return result; } /******************************************************************************/ @@ -477,99 +583,6 @@ void print_completion_result(CXCompletionResult *completion_result, fprintf(file, "\n"); } -void free_remapped_files(struct CXUnsavedFile *unsaved_files, - int num_unsaved_files) { - int i; - for (i = 0; i != num_unsaved_files; ++i) { - free((char *)unsaved_files[i].Filename); - free((char *)unsaved_files[i].Contents); - } -} - -int parse_remapped_files(int argc, const char **argv, int start_arg, - struct CXUnsavedFile **unsaved_files, - int *num_unsaved_files) { - int i; - int arg; - int prefix_len = strlen("-remap-file="); - *unsaved_files = 0; - *num_unsaved_files = 0; - - /* Count the number of remapped files. */ - for (arg = start_arg; arg < argc; ++arg) { - if (strncmp(argv[arg], "-remap-file=", prefix_len)) - break; - - ++*num_unsaved_files; - } - - if (*num_unsaved_files == 0) - return 0; - - *unsaved_files - = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * - *num_unsaved_files); - for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { - struct CXUnsavedFile *unsaved = *unsaved_files + i; - const char *arg_string = argv[arg] + prefix_len; - int filename_len; - char *filename; - char *contents; - FILE *to_file; - const char *semi = strchr(arg_string, ';'); - if (!semi) { - fprintf(stderr, - "error: -remap-file=from;to argument is missing semicolon\n"); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - - /* Open the file that we're remapping to. */ - to_file = fopen(semi + 1, "r"); - if (!to_file) { - fprintf(stderr, "error: cannot open file %s that we are remapping to\n", - semi + 1); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - - /* Determine the length of the file we're remapping to. */ - fseek(to_file, 0, SEEK_END); - unsaved->Length = ftell(to_file); - fseek(to_file, 0, SEEK_SET); - - /* Read the contents of the file we're remapping to. */ - contents = (char *)malloc(unsaved->Length + 1); - if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { - fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", - (feof(to_file) ? "EOF" : "error"), semi + 1); - fclose(to_file); - free_remapped_files(*unsaved_files, i); - *unsaved_files = 0; - *num_unsaved_files = 0; - return -1; - } - contents[unsaved->Length] = 0; - unsaved->Contents = contents; - - /* Close the file. */ - fclose(to_file); - - /* Copy the file name that we're remapping from. */ - filename_len = semi - arg_string; - filename = (char *)malloc(filename_len + 1); - memcpy(filename, arg_string, filename_len); - filename[filename_len] = 0; - unsaved->Filename = filename; - } - - return 0; -} - int perform_code_completion(int argc, const char **argv) { const char *input = argv[1]; char *filename = 0; @@ -624,7 +637,7 @@ int inspect_cursor_at(int argc, const char **argv) { CXCursor Cursor; CursorSourceLocation *Locations = 0; unsigned NumLocations = 0, Loc; - + /* Count the number of locations. */ while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1]) ++NumLocations; @@ -645,15 +658,12 @@ int inspect_cursor_at(int argc, const char **argv) { &num_unsaved_files)) return -1; - if (num_unsaved_files > 0) { - fprintf(stderr, "cannot remap files when looking for a cursor\n"); - return -1; - } - CIdx = clang_createIndex(0, 1); TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], argc - num_unsaved_files - 2 - NumLocations, - argv + num_unsaved_files + 1 + NumLocations); + argv + num_unsaved_files + 1 + NumLocations, + num_unsaved_files, + unsaved_files); if (!TU) { fprintf(stderr, "unable to parse input\n"); return -1; |