Skip to content

Commit a1f5eae

Browse files
committed
using directives in a class are slightly different from global using
1 parent ac1f3dc commit a1f5eae

File tree

2 files changed

+100
-21
lines changed

2 files changed

+100
-21
lines changed

CppHeaderParser/CppHeaderParser.py

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,8 @@ class CppClass(dict):
589589
* ``nested_classes`` - Classes and structs defined within this class
590590
* ``final`` - True if final
591591
* ``abstract`` - True if abstract
592+
* ``using`` - Using directives in this class scope: key is name for lookup,
593+
value is :class:`.CppVariable`
592594
* ``parent`` - If not None, the class that this class is nested in
593595
594596
An example of how this could look is as follows::
@@ -654,6 +656,7 @@ def __init__(self, nameStack, curTemplate, doxygen, location):
654656
self._public_typedefs = {}
655657
self._public_forward_declares = []
656658
self["namespace"] = ""
659+
self["using"] = {}
657660

658661
debug_print("Class: %s", nameStack)
659662
debug_print("Template: %s", curTemplate)
@@ -1124,12 +1127,14 @@ class CppVariable(_CppVariable):
11241127
* ``default`` - Default value of the variable, this key will only
11251128
exist if there is a default value
11261129
* ``extern`` - True if its an extern, False if not
1130+
* ``parent`` - If not None, either the class this is a property of, or the
1131+
method this variable is a parameter in
11271132
"""
11281133

11291134
Vars = []
11301135

11311136
def __init__(self, nameStack, doxygen, location, **kwargs):
1132-
debug_print("trace %s", nameStack)
1137+
debug_print("var trace %s", nameStack)
11331138
if len(nameStack) and nameStack[0] == "extern":
11341139
self["extern"] = True
11351140
del nameStack[0]
@@ -1497,21 +1502,33 @@ def resolve_type(self, string, result): # recursive
14971502
result["fundamental"] = False
14981503
result["class"] = klass
14991504
result["unresolved"] = False
1500-
elif self.using:
1501-
# search for type in all enclosing namespaces
1502-
for ns in _iter_ns_str_reversed(result.get("namespace", "")):
1503-
nsalias = ns + alias
1504-
used = self.using.get(nsalias)
1505-
if used:
1506-
for i in ("type", "namespace", "ctypes_type", "raw_type"):
1507-
if i in used:
1508-
result[i] = used[i]
1509-
result["unresolved"] = False
1510-
break
1511-
else:
1512-
result["unresolved"] = True
15131505
else:
1514-
result["unresolved"] = True
1506+
used = None
1507+
1508+
# Search for using directives in parents
1509+
parent = result["parent"]
1510+
while parent:
1511+
p_using = parent.get("using")
1512+
if p_using:
1513+
used = p_using.get(alias)
1514+
if used:
1515+
break
1516+
parent = parent["parent"]
1517+
1518+
if not used and self.using:
1519+
# search for type in all enclosing namespaces
1520+
# TODO: would be nice if namespaces were an object?
1521+
for ns in _iter_ns_str_reversed(result.get("namespace", "")):
1522+
nsalias = ns + alias
1523+
used = self.using.get(nsalias)
1524+
if used:
1525+
break
1526+
1527+
if used:
1528+
for i in ("type", "namespace", "ctypes_type", "raw_type"):
1529+
if i in used:
1530+
result[i] = used[i]
1531+
result["unresolved"] = False
15151532
else:
15161533
result["fundamental"] = True
15171534
result["unresolved"] = False
@@ -2544,8 +2561,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
25442561
self.anon_struct_counter = 0
25452562
self.anon_union_counter = [-1, 0]
25462563

2547-
#: Using directives in this header: key is full name for lookup, value
2548-
#: is :class:`.CppVariable`
2564+
#: Using directives in this header outside of class scope: key is
2565+
#: full name for lookup, value is :class:`.CppVariable`
25492566
self.using = {}
25502567

25512568
if len(self.headerFileName):
@@ -3116,23 +3133,40 @@ def _evaluate_stack(self, token=None):
31163133
else:
31173134
if len(self.nameStack) > 3 and self.nameStack[2] == "=":
31183135
# using foo = ns::bar
3136+
# -> type alias: same behavior in all scopes
31193137
alias = self.nameStack[1]
31203138
ns, stack = _split_namespace(self.nameStack[3:])
31213139
atype = CppVariable(
31223140
stack, self._get_stmt_doxygen(), self._get_location(stack)
31233141
)
3142+
3143+
# namespace refers to the embedded type
3144+
atype["namespace"] = ns
31243145
else:
31253146
# using foo::bar
3147+
# -> in global scope this is bringing in something
3148+
# from a different namespace
3149+
# -> in class scope this is bringing in a member
3150+
# from a base class
31263151
ns, stack = _split_namespace(self.nameStack[1:])
31273152
atype = CppVariable(
31283153
stack, self._get_stmt_doxygen(), self._get_location(stack)
31293154
)
31303155
alias = atype["type"]
3156+
if self.curClass:
3157+
atype["baseclass"] = ns
3158+
else:
3159+
atype["namespace"] = ns
31313160

3132-
atype["namespace"] = ns
31333161
atype["raw_type"] = ns + atype["type"]
3134-
alias = self.current_namespace() + alias
3135-
self.using[alias] = atype
3162+
3163+
if self.curClass:
3164+
klass = self.classes[self.curClass]
3165+
klass["using"][alias] = atype
3166+
else:
3167+
# lookup is done
3168+
alias = self.current_namespace() + alias
3169+
self.using[alias] = atype
31363170
elif is_method_namestack(self.stack) and "(" in self.nameStack:
31373171
debug_print("trace")
31383172
self._evaluate_method_stack()

test/test_CppHeaderParser.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2787,18 +2787,26 @@ def setUp(self):
27872787
using VoidFunction = std::function<void()>;
27882788
27892789
void fn(string &s, VoidFunction fn, thing * t);
2790+
2791+
class A : public B {
2792+
public:
2793+
using B::B;
2794+
using IntFunction = std::function<int()>;
2795+
2796+
void a(string &s, IntFunction fn, thing * t);
2797+
};
27902798
}
27912799
""",
27922800
"string",
27932801
)
27942802

