Skip to content

Commit 0867d0b

Browse files
hermas55mhermas
authored andcommitted
Fix default parameters with specifiers issue
1 parent c6bd927 commit 0867d0b

File tree

3 files changed

+131
-104
lines changed

3 files changed

+131
-104
lines changed

googlemock/scripts/generator/cpp/ast.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,10 @@ def GetScope(self):
929929
def _GetNextToken(self):
930930
if self.token_queue:
931931
return self.token_queue.pop()
932-
return next(self.tokens)
932+
try:
933+
return next(self.tokens)
934+
except StopIteration:
935+
return
933936

934937
def _AddBackToken(self, token):
935938
if token.whence == tokenize.WHENCE_STREAM:

googlemock/scripts/generator/cpp/gmock_class.py

Lines changed: 81 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262

6363

6464
def _RenderType(ast_type):
65-
"""Renders the potentially recursively templated type into a string.
65+
"""Renders the potentially recursively templated type into a string.
6666
6767
Args:
6868
ast_type: The AST of the type.
@@ -71,97 +71,92 @@ def _RenderType(ast_type):
7171
Rendered string and a boolean to indicate whether we have multiple args
7272
(which is not handled correctly).
7373
"""
74-
has_multiarg_error = False
75-
# Add modifiers like 'const'.
76-
modifiers = ''
77-
if ast_type.modifiers:
78-
modifiers = ' '.join(ast_type.modifiers) + ' '
79-
return_type = modifiers + ast_type.name
80-
if ast_type.templated_types:
81-
# Collect template args.
82-
template_args = []
83-
for arg in ast_type.templated_types:
84-
rendered_arg, e = _RenderType(arg)
85-
if e: has_multiarg_error = True
86-
template_args.append(rendered_arg)
87-
return_type += '<' + ', '.join(template_args) + '>'
88-
# We are actually not handling multi-template-args correctly. So mark it.
89-
if len(template_args) > 1:
90-
has_multiarg_error = True
91-
if ast_type.pointer:
92-
return_type += '*'
93-
if ast_type.reference:
94-
return_type += '&'
95-
return return_type, has_multiarg_error
74+
has_multiarg_error = False
75+
# Add modifiers like 'const'.
76+
modifiers = ''
77+
if ast_type.modifiers:
78+
modifiers = ' '.join(ast_type.modifiers) + ' '
79+
return_type = modifiers + ast_type.name
80+
if ast_type.templated_types:
81+
# Collect template args.
82+
template_args = []
83+
for arg in ast_type.templated_types:
84+
rendered_arg, e = _RenderType(arg)
85+
if e: has_multiarg_error = True
86+
template_args.append(rendered_arg)
87+
return_type += '<' + ', '.join(template_args) + '>'
88+
# We are actually not handling multi-template-args correctly. So mark it.
89+
if len(template_args) > 1:
90+
has_multiarg_error = True
91+
if ast_type.pointer:
92+
return_type += '*'
93+
if ast_type.reference:
94+
return_type += '&'
95+
return return_type, has_multiarg_error
9696

9797

9898
def _GetNumParameters(parameters, source):
99-
num_parameters = len(parameters)
100-
if num_parameters == 1:
101-
first_param = parameters[0]
102-
if source[first_param.start:first_param.end].strip() == 'void':
103-
# We must treat T(void) as a function with no parameters.
104-
return 0
105-
return num_parameters
99+
num_parameters = len(parameters)
100+
if num_parameters == 1:
101+
first_param = parameters[0]
102+
if source[first_param.start:first_param.end].strip() == 'void':
103+
# We must treat T(void) as a function with no parameters.
104+
return 0
105+
return num_parameters
106106

107107

108108
def _GenerateMethods(output_lines, source, class_node):
109-
function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL |
110-
ast.FUNCTION_OVERRIDE)
111-
ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
112-
indent = ' ' * _INDENT
113-
114-
for node in class_node.body:
115-
# We only care about virtual functions.
116-
if (isinstance(node, ast.Function) and
117-
node.modifiers & function_type and
118-
not node.modifiers & ctor_or_dtor):
119-
# Pick out all the elements we need from the original function.
120-
const = ''
121-
if node.modifiers & ast.FUNCTION_CONST:
122-
const = 'CONST_'
123-
num_parameters = _GetNumParameters(node.parameters, source)
124-
return_type = 'void'
125-
if node.return_type:
126-
return_type, has_multiarg_error = _RenderType(node.return_type)
127-
if has_multiarg_error:
128-
for line in [
129-
'// The following line won\'t really compile, as the return',
130-
'// type has multiple template arguments. To fix it, use a',
131-
'// typedef for the return type.']:
132-
output_lines.append(indent + line)
133-
tmpl = ''
134-
if class_node.templated_types:
135-
tmpl = '_T'
136-
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
137-
138-
args = ''
139-
if node.parameters:
140-
# Due to the parser limitations, it is impossible to keep comments
141-
# while stripping the default parameters. When defaults are
142-
# present, we choose to strip them and comments (and produce
143-
# compilable code).
144-
# TODO([email protected]): Investigate whether it is possible to
145-
# preserve parameter name when reconstructing parameter text from
146-
# the AST.
147-
if len([param for param in node.parameters if param.default]) > 0:
148-
args = ', '.join(param.type.name for param in node.parameters)
149-
else:
150-
# Get the full text of the parameters from the start
151-
# of the first parameter to the end of the last parameter.
152-
start = node.parameters[0].start
153-
end = node.parameters[-1].end
154-
# Remove // comments.
155-
args_strings = re.sub(r'//.*', '', source[start:end])
156-
# Condense multiple spaces and eliminate newlines putting the
157-
# parameters together on a single line. Ensure there is a
158-
# space in an argument which is split by a newline without
159-
# intervening whitespace, e.g.: int\nBar
160-
args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
161-
162-
# Create the mock method definition.
163-
output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name),
164-
'%s%s(%s));' % (indent*3, return_type, args)])
109+
function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL |
110+
ast.FUNCTION_OVERRIDE)
111+
ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
112+
indent = ' ' * _INDENT
113+
114+
for node in class_node.body:
115+
# We only care about virtual functions.
116+
if (isinstance(node, ast.Function) and
117+
node.modifiers & function_type and
118+
not node.modifiers & ctor_or_dtor):
119+
# Pick out all the elements we need from the original function.
120+
const = ''
121+
if node.modifiers & ast.FUNCTION_CONST:
122+
const = 'CONST_'
123+
num_parameters = _GetNumParameters(node.parameters, source)
124+
return_type = 'void'
125+
if node.return_type:
126+
return_type, has_multiarg_error = _RenderType(node.return_type)
127+
if has_multiarg_error:
128+
for line in [
129+
'// The following line won\'t really compile, as the return',
130+
'// type has multiple template arguments. To fix it, use a',
131+
'// typedef for the return type.']:
132+
output_lines.append(indent + line)
133+
tmpl = ''
134+
if class_node.templated_types:
135+
tmpl = '_T'
136+
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
137+
138+
args = ''
139+
if node.parameters:
140+
# Get the full text of the parameters from the start
141+
# of the first parameter to the end of the last parameter.
142+
start = node.parameters[0].start
143+
end = node.parameters[-1].end
144+
# Remove // comments.
145+
args_strings = re.sub(r'//.*', '', source[start:end])
146+
# Remove /* comments */.
147+
args_strings = re.sub(r'/\*.*\*/', '', args_strings)
148+
# Remove default arguments.
149+
args_strings = re.sub(r'=.*,', ',', args_strings)
150+
args_strings = re.sub(r'=.*', '', args_strings)
151+
# Condense multiple spaces and eliminate newlines putting the
152+
# parameters together on a single line. Ensure there is a
153+
# space in an argument which is split by a newline without
154+
# intervening whitespace, e.g.: int\nBar
155+
args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
156+
157+
# Create the mock method definition.
158+
output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name),
159+
'%s%s(%s));' % (indent * 3, return_type, args)])
165160

166161

167162
def _GenerateMocks(filename, source, ast_list, desired_class_names):

googlemock/scripts/generator/cpp/gmock_class_test.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -193,20 +193,49 @@ class Foo {
193193
};
194194
"""
195195
self.assertEqualIgnoreLeadingWhitespace(
196-
'MOCK_METHOD2(Bar,\nvoid(int, char));',
196+
'MOCK_METHOD2(Bar,\nvoid(int a, char c ));',
197197
self.GenerateMethodSource(source))
198198

