diff --git a/robotpy_build/autowrap/context.py b/robotpy_build/autowrap/context.py index 63f13c87..737f770d 100644 --- a/robotpy_build/autowrap/context.py +++ b/robotpy_build/autowrap/context.py @@ -296,6 +296,9 @@ class BaseClassData: #: turned into underscores. full_cpp_name_identifier: str # was x_qualname_ + #: This ends with :: + namespace_: str + #: C++ name + components, no template parameters dep_cpp_name: str diff --git a/robotpy_build/autowrap/cxxparser.py b/robotpy_build/autowrap/cxxparser.py index ad27ca4c..357b8ee3 100644 --- a/robotpy_build/autowrap/cxxparser.py +++ b/robotpy_build/autowrap/cxxparser.py @@ -191,7 +191,9 @@ def _count_and_unwrap( assert False -def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[str]]: +def _fmt_base_name( + typename: PQName, +) -> typing.Tuple[str, str, str, str, typing.List[str]]: all_parts = [] nameonly_parts = [] @@ -209,10 +211,12 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[ if last_segment.specialization: most_parts = all_parts[:-1] + ns_parts = all_parts[:-1] all_parts.append(last_segment.format()) most_parts.append(last_segment.name) tparam_list = [arg.format() for arg in last_segment.specialization.args] else: + ns_parts = all_parts[:] all_parts.append(last_segment.name) most_parts = all_parts tparam_list = [] @@ -221,6 +225,7 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[ "::".join(most_parts), "::".join(all_parts), "::".join(nameonly_parts), + "::".join(ns_parts), tparam_list, ) @@ -824,8 +829,8 @@ def _process_class_bases( if base.access == "private": continue - cpp_name, cpp_name_w_templates, dep_cpp_name, tparam_list = _fmt_base_name( - base.typename + cpp_name, cpp_name_w_templates, dep_cpp_name, base_ns, tparam_list = ( + _fmt_base_name(base.typename) ) if ignored_bases.pop(cpp_name_w_templates, None): continue @@ -846,6 +851,11 @@ def _process_class_bases( cpp_name = user_bqual[:tp] template_params = user_bqual[tp + 1 : -1] dep_cpp_name = cpp_name + ns_idx = cpp_name.rfind("::") + if ns_idx == -1: + base_ns = "" + else: + base_ns = cpp_name[:ns_idx] else: # TODO: we don't handle nested child classes with templates here # ... but that has to be rather obscure? @@ -858,17 +868,22 @@ def _process_class_bases( # If no explicit namespace specified, we assume base classes # live in the same namespace as the class if len(base.typename.segments) == 1: + base_ns = cls_namespace cpp_name = f"{cls_namespace}::{cpp_name}" cpp_name_w_templates = f"{cls_namespace}::{cpp_name_w_templates}" dep_cpp_name = f"{cls_namespace}::{dep_cpp_name}" base_identifier = cpp_name.translate(_qualname_trans) + if base_ns: + base_ns = f"{base_ns}::" + bases.append( BaseClassData( full_cpp_name=cpp_name, full_cpp_name_w_templates=cpp_name_w_templates, full_cpp_name_identifier=base_identifier, + namespace_=base_ns, dep_cpp_name=dep_cpp_name, template_params=template_params, ) @@ -1242,8 +1257,8 @@ def on_class_end(self, state: AWClassBlockState) -> None: if cdata.template_argument_list: tmpl = f", {cdata.template_argument_list}" - trampoline_cfg = f"rpygen::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>" - tname = f"rpygen::PyTrampoline_{cdata.cls_cpp_identifier}" + trampoline_cfg = f"{cdata.ctx.namespace}::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>" + tname = f"{cdata.ctx.namespace}::PyTrampoline_{cdata.cls_cpp_identifier}" tvar = f"{ctx.cpp_name}_Trampoline" ctx.trampoline = TrampolineData( diff --git a/robotpy_build/autowrap/render_cls_rpy_include.py b/robotpy_build/autowrap/render_cls_rpy_include.py index 57e15716..436a53e2 100644 --- a/robotpy_build/autowrap/render_cls_rpy_include.py +++ b/robotpy_build/autowrap/render_cls_rpy_include.py @@ -101,10 +101,8 @@ def _render_cls_trampoline( for base in cls.bases: r.writeln(f"#include ") - r.writeln("\nnamespace rpygen {") - if cls.namespace: - r.writeln(f"\nusing namespace {cls.namespace};") + r.writeln(f"\nnamespace {cls.namespace} {{") if hctx.using_declarations: r.writeln() @@ -122,7 +120,7 @@ def _render_cls_trampoline( # r.writeln( - f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = EmptyTrampolineCfg>" + f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = rpygen::EmptyTrampolineCfg>" ) if cls.bases: @@ -131,7 +129,7 @@ def _render_cls_trampoline( with r.indent(): for base in cls.bases: r.writeln( - f"PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}" + f"{base.namespace_}PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}" ) r.writeln("CfgBase") @@ -168,7 +166,7 @@ def _render_cls_trampoline( for base in cls.bases: r.rel_indent(2) - r.writeln(f"PyTrampoline_{base.full_cpp_name_identifier}<") + r.writeln(f"{base.namespace_}PyTrampoline_{base.full_cpp_name_identifier}<") with r.indent(): r.writeln("PyTrampolineBase") @@ -284,7 +282,10 @@ def _render_cls_trampoline( r.writeln() r.write_trim(trampoline.inline_code) - r.writeln("};\n\n}; // namespace rpygen") + r.writeln("};\n\n") + + if cls.namespace: + r.writeln(f"}}; // namespace {cls.namespace}") def _render_cls_trampoline_virtual_method( diff --git a/tests/cpp/pyproject.toml.tmpl b/tests/cpp/pyproject.toml.tmpl index 5d911165..f22d1a3b 100644 --- a/tests/cpp/pyproject.toml.tmpl +++ b/tests/cpp/pyproject.toml.tmpl @@ -61,6 +61,7 @@ generate = [ { lifetime = "lifetime.h" }, { nested = "nested.h" }, { ns_class = "ns_class.h" }, + { ns_hidden = "ns_hidden.h" }, { operators = "operators.h" }, { overloads = "overloads.h" }, { parameters = "parameters.h" }, diff --git a/tests/cpp/rpytest/ft/include/ns_hidden.h b/tests/cpp/rpytest/ft/include/ns_hidden.h new file mode 100644 index 00000000..68f31d96 --- /dev/null +++ b/tests/cpp/rpytest/ft/include/ns_hidden.h @@ -0,0 +1,23 @@ +#pragma once + +namespace n { + enum class E { + Item, + }; +}; + +namespace o { + struct O { + O() = default; + virtual ~O() = default; + }; +}; + +namespace n::h { + class C : public o::O { + public: + // E is resolved here because it's in the parent namespace but our + // trampoline was originally in a different namespace and failed + virtual E fn() { return E::Item; } + }; +};