Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-09 08:19:08

0001 #!/usr/bin/env python
0002 #
0003 # Copyright 2008 Google Inc.  All Rights Reserved.
0004 #
0005 # Licensed under the Apache License, Version 2.0 (the "License");
0006 # you may not use this file except in compliance with the License.
0007 # You may obtain a copy of the License at
0008 #
0009 #      http://www.apache.org/licenses/LICENSE-2.0
0010 #
0011 # Unless required by applicable law or agreed to in writing, software
0012 # distributed under the License is distributed on an "AS IS" BASIS,
0013 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014 # See the License for the specific language governing permissions and
0015 # limitations under the License.
0016 
0017 """Generate Google Mock classes from base classes.
0018 
0019 This program will read in a C++ source file and output the Google Mock
0020 classes for the specified classes.  If no class is specified, all
0021 classes in the source file are emitted.
0022 
0023 Usage:
0024   gmock_class.py header-file.h [ClassName]...
0025 
0026 Output is sent to stdout.
0027 """
0028 
0029 __author__ = 'nnorwitz@google.com (Neal Norwitz)'
0030 
0031 
0032 import os
0033 import re
0034 import sys
0035 
0036 from cpp import ast
0037 from cpp import utils
0038 
0039 # Preserve compatibility with Python 2.3.
0040 try:
0041   _dummy = set
0042 except NameError:
0043   import sets
0044   set = sets.Set
0045 
0046 _VERSION = (1, 0, 1)  # The version of this script.
0047 # How many spaces to indent.  Can set me with the INDENT environment variable.
0048 _INDENT = 2
0049 
0050 
0051 def _GenerateMethods(output_lines, source, class_node):
0052   function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL |
0053                    ast.FUNCTION_OVERRIDE)
0054   ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
0055   indent = ' ' * _INDENT
0056 
0057   for node in class_node.body:
0058     # We only care about virtual functions.
0059     if (isinstance(node, ast.Function) and
0060         node.modifiers & function_type and
0061         not node.modifiers & ctor_or_dtor):
0062       # Pick out all the elements we need from the original function.
0063       const = ''
0064       if node.modifiers & ast.FUNCTION_CONST:
0065         const = 'CONST_'
0066       return_type = 'void'
0067       if node.return_type:
0068         # Add modifiers like 'const'.
0069         modifiers = ''
0070         if node.return_type.modifiers:
0071           modifiers = ' '.join(node.return_type.modifiers) + ' '
0072         return_type = modifiers + node.return_type.name
0073         template_args = [arg.name for arg in node.return_type.templated_types]
0074         if template_args:
0075           return_type += '<' + ', '.join(template_args) + '>'
0076           if len(template_args) > 1:
0077             for line in [
0078                 '// The following line won\'t really compile, as the return',
0079                 '// type has multiple template arguments.  To fix it, use a',
0080                 '// typedef for the return type.']:
0081               output_lines.append(indent + line)
0082         if node.return_type.pointer:
0083           return_type += '*'
0084         if node.return_type.reference:
0085           return_type += '&'
0086         num_parameters = len(node.parameters)
0087         if len(node.parameters) == 1:
0088           first_param = node.parameters[0]
0089           if source[first_param.start:first_param.end].strip() == 'void':
0090             # We must treat T(void) as a function with no parameters.
0091             num_parameters = 0
0092       tmpl = ''
0093       if class_node.templated_types:
0094         tmpl = '_T'
0095       mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
0096 
0097       args = ''
0098       if node.parameters:
0099         # Due to the parser limitations, it is impossible to keep comments
0100         # while stripping the default parameters.  When defaults are
0101         # present, we choose to strip them and comments (and produce
0102         # compilable code).
0103         # TODO(nnorwitz@google.com): Investigate whether it is possible to
0104         # preserve parameter name when reconstructing parameter text from
0105         # the AST.
0106         if len([param for param in node.parameters if param.default]) > 0:
0107           args = ', '.join(param.type.name for param in node.parameters)
0108         else:
0109           # Get the full text of the parameters from the start
0110           # of the first parameter to the end of the last parameter.
0111           start = node.parameters[0].start
0112           end = node.parameters[-1].end
0113           # Remove // comments.
0114           args_strings = re.sub(r'//.*', '', source[start:end])
0115           # Condense multiple spaces and eliminate newlines putting the
0116           # parameters together on a single line.  Ensure there is a
0117           # space in an argument which is split by a newline without
0118           # intervening whitespace, e.g.: int\nBar
0119           args = re.sub('  +', ' ', args_strings.replace('\n', ' '))
0120 
0121       # Create the mock method definition.
0122       output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name),
0123                            '%s%s(%s));' % (indent*3, return_type, args)])
0124 
0125 
0126 def _GenerateMocks(filename, source, ast_list, desired_class_names):
0127   processed_class_names = set()
0128   lines = []
0129   for node in ast_list:
0130     if (isinstance(node, ast.Class) and node.body and
0131         # desired_class_names being None means that all classes are selected.
0132         (not desired_class_names or node.name in desired_class_names)):
0133       class_name = node.name
0134       parent_name = class_name
0135       processed_class_names.add(class_name)
0136       class_node = node
0137       # Add namespace before the class.
0138       if class_node.namespace:
0139         lines.extend(['namespace %s {' % n for n in class_node.namespace])  # }
0140         lines.append('')
0141 
0142       # Add template args for templated classes.
0143       if class_node.templated_types:
0144         # TODO(paulchang): The AST doesn't preserve template argument order,
0145         # so we have to make up names here.
0146         # TODO(paulchang): Handle non-type template arguments (e.g.
0147         # template<typename T, int N>).
0148         template_arg_count = len(class_node.templated_types.keys())
0149         template_args = ['T%d' % n for n in range(template_arg_count)]
0150         template_decls = ['typename ' + arg for arg in template_args]
0151         lines.append('template <' + ', '.join(template_decls) + '>')
0152         parent_name += '<' + ', '.join(template_args) + '>'
0153 
0154       # Add the class prolog.
0155       lines.append('class Mock%s : public %s {'  # }
0156                    % (class_name, parent_name))
0157       lines.append('%spublic:' % (' ' * (_INDENT // 2)))
0158 
0159       # Add all the methods.
0160       _GenerateMethods(lines, source, class_node)
0161 
0162       # Close the class.
0163       if lines:
0164         # If there are no virtual methods, no need for a public label.
0165         if len(lines) == 2:
0166           del lines[-1]
0167 
0168         # Only close the class if there really is a class.
0169         lines.append('};')
0170         lines.append('')  # Add an extra newline.
0171 
0172       # Close the namespace.
0173       if class_node.namespace:
0174         for i in range(len(class_node.namespace)-1, -1, -1):
0175           lines.append('}  // namespace %s' % class_node.namespace[i])
0176         lines.append('')  # Add an extra newline.
0177 
0178   if desired_class_names:
0179     missing_class_name_list = list(desired_class_names - processed_class_names)
0180     if missing_class_name_list:
0181       missing_class_name_list.sort()
0182       sys.stderr.write('Class(es) not found in %s: %s\n' %
0183                        (filename, ', '.join(missing_class_name_list)))
0184   elif not processed_class_names:
0185     sys.stderr.write('No class found in %s\n' % filename)
0186 
0187   return lines
0188 
0189 
0190 def main(argv=sys.argv):
0191   if len(argv) < 2:
0192     sys.stderr.write('Google Mock Class Generator v%s\n\n' %
0193                      '.'.join(map(str, _VERSION)))
0194     sys.stderr.write(__doc__)
0195     return 1
0196 
0197   global _INDENT
0198   try:
0199     _INDENT = int(os.environ['INDENT'])
0200   except KeyError:
0201     pass
0202   except:
0203     sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT'))
0204 
0205   filename = argv[1]
0206   desired_class_names = None  # None means all classes in the source file.
0207   if len(argv) >= 3:
0208     desired_class_names = set(argv[2:])
0209   source = utils.ReadFile(filename)
0210   if source is None:
0211     return 1
0212 
0213   builder = ast.BuilderFromSource(source, filename)
0214   try:
0215     entire_ast = filter(None, builder.Generate())
0216   except KeyboardInterrupt:
0217     return
0218   except:
0219     # An error message was already printed since we couldn't parse.
0220     sys.exit(1)
0221   else:
0222     lines = _GenerateMocks(filename, source, entire_ast, desired_class_names)
0223     sys.stdout.write('\n'.join(lines))
0224 
0225 
0226 if __name__ == '__main__':
0227   main(sys.argv)