Skip to content

Commit b1c1789

Browse files
committed
fix: update visibility detection
1 parent f45a49c commit b1c1789

8 files changed

Lines changed: 58 additions & 38 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ This tool takes a [sample.h](https://github.com/edimetia3d/pybind11_weaver/blob/
1616
- [x] Namespace hierarchy to Python submodules
1717
- [x] Enum
1818
- [x] Function, function overload
19+
- [ ] Operation overloading
1920
- [x] Class method, method overloading, static method, static method overloading, constructor, constructor overloading
2021
- [x] Class field
2122
- [x] Class access control
2223
- [x] Generate docstring from c++ comment, for enum, enum item, function, class, class method, class field
2324
- [ ] Trampoline class for virtual function
2425
- [x] Support working with hand-written code
2526
- [ ] Auto snake case
27+
- [ ] Binding for Template specialization
2628

2729
## Background & Recommendations
2830

pybind11_weaver/entity/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import logging
2+
13
from . import entity_base
24
from . import enum
35
from . import klass
@@ -6,9 +8,17 @@
68

79
from clang import cindex
810

11+
from pybind11_weaver import gen_unit
12+
13+
_logger = logging.getLogger(__name__)
914
_KIND = cindex.CursorKind
1015

11-
from pybind11_weaver import gen_unit
16+
17+
def _is_specialization(cursor: cindex.Cursor):
18+
if "<" in cursor.displayname and ">" in cursor.displayname:
19+
_logger.warning(f"Specialized template not supported `{cursor.canonical.displayname}` ")
20+
return True
21+
return False
1222

1323

1424
def create_entity(gu: gen_unit.GenUnit, cursor: cindex.Cursor):
@@ -26,9 +36,9 @@ def create_entity(gu: gen_unit.GenUnit, cursor: cindex.Cursor):
2636
return enum.EnumEntity(gu, cursor)
2737
if kind == _KIND.NAMESPACE:
2838
return namespace.NamespaceEntity(gu, cursor)
29-
if kind in [_KIND.CLASS_DECL, _KIND.STRUCT_DECL] and cursor.is_definition():
39+
if kind in [_KIND.CLASS_DECL, _KIND.STRUCT_DECL] and cursor.is_definition() and not _is_specialization(cursor):
3040
return klass.ClassEntity(gu, cursor)
31-
if kind == _KIND.FUNCTION_DECL:
41+
if kind == _KIND.FUNCTION_DECL and not _is_specialization(cursor):
3242
return funktion.FunctionEntity(gu, cursor)
3343

3444
return None

pybind11_weaver/entity/klass.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from typing import List, Dict
2+
import logging
23

34
from clang import cindex
45

56
from . import entity_base
67
from pybind11_weaver.utils import fn
78

8-
import logging
9-
109
from pybind11_weaver import gen_unit
1110

1211
_logger = logging.getLogger(__name__)
@@ -74,16 +73,23 @@ def update_stmts(self, pybind11_obj_sym: str) -> List[str]:
7473
codes = []
7574

7675
def is_pubic(cursor):
77-
return cursor.access_specifier == cindex.AccessSpecifier.PUBLIC and self.gu.is_visible(cursor)
76+
return cursor.access_specifier == cindex.AccessSpecifier.PUBLIC and not cursor.is_deleted_method()
77+
78+
def not_operator(cursor):
79+
is_operator = "operator" in cursor.spelling
80+
if is_operator:
81+
_logger.warning(f"Operator overloading not supported `{cursor.spelling}`")
82+
return not is_operator
7883

7984
# generate constructor binding
8085
ctor_found = False
8186
for cursor in self.cursor.get_children():
82-
if cursor.kind == cindex.CursorKind.CONSTRUCTOR and is_pubic(cursor):
87+
if cursor.kind == cindex.CursorKind.CONSTRUCTOR:
8388
ctor_found = True
84-
param_types = fn.fn_arg_type(cursor)
85-
codes.append(
86-
f"{pybind11_obj_sym}.def(pybind11::init<{','.join(param_types)}>());")
89+
if is_pubic(cursor) and not (cursor.is_move_constructor() or cursor.is_copy_constructor()):
90+
param_types = fn.fn_arg_type(cursor)
91+
codes.append(
92+
f"{pybind11_obj_sym}.def(pybind11::init<{','.join(param_types)}>());")
8793
if not ctor_found:
8894
codes.append(f"{pybind11_obj_sym}.def(pybind11::init<>());")
8995
if self.gu.io_config.gen_docstring:
@@ -93,7 +99,7 @@ def is_pubic(cursor):
9399
# generate method binding
94100
methods: Dict[str, MethodCoder] = dict()
95101
for cursor in self.cursor.get_children():
96-
if cursor.kind == cindex.CursorKind.CXX_METHOD and is_pubic(cursor):
102+
if cursor.kind == cindex.CursorKind.CXX_METHOD and is_pubic(cursor) and not_operator(cursor):
97103
if not cursor.spelling in methods:
98104
methods[cursor.spelling] = MethodCoder(cursor, self.qualified_name(),
99105
self.gu.io_config.gen_docstring)
@@ -118,9 +124,14 @@ def is_pubic(cursor):
118124

119125
# generate field binding
120126
for cursor in self.cursor.get_children():
121-
if cursor.kind == cindex.CursorKind.FIELD_DECL and is_pubic(cursor):
127+
if cursor.kind == cindex.CursorKind.FIELD_DECL and \
128+
is_pubic(cursor) and \
129+
cursor.type.kind != cindex.TypeKind.CONSTANTARRAY:
130+
filed_binder = "def_readwrite"
131+
if cursor.type.is_const_qualified():
132+
filed_binder = "def_readonly"
122133
codes.append(
123-
f"{pybind11_obj_sym}.def_readwrite(\"{cursor.spelling}\",&{self.qualified_name()}::{cursor.spelling});")
134+
f"{pybind11_obj_sym}.{filed_binder}(\"{cursor.spelling}\",&{self.qualified_name()}::{cursor.spelling});")
124135
if self.gu.io_config.gen_docstring:
125136
codes[-1] = entity_base._inject_docstring(codes[-1], cursor, "last_arg")
126137

