Introduce a new libclang API, clang_reparseTranslationUnit(), which
reparses an already-parsed translation unit. At the moment it's just a
convenience function, but we hope to use it for performance
optimizations.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108756 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 4ed24b1..569ef20 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -558,7 +558,7 @@
   struct CXUnsavedFile *unsaved_files = 0;
   int num_unsaved_files = 0;
   int result;
-
+  
   Idx = clang_createIndex(/* excludeDeclsFromPCH */
                           !strcmp(filter, "local") ? 1 : 0,
                           /* displayDiagnosics=*/1);
@@ -578,6 +578,7 @@
                                                  unsaved_files);
   if (!TU) {
     fprintf(stderr, "Unable to load translation unit!\n");
+    free_remapped_files(unsaved_files, num_unsaved_files);
     clang_disposeIndex(Idx);
     return 1;
   }
@@ -588,6 +589,57 @@
   return result;
 }
 
+int perform_test_reparse_source(int argc, const char **argv, int trials,
+                                const char *filter, CXCursorVisitor Visitor,
+                                PostVisitTU PV) {
+  const char *UseExternalASTs =
+  getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
+  CXIndex Idx;
+  CXTranslationUnit TU;
+  struct CXUnsavedFile *unsaved_files = 0;
+  int num_unsaved_files = 0;
+  int result;
+  int trial;
+  
+  Idx = clang_createIndex(/* excludeDeclsFromPCH */
+                          !strcmp(filter, "local") ? 1 : 0,
+                          /* displayDiagnosics=*/1);
+  
+  if (UseExternalASTs && strlen(UseExternalASTs))
+    clang_setUseExternalASTGeneration(Idx, 1);
+  
+  if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
+    clang_disposeIndex(Idx);
+    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");
+    free_remapped_files(unsaved_files, num_unsaved_files);
+    clang_disposeIndex(Idx);
+    return 1;
+  }
+  
+  for (trial = 0; trial < trials; ++trial) {
+    if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files)) {
+      clang_disposeTranslationUnit(TU);
+      free_remapped_files(unsaved_files, num_unsaved_files);
+      clang_disposeIndex(Idx);
+      return -1;      
+    }
+  }
+  
+  result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
+  free_remapped_files(unsaved_files, num_unsaved_files);
+  clang_disposeIndex(Idx);
+  return result;
+}
+
 /******************************************************************************/
 /* Logic for testing clang_getCursor().                                       */
 /******************************************************************************/
@@ -1219,6 +1271,8 @@
            "[FileCheck prefix]\n"
     "       c-index-test -test-load-source <symbol filter> {<args>}*\n");
   fprintf(stderr,
+    "       c-index-test -test-load-source-reparse <trials> <symbol filter> "
+    "          {<args>}*\n"
     "       c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
     "       c-index-test -test-annotate-tokens=<range> {<args>}*\n"
     "       c-index-test -test-inclusion-stack-source {<args>}*\n"
@@ -1252,6 +1306,14 @@
       return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
                                   NULL);
   }
+  else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
+    CXCursorVisitor I = GetVisitor(argv[1] + 25);
+    if (I) {
+      int trials = atoi(argv[2]);
+      return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I, 
+                                         NULL);
+    }
+  }
   else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
     CXCursorVisitor I = GetVisitor(argv[1] + 17);
     if (I)
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 7f32a1c..efc61a0 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1390,6 +1390,25 @@
     delete static_cast<ASTUnit *>(CTUnit);
 }
 
+int clang_reparseTranslationUnit(CXTranslationUnit TU,
+                                 unsigned num_unsaved_files,
+                                 struct CXUnsavedFile *unsaved_files) {
+  if (!TU)
+    return 1;
+  
+  llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+  for (unsigned I = 0; I != num_unsaved_files; ++I) {
+    llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+    const llvm::MemoryBuffer *Buffer
+    = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+    RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
+                                           Buffer));
+  }
+  
+  return static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(),
+                                             RemappedFiles.size())? 1 : 0;
+}
+  
 CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
   if (!CTUnit)
     return createCXString("");
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index f21fec6..e09a6a0 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -86,6 +86,7 @@
 _clang_isStatement
 _clang_isTranslationUnit
 _clang_isUnexposed
+_clang_reparseTranslationUnit
 _clang_setUseExternalASTGeneration
 _clang_tokenize
 _clang_visitChildren
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index dcb40d4..4b6ddd1 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -86,6 +86,7 @@
 clang_isStatement
 clang_isTranslationUnit
 clang_isUnexposed
+clang_reparseTranslationUnit
 clang_setUseExternalASTGeneration
 clang_tokenize
 clang_visitChildren