[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)

via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 10 04:25:37 PDT 2024


https://github.com/TsXor updated https://github.com/llvm/llvm-project/pull/102410

>From 4858eef099dbca66b2e3d36fc17aef574c1f3d58 Mon Sep 17 00:00:00 2001
From: TsXor <zhang050525 at outlook.com>
Date: Thu, 8 Aug 2024 09:25:52 +0800
Subject: [PATCH 1/2] fix error handling of TranslationUnit.reparse

---
 clang/bindings/python/clang/cindex.py | 42 +++++++++++++++++++++++----
 clang/docs/ReleaseNotes.rst           |  3 ++
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 2038ef6045c7df..e4591828f91968 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -149,8 +149,8 @@ def b(x: str | bytes) -> bytes:
 # this by marshalling object arguments as void**.
 c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
 
-### Exception Classes ###
 
+### Exception Classes ###
 
 class TranslationUnitLoadError(Exception):
     """Represents an error that occurred when loading a TranslationUnit.
@@ -161,7 +161,35 @@ class TranslationUnitLoadError(Exception):
     FIXME: Make libclang expose additional error information in this scenario.
     """
 
-    pass
+    # A generic error code, no further details are available.
+    #
+    # Errors of this kind can get their own specific error codes in future
+    # libclang versions.
+    ERROR_FAILURE = 1
+
+    # libclang crashed while performing the requested operation.
+    ERROR_CRASHED = 2
+
+    # The function detected that the arguments violate the function
+    # contract.
+    ERROR_INVALID_ARGUMENTS = 3
+
+    # An AST deserialization error has occurred.
+    ERROR_AST_READ_ERROR = 4
+
+    def __init__(self, enumeration: int | None, message: str):
+        if enumeration is not None:
+            assert isinstance(enumeration, int)
+
+            if enumeration < 1 or enumeration > 4:
+                raise Exception(
+                    "Encountered undefined CXError "
+                    "constant: %d. Please file a bug to have this "
+                    "value supported." % enumeration
+                )
+
+        self.error_code = enumeration
+        Exception.__init__(self, "Error %d: %s" % (enumeration or 0, message))
 
 
 class TranslationUnitSaveError(Exception):
@@ -3094,7 +3122,8 @@ def from_source(
         )
 
         if not ptr:
-            raise TranslationUnitLoadError("Error parsing translation unit.")
+            # FIXME: use clang_parseTranslationUnit2 to preserve error code
+            raise TranslationUnitLoadError(None, "Error parsing translation unit.")
 
         return cls(ptr, index=index)
 
@@ -3118,7 +3147,8 @@ def from_ast_file(cls, filename, index=None):
 
         ptr = conf.lib.clang_createTranslationUnit(index, os.fspath(filename))
         if not ptr:
-            raise TranslationUnitLoadError(filename)
+            # FIXME: use clang_createTranslationUnit2 to preserve error code
+            raise TranslationUnitLoadError(None, filename)
 
         return cls(ptr=ptr, index=index)
 
@@ -3263,9 +3293,11 @@ def reparse(self, unsaved_files=None, options=0):
             unsaved_files = []
 
         unsaved_files_array = self.process_unsaved_files(unsaved_files)
-        ptr = conf.lib.clang_reparseTranslationUnit(
+        result = conf.lib.clang_reparseTranslationUnit(
             self, len(unsaved_files), unsaved_files_array, options
         )
+        if result != 0:
+            raise TranslationUnitLoadError(result, 'Error reparsing TranslationUnit.')
 
     def save(self, filename):
         """Saves the TranslationUnit to a file.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ba70b138a04c4a..33a8c493e5e998 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -59,6 +59,9 @@ Clang Python Bindings Potentially Breaking Changes
 - Calling a property on the `CompletionChunk` or `CompletionString` class
   statically now leads to an error, instead of returning a `CachedProperty` object
   that is used internally. Properties are only available on instances.
+- `TranslationUnitLoadError` now contains an optional error code in `error_code`
+  attribute. Also, `TranslationUnit.reparse` will throw `TranslationUnitLoadError`
+  when operation fails.
 
 What's New in Clang |release|?
 ==============================

>From c168a55356d94ffcccbd960b189b5b15feb272cb Mon Sep 17 00:00:00 2001
From: TsXor <zhang050525 at outlook.com>
Date: Sat, 10 Aug 2024 19:20:56 +0800
Subject: [PATCH 2/2] preserve error code in TU parsing APIs

---
 clang/bindings/python/clang/cindex.py | 51 ++++++++++++++++-----------
 clang/docs/ReleaseNotes.rst           |  2 +-
 2 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index e4591828f91968..63d23f55a5a742 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -177,16 +177,15 @@ class TranslationUnitLoadError(Exception):
     # An AST deserialization error has occurred.
     ERROR_AST_READ_ERROR = 4
 
-    def __init__(self, enumeration: int | None, message: str):
-        if enumeration is not None:
-            assert isinstance(enumeration, int)
+    def __init__(self, enumeration: int, message: str):
+        assert isinstance(enumeration, int)
 
-            if enumeration < 1 or enumeration > 4:
-                raise Exception(
-                    "Encountered undefined CXError "
-                    "constant: %d. Please file a bug to have this "
-                    "value supported." % enumeration
-                )
+        if enumeration < 1 or enumeration > 4:
+            raise Exception(
+                "Encountered undefined CXError "
+                "constant: %d. Please file a bug to have this "
+                "value supported." % enumeration
+            )
 
         self.error_code = enumeration
         Exception.__init__(self, "Error %d: %s" % (enumeration or 0, message))
@@ -3111,7 +3110,8 @@ def from_source(
 
         unsaved_array = cls.process_unsaved_files(unsaved_files)
 
-        ptr = conf.lib.clang_parseTranslationUnit(
+        ptr = c_object_p()
+        errc = conf.lib.clang_parseTranslationUnit2(
             index,
             os.fspath(filename) if filename is not None else None,
             args_array,
@@ -3119,11 +3119,11 @@ def from_source(
             unsaved_array,
             len(unsaved_files),
             options,
+            byref(ptr),
         )
 
-        if not ptr:
-            # FIXME: use clang_parseTranslationUnit2 to preserve error code
-            raise TranslationUnitLoadError(None, "Error parsing translation unit.")
+        if errc != 0:
+            raise TranslationUnitLoadError(errc, "Error parsing translation unit.")
 
         return cls(ptr, index=index)
 
@@ -3145,10 +3145,15 @@ def from_ast_file(cls, filename, index=None):
         if index is None:
             index = Index.create()
 
-        ptr = conf.lib.clang_createTranslationUnit(index, os.fspath(filename))
-        if not ptr:
-            # FIXME: use clang_createTranslationUnit2 to preserve error code
-            raise TranslationUnitLoadError(None, filename)
+        ptr = c_object_p()
+        errc = conf.lib.clang_createTranslationUnit2(
+            index,
+            os.fspath(filename),
+            byref(ptr)
+        )
+
+        if errc != 0:
+            raise TranslationUnitLoadError(errc, filename)
 
         return cls(ptr=ptr, index=index)
 
@@ -3293,11 +3298,11 @@ def reparse(self, unsaved_files=None, options=0):
             unsaved_files = []
 
         unsaved_files_array = self.process_unsaved_files(unsaved_files)
-        result = conf.lib.clang_reparseTranslationUnit(
+        errc = conf.lib.clang_reparseTranslationUnit(
             self, len(unsaved_files), unsaved_files_array, options
         )
-        if result != 0:
-            raise TranslationUnitLoadError(result, 'Error reparsing TranslationUnit.')
+        if errc != 0:
+            raise TranslationUnitLoadError(errc, 'Error reparsing TranslationUnit.')
 
     def save(self, filename):
         """Saves the TranslationUnit to a file.
@@ -3751,6 +3756,7 @@ def write_main_file_to_stdout(self):
     ("clang_codeCompleteGetNumDiagnostics", [CodeCompletionResults], c_int),
     ("clang_createIndex", [c_int, c_int], c_object_p),
     ("clang_createTranslationUnit", [Index, c_interop_string], c_object_p),
+    ("clang_createTranslationUnit2", [Index, c_interop_string, POINTER(c_object_p)], c_int),
     ("clang_CXRewriter_create", [TranslationUnit], c_object_p),
     ("clang_CXRewriter_dispose", [Rewriter]),
     ("clang_CXRewriter_insertTextBefore", [Rewriter, SourceLocation, c_interop_string]),
@@ -3945,6 +3951,11 @@ def write_main_file_to_stdout(self):
         [Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int],
         c_object_p,
     ),
+    (
+        "clang_parseTranslationUnit2",
+        [Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int, POINTER(c_object_p)],
+        c_int,
+    ),
     ("clang_reparseTranslationUnit", [TranslationUnit, c_int, c_void_p, c_int], c_int),
     ("clang_saveTranslationUnit", [TranslationUnit, c_interop_string, c_uint], c_int),
     (
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 33a8c493e5e998..1f42fc732fd292 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -59,7 +59,7 @@ Clang Python Bindings Potentially Breaking Changes
 - Calling a property on the `CompletionChunk` or `CompletionString` class
   statically now leads to an error, instead of returning a `CachedProperty` object
   that is used internally. Properties are only available on instances.
-- `TranslationUnitLoadError` now contains an optional error code in `error_code`
+- `TranslationUnitLoadError` now contains an error code in `error_code`
   attribute. Also, `TranslationUnit.reparse` will throw `TranslationUnitLoadError`
   when operation fails.
 



More information about the cfe-commits mailing list