pybind11_weaver/entity_tree.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
from pybind11_weaver.entity import entity_base
99
from pybind11_weaver.entity import funktion, klass
1010

11+
from pybind11_weaver.utils import common
12+
1113

1214
class _DummyNode(entity_base.Entity):
1315

14-
def __init__(self, cursor: cindex.Cursor):
15-
entity_base.Entity.__init__(self, cursor)
16+
def __init__(self, gu: gen_unit.GenUnit, cursor: cindex.Cursor):
17+
entity_base.Entity.__init__(self, gu, cursor)
1618

1719
def transfer(self, new_entity: "Entity"):
1820
# update parent
@@ -51,7 +53,7 @@ def nest_update_parent(self, entity: entity_base.Entity) -> None:
5153
outer = self.entities
5254
for name in scopes:
5355
if name not in outer:
54-
outer[name] = _DummyNode(None)
56+
outer[name] = _DummyNode(entity.gu, None)
5557
if not outer is self.entities:
5658
outer[name].update_parent(outer)
5759
outer = outer[name]
@@ -62,9 +64,9 @@ def nest_update_parent(self, entity: entity_base.Entity) -> None:
6264
if isinstance(outer[entity_name], _DummyNode):
6365
outer[entity_name].transfer(entity)
6466
else:
65-
assert isinstance(entity, funktion.FunctionEntity)
66-
assert isinstance(outer[entity_name], funktion.FunctionEntity)
67-
outer[entity_name].overloads.append(entity.cursor)
67+
if isinstance(entity, funktion.FunctionEntity):
68+
assert isinstance(outer[entity_name], funktion.FunctionEntity)
69+
outer[entity_name].overloads.append(entity.cursor)
6870
else:
6971
outer[entity_name] = entity
7072
if not outer is self.entities:
@@ -76,8 +78,6 @@ def load_from_gu(self, gu: gen_unit.GenUnit) -> None:
7678
for cursor in root_cursor.walk_preorder():
7779
if not self.check_valid_cursor(cursor, valid_file_tail_names):
7880
continue
79-
if not gu.is_visible(cursor):
80-
continue
8181
new_entity = create_entity(gu, cursor)
8282
if new_entity is not None:
8383
self.nest_update_parent(new_entity)

pybind11_weaver/gen_unit.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,20 +116,6 @@ def __init__(self, tu, io_config: Dict[str, Any], cxx_flags: List[str]):
116116
self.src_files: List[str] = io_config["inputs"]
117117
self.io_config = GenUnit.IOConifg(io_config)
118118
self.cxx_flags = cxx_flags
119-
self.fvisibility_hidden = ("-fvisibility=hidden" in " ".join(cxx_flags))
120-
121-
def is_visible(self, cursor: cindex.Cursor):
122-
"""Utility method to check if a cursor is visible in the current translation unit."""
123-
if cursor.kind in [cindex.CursorKind.ENUM_DECL, cindex.CursorKind.NAMESPACE]:
124-
return True
125-
visible = not self.fvisibility_hidden
126-
for c in cursor.get_children():
127-
if c.kind == cindex.CursorKind.VISIBILITY_ATTR:
128-
if c.spelling == "default":
129-
visible = True
130-
elif c.spelling == "hidden":
131-
visible = False
132-
return visible
133119

134120
def src_file_tail_names(self):
135121
files = []

pybind11_weaver/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def parse_args():
1818
if hasattr(args, "get_include") and args.get_include:
1919
print(pybind11_weaver.get_include())
2020
exit(0)
21+
if args.config is None:
22+
parser.print_help()
23+
exit(0)
2124
return args
2225

2326

pybind11_weaver/utils/common.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from clang import cindex
2+
3+
4+
def is_visible(cursor: cindex.Cursor):
5+
if cursor.kind not in [cindex.CursorKind.FUNCTION_DECL, cindex.CursorKind.CXX_METHOD]:
6+
return True # only control visibility of function and method
7+
return cursor.linkage == cindex.LinkageKind.EXTERNAL

pybind11_weaver/utils/fn.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55

66
def fn_arg_type(cursor: cindex.Cursor):
7-
return [param.type.spelling for param in cursor.get_arguments()]
7+
return [param.type.get_canonical().spelling for param in cursor.get_arguments()]
88

99

1010
def fn_ret_type(cursor: cindex.Cursor):
11-
return cursor.result_type.spelling
11+
return cursor.result_type.get_canonical().spelling
1212

1313

1414
def get_fn_pointer_type(cursor: cindex.Cursor):
1515
if cursor.kind == cindex.CursorKind.CXX_METHOD and not cursor.is_static_method():
16-
return f"{fn_ret_type(cursor)} ({scope_list.get_full_qualified_name(cursor.semantic_parent)}::*)({','.join(fn_arg_type(cursor))})"
16+
const_mark = "const" if cursor.is_const_method() else ""
17+
return f"{fn_ret_type(cursor)} ({scope_list.get_full_qualified_name(cursor.semantic_parent)}::*)({','.join(fn_arg_type(cursor))}) {const_mark}"
1718
else:
1819
return f"{fn_ret_type(cursor)} (*)({','.join(fn_arg_type(cursor))})"

0 commit comments

Comments
 (0)