199199
def testMultipleDefaultParameters(self):
200200
source = """
201201
class Foo {
202202
public:
203-
virtual void Bar(int a = 42, char c = 'x') = 0;
203+
virtual void Bar(
204+
int a = 42,
205+
char c = 'x',
206+
const int* const p = nullptr,
207+
const std::string& s = "42",
208+
char tab[] = {'4','2'},
209+
int const *& rp = aDefaultPointer) = 0;
204210
};
205211
"""
206212
self.assertEqualIgnoreLeadingWhitespace(
207-
'MOCK_METHOD2(Bar,\nvoid(int, char));',
213+
"MOCK_METHOD7(Bar,\n"
214+
"void(int a , char c , const int* const p , const std::string& s , char tab[] , int const *& rp ));",
208215
self.GenerateMethodSource(source))
209216

217+
def testConstDefaultParameter(self):
218+
source = """
219+
class Test {
220+
public:
221+
virtual bool Bar(const int test_arg = 42) = 0;
222+
};
223+
"""
224+
expected = 'MOCK_METHOD1(Bar,\nbool(const int test_arg ));'
225+
self.assertEqualIgnoreLeadingWhitespace(
226+
expected, self.GenerateMethodSource(source))
227+
228+
def testConstRefDefaultParameter(self):
229+
source = """
230+
class Test {
231+
public:
232+
virtual bool Bar(const std::string& test_arg = "42" ) = 0;
233+
};
234+
"""
235+
expected = 'MOCK_METHOD1(Bar,\nbool(const std::string& test_arg ));'
236+
self.assertEqualIgnoreLeadingWhitespace(
237+
expected, self.GenerateMethodSource(source))
238+
210239
def testRemovesCommentsWhenDefaultsArePresent(self):
211240
source = """
212241
class Foo {
@@ -216,7 +245,7 @@ class Foo {
216245
};
217246
"""
218247
self.assertEqualIgnoreLeadingWhitespace(
219-
'MOCK_METHOD2(Bar,\nvoid(int, char));',
248+
'MOCK_METHOD2(Bar,\nvoid(int a , char c));',
220249
self.GenerateMethodSource(source))
221250

