libclang: Allow callers of clang_saveTranslationUnit() to distinguish
between different classes of errors. Addresses most of
<rdar://problem/9660328>.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134495 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 01e7bce..5bf2031 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -933,6 +933,41 @@
 CINDEX_LINKAGE unsigned clang_defaultSaveOptions(CXTranslationUnit TU);
 
 /**
+ * \brief Describes the kind of error that occurred (if any) in a call to
+ * \c clang_saveTranslationUnit().
+ */
+enum CXSaveError {
+  /**
+   * \brief Indicates that no error occurred while saving a translation unit.
+   */
+  CXSaveError_None = 0,
+  
+  /**
+   * \brief Indicates that an unknown error occurred while attempting to save
+   * the file.
+   *
+   * This error typically indicates that file I/O failed when attempting to 
+   * write the file.
+   */
+  CXSaveError_Unknown = 1,
+  
+  /**
+   * \brief Indicates that errors during translation prevented this attempt
+   * to save the translation unit.
+   * 
+   * Errors that prevent the translation unit from being saved can be
+   * extracted using \c clang_getNumDiagnostics() and \c clang_getDiagnostic().
+   */
+  CXSaveError_TranslationErrors = 2,
+  
+  /**
+   * \brief Indicates that the translation unit to be saved was somehow
+   * invalid (e.g., NULL).
+   */
+  CXSaveError_InvalidTU = 3
+};
+  
+/**
  * \brief Saves a translation unit into a serialized representation of
  * that translation unit on disk.
  *
@@ -951,8 +986,9 @@
  * is saved. This should be a bitwise OR of the
  * CXSaveTranslationUnit_XXX flags.
  *
- * \returns Zero if the translation unit was saved successfully, a
- * non-zero value otherwise.
+ * \returns A value that will match one of the enumerators of the CXSaveError
+ * enumeration. Zero (CXSaveError_None) indicates that the translation unit was 
+ * saved successfully, while a non-zero value indicates that a problem occurred.
  */
 CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU,
                                              const char *FileName,
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index b441995..b475880 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -680,8 +680,8 @@
 
   /// \brief Save this translation unit to a file with the given name.
   ///
-  /// \returns True if an error occurred, false otherwise.
-  bool Save(llvm::StringRef File);
+  /// \returns An indication of whether the save was successful or not.
+  CXSaveError Save(llvm::StringRef File);
 
   /// \brief Serialize this translation unit with the given output stream.
   ///
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 86a9a35..8f61d6a 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -2287,9 +2287,9 @@
   }
 }
 
-bool ASTUnit::Save(llvm::StringRef File) {
+CXSaveError ASTUnit::Save(llvm::StringRef File) {
   if (getDiagnostics().hasErrorOccurred())
-    return true;
+    return CXSaveError_TranslationErrors;
   
   // FIXME: Can we somehow regenerate the stat cache here, or do we need to 
   // unconditionally create a stat cache when we parse the file?
@@ -2297,11 +2297,11 @@
   llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
                            llvm::raw_fd_ostream::F_Binary);
   if (!ErrorInfo.empty() || Out.has_error())
-    return true;
+    return CXSaveError_Unknown;
 
   serialize(Out);
   Out.close();
-  return Out.has_error();
+  return Out.has_error()? CXSaveError_Unknown : CXSaveError_None;
 }
 
 bool ASTUnit::serialize(llvm::raw_ostream &OS) {
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 837fc89..d1bdf96 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1517,12 +1517,36 @@
     return 1;
   }
 
-  if (clang_saveTranslationUnit(TU, filename, clang_defaultSaveOptions(TU)))
-    fprintf(stderr, "Unable to write PCH file %s\n", filename);
+  int result = 0;
+  
+  switch (clang_saveTranslationUnit(TU, filename, 
+                                    clang_defaultSaveOptions(TU))) {
+  case CXSaveError_None:
+    break;
+
+  case CXSaveError_TranslationErrors:
+    fprintf(stderr, "Unable to write PCH file %s: translation errors\n", 
+            filename);
+    result = 2;    
+    break;
+
+  case CXSaveError_InvalidTU:
+    fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n", 
+            filename);
+    result = 3;    
+    break;
+
+  case CXSaveError_Unknown:
+  default:
+    fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
+    result = 1;
+    break;
+  }
+  
   clang_disposeTranslationUnit(TU);
   free_remapped_files(unsaved_files, num_unsaved_files);
   clang_disposeIndex(Idx);
-  return 0;  
+  return result;
 }
 
 /******************************************************************************/
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index fc331d0..b75850d 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2594,9 +2594,9 @@
 int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
                               unsigned options) {
   if (!TU)
-    return 1;
+    return CXSaveError_InvalidTU;
   
-  int result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
+  CXSaveError result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
   if (getenv("LIBCLANG_RESOURCE_USAGE"))
     PrintLibclangResourceUsage(TU);
   return result;