Skip to content

Commit 67a5956

Browse files
committed
More robust ctor initializer discard code
1 parent 9b354bd commit 67a5956

File tree

2 files changed

+121
-19
lines changed

2 files changed

+121
-19
lines changed

CppHeaderParser/CppHeaderParser.py

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ def is_method_namestack(stack):
193193
elif "{" in stack and stack.index("{") < stack.index("("):
194194
r = False # struct that looks like a method/class
195195
elif "(" in stack and ")" in stack:
196-
if "{" in stack and "}" in stack:
196+
if stack[-1] == ":":
197+
r = True
198+
elif "{" in stack and "}" in stack:
197199
r = True
198200
elif stack[-1] == ";":
199201
if is_function_pointer_stack(stack):
@@ -994,22 +996,6 @@ def __init__(self, nameStack, curClass, methinfo, curTemplate, doxygen, location
994996
self.update(methinfo)
995997
set_location_info(self, location)
996998

997-
# Filter out initializer lists used in constructors
998-
try:
999-
paren_depth_counter = 0
1000-
for i in range(0, len(nameStack)):
1001-
elm = nameStack[i]
1002-
if elm == "(":
1003-
paren_depth_counter += 1
1004-
if elm == ")":
1005-
paren_depth_counter -= 1
1006-
if paren_depth_counter == 0 and nameStack[i + 1] == ":":
1007-
debug_print("Stripping out initializer list")
1008-
nameStack = nameStack[: i + 1]
1009-
break
1010-
except:
1011-
pass
1012-
1013999
paramsStack = self._params_helper1(nameStack)
10141000

10151001
debug_print("curTemplate: %s", curTemplate)
@@ -2018,6 +2004,10 @@ def parse_method_type(self, stack):
20182004
self.braceHandled = True
20192005
elif stack[-1] == ";":
20202006
info["defined"] = False
2007+
elif stack[-1] == ":":
2008+
info["defined"] = True
2009+
self._discard_ctor_initializer()
2010+
self.braceHandled = True
20212011
else:
20222012
assert 0
20232013

@@ -2806,6 +2796,12 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
28062796
self.nameStack = []
28072797
self.stack = []
28082798
self.stmtTokens = []
2799+
elif is_method_namestack(self.stack):
2800+
debug_print("trace")
2801+
self._evaluate_method_stack()
2802+
self.nameStack = []
2803+
self.stack = []
2804+
self.stmtTokens = []
28092805
else:
28102806
self.nameStack.append(tok.value)
28112807

@@ -2923,7 +2919,7 @@ def _parse_error(self, tokens, expected):
29232919
def _next_token_must_be(self, *tokenTypes):
29242920
tok = self.lex.token()
29252921
if tok.type not in tokenTypes:
2926-
raise self._parse_error((tok,), " or ".join(tokenTypes))
2922+
raise self._parse_error((tok,), "' or '".join(tokenTypes))
29272923
return tok
29282924

29292925
_end_balanced_tokens = {">", "}", "]", ")", "DBL_RBRACKET"}
@@ -2983,6 +2979,59 @@ def _discard_contents(self, start_type, end_type):
29832979
if level == 0:
29842980
break
29852981

2982+
def _discard_ctor_initializer(self):
2983+
"""
2984+
ctor_initializer: ":" mem_initializer_list
2985+
2986+
mem_initializer_list: mem_initializer ["..."]
2987+
| mem_initializer "," mem_initializer_list ["..."]
2988+
2989+
mem_initializer: mem_initializer_id "(" [expression_list] ")"
2990+
| mem_initializer_id braced_init_list
2991+
2992+
mem_initializer_id: class_or_decltype
2993+
| IDENTIFIER
2994+
"""
2995+
debug_print("discarding ctor intializer")
2996+
# all of this is discarded.. the challenge is to determine
2997+
# when the initializer ends and the function starts
2998+
while True:
2999+
tok = self.lex.token()
3000+
if tok.type == "DBL_COLON":
3001+
tok = self.lex.token()
3002+
3003+
if tok.type == "decltype":
3004+
tok = self._next_token_must_be("(")
3005+
self._consume_balanced_tokens(tok)
3006+
tok = self.lex.token()
3007+
3008+
# each initializer is either foo() or foo{}, so look for that
3009+
while True:
3010+
if tok.type not in ("{", "("):
3011+
tok = self.lex.token()
3012+
continue
3013+
3014+
if tok.type == "{":
3015+
self._discard_contents("{", "}")
3016+
elif tok.type == "(":
3017+
self._discard_contents("(", ")")
3018+
3019+
tok = self.lex.token()
3020+
break
3021+
3022+
# at the end
3023+
if tok.type == "ELLIPSIS":
3024+
tok = self.lex.token()
3025+
3026+
if tok.type == ",":
3027+
continue
3028+
elif tok.type == "{":
3029+
# reached the function
3030+
self._discard_contents("{", "}")
3031+
return
3032+
else:
3033+
raise self._parse_error((tok,), ",' or '{")
3034+
29863035
def _evaluate_stack(self, token=None):
29873036
"""Evaluates the current name stack"""
29883037

@@ -3133,7 +3182,7 @@ def _evaluate_stack(self, token=None):
31333182
self.nameStackHistory[self.braceDepth] = (nameStackCopy, self.curClass)
31343183
except:
31353184
self.nameStackHistory.append((nameStackCopy, self.curClass))
3136-
3185+
31373186
# its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here
31383187
self.nameStack = []
31393188
self.lex.doxygenCommentCache = ""

CppHeaderParser/test/test_CppHeaderParser.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,5 +3366,58 @@ def test_nothing(self):
33663366
self.assertEqual(self.cppHeader.functions, [])
33673367

33683368

3369+
class InitializerWithInitializerList_TestCase(unittest.TestCase):
3370+
def setUp(self):
3371+
self.cppHeader = CppHeaderParser.CppHeader(
3372+
"""
3373+
struct ComplexInit : SomeBase {
3374+
ComplexInit(int i) :
3375+
m_stuff{i,2}
3376+
{
3377+
auto i = something();
3378+
}
3379+
3380+
void fn();
3381+
3382+
std::vector<int> m_stuff;
3383+
};
3384+
3385+
template <typename T>
3386+
class future final {
3387+
public:
3388+
template <typename R>
3389+
future(future<R>&& oth) noexcept
3390+
: future(oth.then([](R&& val) -> T { return val; })) {}
3391+
};
3392+
3393+
3394+
""",
3395+
"string",
3396+
)
3397+
3398+
def test_cls_props(self):
3399+
c = self.cppHeader.classes["ComplexInit"]
3400+
self.assertEqual(2, len(c["methods"]["public"]))
3401+
self.assertEqual(0, len(c["methods"]["private"]))
3402+
self.assertEqual(0, len(c["methods"]["private"]))
3403+
self.assertEqual(1, len(c["properties"]["public"]))
3404+
self.assertEqual(0, len(c["properties"]["private"]))
3405+
self.assertEqual(0, len(c["properties"]["protected"]))
3406+
3407+
self.assertEqual(c["methods"]["public"][0]["name"], "ComplexInit")
3408+
self.assertEqual(c["methods"]["public"][1]["name"], "fn")
3409+
3410+
self.assertEqual(c["properties"]["public"][0]["name"], "m_stuff")
3411+
3412+
def test_future(self):
3413+
c = self.cppHeader.classes["future"]
3414+
self.assertEqual(1, len(c["methods"]["public"]))
3415+
self.assertEqual(0, len(c["methods"]["private"]))
3416+
self.assertEqual(0, len(c["methods"]["private"]))
3417+
self.assertEqual(0, len(c["properties"]["public"]))
3418+
self.assertEqual(0, len(c["properties"]["private"]))
3419+
self.assertEqual(0, len(c["properties"]["protected"]))
3420+
self.assertEqual(c["methods"]["public"][0]["name"], "future")
3421+
33693422
if __name__ == "__main__":
33703423
unittest.main()

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