Commit d0930731 by Abseil Team Committed by Mark Barolak

Googletest export

Fix gmock_gen to use MOCK_METHOD instead of old style macros. Fix several related bugs in argument parsing and return types. - handle commas more correctly in return types - handle commas correctly in arguments - handle default values more correctly PiperOrigin-RevId: 294435093
parent 56de7cc8
...@@ -610,9 +610,21 @@ class TypeConverter(object): ...@@ -610,9 +610,21 @@ class TypeConverter(object):
result.append(p) result.append(p)
template_count = 0 template_count = 0
brace_count = 0
for s in tokens: for s in tokens:
if not first_token: if not first_token:
first_token = s first_token = s
# Check for braces before templates, as we can have unmatched '<>'
# inside default arguments.
if s.name == '{':
brace_count += 1
elif s.name == '}':
brace_count -= 1
if brace_count > 0:
type_modifiers.append(s)
continue
if s.name == '<': if s.name == '<':
template_count += 1 template_count += 1
elif s.name == '>': elif s.name == '>':
......
...@@ -53,10 +53,8 @@ def _RenderType(ast_type): ...@@ -53,10 +53,8 @@ def _RenderType(ast_type):
ast_type: The AST of the type. ast_type: The AST of the type.
Returns: Returns:
Rendered string and a boolean to indicate whether we have multiple args Rendered string of the type.
(which is not handled correctly).
""" """
has_multiarg_error = False
# Add modifiers like 'const'. # Add modifiers like 'const'.
modifiers = '' modifiers = ''
if ast_type.modifiers: if ast_type.modifiers:
...@@ -66,82 +64,81 @@ def _RenderType(ast_type): ...@@ -66,82 +64,81 @@ def _RenderType(ast_type):
# Collect template args. # Collect template args.
template_args = [] template_args = []
for arg in ast_type.templated_types: for arg in ast_type.templated_types:
rendered_arg, e = _RenderType(arg) rendered_arg = _RenderType(arg)
if e: has_multiarg_error = True
template_args.append(rendered_arg) template_args.append(rendered_arg)
return_type += '<' + ', '.join(template_args) + '>' return_type += '<' + ', '.join(template_args) + '>'
# We are actually not handling multi-template-args correctly. So mark it.
if len(template_args) > 1:
has_multiarg_error = True
if ast_type.pointer: if ast_type.pointer:
return_type += '*' return_type += '*'
if ast_type.reference: if ast_type.reference:
return_type += '&' return_type += '&'
return return_type, has_multiarg_error return return_type
def _GetNumParameters(parameters, source): def _GenerateArg(source):
num_parameters = len(parameters) """Strips out comments, default arguments, and redundant spaces from a single argument.
if num_parameters == 1:
first_param = parameters[0] Args:
if source[first_param.start:first_param.end].strip() == 'void': source: A string for a single argument.
# We must treat T(void) as a function with no parameters.
return 0 Returns:
return num_parameters Rendered string of the argument.
"""
# Remove end of line comments before eliminating newlines.
arg = re.sub(r'//.*', '', source)
# Remove c-style comments.
arg = re.sub(r'/\*.*\*/', '', arg)
# Remove default arguments.
arg = re.sub(r'=.*', '', arg)
# Collapse spaces and newlines into a single space.
arg = re.sub(r'\s+', ' ', arg)
return arg.strip()
def _EscapeForMacro(s):
"""Escapes a string for use as an argument to a C++ macro."""
paren_count = 0
for c in s:
if c == '(':
paren_count += 1
elif c == ')':
paren_count -= 1
elif c == ',' and paren_count == 0:
return '(' + s + ')'
return s
def _GenerateMethods(output_lines, source, class_node): def _GenerateMethods(output_lines, source, class_node):
function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | function_type = (
ast.FUNCTION_OVERRIDE) ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL | ast.FUNCTION_OVERRIDE)
ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
indent = ' ' * _INDENT indent = ' ' * _INDENT
for node in class_node.body: for node in class_node.body:
# We only care about virtual functions. # We only care about virtual functions.
if (isinstance(node, ast.Function) and if (isinstance(node, ast.Function) and node.modifiers & function_type and
node.modifiers & function_type and
not node.modifiers & ctor_or_dtor): not node.modifiers & ctor_or_dtor):
# Pick out all the elements we need from the original function. # Pick out all the elements we need from the original function.
const = '' modifiers = 'override'
if node.modifiers & ast.FUNCTION_CONST: if node.modifiers & ast.FUNCTION_CONST:
const = 'CONST_' modifiers = 'const, ' + modifiers
num_parameters = _GetNumParameters(node.parameters, source)
return_type = 'void' return_type = 'void'
if node.return_type: if node.return_type:
return_type, has_multiarg_error = _RenderType(node.return_type) return_type = _EscapeForMacro(_RenderType(node.return_type))
if has_multiarg_error:
for line in [ args = []
'// The following line won\'t really compile, as the return', for p in node.parameters:
'// type has multiple template arguments. To fix it, use a', arg = _GenerateArg(source[p.start:p.end])
'// typedef for the return type.']: args.append(_EscapeForMacro(arg))
output_lines.append(indent + line)
tmpl = ''
if class_node.templated_types:
tmpl = '_T'
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
args = ''
if node.parameters:
# Get the full text of the parameters from the start
# of the first parameter to the end of the last parameter.
start = node.parameters[0].start
end = node.parameters[-1].end
# Remove // comments.
args_strings = re.sub(r'//.*', '', source[start:end])
# Remove /* comments */.
args_strings = re.sub(r'/\*.*\*/', '', args_strings)
# Remove default arguments.
args_strings = re.sub(r'=.*,', ',', args_strings)
args_strings = re.sub(r'=.*', '', args_strings)
# Condense multiple spaces and eliminate newlines putting the
# parameters together on a single line. Ensure there is a
# space in an argument which is split by a newline without
# intervening whitespace, e.g.: int\nBar
args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
# Create the mock method definition. # Create the mock method definition.
output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name), output_lines.extend([
'%s%s(%s));' % (indent * 3, return_type, args)]) '%sMOCK_METHOD(%s, %s, (%s), (%s));' %
(indent, return_type, node.name, ', '.join(args), modifiers)
])
def _GenerateMocks(filename, source, ast_list, desired_class_names): def _GenerateMocks(filename, source, ast_list, desired_class_names):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment