[clang] Fix all mypy --strict errors in clang python binding (PR #101784)

2024-08-03 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@TsXor thank you for your work!
I am generally all in favor of typing annotations, and I like that `ctyped` 
adds a stronger connection between the Python function definitions and the C 
library functions in terms of types.

That said, this PR is pretty massive and grows the Python bindings by about 800 
lines of code (ignoring tests), which imo is quite a lot just to pass the 
strict type check. There are also a lot of refactoring and other changes in 
this PR that, while generally welcome, seem unrelated and should be factored 
out. In general, multiple smaller PRs are preferred over something of this 
size, to have clearer boundaries and ease reviewing.

For reference, I'd like to point out that I've also opened a PR for strict 
typing in #78114, which has been under review for a while.
With that out of the way: I'm still a very new contributor and since I've 
opened a PR for essentially the exact same thing, don't feel comfortable 
deciding on how to proceed with this. I'm summoning @Endilll: what are your 
thoughts on this?

https://github.com/llvm/llvm-project/pull/101784
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang] Fix symbol version of `getBinaryOpcode` functions (PR #101820)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum closed 
https://github.com/llvm/llvm-project/pull/101820
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang] Move getBinaryOpcode library functions to LLVM 19 (PR #101820)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/101820
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang] Move getBinaryOpcode library functions to LLVM 19 (PR #101820)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101820

None

>From aff16c3b3a0cb7065a5ac143ae06850bbbeb666a Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 3 Aug 2024 13:43:41 +0100
Subject: [PATCH] [libclang] Move getBinaryOpcode library functions to LLVM 19

---
 clang/tools/libclang/libclang.map | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/clang/tools/libclang/libclang.map 
b/clang/tools/libclang/libclang.map
index 91c329b5765d4..371fe512ce71c 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -54,8 +54,6 @@ LLVM_13 {
 clang_Cursor_Evaluate;
 clang_Cursor_getArgument;
 clang_Cursor_getBriefCommentText;
-clang_Cursor_getBinaryOpcode;
-clang_Cursor_getBinaryOpcodeStr;
 clang_Cursor_getCXXManglings;
 clang_Cursor_getCommentRange;
 clang_Cursor_getMangling;
@@ -430,6 +428,12 @@ LLVM_17 {
 clang_getCursorUnaryOperatorKind;
 };
 
+LLVM_19 {
+  global:
+clang_Cursor_getBinaryOpcode;
+clang_Cursor_getBinaryOpcodeStr;
+};
+
 # Example of how to add a new symbol version entry.  If you do add a new symbol
 # version, please update the example to depend on the version you added.
 # LLVM_X {

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang] Move getBinaryOpcode library functions to LLVM 19 (PR #101820)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum milestoned 
https://github.com/llvm/llvm-project/pull/101820
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-08-03 Thread Jannick Kremer via cfe-commits


@@ -54,6 +54,8 @@ LLVM_13 {
 clang_Cursor_Evaluate;
 clang_Cursor_getArgument;
 clang_Cursor_getBriefCommentText;
+clang_Cursor_getBinaryOpcode;
+clang_Cursor_getBinaryOpcodeStr;

DeinAlptraum wrote:

I will open a fix PR rightaway

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-08-03 Thread Jannick Kremer via cfe-commits


@@ -54,6 +54,8 @@ LLVM_13 {
 clang_Cursor_Evaluate;
 clang_Cursor_getArgument;
 clang_Cursor_getBriefCommentText;
+clang_Cursor_getBinaryOpcode;
+clang_Cursor_getBinaryOpcodeStr;

DeinAlptraum wrote:

This is the `LLVM_13` section of the file.
>From the top of the file:
```
# If you add a symbol to this file, make sure to add it with the correct
# version.  For example, if the LLVM main branch is LLVM 14.0.0, add new
# symbols with the version LLVM_14.
# On platforms where versions scripts are not used, this file will be used to
# generate a list of exports for libclang.so
```
I'm not familiar with how the bindings actually interact with the C++ side, so 
I don't know what kinds of problems this would cause. Does this need to be 
backported for 19.x?
@Endilll are you familiar with this?

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/101802
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)

2024-08-03 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101802

This resolves #22617 and #52827 

>From 444d9480cf9629c81ae26636922af20db5bd52bf Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 3 Aug 2024 09:28:02 +0100
Subject: [PATCH] [libclang/python] Fix bug in SourceRange.__contains__, add
 tests

---
 clang/bindings/python/clang/cindex.py |  4 ++
 .../python/tests/cindex/test_source_range.py  | 56 +++
 2 files changed, 60 insertions(+)
 create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index c251c46a04adf..5fd7cc6481073 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -386,6 +386,10 @@ def __contains__(self, other):
 # same file, in between lines
 if self.start.line < other.line < self.end.line:
 return True
+# between columns in one-liner range
+elif self.start.line == other.line == self.end.line:
+if self.start.column <= other.column <= self.end.column:
+return True
 elif self.start.line == other.line:
 # same file first line
 if self.start.column <= other.column:
diff --git a/clang/bindings/python/tests/cindex/test_source_range.py 
b/clang/bindings/python/tests/cindex/test_source_range.py
new file mode 100644
index 0..9f76848e89020
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_source_range.py
@@ -0,0 +1,56 @@
+import unittest
+
+from clang.cindex import SourceLocation, SourceRange
+
+from .util import get_tu
+
+
+def create_location(tu, line, column):
+return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, 
column)
+
+
+def create_range(tu, line1, column1, line2, column2):
+return SourceRange.from_locations(
+create_location(tu, line1, column1), create_location(tu, line2, 
column2)
+)
+
+
+class TestSourceRange(unittest.TestCase):
+def test_contains(self):
+tu = get_tu(
+"""a
+a
+a
+a"""
+)
+
+l13 = create_location(tu, 1, 3)
+l21 = create_location(tu, 2, 1)
+l22 = create_location(tu, 2, 2)
+l23 = create_location(tu, 2, 3)
+l24 = create_location(tu, 2, 4)
+l25 = create_location(tu, 2, 5)
+l33 = create_location(tu, 3, 3)
+l31 = create_location(tu, 3, 1)
+r22_24 = create_range(tu, 2, 2, 2, 4)
+r23_23 = create_range(tu, 2, 3, 2, 3)
+r24_32 = create_range(tu, 2, 4, 3, 2)
+r14_32 = create_range(tu, 1, 4, 3, 2)
+
+assert l13 not in r22_24  # Line before start
+assert l21 not in r22_24  # Column before start
+assert l22 in r22_24  # Colum on start
+assert l23 in r22_24  # Column in range
+assert l24 in r22_24  # Column on end
+assert l25 not in r22_24  # Column after end
+assert l33 not in r22_24  # Line after end
+
+assert l23 in r23_23  # In one-column range
+
+assert l23 not in r24_32  # Outside range in first line
+assert l33 not in r24_32  # Outside range in last line
+assert l25 in r24_32  # In range in first line
+assert l31 in r24_32  # In range in last line
+
+assert l21 in r14_32  # In range at start of center line
+assert l25 in r14_32  # In range at end of center line

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix `get_exception_specification_kind` (PR #101548)

2024-08-02 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

Could you merge this for me?

On related note, do you think my contributions would count for "a track record 
of submitting high quality patches", i.e. should I apply for commit access?

https://github.com/llvm/llvm-project/pull/101548
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix get_exception_specification_kind (PR #101548)

2024-08-02 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

I can't think of any more genereal approach that prevents this sort of problem. 
Type checking would help with this (e.g. giving an error when an unknown 
attribute is called on an object) though it wouldn't have worked in this 
specific case... otherwise nothing to do but add more tests I guess.

https://github.com/llvm/llvm-project/pull/101548
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix get_exception_specification_kind (PR #101548)

2024-08-02 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/101548

>From e7e66f0f90d7fb9adf3d3f546becd87c7527fa4c Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Thu, 1 Aug 2024 20:01:34 +0100
Subject: [PATCH 1/2] [libclang/python] Fix get_exception_specification_kind

---
 clang/bindings/python/clang/cindex.py|  2 +-
 .../cindex/test_exception_specification_kind.py  | 12 ++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 2038ef6045c7d..c251c46a04adf 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2654,7 +2654,7 @@ def get_exception_specification_kind(self):
 the ExceptionSpecificationKind enumeration.
 """
 return ExceptionSpecificationKind.from_id(
-conf.lib.clang.getExceptionSpecificationType(self)
+conf.lib.clang_getExceptionSpecificationType(self)
 )
 
 @property
diff --git 
a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py 
b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
index 8e2a6b5c50223..e4742db31adbe 100644
--- a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
+++ b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
@@ -13,7 +13,7 @@
 
 def find_function_declarations(node, declarations=[]):
 if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
-declarations.append((node.spelling, node.exception_specification_kind))
+declarations.append(node)
 for child in node.get_children():
 declarations = find_function_declarations(child, declarations)
 return declarations
@@ -33,4 +33,12 @@ def test_exception_specification_kind(self):
 ("square2", ExceptionSpecificationKind.BASIC_NOEXCEPT),
 ("square3", ExceptionSpecificationKind.COMPUTED_NOEXCEPT),
 ]
-self.assertListEqual(declarations, expected)
+from_cursor = [
+(node.spelling, node.exception_specification_kind) for node in 
declarations
+]
+from_type = [
+(node.spelling, node.type.get_exception_specification_kind())
+for node in declarations
+]
+self.assertListEqual(from_cursor, expected)
+self.assertListEqual(from_type, expected)

>From 446507880b0204a7b7941826c1fcaab467c36109 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 2 Aug 2024 08:06:49 +0100
Subject: [PATCH 2/2] Add release note

---
 clang/docs/ReleaseNotes.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ba70b138a04c4..8101d4327cd47 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -299,6 +299,7 @@ Sanitizers
 
 Python Binding Changes
 --
+- Fixed an issue that led to crashes when calling 
``Type.get_exception_specification_kind``.
 
 OpenMP Support
 --

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix get_exception_specification_kind (PR #101548)

2024-08-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/101548
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix get_exception_specification_kind (PR #101548)

2024-08-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/101548

>From e7e66f0f90d7fb9adf3d3f546becd87c7527fa4c Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Thu, 1 Aug 2024 20:01:34 +0100
Subject: [PATCH] [libclang/python] Fix get_exception_specification_kind

---
 clang/bindings/python/clang/cindex.py|  2 +-
 .../cindex/test_exception_specification_kind.py  | 12 ++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 2038ef6045c7d..c251c46a04adf 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2654,7 +2654,7 @@ def get_exception_specification_kind(self):
 the ExceptionSpecificationKind enumeration.
 """
 return ExceptionSpecificationKind.from_id(
-conf.lib.clang.getExceptionSpecificationType(self)
+conf.lib.clang_getExceptionSpecificationType(self)
 )
 
 @property
diff --git 
a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py 
b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
index 8e2a6b5c50223..e4742db31adbe 100644
--- a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
+++ b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
@@ -13,7 +13,7 @@
 
 def find_function_declarations(node, declarations=[]):
 if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
-declarations.append((node.spelling, node.exception_specification_kind))
+declarations.append(node)
 for child in node.get_children():
 declarations = find_function_declarations(child, declarations)
 return declarations
@@ -33,4 +33,12 @@ def test_exception_specification_kind(self):
 ("square2", ExceptionSpecificationKind.BASIC_NOEXCEPT),
 ("square3", ExceptionSpecificationKind.COMPUTED_NOEXCEPT),
 ]
-self.assertListEqual(declarations, expected)
+from_cursor = [
+(node.spelling, node.exception_specification_kind) for node in 
declarations
+]
+from_type = [
+(node.spelling, node.type.get_exception_specification_kind())
+for node in declarations
+]
+self.assertListEqual(from_cursor, expected)
+self.assertListEqual(from_type, expected)

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix get_exception_specification_kind (PR #101548)

2024-08-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101548

This fixes a bug with `get_exception_ specification_kind`. The function did not 
work before. Also add a test that confirms that it works now.

>From 7e5ff53e8dc56e15f84c3868a25a779be54a22f0 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Thu, 1 Aug 2024 20:01:34 +0100
Subject: [PATCH] [libclang/python] Fix get_exception_specification_kind

---
 clang/bindings/python/clang/cindex.py  | 2 +-
 .../tests/cindex/test_exception_specification_kind.py  | 7 +--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 2038ef6045c7d..c251c46a04adf 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2654,7 +2654,7 @@ def get_exception_specification_kind(self):
 the ExceptionSpecificationKind enumeration.
 """
 return ExceptionSpecificationKind.from_id(
-conf.lib.clang.getExceptionSpecificationType(self)
+conf.lib.clang_getExceptionSpecificationType(self)
 )
 
 @property
diff --git 
a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py 
b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
index 8e2a6b5c50223..6653c22eaf9cd 100644
--- a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
+++ b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
@@ -13,7 +13,7 @@
 
 def find_function_declarations(node, declarations=[]):
 if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
-declarations.append((node.spelling, node.exception_specification_kind))
+declarations.append(node)
 for child in node.get_children():
 declarations = find_function_declarations(child, declarations)
 return declarations
@@ -33,4 +33,7 @@ def test_exception_specification_kind(self):
 ("square2", ExceptionSpecificationKind.BASIC_NOEXCEPT),
 ("square3", ExceptionSpecificationKind.COMPUTED_NOEXCEPT),
 ]
-self.assertListEqual(declarations, expected)
+from_cursor = [(node.spelling, node.exception_specification_kind) for 
node in declarations]
+from_type = [(node.spelling, 
node.type.get_exception_specification_kind()) for node in declarations]
+self.assertListEqual(from_cursor, expected)
+self.assertListEqual(from_type, expected)

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-31 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

I'm planning to do one last split that contains all "logic" changes, after 
which this PR should contain only actual typing annotations and nothing else. 
Will open a PR for that other change one of these days

https://github.com/llvm/llvm-project/pull/78114
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-31 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/78114

>From 04641f7ea15382df2d43fecc32bd1b699e0b2481 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 12 Jul 2024 15:08:06 +0100
Subject: [PATCH] [libclang/python] Add strict typing to clang Python bindings

---
 clang/bindings/python/clang/cindex.py | 654 ++
 1 file changed, 364 insertions(+), 290 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 2038ef6045c7d..32ed0920ff31e 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -71,8 +71,11 @@
 from typing import (
 Any,
 Callable,
+cast as Tcast,
 Generic,
+Iterator,
 Optional,
+Sequence,
 Type as TType,
 TypeVar,
 TYPE_CHECKING,
@@ -81,14 +84,19 @@
 
 if TYPE_CHECKING:
 from ctypes import _Pointer
+from io import TextIOWrapper
 from typing_extensions import Protocol, TypeAlias
 
 StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+InMemoryFile: TypeAlias = (
+"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]"
+)
 LibFunc: TypeAlias = TUnion[
 "tuple[str, Optional[list[Any]]]",
 "tuple[str, Optional[list[Any]], Any]",
 "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
 ]
+CObjP: TypeAlias = _Pointer[Any]
 
 TSeq = TypeVar("TSeq", covariant=True)
 
@@ -147,7 +155,7 @@ def b(x: str | bytes) -> bytes:
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -183,7 +191,7 @@ class TranslationUnitSaveError(Exception):
 # Indicates that the translation unit was somehow invalid.
 ERROR_INVALID_TU = 3
 
-def __init__(self, enumeration, message):
+def __init__(self, enumeration: int, message: str):
 assert isinstance(enumeration, int)
 
 if enumeration < 1 or enumeration > 3:
@@ -255,23 +263,25 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
@@ -279,7 +289,7 @@ def from_position(tu, file, line, column):
 return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
@@ -289,37 +299,39 @@ def from_offset(tu, file, offset):
 return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]
 
 @property
-def file(self):
+def file(self) -> File | None:
 """Get the file represented by this source location."""
 return self._get_instantiation()[0]
 
 @property
-def line(self):
+def line(self) -> int:
 """Get the line represented by this source location."""
 return self._get_instantiation()[1]
 
 @property
-def column(self):
+def column(self) -> int:
 """Get the column represented by this source location."""
 return self._get_instantiation()[2]
 
 @property
-def offset(self):
+def offset(self) -> int:
 """Get the file offset represented by this source location."""
 return self._get_instantiation()[3]
 
 @property
-def is_in_system_header(self):
+def is_in_system_header(self) -> bool:
 """Returns true if the given source location is in a system header."""
 return conf.lib.clang_Location_isInSystemHeader(self)  # type: 

[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-31 Thread Jannick Kremer via cfe-commits


@@ -255,71 +263,75 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]

DeinAlptraum wrote:

I've opened a PR separating these at #101310 

https://github.com/llvm/llvm-project/pull/78114
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] type-ignore `Any` returns from library calls (PR #101310)

2024-07-31 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101310

On its own, this change leads to _more_ strict typing errors as the functions 
are mostly not annotated so far, so the `# type: ignore`s are reported as 
Unused. This is part of the work leading up to #78114 though, and one of the 
bigger parts factored out from it, so these will later lead to less strict 
typing errors as the functions are annotated with return types.

>From 7bf4412849774be51c170584089bde8010d0814a Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Wed, 31 Jul 2024 10:27:09 +0100
Subject: [PATCH] [libclang/python] type-ignore `Any` returns from library
 calls

---
 clang/bindings/python/clang/cindex.py | 194 +-
 1 file changed, 97 insertions(+), 97 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..60723e1aaeff7 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -276,7 +276,7 @@ def from_position(tu, file, line, column):
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
 def from_offset(tu, file, offset):
@@ -286,7 +286,7 @@ def from_offset(tu, file, offset):
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]
 
 @property
 def file(self):
@@ -311,10 +311,10 @@ def offset(self):
 @property
 def is_in_system_header(self):
 """Returns true if the given source location is in a system header."""
-return conf.lib.clang_Location_isInSystemHeader(self)
+return conf.lib.clang_Location_isInSystemHeader(self)  # type: ignore 
[no-any-return]
 
 def __eq__(self, other):
-return conf.lib.clang_equalLocations(self, other)
+return conf.lib.clang_equalLocations(self, other)  # type: ignore 
[no-any-return]
 
 def __ne__(self, other):
 return not self.__eq__(other)
@@ -347,7 +347,7 @@ class SourceRange(Structure):
 # object.
 @staticmethod
 def from_locations(start, end):
-return conf.lib.clang_getRange(start, end)
+return conf.lib.clang_getRange(start, end)  # type: ignore 
[no-any-return]
 
 @property
 def start(self):
@@ -355,7 +355,7 @@ def start(self):
 Return a SourceLocation representing the first character within a
 source range.
 """
-return conf.lib.clang_getRangeStart(self)
+return conf.lib.clang_getRangeStart(self)  # type: ignore 
[no-any-return]
 
 @property
 def end(self):
@@ -363,10 +363,10 @@ def end(self):
 Return a SourceLocation representing the last character within a
 source range.
 """
-return conf.lib.clang_getRangeEnd(self)
+return conf.lib.clang_getRangeEnd(self)  # type: ignore [no-any-return]
 
 def __eq__(self, other):
-return conf.lib.clang_equalRanges(self, other)
+return conf.lib.clang_equalRanges(self, other)  # type: ignore 
[no-any-return]
 
 def __ne__(self, other):
 return not self.__eq__(other)
@@ -429,15 +429,15 @@ def __del__(self):
 
 @property
 def severity(self):
-return conf.lib.clang_getDiagnosticSeverity(self)
+return conf.lib.clang_getDiagnosticSeverity(self)  # type: ignore 
[no-any-return]
 
 @property
 def location(self):
-return conf.lib.clang_getDiagnosticLocation(self)
+return conf.lib.clang_getDiagnosticLocation(self)  # type: ignore 
[no-any-return]
 
 @property
 def spelling(self):
-return conf.lib.clang_getDiagnosticSpelling(self)
+return conf.lib.clang_getDiagnosticSpelling(self)  # type: ignore 
[no-any-return]
 
 @property
 def ranges(self) -> NoSliceSequence[SourceRange]:
@@ -451,7 +451,7 @@ def __len__(self) -> int:
 def __getitem__(self, key: int) -> SourceRange:
 if key >= len(self):
 raise IndexError
-return conf.lib.clang_getDiagnosticRange(self.diag, key)
+return conf.lib.clang_getDiagnosticRange(self.diag, key)  # 
type: ignore [no-any-return]
 
 return RangeIterator(self)
 
@@ -494,17 +494,17 @@ def __getitem__(self, key: int) -> Diagnostic:
 @property
 def category_number(self):
 """The category number for this diagnostic or 0 if unavailable."""
-return conf.lib.clang_getDiagnosticCategory(self)
+return conf.lib.clang_getDiagnosticCategory(self)  # type: ignore 

[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-31 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/78114
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Factor out unsaved files processing (PR #101308)

2024-07-31 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101308

Factor out the processing of unsaved files into its own function as suggested 
by @Endilll  
[here](https://github.com/llvm/llvm-project/pull/78114/files#r1697730196)

>From 8780961064341bbbfd6cf97d9c6d5a4f7d012d49 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Wed, 31 Jul 2024 10:10:33 +0100
Subject: [PATCH] [libclang/python] Factor out unsaved files processing

---
 clang/bindings/python/clang/cindex.py | 47 ++-
 1 file changed, 17 insertions(+), 30 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..f669c279aab6d 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -3011,6 +3011,20 @@ class TranslationUnit(ClangObject):
 # into the set of code completions returned from this translation unit.
 PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 128
 
+@staticmethod
+def process_unsaved_files(unsaved_files) -> Array[_CXUnsavedFile] | None:
+unsaved_array = None
+if len(unsaved_files):
+unsaved_array = (_CXUnsavedFile * len(unsaved_files))()
+for i, (name, contents) in enumerate(unsaved_files):
+if hasattr(contents, "read"):
+contents = contents.read()
+binary_contents = b(contents)
+unsaved_array[i].name = b(os.fspath(name))
+unsaved_array[i].contents = binary_contents
+unsaved_array[i].length = len(binary_contents)
+return unsaved_array
+
 @classmethod
 def from_source(
 cls, filename, args=None, unsaved_files=None, options=0, index=None
@@ -3067,16 +3081,7 @@ def from_source(
 if len(args) > 0:
 args_array = (c_char_p * len(args))(*[b(x) for x in args])
 
-unsaved_array = None
-if len(unsaved_files) > 0:
-unsaved_array = (_CXUnsavedFile * len(unsaved_files))()
-for i, (name, contents) in enumerate(unsaved_files):
-if hasattr(contents, "read"):
-contents = contents.read()
-contents = b(contents)
-unsaved_array[i].name = b(os.fspath(name))
-unsaved_array[i].contents = contents
-unsaved_array[i].length = len(contents)
+unsaved_array = cls.process_unsaved_files(unsaved_files)
 
 ptr = conf.lib.clang_parseTranslationUnit(
 index,
@@ -3257,16 +3262,7 @@ def reparse(self, unsaved_files=None, options=0):
 if unsaved_files is None:
 unsaved_files = []
 
-unsaved_files_array = 0
-if len(unsaved_files):
-unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
-for i, (name, contents) in enumerate(unsaved_files):
-if hasattr(contents, "read"):
-contents = contents.read()
-contents = b(contents)
-unsaved_files_array[i].name = b(os.fspath(name))
-unsaved_files_array[i].contents = contents
-unsaved_files_array[i].length = len(contents)
+unsaved_files_array = self.process_unsaved_files(unsaved_files)
 ptr = conf.lib.clang_reparseTranslationUnit(
 self, len(unsaved_files), unsaved_files_array, options
 )
@@ -3329,16 +3325,7 @@ def codeComplete(
 if unsaved_files is None:
 unsaved_files = []
 
-unsaved_files_array = 0
-if len(unsaved_files):
-unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
-for i, (name, contents) in enumerate(unsaved_files):
-if hasattr(contents, "read"):
-contents = contents.read()
-contents = b(contents)
-unsaved_files_array[i].name = b(os.fspath(name))
-unsaved_files_array[i].contents = contents
-unsaved_files_array[i].length = len(contents)
+unsaved_files_array = self.process_unsaved_files(unsaved_files)
 ptr = conf.lib.clang_codeCompleteAt(
 self,
 os.fspath(path),

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-31 Thread Jannick Kremer via cfe-commits


@@ -3257,21 +3323,21 @@ def reparse(self, unsaved_files=None, options=0):
 if unsaved_files is None:
 unsaved_files = []
 
-unsaved_files_array = 0
+unsaved_files_array: int | Array[_CXUnsavedFile] = 0
 if len(unsaved_files):
 unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
 for i, (name, contents) in enumerate(unsaved_files):
 if hasattr(contents, "read"):
 contents = contents.read()
-contents = b(contents)
+binary_contents = b(contents)

DeinAlptraum wrote:

Assigning an incompatible type to a variable of a different type is a type 
error. Changing `binary_contents` back to `contents` produces a type error like 
this on that line:
`clang/cindex.py:3332: error: Incompatible types in assignment (expression has 
type "bytes", variable has type "str | TextIOWrapper")`
Good point with the repetition though, I'll make separate PRs for these to 
collect this into a common function.

https://github.com/llvm/llvm-project/pull/78114
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-30 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

I rebased this on the other changes, so there's mostly relatively simple 
annotations left now. Still a few hundred of them though. @Endilll do you want 
me to split this further, or is this fine?

https://github.com/llvm/llvm-project/pull/78114
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-30 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/78114

>From 6f93e30dc7fdeaa18ae181c15aaed257c902d4c8 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 12 Jul 2024 15:08:06 +0100
Subject: [PATCH] [libclang/python] Add strict typing to clang Python bindings

---
 clang/bindings/python/clang/cindex.py | 868 ++
 1 file changed, 471 insertions(+), 397 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..f876b07bf6ae5 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -71,8 +71,11 @@
 from typing import (
 Any,
 Callable,
+cast as Tcast,
 Generic,
+Iterator,
 Optional,
+Sequence,
 Type as TType,
 TypeVar,
 TYPE_CHECKING,
@@ -81,14 +84,19 @@
 
 if TYPE_CHECKING:
 from ctypes import _Pointer
+from io import TextIOWrapper
 from typing_extensions import Protocol, TypeAlias
 
 StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+InMemoryFile: TypeAlias = (
+"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]"
+)
 LibFunc: TypeAlias = TUnion[
 "tuple[str, Optional[list[Any]]]",
 "tuple[str, Optional[list[Any]], Any]",
 "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
 ]
+CObjP: TypeAlias = _Pointer[Any]
 
 TSeq = TypeVar("TSeq", covariant=True)
 
@@ -147,7 +155,7 @@ def b(x: str | bytes) -> bytes:
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -183,7 +191,7 @@ class TranslationUnitSaveError(Exception):
 # Indicates that the translation unit was somehow invalid.
 ERROR_INVALID_TU = 3
 
-def __init__(self, enumeration, message):
+def __init__(self, enumeration: int, message: str):
 assert isinstance(enumeration, int)
 
 if enumeration < 1 or enumeration > 3:
@@ -255,71 +263,75 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]
 
 @property
-def file(self):
+def file(self) -> File | None:
 """Get the file represented by this source location."""
 return self._get_instantiation()[0]
 
 @property
-def line(self):
+def line(self) -> int:
 """Get the line represented by this source location."""
 return self._get_instantiation()[1]
 
 @property
-def column(self):
+def column(self) -> int:
 """Get the column represented by this source location."""
 return self._get_instantiation()[2]
 
 @property
-def offset(self):
+def offset(self) -> int:
 """Get the file offset represented by this source location."""
 return self._get_instantiation()[3]
 
 @property
-def is_in_system_header(self):
+def is_in_system_header(self) -> bool:
 

[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-30 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/78114

>From 883bda054bb6a70edd2f2d738ffccff3a0b47a35 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 12 Jul 2024 15:08:06 +0100
Subject: [PATCH] [libclang/python] Add strict typing to clang Python bindings

---
 clang/bindings/python/clang/cindex.py | 869 ++
 1 file changed, 472 insertions(+), 397 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..bc680fdc2c24c 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -71,24 +71,33 @@
 from typing import (
 Any,
 Callable,
+cast as Tcast,
 Generic,
+Iterator,
 Optional,
+Sequence,
 Type as TType,
 TypeVar,
 TYPE_CHECKING,
 Union as TUnion,
 )
+from typing_extensions import Protocol, TypeAlias
 
 if TYPE_CHECKING:
 from ctypes import _Pointer
+from io import TextIOWrapper
 from typing_extensions import Protocol, TypeAlias
 
 StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+InMemoryFile: TypeAlias = (
+"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]"
+)
 LibFunc: TypeAlias = TUnion[
 "tuple[str, Optional[list[Any]]]",
 "tuple[str, Optional[list[Any]], Any]",
 "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
 ]
+CObjP: TypeAlias = _Pointer[Any]
 
 TSeq = TypeVar("TSeq", covariant=True)
 
@@ -147,7 +156,7 @@ def b(x: str | bytes) -> bytes:
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -183,7 +192,7 @@ class TranslationUnitSaveError(Exception):
 # Indicates that the translation unit was somehow invalid.
 ERROR_INVALID_TU = 3
 
-def __init__(self, enumeration, message):
+def __init__(self, enumeration: int, message: str):
 assert isinstance(enumeration, int)
 
 if enumeration < 1 or enumeration > 3:
@@ -255,71 +264,75 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]
 
 @property
-def file(self):
+def file(self) -> File | None:
 """Get the file represented by this source location."""
 return self._get_instantiation()[0]
 
 @property
-def line(self):
+def line(self) -> int:
 """Get the line represented by this source location."""
 return self._get_instantiation()[1]
 
 @property
-def column(self):
+def column(self) -> int:
 """Get the column represented by this source location."""
 return self._get_instantiation()[2]
 
 @property
-def offset(self):
+def offset(self) -> int:
 """Get the file offset represented by this source location."""
 return self._get_instantiation()[3]
 
 @property
-def 

[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-30 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/78114

>From d16056310b86aaa98011cb8551c38365f0e7748f Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 12 Jul 2024 15:08:06 +0100
Subject: [PATCH] [libclang/python] Add strict typing to clang Python bindings

---
 clang/bindings/python/clang/cindex.py | 868 ++
 1 file changed, 471 insertions(+), 397 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..a7dd797dc4498 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -71,24 +71,33 @@
 from typing import (
 Any,
 Callable,
+cast as Tcast,
 Generic,
+Iterator,
 Optional,
+Sequence,
 Type as TType,
 TypeVar,
 TYPE_CHECKING,
 Union as TUnion,
 )
+from typing_extensions import Protocol, TypeAlias
 
 if TYPE_CHECKING:
 from ctypes import _Pointer
+from io import TextIOWrapper
 from typing_extensions import Protocol, TypeAlias
 
 StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+InMemoryFile: TypeAlias = (
+"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]"
+)
 LibFunc: TypeAlias = TUnion[
 "tuple[str, Optional[list[Any]]]",
 "tuple[str, Optional[list[Any]], Any]",
 "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
 ]
+CObjP: TypeAlias = _Pointer[Any]
 
 TSeq = TypeVar("TSeq", covariant=True)
 
@@ -147,7 +156,7 @@ def b(x: str | bytes) -> bytes:
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -183,7 +192,7 @@ class TranslationUnitSaveError(Exception):
 # Indicates that the translation unit was somehow invalid.
 ERROR_INVALID_TU = 3
 
-def __init__(self, enumeration, message):
+def __init__(self, enumeration: int, message: str):
 assert isinstance(enumeration, int)
 
 if enumeration < 1 or enumeration > 3:
@@ -255,71 +264,75 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column)  # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset)  # type: 
ignore [no-any-return]
 
 @property
-def file(self):
+def file(self) -> File | None:
 """Get the file represented by this source location."""
 return self._get_instantiation()[0]
 
 @property
-def line(self):
+def line(self) -> int:
 """Get the line represented by this source location."""
 return self._get_instantiation()[1]
 
 @property
-def column(self):
+def column(self) -> int:
 """Get the column represented by this source location."""
 return self._get_instantiation()[2]
 
 @property
-def offset(self):
+def offset(self) -> int:
 """Get the file offset represented by this source location."""
 return self._get_instantiation()[3]
 
 @property
-def 

[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)

2024-07-30 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/78114

>From 717c43a4c027681fa957ed35a365400c129ff0b1 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 12 Jul 2024 15:08:06 +0100
Subject: [PATCH] [libclang/python] Add strict typing to clang Python bindings

---
 clang/bindings/python/clang/cindex.py | 865 ++
 1 file changed, 467 insertions(+), 398 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 72509a8a54f28..fb44082242325 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -71,24 +71,33 @@
 from typing import (
 Any,
 Callable,
+cast as Tcast,
 Generic,
+Iterator,
 Optional,
+Sequence,
 Type as TType,
 TypeVar,
 TYPE_CHECKING,
 Union as TUnion,
 )
+from typing_extensions import Protocol, TypeAlias
 
 if TYPE_CHECKING:
 from ctypes import _Pointer
+from io import TextIOWrapper
 from typing_extensions import Protocol, TypeAlias
 
 StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+InMemoryFile: TypeAlias = (
+"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]"
+)
 LibFunc: TypeAlias = TUnion[
 "tuple[str, Optional[list[Any]]]",
 "tuple[str, Optional[list[Any]], Any]",
 "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
 ]
+CObjP: TypeAlias = _Pointer[Any]
 
 TSeq = TypeVar("TSeq", covariant=True)
 
@@ -136,7 +145,6 @@ def from_param(cls, param: str | bytes | None) -> 
c_interop_string:
 def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
-
 def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
@@ -147,7 +155,7 @@ def b(x: str | bytes) -> bytes:
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p)
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -183,7 +191,7 @@ class TranslationUnitSaveError(Exception):
 # Indicates that the translation unit was somehow invalid.
 ERROR_INVALID_TU = 3
 
-def __init__(self, enumeration, message):
+def __init__(self, enumeration: int, message: str):
 assert isinstance(enumeration, int)
 
 if enumeration < 1 or enumeration > 3:
@@ -255,71 +263,75 @@ class SourceLocation(Structure):
 """
 
 _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
-_data = None
+_data: tuple[File | None, int, int, int] | None = None
 
-def _get_instantiation(self):
+def _get_instantiation(self) -> tuple[File | None, int, int, int]:
 if self._data is None:
 f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
 conf.lib.clang_getInstantiationLocation(
 self, byref(f), byref(l), byref(c), byref(o)
 )
 if f:
-f = File(f)
+file = File(f)
 else:
-f = None
-self._data = (f, int(l.value), int(c.value), int(o.value))
+file = None
+self._data = (file, int(l.value), int(c.value), int(o.value))
 return self._data
 
 @staticmethod
-def from_position(tu, file, line, column):
+def from_position(
+tu: TranslationUnit, file: File, line: int, column: int
+) -> SourceLocation:
 """
 Retrieve the source location associated with a given file/line/column 
in
 a particular translation unit.
 """
-return conf.lib.clang_getLocation(tu, file, line, column)
+return conf.lib.clang_getLocation(tu, file, line, column) # type: 
ignore [no-any-return]
 
 @staticmethod
-def from_offset(tu, file, offset):
+def from_offset(tu: TranslationUnit, file: File, offset: int) -> 
SourceLocation:
 """Retrieve a SourceLocation from a given character offset.
 
 tu -- TranslationUnit file belongs to
 file -- File instance to obtain offset from
 offset -- Integer character offset within file
 """
-return conf.lib.clang_getLocationForOffset(tu, file, offset)
+return conf.lib.clang_getLocationForOffset(tu, file, offset) # type: 
ignore [no-any-return]
 
 @property
-def file(self):
+def file(self) -> File | None:
 """Get the file represented by this source location."""
 return self._get_instantiation()[0]
 
 @property
-def line(self):
+def line(self) -> int:
 """Get the line represented by this source location."""
 return self._get_instantiation()[1]
 
 @property
-def column(self):
+def column(self) -> int:
 """Get the column represented by this source location."""
   

[clang] [Clang][Sema] Remove duplicate check in if-condition (PR #101070)

2024-07-29 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@zyn0217 I hope you're the right person to ask for a review here?

https://github.com/llvm/llvm-project/pull/101070
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Remove duplicate check in if-condition (PR #101070)

2024-07-29 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/101070

Resolves #101041 

>From 521082f25bc42104fd436a412b2de2edb60b7b0e Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Mon, 29 Jul 2024 20:24:15 +0100
Subject: [PATCH] [Clang][Sema] Remove duplicate check in if-condition

---
 clang/lib/Sema/SemaOpenMP.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 9c80b3eec914c..1d378e6b830ae 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -23087,8 +23087,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause(
   if (DSAStack->getCurrentDirective() == OMPD_ordered &&
   DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink &&
   DepType != OMPC_DOACROSS_sink_omp_cur_iteration &&
-  DepType != OMPC_DOACROSS_source_omp_cur_iteration &&
-  DepType != OMPC_DOACROSS_source) {
+  DepType != OMPC_DOACROSS_source_omp_cur_iteration) {
 Diag(DepLoc, diag::err_omp_unexpected_clause_value)
 << "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross);
 return nullptr;

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Export all enums (PR #100941)

2024-07-29 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

This may be my fault, I don't remember if I pulled main before branching for 
this PR, especially seeing how my last PR also had unrelated test failures

https://github.com/llvm/llvm-project/pull/100941
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-29 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From 00631fc559197d2bc6bfa9e8ccdae47f33926a37 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH 1/2] [libclang/python] Fix some type errors, add type
 annotations

---
 clang/bindings/python/clang/cindex.py | 195 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index be024da5e005c..6c70588c28ffa 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+from typing_extensions import Protocol, TypeAlias
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +148,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +200,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +212,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a 

[clang] [libclang/python] Export all enums (PR #100941)

2024-07-29 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/100941

>From 4b1322b8add0a1189f0f1cbf5583841f3a591f0c Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sun, 28 Jul 2024 18:30:35 +0100
Subject: [PATCH] [libclang/python] Export all enums

---
 clang/bindings/python/clang/cindex.py | 5 +
 1 file changed, 5 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index be024da5e005c..d9009a8666338 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -4077,6 +4077,7 @@ def function_exists(self, name):
 conf = Config()
 
 __all__ = [
+"AccessSpecifier",
 "AvailabilityKind",
 "BinaryOperator",
 "Config",
@@ -4087,12 +4088,16 @@ def function_exists(self, name):
 "CursorKind",
 "Cursor",
 "Diagnostic",
+"ExceptionSpecificationKind",
 "File",
 "FixIt",
 "Index",
 "LinkageKind",
+"RefQualifierKind",
 "SourceLocation",
 "SourceRange",
+"StorageClass",
+"TemplateArgumentKind",
 "TLSKind",
 "TokenKind",
 "Token",

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Export all enums (PR #100941)

2024-07-29 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

Could you also merge please? (or are you waiting for something else?)

https://github.com/llvm/llvm-project/pull/100941
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Export all enums (PR #100941)

2024-07-28 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll can I ask you for a review again?

https://github.com/llvm/llvm-project/pull/100941
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Export all enums (PR #100941)

2024-07-28 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/100941

This resolves #48212 and also adds the remaining unexposed Enums

>From c4007832c8ed7cdb56aceebcf61b24ecb75f2aa4 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sun, 28 Jul 2024 18:30:35 +0100
Subject: [PATCH] [libclang/python] Export all enums

---
 clang/bindings/python/clang/cindex.py | 5 +
 1 file changed, 5 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index be024da5e005c..d9009a8666338 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -4077,6 +4077,7 @@ def function_exists(self, name):
 conf = Config()
 
 __all__ = [
+"AccessSpecifier",
 "AvailabilityKind",
 "BinaryOperator",
 "Config",
@@ -4087,12 +4088,16 @@ def function_exists(self, name):
 "CursorKind",
 "Cursor",
 "Diagnostic",
+"ExceptionSpecificationKind",
 "File",
 "FixIt",
 "Index",
 "LinkageKind",
+"RefQualifierKind",
 "SourceLocation",
 "SourceRange",
+"StorageClass",
+"TemplateArgumentKind",
 "TLSKind",
 "TokenKind",
 "Token",

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-23 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

Since the release branching is done, I've rebased on main to fix the release 
notes

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-23 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From c64b124ccc22cd9f92b0a55f60ec92d7101d0048 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH 1/2] [libclang/python] Fix some type errors, add type
 annotations

---
 clang/bindings/python/clang/cindex.py | 195 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index be024da5e005c..6c70588c28ffa 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+from typing_extensions import Protocol, TypeAlias
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +148,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +200,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +212,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a 

[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

Got it, thank you!

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@nikic could you explain why?

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

I added breaking change notes where I thought them appropriate, could you merge 
if you are happy with this?

Regarding the relase: I believe I've taken care not to break anything (besides 
things noted in breaking change notes) so hopefully not much need for that. If 
any unexpected breakages do come to my attention, I will try to get that in 
though.
This PR is also probably the last step before #78114, so that one can hopefully 
still be picked onto `releases/19.x` so that we have the entire "strict typing" 
thing in the release.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits


@@ -66,46 +66,77 @@
 
 import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int: ...
+def __getitem__(self, key: int) -> TSeq: ...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""

DeinAlptraum wrote:

I just checked the `c_interop_string` usage again, and this type is apparently 
only used for converting strings that are fed _into_ the C interface functions, 
never returned. So no breaking change after all. Does make me wonder why it has 
a `__str__` though.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits


@@ -200,13 +236,16 @@ class _CXString(Structure):
 
 _fields_ = [("spelling", c_char_p), ("free", c_int)]
 
-def __del__(self):
+def __del__(self) -> None:
 conf.lib.clang_disposeString(self)
 
 @staticmethod
-def from_result(res, fn=None, args=None):
+def from_result(res: _CXString, fn: Any = None, args: Any = None) -> str:
 assert isinstance(res, _CXString)
-return conf.lib.clang_getCString(res)
+pystr: str | None = conf.lib.clang_getCString(res)
+if pystr is None:
+return ""
+return pystr

DeinAlptraum wrote:

The interface changes, isn't that a breaking change in every case? I.e. if you 
were checking for empty results before by doing `is None`, that doesn't work 
anymore. You would now have to change that to `== ""`.
I've added a breaking change note for this, but happy to remove this again if 
I'm missing something here.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-21 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From c0216b8a50f7ccc6ee24db69802055c3942a183e Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH 1/2] [libclang/python] Fix some type errors, add type
 annotations

---
 clang/bindings/python/clang/cindex.py | 195 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 1d3ab89190407..e8b7c006b6679 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+from typing_extensions import Protocol, TypeAlias
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +148,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +200,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +212,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a 

[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-19 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

\*Ping*
@Endilll do you have time to take a look at this?

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll I am once again asking for your support
This PR collects several of the changes towards #78114 that I assume might need 
some discussion. I tried to leave PR comments with explanations in each of 
those places.
@boomanaiden154 @linux4life798 review from you would also be appreciated!

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From c0216b8a50f7ccc6ee24db69802055c3942a183e Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH] [libclang/python] Fix some type errors, add type annotations

---
 clang/bindings/python/clang/cindex.py | 195 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 1d3ab89190407..e8b7c006b6679 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+from typing_extensions import Protocol, TypeAlias
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +148,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +200,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +212,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a static 

[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...

DeinAlptraum wrote:

This defines the proper interface for all the classes with "Iterator" in their 
name. None of them are actually iterators in terms of the Python protocol 
`Iterator`, as they are expected to support `__len__` and __getitem__`. They're 
the closest to the `Sequence` protocol, but without the support for slicing.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From c9e439d18ccc0749153e211d796ae202554cb229 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH] [libclang/python] Fix some type errors, add type annotations

---
 clang/bindings/python/clang/cindex.py | 195 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 130 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 1d3ab89190407..e71cdcdddcc48 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,81 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int:
+...
+
+def __getitem__(self, key: int) -> TSeq:
+...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +148,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +200,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +212,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a static 

[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -2318,25 +2356,25 @@ def kind(self):
 """Return the kind of this type."""
 return TypeKind.from_id(self._kind_id)
 
-def argument_types(self):
+def argument_types(self) -> NoSliceSequence[Type]:
 """Retrieve a container for the non-variadic arguments for this type.
 
 The returned object is iterable and indexable. Each item in the
 container is a Type instance.
 """
 
-class ArgumentsIterator(collections.abc.Sequence):

DeinAlptraum wrote:

This is a type-error since `ArgumentsIterator` doesn't actually implement the 
`Sequence` protocol: it does not support slicing.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/98745

>From 2c31f3fe5d232381b868e96158be6f2acf7da1c6 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH] [libclang/python] Fix some type errors, add type annotations

---
 clang/bindings/python/clang/cindex.py | 192 +++---
 .../tests/cindex/test_code_completion.py  |  22 +-
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 127 insertions(+), 91 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 1d3ab89190407..9b50192068213 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -64,48 +64,78 @@
 
 from ctypes import *
 
-import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int: ...
+def __getitem__(self, key: int) -> TSeq: ...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +145,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +197,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +209,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a static attribute of 
'{class_name}'"
+   

[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -169,25 +198,32 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
 executed. The value it returns is set as the new value of that instance's
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise TypeError(
+f"'{property_name}' is not a static attribute of 
'{class_name}'"
+)

DeinAlptraum wrote:

`CachedProperty` is a decorator used as a replacement for `@property` where the 
actual function might include heavier computations, so after the first call 
this caches the result of a decorated function as an attribute of the instance 
it belongs to.

The `if instance is None` case occurs only when trying to call this statically, 
i.e. when the decorated function is called on the class it belongs to, instead 
of on an instance. In that case the existing implementation returns the 
`CachedProperty` object, which... doesn't seem to make any sense. That object 
itself is useless, it is an implementation detail that the user is not supposed 
to see, so I can't think of a reason why this would return `self`. This would 
also make the type annotation more complicated, so I changed this to throw an 
error instead, when trying to access a property as if it were a static attribute

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -3895,28 +3932,28 @@ def register_function(lib, item, ignore_errors):
 func.errcheck = item[3]
 
 
-def register_functions(lib, ignore_errors):
+def register_functions(lib: CDLL, ignore_errors: bool) -> None:
 """Register function prototypes with a libclang library instance.
 
 This must be called as part of library instantiation so Python knows how
 to call out to the shared library.
 """
 
-def register(item):
-return register_function(lib, item, ignore_errors)
+def register(item: LibFunc) -> None:
+register_function(lib, item, ignore_errors)

DeinAlptraum wrote:

`return` removed since `register_function()` doesn't return anything anyway.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -66,46 +66,77 @@
 
 import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int: ...
+def __getitem__(self, key: int) -> TSeq: ...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""

DeinAlptraum wrote:

This violated the `__str__` magic method definition, as it is not allowed to 
return `None`. I guess this is also worth a "potentially breaking change"?

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -66,46 +66,77 @@
 
 import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int: ...
+def __getitem__(self, key: int) -> TSeq: ...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")

DeinAlptraum wrote:

This violates the superclass' interface, but I highly doubt that we actually 
want to return `bytes` here as the superclass mandates, so I had to `type: 
ignore` this.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -115,9 +146,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}

DeinAlptraum wrote:

`callbacks` could have been a `TypedDict`, but these are always a mouthful and 
I don't see a reason to have this dict in the first place, so I removed it.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -200,13 +236,16 @@ class _CXString(Structure):
 
 _fields_ = [("spelling", c_char_p), ("free", c_int)]
 
-def __del__(self):
+def __del__(self) -> None:
 conf.lib.clang_disposeString(self)
 
 @staticmethod
-def from_result(res, fn=None, args=None):
+def from_result(res: _CXString, fn: Any = None, args: Any = None) -> str:
 assert isinstance(res, _CXString)
-return conf.lib.clang_getCString(res)
+pystr: str | None = conf.lib.clang_getCString(res)
+if pystr is None:
+return ""
+return pystr

DeinAlptraum wrote:

`conf.lib.clang_getCString` may sometimes (though seemingly rarely) return 
`None` instead of a Python `str`. `_CXString.from_result()` is used in a lot of 
places throughout this file, and while parts of it seem to be aware of this 
(e.g. doc string saying that this may return `None`) other places are not (e.g. 
calling `len` on the return value). Many parts of the interface also directly 
return the result of this function, and having to check for `None` in all of 
these places seems potentially impractical, so I went for returning empty 
strings instead of `None` instead.

But due to the inconsistent usage throughout this file, I'm not sure how far 
this corresponds more or less to the original intention.

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -66,46 +66,77 @@
 
 import collections.abc
 import os
+import sys

DeinAlptraum wrote:

This is used for `sys.stdout.flush()` in this file, and leads to a type error. 
I don't know why this isn't already imported

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits


@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function

DeinAlptraum wrote:

All of these are already activated by default since Python 3.0. `annotations` 
is necessary though, for some of the type annotation features used in this PR

https://github.com/llvm/llvm-project/pull/98745
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)

2024-07-13 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum created 
https://github.com/llvm/llvm-project/pull/98745

This fixes a few of the more debatable type errors, and adds related 
annotations, as the next step towards #76664.

>From 06483bd3e398dd9dba757904e622d5dd1b37db77 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Sat, 13 Jul 2024 14:12:34 +0100
Subject: [PATCH] [libclang/python] Fix some type errors, add type annotations

---
 clang/bindings/python/clang/cindex.py | 137 +++---
 .../tests/cindex/test_code_completion.py  |  22 +--
 .../python/tests/cindex/test_comment.py   |   4 +-
 3 files changed, 100 insertions(+), 63 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 1d3ab89190407..469d602b2a642 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -43,7 +43,7 @@
 Most object information is exposed using properties, when the underlying API
 call is efficient.
 """
-from __future__ import absolute_import, division, print_function
+from __future__ import annotations
 
 # TODO
 # 
@@ -66,46 +66,77 @@
 
 import collections.abc
 import os
+import sys
 from enum import Enum
 
+from typing import (
+Any,
+Callable,
+Generic,
+Optional,
+Type as TType,
+TypeVar,
+TYPE_CHECKING,
+Union as TUnion,
+)
+from typing_extensions import Protocol, TypeAlias
+
+if TYPE_CHECKING:
+from ctypes import _Pointer
+
+StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+LibFunc: TypeAlias = TUnion[
+"tuple[str, Optional[list[Any]]]",
+"tuple[str, Optional[list[Any]], Any]",
+"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+]
+CObjP: TypeAlias = _Pointer[Any]
+
+TSeq = TypeVar("TSeq", covariant=True)
+
+class NoSliceSequence(Protocol[TSeq]):
+def __len__(self) -> int: ...
+def __getitem__(self, key: int) -> TSeq: ...
+
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
 class c_interop_string(c_char_p):
-def __init__(self, p=None):
+def __init__(self, p: str | bytes | None = None):
 if p is None:
 p = ""
 if isinstance(p, str):
 p = p.encode("utf8")
 super(c_char_p, self).__init__(p)
 
-def __str__(self):
-return self.value
+def __str__(self) -> str:
+return self.value or ""
 
 @property
-def value(self):
-if super(c_char_p, self).value is None:
+def value(self) -> str | None:  # type: ignore [override]
+val = super(c_char_p, self).value
+if val is None:
 return None
-return super(c_char_p, self).value.decode("utf8")
+return val.decode("utf8")
 
 @classmethod
-def from_param(cls, param):
+def from_param(cls, param: str | bytes | None) -> c_interop_string:
 if isinstance(param, str):
 return cls(param)
 if isinstance(param, bytes):
 return cls(param)
 if param is None:
 # Support passing null to C functions expecting char arrays
-return None
+return cls(param)
 raise TypeError(
 "Cannot convert '{}' to '{}'".format(type(param).__name__, 
cls.__name__)
 )
 
 @staticmethod
-def to_python_string(x, *args):
+def to_python_string(x: c_interop_string, *args: Any) -> str | None:
 return x.value
 
 
-def b(x):
+def b(x: str | bytes) -> bytes:
 if isinstance(x, bytes):
 return x
 return x.encode("utf8")
@@ -115,9 +146,7 @@ def b(x):
 # object. This is a problem, because it means that from_parameter will see an
 # integer and pass the wrong value on platforms where int != void*. Work around
 # this by marshalling object arguments as void**.
-c_object_p = POINTER(c_void_p)
-
-callbacks = {}
+c_object_p: TType[CObjP] = POINTER(c_void_p)
 
 ### Exception Classes ###
 
@@ -169,8 +198,11 @@ def __init__(self, enumeration, message):
 
 ### Structures and Utility Classes ###
 
+TInstance = TypeVar("TInstance")
+TResult = TypeVar("TResult")
+
 
-class CachedProperty:
+class CachedProperty(Generic[TInstance, TResult]):
 """Decorator that lazy-loads the value of a property.
 
 The first time the property is accessed, the original property function is
@@ -178,16 +210,20 @@ class CachedProperty:
 property, replacing the original method.
 """
 
-def __init__(self, wrapped):
+def __init__(self, wrapped: Callable[[TInstance], TResult]):
 self.wrapped = wrapped
 try:
 self.__doc__ = wrapped.__doc__
 except:
 pass
 
-def __get__(self, instance, instance_type=None):
+def __get__(self, instance: TInstance, instance_type: Any = None) -> 
TResult:
 if instance is None:
-return self
+property_name = self.wrapped.__name__
+class_name = instance_type.__name__
+raise 

[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-13 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

LGTM!

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-12 Thread Jannick Kremer via cfe-commits


@@ -1820,6 +1820,18 @@ def availability(self):
 
 return AvailabilityKind.from_id(self._availability)
 
+@property
+def binary_operator(self):
+"""
+Retrieves the opcode if this cursor points to a binary operator
+:return:
+"""
+
+if not hasattr(self, "_binopcode"):
+self._binopcode = conf.lib.clang_Cursor_getBinaryOpcode(self)

DeinAlptraum wrote:

You're right, I missed that - that's also necessary so you get `BinaryOperator` 
when doing `from cindex import *`

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-12 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum commented:

The Python changes look good to me, just one part that might need changes.
Can someone approve the CI workflows so we also get the results for the 
bindings tests to confirm?

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-12 Thread Jannick Kremer via cfe-commits


@@ -1820,6 +1820,18 @@ def availability(self):
 
 return AvailabilityKind.from_id(self._availability)
 
+@property
+def binary_operator(self):
+"""
+Retrieves the opcode if this cursor points to a binary operator
+:return:
+"""
+
+if not hasattr(self, "_binopcode"):
+self._binopcode = conf.lib.clang_Cursor_getBinaryOpcode(self)

DeinAlptraum wrote:

Have you checked that the tests pass? I am not completely sure about the inner 
workings of this, but it seems  to me that all `conf.lib` functions should be 
registered with the lib object by adding an entry for the function in the 
`functionlist` object at the end of the file.
For comparison, see e.g. `clang_Cursor_getOffsetOfField`

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-12 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-12 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

CI is done, so could you merge this? Thanks for the reviews and support 
@Endilll!

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Retrieve BinaryOperator::getOpcode and BinaryOperator::getOpcodeStr via libclang and its python interface (PR #98489)

2024-07-11 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

For a quick overview of the changes you'll need to make after #95608  in the 
Python bindings:
- remove `_kind`, `_name_map` and `__repr__()` from the `BinaryOperator` 
definition
- declare all variants of `BinaryOperator` within the class definition, i.e. 
`Invalid = 0` instead of `BinaryOperator.Invalid = BinaryOperator(0)`
- add `BinaryOperator` to the list of enum kinds tested in 
`clang/bindings/python/tests/cindex/test_enums.py`

https://github.com/llvm/llvm-project/pull/98489
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/6] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

I added a release note to the `Clang Python Bindings Potentially Breaking 
Changes` section

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/5] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

Hmm what do you think should be mentioned in a release note @Endilll ?
Since this is just refactoring, if I did everything correctly, users of the 
bindings should not notice any difference (except for different error 
messages). So just mention refactoring of enums in the bindings?

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits


@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None

DeinAlptraum wrote:

Thank you for the feedback! I've removed the `try`-`except` block now so we're 
just using the `Enum` error message

Irrelevant now, but regarding `from None`:
This effectively removes the previous exception context. Since we are 
re-raising an exception here, we would get both the exception we raised 
ourselves _and_  the exception that we caught here.

E.g. currently we get 
```
>>> cindex.TokenKind.from_id(5)
Traceback (most recent call last):
  File "", line 1, in 
  File 
"/data/shared/programming/repos/llvm-project/clang/bindings/python/clang/cindex.py",
 line 589, in from_id
raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
ValueError: Unknown TokenKind 5
```

and without the `from None` we would get
```
>>> cindex.TokenKind.from_id(5)
Traceback (most recent call last):
  File 
"/data/shared/programming/repos/llvm-project/clang/bindings/python/clang/cindex.py",
 line 587, in from_id
return cls(id)
   ^^^
  File "/usr/lib/python3.12/enum.py", line 757, in __call__
return cls.__new__(cls, value)
   ^^^
  File "/usr/lib/python3.12/enum.py", line 1171, in __new__
raise ve_exc
ValueError: 5 is not a valid TokenKind

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "", line 1, in 
  File 
"/data/shared/programming/repos/llvm-project/clang/bindings/python/clang/cindex.py",
 line 589, in from_id
raise ValueError("Unknown %s %d" % (cls.__name__, id))
ValueError: Unknown TokenKind 5
```

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/4] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-11 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

*Ping\*
@Endilll how should we proceed with this?

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-04 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll do you think this needs a second review?
If not, could you merge this? Since I don't have commit access

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits


@@ -10,26 +10,6 @@
 
 
 class TestTokenKind(unittest.TestCase):
-def test_constructor(self):

DeinAlptraum wrote:

So the existing "custom" enum implementation included a sort of constructor, as 
we see in this test, that takes a number and name and then adds that as a new 
variant to the existing enum. No such constructor exists for the builtin `Enum` 
class, so there isn't really an equivalent for this test under the new 
implementation.
We could test that it is impossible for the user to add their own variants 
dynamically at runtime by doing something like `TokenKind.NEW_VARIANT = 6`, but 
that doesn't really seem like our problem, and was also possible under the old 
implementation

Your comment did however raise another question for me: while we've covered 
that there are no duplicate names with different IDs, we haven't covered that 
there are no duplicate IDs with different names, and this is indeed possible in 
the enum class, and not covered by our current tests so I just added one.

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/3] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits


@@ -10,26 +10,6 @@
 
 
 class TestTokenKind(unittest.TestCase):
-def test_constructor(self):

DeinAlptraum wrote:

thNot really:
- `test_constructor`: this tests the ability to add enum variants "on the fly", 
which is not possible with the Python stdlib's `Enum` class
- `test_bad_register`: the `Enum` class tests for this on initialization, so if 
you define a duplicate `Enum` variant, you will get a failure on import 
already. This makes the test both a) effectively covered by that and b) you 
couldn't import the module to run such a test anyway in a case where there's a 
duplicate
- `test_unknown_value`: this is covered in `test_from_id` in `test_enums.py` 
since I added the `TokenKind` class to the test there 

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-07-01 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

\*Ping*

@boomanaiden154 @linux4life798 a review/feedback would be appreciated!

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-24 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-24 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll done with the TokenKind refactoring, so this is ready to go from my 
side.

Regarding reviewers, can you recommend any others? Since I assume I'll open a 
couple more PRs for the Python bindings after this

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-24 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/2] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-24 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum updated 
https://github.com/llvm/llvm-project/pull/95608

>From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001
From: Jannick Kremer 
Date: Fri, 14 Jun 2024 22:12:09 +0100
Subject: [PATCH 1/2] [libclang/python] Refactor enum usage

Use Python's builtin enum class instead of writing our own.

This is preparation for strict typing in PR #78114
---
 clang/bindings/python/clang/cindex.py | 1670 -
 .../python/tests/cindex/test_enums.py |   14 +-
 2 files changed, 768 insertions(+), 916 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b3d51e4d2a668..aacfc333723c4 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -68,6 +68,7 @@
 
 import collections.abc
 import os
+from enum import Enum
 
 
 # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,
 self.name,
 )
 
@@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration):
 A CursorKind describes the kind of entity that a cursor points to.
 """
 
-# The required BaseEnumeration declarations.
-_kinds = []
-_name_map = None
-
 @staticmethod
 def get_all_kinds():
 """Return all CursorKind enumeration instances."""
-return [x for x in CursorKind._kinds if not x is None]
+return list(CursorKind)
 
 def is_declaration(self):
 """Test if this is a declaration kind."""
@@ -710,822 +681,820 @@ def is_unexposed(self):
 """Test if this is an unexposed kind."""
 return conf.lib.clang_isUnexposed(self)
 
-def __repr__(self):
-return "CursorKind.%s" % (self.name,)
-
 
-###
-# Declaration Kinds
+###
+# Declaration Kinds
 
-# A declaration whose specific kind is not exposed via this interface.
-#
-# Unexposed declarations have the same operations as any other kind of
-# declaration; one can extract their location information, spelling, find their
-# definitions, etc. However, the specific kind of the declaration is not
-# reported.
-CursorKind.UNEXPOSED_DECL = CursorKind(1)
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find
+# their definitions, etc. However, the specific kind of the declaration is
+# not reported.
+UNEXPOSED_DECL = 1
 
-# A C or C++ struct.
-CursorKind.STRUCT_DECL = CursorKind(2)
+# A C or C++ struct.
+STRUCT_DECL = 2
 
-# A C or C++ union.
-CursorKind.UNION_DECL = CursorKind(3)
+# A C or C++ union.
+UNION_DECL = 3
 
-# A C++ class.
-CursorKind.CLASS_DECL = CursorKind(4)
+# A C++ class.
+CLASS_DECL = 4
 
-# An enumeration.
-CursorKind.ENUM_DECL = CursorKind(5)
+# An enumeration.
+ENUM_DECL = 5
 
-# A field (in C) or non-static data member (in C++) in a struct, union, or C++
-# class.
-CursorKind.FIELD_DECL = CursorKind(6)
+# A field (in C) or non-static data member (in C++) in a struct, union, or
+# C++ class.

[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-22 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll are you taking a look at this, and/or should I ask other reviewers?

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-15 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits

DeinAlptraum wrote:

@Endilll can I ask you for a review again?
As a next step towards the python-bindings strict typing PR, this one captures 
all the enum refactoring changes necessary towards that goal. Don't be scared 
by the LoC changed: 90% of that is just indentation changes :)

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits


@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None
 
 def __repr__(self):
 return "%s.%s" % (
-self.__class__,
+self.__class__.__name__,

DeinAlptraum wrote:

This `__repr__` was effectively unused before as each subclass defined its own. 
This change is necessary so that all subclasses still return exactly the same 
representation as they did before

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits


@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]
-
 @classmethod
 def from_id(cls, id):
-if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
-raise ValueError("Unknown template argument kind %d" % id)
-return cls._kinds[id]
+try:
+return cls(id)
+except ValueError:
+raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None

DeinAlptraum wrote:

In hindsight, should the change of error message go into a separate PR? The one 
we had before, `Unknown template argument kind`, doesn't make much sense since 
this is the base class of not just `TemplateArgumentKind`.
If we don't consider changing error messages as a breaking change, then we 
could also remove the try-except part entirely since `Enum` already throws a 
meanginful error, looking like this: `ValueError: 703 is not a valid CursorKind`

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits


@@ -31,17 +31,9 @@ class TestCursorKind(unittest.TestCase):
 def test_from_id(self):
 """Check that kinds can be constructed from valid IDs"""
 for enum in self.enums:
-self.assertEqual(enum.from_id(2), enum._kinds[2])
+self.assertEqual(enum.from_id(2), enum(2))
+max_value = max([variant.value for variant in enum])
 with self.assertRaises(ValueError):
-enum.from_id(len(enum._kinds))
+enum.from_id(max_value + 1)
 with self.assertRaises(ValueError):
 enum.from_id(-1)
-
-def test_unique_kinds(self):
-"""Check that no kind name has been used multiple times"""
-for enum in self.enums:
-for id in range(len(enum._kinds)):
-try:
-enum.from_id(id).name
-except ValueError:
-pass

DeinAlptraum wrote:

This test is effectively pointless now, since the enum class errors out as soon 
as the module is loaded in case there are duplicate enum variants

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum commented:

There is also `TokenKind`: this one does not currently inherit from 
`BaseEnumeration` and is defined somewhat differently, having all its variants 
and their IDs as a dictionary in `enumerations.py`. This seems quite arbitrary 
to me, is there any reason it is done this way? Otherwise I would also move 
this to `cindex.py` as another subclass of `BaseEnumeration`

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits

https://github.com/DeinAlptraum edited 
https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Refactor enum usage (PR #95608)

2024-06-14 Thread Jannick Kremer via cfe-commits


@@ -611,51 +612,25 @@ def register(value, name):
 
 
 ### Cursor Kinds ###
-class BaseEnumeration:
+class BaseEnumeration(Enum):
 """
 Common base class for named enumerations held in sync with Index.h values.
-
-Subclasses must define their own _kinds and _name_map members, as:
-_kinds = []
-_name_map = None
-These values hold the per-subclass instances and value-to-name mappings,
-respectively.
-
 """
 
-def __init__(self, value):
-if value >= len(self.__class__._kinds):
-self.__class__._kinds += [None] * (value - 
len(self.__class__._kinds) + 1)
-if self.__class__._kinds[value] is not None:
-raise ValueError(
-"{0} value {1} already loaded".format(str(self.__class__), 
value)
-)
-self.value = value
-self.__class__._kinds[value] = self
-self.__class__._name_map = None
 
 def from_param(self):
 return self.value
 
-@property
-def name(self):
-"""Get the enumeration name of this cursor kind."""
-if self._name_map is None:
-self._name_map = {}
-for key, value in self.__class__.__dict__.items():
-if isinstance(value, self.__class__):
-self._name_map[value] = key
-return self._name_map[self]

DeinAlptraum wrote:

The `Enum` class already provides a `name` attribute that follows the exact 
same format as we had before

https://github.com/llvm/llvm-project/pull/95608
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >