Skip to content

Commit 598664a

Browse files
committed
interrogate: disambiguate case where static method shadows a property
While it becomes possible to do this now, it should not become standard practice, and we should deprecate cases where we already do it by renaming either the static method or the property. Fixes panda3d#444
1 parent d62c2bf commit 598664a

File tree

1 file changed

+68
-4
lines changed

1 file changed

+68
-4
lines changed

dtool/src/interrogate/interfaceMakerPythonNative.cxx

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,16 @@ write_module_class(ostream &out, Object *obj) {
16481648

16491649
if (!func->_has_this) {
16501650
flags += " | METH_STATIC";
1651+
1652+
// Skip adding this entry if we also have a property with the same name.
1653+
// In that case, we will use a Dtool_StaticProperty to disambiguate
1654+
// access to this method. See GitHub issue #444.
1655+
for (const Property *property : obj->_properties) {
1656+
if (property->_has_this &&
1657+
property->_ielement.get_name() == func->_ifunc.get_name()) {
1658+
continue;
1659+
}
1660+
}
16511661
}
16521662

16531663
bool has_nonslotted = false;
@@ -2665,6 +2675,14 @@ write_module_class(ostream &out, Object *obj) {
26652675
continue;
26662676
}
26672677

2678+
// Actually, if we have a conflicting static method with the same name,
2679+
// we will need to use Dtool_StaticProperty instead.
2680+
for (const Function *func : obj->_methods) {
2681+
if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) {
2682+
continue;
2683+
}
2684+
}
2685+
26682686
if (num_getset == 0) {
26692687
out << "static PyGetSetDef Dtool_Properties_" << ClassName << "[] = {\n";
26702688
}
@@ -3240,9 +3258,23 @@ write_module_class(ostream &out, Object *obj) {
32403258
// Also add the static properties, which can't be added via getset.
32413259
for (Property *property : obj->_properties) {
32423260
const InterrogateElement &ielem = property->_ielement;
3243-
if (property->_has_this || property->_getter_remaps.empty()) {
3261+
if (property->_getter_remaps.empty()) {
32443262
continue;
32453263
}
3264+
if (property->_has_this) {
3265+
// Actually, continue if we have a conflicting static method with the
3266+
// same name, which may still require use of Dtool_StaticProperty.
3267+
bool have_shadow = false;
3268+
for (const Function *func : obj->_methods) {
3269+
if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) {
3270+
have_shadow = true;
3271+
break;
3272+
}
3273+
}
3274+
if (!have_shadow) {
3275+
continue;
3276+
}
3277+
}
32463278

32473279
string name1 = methodNameFromCppName(ielem.get_name(), "", false);
32483280
// string name2 = methodNameFromCppName(ielem.get_name(), "", true);
@@ -6896,8 +6928,42 @@ write_getset(ostream &out, Object *obj, Property *property) {
68966928

68976929
// Now write the actual getter wrapper. It will be a different wrapper
68986930
// depending on whether it's a mapping or a sequence.
6931+
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
6932+
6933+
// Is this property shadowing a static method with the same name? This is a
6934+
// special case to handle WindowProperties::make -- see GH #444.
6935+
if (property->_has_this) {
6936+
for (const Function *func : obj->_methods) {
6937+
if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) {
6938+
string flags;
6939+
string fptr = "&" + func->_name;
6940+
switch (func->_args_type) {
6941+
case AT_keyword_args:
6942+
flags = "METH_VARARGS | METH_KEYWORDS";
6943+
fptr = "(PyCFunction) " + fptr;
6944+
break;
6945+
case AT_varargs:
6946+
flags = "METH_VARARGS";
6947+
break;
6948+
case AT_single_arg:
6949+
flags = "METH_O";
6950+
break;
6951+
default:
6952+
flags = "METH_NOARGS";
6953+
break;
6954+
}
6955+
out << " if (self == nullptr) {\n"
6956+
<< " static PyMethodDef def = {\"" << ielem.get_name() << "\", "
6957+
<< fptr << ", " << flags << " | METH_STATIC, (const char *)"
6958+
<< func->_name << "_comment};\n"
6959+
<< " return PyCFunction_New(&def, nullptr);\n"
6960+
<< " }\n\n";
6961+
break;
6962+
}
6963+
}
6964+
}
6965+
68996966
if (ielem.is_mapping()) {
6900-
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
69016967
if (property->_has_this) {
69026968
out << " nassertr(self != nullptr, nullptr);\n";
69036969
}
@@ -6924,7 +6990,6 @@ write_getset(ostream &out, Object *obj, Property *property) {
69246990
"}\n\n";
69256991

69266992
} else if (ielem.is_sequence()) {
6927-
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
69286993
if (property->_has_this) {
69296994
out << " nassertr(self != nullptr, nullptr);\n";
69306995
}
@@ -6955,7 +7020,6 @@ write_getset(ostream &out, Object *obj, Property *property) {
69557020

69567021
} else {
69577022
// Write out a regular, unwrapped getter.
6958-
out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n";
69597023
FunctionRemap *remap = property->_getter_remaps.front();
69607024

69617025
if (remap->_has_this) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy