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
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index ddbdf53..6cd545f 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -873,10 +873,22 @@
 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 @@
                                    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 @@
   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 @@
     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 f70479b..f3b60dc 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -221,35 +221,10 @@
   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 f26c8ce..53636a4 100644
--- a/tools/CIndex/CIndexer.cpp
+++ b/tools/CIndex/CIndexer.cpp
@@ -94,3 +94,40 @@
 
   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 1a4e4b7..d01454f 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 @@
   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