github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/src/third_party/googlemock/scripts/gmock_doctor.py (about)

     1  #!/usr/bin/env python
     2  #
     3  # Copyright 2008, Google Inc.
     4  # All rights reserved.
     5  #
     6  # Redistribution and use in source and binary forms, with or without
     7  # modification, are permitted provided that the following conditions are
     8  # met:
     9  #
    10  #     * Redistributions of source code must retain the above copyright
    11  # notice, this list of conditions and the following disclaimer.
    12  #     * Redistributions in binary form must reproduce the above
    13  # copyright notice, this list of conditions and the following disclaimer
    14  # in the documentation and/or other materials provided with the
    15  # distribution.
    16  #     * Neither the name of Google Inc. nor the names of its
    17  # contributors may be used to endorse or promote products derived from
    18  # this software without specific prior written permission.
    19  #
    20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  """Converts compiler's errors in code using Google Mock to plain English."""
    33  
    34  __author__ = 'wan@google.com (Zhanyong Wan)'
    35  
    36  import re
    37  import sys
    38  
    39  _VERSION = '1.0.3'
    40  
    41  _EMAIL = 'googlemock@googlegroups.com'
    42  
    43  _COMMON_GMOCK_SYMBOLS = [
    44      # Matchers
    45      '_',
    46      'A',
    47      'AddressSatisfies',
    48      'AllOf',
    49      'An',
    50      'AnyOf',
    51      'ContainerEq',
    52      'Contains',
    53      'ContainsRegex',
    54      'DoubleEq',
    55      'ElementsAre',
    56      'ElementsAreArray',
    57      'EndsWith',
    58      'Eq',
    59      'Field',
    60      'FloatEq',
    61      'Ge',
    62      'Gt',
    63      'HasSubstr',
    64      'IsInitializedProto',
    65      'Le',
    66      'Lt',
    67      'MatcherCast',
    68      'Matches',
    69      'MatchesRegex',
    70      'NanSensitiveDoubleEq',
    71      'NanSensitiveFloatEq',
    72      'Ne',
    73      'Not',
    74      'NotNull',
    75      'Pointee',
    76      'Property',
    77      'Ref',
    78      'ResultOf',
    79      'SafeMatcherCast',
    80      'StartsWith',
    81      'StrCaseEq',
    82      'StrCaseNe',
    83      'StrEq',
    84      'StrNe',
    85      'Truly',
    86      'TypedEq',
    87      'Value',
    88  
    89      # Actions
    90      'Assign',
    91      'ByRef',
    92      'DeleteArg',
    93      'DoAll',
    94      'DoDefault',
    95      'IgnoreResult',
    96      'Invoke',
    97      'InvokeArgument',
    98      'InvokeWithoutArgs',
    99      'Return',
   100      'ReturnNew',
   101      'ReturnNull',
   102      'ReturnRef',
   103      'SaveArg',
   104      'SetArgReferee',
   105      'SetArgPointee',
   106      'SetArgumentPointee',
   107      'SetArrayArgument',
   108      'SetErrnoAndReturn',
   109      'Throw',
   110      'WithArg',
   111      'WithArgs',
   112      'WithoutArgs',
   113  
   114      # Cardinalities
   115      'AnyNumber',
   116      'AtLeast',
   117      'AtMost',
   118      'Between',
   119      'Exactly',
   120  
   121      # Sequences
   122      'InSequence',
   123      'Sequence',
   124  
   125      # Misc
   126      'DefaultValue',
   127      'Mock',
   128      ]
   129  
   130  # Regex for matching source file path and line number in the compiler's errors.
   131  _GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
   132  _CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
   133  _CLANG_NON_GMOCK_FILE_LINE_RE = (
   134      r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
   135  
   136  
   137  def _FindAllMatches(regex, s):
   138    """Generates all matches of regex in string s."""
   139  
   140    r = re.compile(regex)
   141    return r.finditer(s)
   142  
   143  
   144  def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
   145    """Diagnoses the given disease by pattern matching.
   146  
   147    Can provide different diagnoses for different patterns.
   148  
   149    Args:
   150      short_name: Short name of the disease.
   151      long_name:  Long name of the disease.
   152      diagnoses:  A list of pairs (regex, pattern for formatting the diagnosis
   153                  for matching regex).
   154      msg:        Compiler's error messages.
   155    Yields:
   156      Tuples of the form
   157        (short name of disease, long name of disease, diagnosis).
   158    """
   159    for regex, diagnosis in diagnoses:
   160      if re.search(regex, msg):
   161        diagnosis = '%(file)s:%(line)s:' + diagnosis
   162        for m in _FindAllMatches(regex, msg):
   163          yield (short_name, long_name, diagnosis % m.groupdict())
   164  
   165  
   166  def _NeedToReturnReferenceDiagnoser(msg):
   167    """Diagnoses the NRR disease, given the error messages by the compiler."""
   168  
   169    gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
   170                 + _GCC_FILE_LINE_RE + r'instantiated from here\n'
   171                 r'.*gmock-actions\.h.*error: creating array with negative size')
   172    clang_regex = (r'error:.*array.*negative.*\r?\n'
   173                   r'(.*\n)*?' +
   174                   _CLANG_NON_GMOCK_FILE_LINE_RE +
   175                   r'note: in instantiation of function template specialization '
   176                   r'\'testing::internal::ReturnAction<(?P<type>.*)>'
   177                   r'::operator Action<.*>\' requested here')
   178    diagnosis = """
   179  You are using a Return() action in a function that returns a reference to
   180  %(type)s.  Please use ReturnRef() instead."""
   181    return _GenericDiagnoser('NRR', 'Need to Return Reference',
   182                             [(clang_regex, diagnosis),
   183                              (gcc_regex, diagnosis % {'type': 'a type'})],
   184                             msg)
   185  
   186  
   187  def _NeedToReturnSomethingDiagnoser(msg):
   188    """Diagnoses the NRS disease, given the error messages by the compiler."""
   189  
   190    gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
   191                 r'*gmock.*actions\.h.*error: void value not ignored)'
   192                 r'|(error: control reaches end of non-void function)')
   193    clang_regex1 = (_CLANG_FILE_LINE_RE +
   194                    r'error: cannot initialize return object '
   195                    r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
   196                    r'with an rvalue of type \'void\'')
   197    clang_regex2 = (_CLANG_FILE_LINE_RE +
   198                    r'error: cannot initialize return object '
   199                    r'of type \'(?P<return_type>.*)\' '
   200                    r'with an rvalue of type \'void\'')
   201    diagnosis = """
   202  You are using an action that returns void, but it needs to return
   203  %(return_type)s.  Please tell it *what* to return.  Perhaps you can use
   204  the pattern DoAll(some_action, Return(some_value))?"""
   205    return _GenericDiagnoser(
   206        'NRS',
   207        'Need to Return Something',
   208        [(gcc_regex, diagnosis % {'return_type': '*something*'}),
   209         (clang_regex1, diagnosis),
   210         (clang_regex2, diagnosis)],
   211        msg)
   212  
   213  
   214  def _NeedToReturnNothingDiagnoser(msg):
   215    """Diagnoses the NRN disease, given the error messages by the compiler."""
   216  
   217    gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
   218                 r'.*gmock-actions\.h.*error: instantiation of '
   219                 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
   220                 r'as type \'void\'')
   221    clang_regex1 = (r'error: field has incomplete type '
   222                    r'\'Result\' \(aka \'void\'\)(\r)?\n'
   223                    r'(.*\n)*?' +
   224                    _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
   225                    r'of function template specialization '
   226                    r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
   227                    r'::operator Action<void \(.*\)>\' requested here')
   228    clang_regex2 = (r'error: field has incomplete type '
   229                    r'\'Result\' \(aka \'void\'\)(\r)?\n'
   230                    r'(.*\n)*?' +
   231                    _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
   232                    r'of function template specialization '
   233                    r'\'testing::internal::DoBothAction<.*>'
   234                    r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
   235                    r'requested here')
   236    diagnosis = """
   237  You are using an action that returns %(return_type)s, but it needs to return
   238  void.  Please use a void-returning action instead.
   239  
   240  All actions but the last in DoAll(...) must return void.  Perhaps you need
   241  to re-arrange the order of actions in a DoAll(), if you are using one?"""
   242    return _GenericDiagnoser(
   243        'NRN',
   244        'Need to Return Nothing',
   245        [(gcc_regex, diagnosis % {'return_type': '*something*'}),
   246         (clang_regex1, diagnosis),
   247         (clang_regex2, diagnosis)],
   248        msg)
   249  
   250  
   251  def _IncompleteByReferenceArgumentDiagnoser(msg):
   252    """Diagnoses the IBRA disease, given the error messages by the compiler."""
   253  
   254    gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
   255                 r'.*gtest-printers\.h.*error: invalid application of '
   256                 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
   257  
   258    clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
   259                   r'\'sizeof\' to an incomplete type '
   260                   r'\'(?P<type>.*)( const)?\'\r?\n'
   261                   r'(.*\n)*?' +
   262                   _CLANG_NON_GMOCK_FILE_LINE_RE +
   263                   r'note: in instantiation of member function '
   264                   r'\'testing::internal2::TypeWithoutFormatter<.*>::'
   265                   r'PrintValue\' requested here')
   266    diagnosis = """
   267  In order to mock this function, Google Mock needs to see the definition
   268  of type "%(type)s" - declaration alone is not enough.  Either #include
   269  the header that defines it, or change the argument to be passed
   270  by pointer."""
   271  
   272    return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
   273                             [(gcc_regex, diagnosis),
   274                              (clang_regex, diagnosis)],
   275                             msg)
   276  
   277  
   278  def _OverloadedFunctionMatcherDiagnoser(msg):
   279    """Diagnoses the OFM disease, given the error messages by the compiler."""
   280  
   281    gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
   282                 r'call to \'Truly\(<unresolved overloaded function type>\)')
   283    clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
   284                   r'call to \'Truly')
   285    diagnosis = """
   286  The argument you gave to Truly() is an overloaded function.  Please tell
   287  your compiler which overloaded version you want to use.
   288  
   289  For example, if you want to use the version whose signature is
   290    bool Foo(int n);
   291  you should write
   292    Truly(static_cast<bool (*)(int n)>(Foo))"""
   293    return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
   294                             [(gcc_regex, diagnosis),
   295                              (clang_regex, diagnosis)],
   296                             msg)
   297  
   298  
   299  def _OverloadedFunctionActionDiagnoser(msg):
   300    """Diagnoses the OFA disease, given the error messages by the compiler."""
   301  
   302    gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
   303                 r'\'Invoke\(<unresolved overloaded function type>')
   304    clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
   305                   r'function for call to \'Invoke\'\r?\n'
   306                   r'(.*\n)*?'
   307                   r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+'
   308                   r'note: candidate template ignored:\s+'
   309                   r'couldn\'t infer template argument \'FunctionImpl\'')
   310    diagnosis = """
   311  Function you are passing to Invoke is overloaded.  Please tell your compiler
   312  which overloaded version you want to use.
   313  
   314  For example, if you want to use the version whose signature is
   315    bool MyFunction(int n, double x);
   316  you should write something like
   317    Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
   318    return _GenericDiagnoser('OFA', 'Overloaded Function Action',
   319                             [(gcc_regex, diagnosis),
   320                              (clang_regex, diagnosis)],
   321                             msg)
   322  
   323  
   324  def _OverloadedMethodActionDiagnoser(msg):
   325    """Diagnoses the OMA disease, given the error messages by the compiler."""
   326  
   327    gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
   328                 r'call to \'Invoke\(.+, <unresolved overloaded function '
   329                 r'type>\)')
   330    clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
   331                   r'for call to \'Invoke\'\r?\n'
   332                   r'(.*\n)*?'
   333                   r'.*\bgmock-\w+-actions\.h:\d+:\d+: '
   334                   r'note: candidate function template not viable: '
   335                   r'requires .*, but 2 (arguments )?were provided')
   336    diagnosis = """
   337  The second argument you gave to Invoke() is an overloaded method.  Please
   338  tell your compiler which overloaded version you want to use.
   339  
   340  For example, if you want to use the version whose signature is
   341    class Foo {
   342      ...
   343      bool Bar(int n, double x);
   344    };
   345  you should write something like
   346    Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
   347    return _GenericDiagnoser('OMA', 'Overloaded Method Action',
   348                             [(gcc_regex, diagnosis),
   349                              (clang_regex, diagnosis)],
   350                             msg)
   351  
   352  
   353  def _MockObjectPointerDiagnoser(msg):
   354    """Diagnoses the MOP disease, given the error messages by the compiler."""
   355  
   356    gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
   357                 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
   358                 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
   359    clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
   360                   r'\'(?P<class_name>.*?) *\' is a pointer; '
   361                   r'maybe you meant to use \'->\'\?')
   362    diagnosis = """
   363  The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
   364  not a *pointer* to it.  Please write '*(%(mock_object)s)' instead of
   365  '%(mock_object)s' as your first argument.
   366  
   367  For example, given the mock class:
   368  
   369    class %(class_name)s : public ... {
   370      ...
   371      MOCK_METHOD0(%(method)s, ...);
   372    };
   373  
   374  and the following mock instance:
   375  
   376    %(class_name)s* mock_ptr = ...
   377  
   378  you should use the EXPECT_CALL like this:
   379  
   380    EXPECT_CALL(*mock_ptr, %(method)s(...));"""
   381  
   382    return _GenericDiagnoser(
   383        'MOP',
   384        'Mock Object Pointer',
   385        [(gcc_regex, diagnosis),
   386         (clang_regex, diagnosis % {'mock_object': 'mock_object',
   387                                    'method': 'method',
   388                                    'class_name': '%(class_name)s'})],
   389         msg)
   390  
   391  
   392  def _NeedToUseSymbolDiagnoser(msg):
   393    """Diagnoses the NUS disease, given the error messages by the compiler."""
   394  
   395    gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
   396                 r'(was not declared in this scope|has not been declared)')
   397    clang_regex = (_CLANG_FILE_LINE_RE +
   398                   r'error: (use of undeclared identifier|unknown type name|'
   399                   r'no template named) \'(?P<symbol>[^\']+)\'')
   400    diagnosis = """
   401  '%(symbol)s' is defined by Google Mock in the testing namespace.
   402  Did you forget to write
   403    using testing::%(symbol)s;
   404  ?"""
   405    for m in (list(_FindAllMatches(gcc_regex, msg)) +
   406              list(_FindAllMatches(clang_regex, msg))):
   407      symbol = m.groupdict()['symbol']
   408      if symbol in _COMMON_GMOCK_SYMBOLS:
   409        yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
   410  
   411  
   412  def _NeedToUseReturnNullDiagnoser(msg):
   413    """Diagnoses the NRNULL disease, given the error messages by the compiler."""
   414  
   415    gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
   416                 '::operator testing::Action<Func>\(\) const.*\n' +
   417                 _GCC_FILE_LINE_RE + r'instantiated from here\n'
   418                 r'.*error: no matching function for call to \'ImplicitCast_\('
   419                 r'(:?long )?int&\)')
   420    clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
   421                   r'call to \'ImplicitCast_\'\r?\n'
   422                   r'(.*\n)*?' +
   423                   _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
   424                   r'of function template specialization '
   425                   r'\'testing::internal::ReturnAction<(int|long)>::operator '
   426                   r'Action<(?P<type>.*)\(\)>\' requested here')
   427    diagnosis = """
   428  You are probably calling Return(NULL) and the compiler isn't sure how to turn
   429  NULL into %(type)s. Use ReturnNull() instead.
   430  Note: the line number may be off; please fix all instances of Return(NULL)."""
   431    return _GenericDiagnoser(
   432        'NRNULL', 'Need to use ReturnNull',
   433        [(clang_regex, diagnosis),
   434         (gcc_regex, diagnosis % {'type': 'the right type'})],
   435        msg)
   436  
   437  
   438  def _TypeInTemplatedBaseDiagnoser(msg):
   439    """Diagnoses the TTB disease, given the error messages by the compiler."""
   440  
   441    # This version works when the type is used as the mock function's return
   442    # type.
   443    gcc_4_3_1_regex_type_in_retval = (
   444        r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
   445        r'error: a function call cannot appear in a constant-expression')
   446    gcc_4_4_0_regex_type_in_retval = (
   447        r'error: a function call cannot appear in a constant-expression'
   448        + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
   449    # This version works when the type is used as the mock function's sole
   450    # parameter type.
   451    gcc_regex_type_of_sole_param = (
   452        _GCC_FILE_LINE_RE +
   453        r'error: \'(?P<type>.+)\' was not declared in this scope\n'
   454        r'.*error: template argument 1 is invalid\n')
   455    # This version works when the type is used as a parameter of a mock
   456    # function that has multiple parameters.
   457    gcc_regex_type_of_a_param = (
   458        r'error: expected `;\' before \'::\' token\n'
   459        + _GCC_FILE_LINE_RE +
   460        r'error: \'(?P<type>.+)\' was not declared in this scope\n'
   461        r'.*error: template argument 1 is invalid\n'
   462        r'.*error: \'.+\' was not declared in this scope')
   463    clang_regex_type_of_retval_or_sole_param = (
   464        _CLANG_FILE_LINE_RE +
   465        r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
   466        r'(.*\n)*?'
   467        r'(?P=file):(?P=line):\d+: error: '
   468        r'non-friend class member \'Result\' cannot have a qualified name'
   469        )
   470    clang_regex_type_of_a_param = (
   471        _CLANG_FILE_LINE_RE +
   472        r'error: C\+\+ requires a type specifier for all declarations\n'
   473        r'(.*\n)*?'
   474        r'(?P=file):(?P=line):(?P=column): error: '
   475        r'C\+\+ requires a type specifier for all declarations'
   476        )
   477    clang_regex_unknown_type = (
   478        _CLANG_FILE_LINE_RE +
   479        r'error: unknown type name \'(?P<type>[^\']+)\''
   480        )
   481  
   482    diagnosis = """
   483  In a mock class template, types or typedefs defined in the base class
   484  template are *not* automatically visible.  This is how C++ works.  Before
   485  you can use a type or typedef named %(type)s defined in base class Base<T>, you
   486  need to make it visible.  One way to do it is:
   487  
   488    typedef typename Base<T>::%(type)s %(type)s;"""
   489  
   490    for diag in _GenericDiagnoser(
   491        'TTB', 'Type in Template Base',
   492        [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
   493         (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
   494         (gcc_regex_type_of_sole_param, diagnosis),
   495         (gcc_regex_type_of_a_param, diagnosis),
   496         (clang_regex_type_of_retval_or_sole_param, diagnosis),
   497         (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})],
   498        msg):
   499      yield diag
   500    # Avoid overlap with the NUS pattern.
   501    for m in _FindAllMatches(clang_regex_unknown_type, msg):
   502      type_ = m.groupdict()['type']
   503      if type_ not in _COMMON_GMOCK_SYMBOLS:
   504        yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict())
   505  
   506  
   507  def _WrongMockMethodMacroDiagnoser(msg):
   508    """Diagnoses the WMM disease, given the error messages by the compiler."""
   509  
   510    gcc_regex = (_GCC_FILE_LINE_RE +
   511                 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
   512                 r'.*\n'
   513                 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
   514    clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
   515                   r'error:.*array.*negative.*r?\n'
   516                   r'(.*\n)*?'
   517                   r'(?P=file):(?P=line):(?P=column): error: too few arguments '
   518                   r'to function call, expected (?P<args>\d+), '
   519                   r'have (?P<wrong_args>\d+)')
   520    diagnosis = """
   521  You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
   522  %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
   523  MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
   524    return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
   525                             [(gcc_regex, diagnosis),
   526                              (clang_regex, diagnosis)],
   527                             msg)
   528  
   529  
   530  def _WrongParenPositionDiagnoser(msg):
   531    """Diagnoses the WPP disease, given the error messages by the compiler."""
   532  
   533    gcc_regex = (_GCC_FILE_LINE_RE +
   534                 r'error:.*testing::internal::MockSpec<.* has no member named \''
   535                 r'(?P<method>\w+)\'')
   536    clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
   537                   r'error: no member named \'(?P<method>\w+)\' in '
   538                   r'\'testing::internal::MockSpec<.*>\'')
   539    diagnosis = """
   540  The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
   541  ".%(method)s".  For example, you should write:
   542    EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
   543  instead of:
   544    EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
   545    return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
   546                             [(gcc_regex, diagnosis),
   547                              (clang_regex, diagnosis)],
   548                             msg)
   549  
   550  
   551  _DIAGNOSERS = [
   552      _IncompleteByReferenceArgumentDiagnoser,
   553      _MockObjectPointerDiagnoser,
   554      _NeedToReturnNothingDiagnoser,
   555      _NeedToReturnReferenceDiagnoser,
   556      _NeedToReturnSomethingDiagnoser,
   557      _NeedToUseReturnNullDiagnoser,
   558      _NeedToUseSymbolDiagnoser,
   559      _OverloadedFunctionActionDiagnoser,
   560      _OverloadedFunctionMatcherDiagnoser,
   561      _OverloadedMethodActionDiagnoser,
   562      _TypeInTemplatedBaseDiagnoser,
   563      _WrongMockMethodMacroDiagnoser,
   564      _WrongParenPositionDiagnoser,
   565      ]
   566  
   567  
   568  def Diagnose(msg):
   569    """Generates all possible diagnoses given the compiler error message."""
   570  
   571    msg = re.sub(r'\x1b\[[^m]*m', '', msg)  # Strips all color formatting.
   572    # Assuming the string is using the UTF-8 encoding, replaces the left and
   573    # the right single quote characters with apostrophes.
   574    msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg)
   575  
   576    diagnoses = []
   577    for diagnoser in _DIAGNOSERS:
   578      for diag in diagnoser(msg):
   579        diagnosis = '[%s - %s]\n%s' % diag
   580        if not diagnosis in diagnoses:
   581          diagnoses.append(diagnosis)
   582    return diagnoses
   583  
   584  
   585  def main():
   586    print ('Google Mock Doctor v%s - '
   587           'diagnoses problems in code using Google Mock.' % _VERSION)
   588  
   589    if sys.stdin.isatty():
   590      print ('Please copy and paste the compiler errors here.  Press c-D when '
   591             'you are done:')
   592    else:
   593      print 'Waiting for compiler errors on stdin . . .'
   594  
   595    msg = sys.stdin.read().strip()
   596    diagnoses = Diagnose(msg)
   597    count = len(diagnoses)
   598    if not count:
   599      print ("""
   600  Your compiler complained:
   601  8<------------------------------------------------------------
   602  %s
   603  ------------------------------------------------------------>8
   604  
   605  Uh-oh, I'm not smart enough to figure out what the problem is. :-(
   606  However...
   607  If you send your source code and the compiler's error messages to
   608  %s, you can be helped and I can get smarter --
   609  win-win for us!""" % (msg, _EMAIL))
   610    else:
   611      print '------------------------------------------------------------'
   612      print 'Your code appears to have the following',
   613      if count > 1:
   614        print '%s diseases:' % (count,)
   615      else:
   616        print 'disease:'
   617      i = 0
   618      for d in diagnoses:
   619        i += 1
   620        if count > 1:
   621          print '\n#%s:' % (i,)
   622        print d
   623      print ("""
   624  How did I do?  If you think I'm wrong or unhelpful, please send your
   625  source code and the compiler's error messages to %s.
   626  Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
   627             _EMAIL)
   628  
   629  
   630  if __name__ == '__main__':
   631    main()