27952803
def test_using(self):
2804+
self.assertEqual(len(self.cppHeader.using), 3)
27962805
self.assertIn("a::string", self.cppHeader.using)
27972806
self.assertIn("a::VoidFunction", self.cppHeader.using)
27982807
self.assertIn("thing", self.cppHeader.using)
27992808

28002809
def test_fn(self):
2801-
self.maxDiff = None
28022810
self.assertEqual(len(self.cppHeader.functions), 1)
28032811
fn = self.cppHeader.functions[0]
28042812
self.assertEqual(fn["name"], "fn")
@@ -2829,6 +2837,43 @@ def test_fn(self):
28292837
],
28302838
)
28312839

2840+
def test_class(self):
2841+
c = self.cppHeader.classes["A"]
2842+
2843+
self.assertEqual(len(c["using"]), 2)
2844+
self.assertIn("B", c["using"])
2845+
self.assertIn("IntFunction", c["using"])
2846+
2847+
self.assertEqual(len(c["methods"]["public"]), 1)
2848+
fn = c["methods"]["public"][0]
2849+
self.assertEqual(fn["name"], "a")
2850+
self.assertEqual(
2851+
filter_pameters(fn["parameters"], ["namespace", "raw_type"]),
2852+
[
2853+
{
2854+
"type": "string",
2855+
"name": "s",
2856+
"desc": None,
2857+
"namespace": "std::",
2858+
"raw_type": "std::string",
2859+
},
2860+
{
2861+
"type": "function<int ( )>",
2862+
"name": "fn",
2863+
"desc": None,
2864+
"namespace": "std::",
2865+
"raw_type": "std::function<int ( )>",
2866+
},
2867+
{
2868+
"type": "thing",
2869+
"name": "t",
2870+
"desc": None,
2871+
"namespace": "std::",
2872+
"raw_type": "std::thing",
2873+
},
2874+
],
2875+
)
2876+
28322877

28332878
class StaticFn_TestCase(unittest.TestCase):
28342879
def setUp(self):

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