222251
def testDoubleSlashCommentsInParameterListAreRemoved(self):
@@ -243,7 +272,7 @@ class Foo {
243272
};
244273
"""
245274
self.assertEqualIgnoreLeadingWhitespace(
246-
'MOCK_METHOD2(Bar,\nconst string&(int /* keeper */, int b));',
275+
'MOCK_METHOD2(Bar,\nconst string&(int , int b));',
247276
self.GenerateMethodSource(source))
248277

249278
def testArgsOfTemplateTypes(self):
@@ -458,8 +487,8 @@ class MockTest : public Test {
458487
self.assertEqualIgnoreLeadingWhitespace(
459488
expected, self.GenerateMocks(source))
460489

461-
def testEnumType(self):
462-
source = """
490+
def testEnumType(self):
491+
source = """
463492
class Test {
464493
public:
465494
enum Bar {
@@ -475,11 +504,11 @@ class MockTest : public Test {
475504
void());
476505
};
477506
"""
478-
self.assertEqualIgnoreLeadingWhitespace(
479-
expected, self.GenerateMocks(source))
507+
self.assertEqualIgnoreLeadingWhitespace(
508+
expected, self.GenerateMocks(source))
480509

481-
def testEnumClassType(self):
482-
source = """
510+
def testEnumClassType(self):
511+
source = """
483512
class Test {
484513
public:
485514
enum class Bar {
@@ -488,18 +517,18 @@ class Test {
488517
virtual void Foo();
489518
};
490519
"""
491-
expected = """\
520+
expected = """\
492521
class MockTest : public Test {
493522
public:
494523
MOCK_METHOD0(Foo,
495524
void());
496525
};
497526
"""
498-
self.assertEqualIgnoreLeadingWhitespace(
499-
expected, self.GenerateMocks(source))
527+
self.assertEqualIgnoreLeadingWhitespace(
528+
expected, self.GenerateMocks(source))
500529

501-
def testStdFunction(self):
502-
source = """
530+
def testStdFunction(self):
531+
source = """
503532
class Test {
504533
public:
505534
Test(std::function<int(std::string)> foo) : foo_(foo) {}
@@ -510,7 +539,7 @@ class Test {
510539
std::function<int(std::string)> foo_;
511540
};
512541
"""
513-
expected = """\
542+
expected = """\
514543
class MockTest : public Test {
515544
public:
516545
MOCK_METHOD0(foo,

0 commit comments

Comments
 (0)