@@ -1555,6 +1555,18 @@ class Cursor(Structure):
1555
1555
1556
1556
_tu : TranslationUnit
1557
1557
1558
+ # This ensures that no operations are possible on null cursors
1559
+ # by guarding all method calls with a not-null assert
1560
+ def __getattribute__ (self , key : str ) -> object :
1561
+ value = super ().__getattribute__ (key )
1562
+ is_property = isinstance (getattr (Cursor , key , None ), property )
1563
+ # Don't guard the is_null method, since it is part of the guard
1564
+ # and leads to infinite recursion otherwise
1565
+ if is_property or callable (value ):
1566
+ if key != "is_null" and self .is_null ():
1567
+ raise Exception ("Tried calling method on a null-cursor." )
1568
+ return value
1569
+
1558
1570
@staticmethod
1559
1571
def from_location (tu : TranslationUnit , location : SourceLocation ) -> Cursor :
1560
1572
# We store a reference to the TU in the instance so the TU won't get
@@ -1575,6 +1587,9 @@ def __ne__(self, other: object) -> bool:
1575
1587
def __hash__ (self ) -> int :
1576
1588
return self .hash
1577
1589
1590
+ def is_null (self ) -> bool :
1591
+ return self == conf .null_cursor
1592
+
1578
1593
def is_definition (self ) -> bool :
1579
1594
"""
1580
1595
Returns true if the declaration pointed at by the cursor is also a
@@ -2124,8 +2139,7 @@ def get_children(self) -> Iterator[Cursor]:
2124
2139
# FIXME: Expose iteration from CIndex, PR6125.
2125
2140
def visitor (child : Cursor , _ : Cursor , children : list [Cursor ]) -> int :
2126
2141
# FIXME: Document this assertion in API.
2127
- # FIXME: There should just be an isNull method.
2128
- assert child != conf .lib .clang_getNullCursor ()
2142
+ assert not child .is_null ()
2129
2143
2130
2144
# Create reference to TU so it isn't GC'd before Cursor.
2131
2145
child ._tu = self ._tu
@@ -2210,7 +2224,7 @@ def has_attrs(self) -> bool:
2210
2224
def from_result (res : Cursor , arg : Cursor | TranslationUnit | Type ) -> Cursor | None :
2211
2225
assert isinstance (res , Cursor )
2212
2226
# FIXME: There should just be an isNull method.
2213
- if res == conf . lib . clang_getNullCursor ():
2227
+ if res . is_null ():
2214
2228
return None
2215
2229
2216
2230
# Store a reference to the TU in the Python object so it won't get GC'd
@@ -2229,7 +2243,7 @@ def from_result(res: Cursor, arg: Cursor | TranslationUnit | Type) -> Cursor | N
2229
2243
@staticmethod
2230
2244
def from_cursor_result (res : Cursor , arg : Cursor ) -> Cursor | None :
2231
2245
assert isinstance (res , Cursor )
2232
- if res == conf . lib . clang_getNullCursor ():
2246
+ if res . is_null ():
2233
2247
return None
2234
2248
2235
2249
res ._tu = arg ._tu
@@ -2728,7 +2742,7 @@ def get_fields(self):
2728
2742
"""Return an iterator for accessing the fields of this type."""
2729
2743
2730
2744
def visitor (field , children ):
2731
- assert field != conf . lib . clang_getNullCursor ()
2745
+ assert not field . is_null ()
2732
2746
2733
2747
# Create reference to TU so it isn't GC'd before Cursor.
2734
2748
field ._tu = self ._tu
@@ -2743,7 +2757,7 @@ def get_bases(self):
2743
2757
"""Return an iterator for accessing the base classes of this type."""
2744
2758
2745
2759
def visitor (base , children ):
2746
- assert base != conf . lib . clang_getNullCursor ()
2760
+ assert not base . is_null ()
2747
2761
2748
2762
# Create reference to TU so it isn't GC'd before Cursor.
2749
2763
base ._tu = self ._tu
@@ -2758,7 +2772,7 @@ def get_methods(self):
2758
2772
"""Return an iterator for accessing the methods of this type."""
2759
2773
2760
2774
def visitor (method , children ):
2761
- assert method != conf . lib . clang_getNullCursor ()
2775
+ assert not method . is_null ()
2762
2776
2763
2777
# Create reference to TU so it isn't GC'd before Cursor.
2764
2778
method ._tu = self ._tu
@@ -4232,6 +4246,7 @@ def set_compatibility_check(check_status: bool) -> None:
4232
4246
def lib (self ) -> CDLL :
4233
4247
lib = self .get_cindex_library ()
4234
4248
register_functions (lib , not Config .compatibility_check )
4249
+ self .null_cursor = lib .clang_getNullCursor ()
4235
4250
Config .loaded = True
4236
4251
return lib
4237
4252
0 commit comments