Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:19:54

0001 #!/usr/bin/env python
0002 #
0003 # Copyright 2008, Google Inc.
0004 # All rights reserved.
0005 #
0006 # Redistribution and use in source and binary forms, with or without
0007 # modification, are permitted provided that the following conditions are
0008 # met:
0009 #
0010 #     * Redistributions of source code must retain the above copyright
0011 # notice, this list of conditions and the following disclaimer.
0012 #     * Redistributions in binary form must reproduce the above
0013 # copyright notice, this list of conditions and the following disclaimer
0014 # in the documentation and/or other materials provided with the
0015 # distribution.
0016 #     * Neither the name of Google Inc. nor the names of its
0017 # contributors may be used to endorse or promote products derived from
0018 # this software without specific prior written permission.
0019 #
0020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0023 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0024 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0025 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0026 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0027 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0028 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0029 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0030 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0031 
0032 """Converts compiler's errors in code using Google Mock to plain English."""
0033 
0034 __author__ = 'wan@google.com (Zhanyong Wan)'
0035 
0036 import re
0037 import sys
0038 
0039 _VERSION = '1.0.3'
0040 
0041 _EMAIL = 'googlemock@googlegroups.com'
0042 
0043 _COMMON_GMOCK_SYMBOLS = [
0044     # Matchers
0045     '_',
0046     'A',
0047     'AddressSatisfies',
0048     'AllOf',
0049     'An',
0050     'AnyOf',
0051     'ContainerEq',
0052     'Contains',
0053     'ContainsRegex',
0054     'DoubleEq',
0055     'ElementsAre',
0056     'ElementsAreArray',
0057     'EndsWith',
0058     'Eq',
0059     'Field',
0060     'FloatEq',
0061     'Ge',
0062     'Gt',
0063     'HasSubstr',
0064     'IsInitializedProto',
0065     'Le',
0066     'Lt',
0067     'MatcherCast',
0068     'Matches',
0069     'MatchesRegex',
0070     'NanSensitiveDoubleEq',
0071     'NanSensitiveFloatEq',
0072     'Ne',
0073     'Not',
0074     'NotNull',
0075     'Pointee',
0076     'Property',
0077     'Ref',
0078     'ResultOf',
0079     'SafeMatcherCast',
0080     'StartsWith',
0081     'StrCaseEq',
0082     'StrCaseNe',
0083     'StrEq',
0084     'StrNe',
0085     'Truly',
0086     'TypedEq',
0087     'Value',
0088 
0089     # Actions
0090     'Assign',
0091     'ByRef',
0092     'DeleteArg',
0093     'DoAll',
0094     'DoDefault',
0095     'IgnoreResult',
0096     'Invoke',
0097     'InvokeArgument',
0098     'InvokeWithoutArgs',
0099     'Return',
0100     'ReturnNew',
0101     'ReturnNull',
0102     'ReturnRef',
0103     'SaveArg',
0104     'SetArgReferee',
0105     'SetArgPointee',
0106     'SetArgumentPointee',
0107     'SetArrayArgument',
0108     'SetErrnoAndReturn',
0109     'Throw',
0110     'WithArg',
0111     'WithArgs',
0112     'WithoutArgs',
0113 
0114     # Cardinalities
0115     'AnyNumber',
0116     'AtLeast',
0117     'AtMost',
0118     'Between',
0119     'Exactly',
0120 
0121     # Sequences
0122     'InSequence',
0123     'Sequence',
0124 
0125     # Misc
0126     'DefaultValue',
0127     'Mock',
0128     ]
0129 
0130 # Regex for matching source file path and line number in the compiler's errors.
0131 _GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
0132 _CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
0133 _CLANG_NON_GMOCK_FILE_LINE_RE = (
0134     r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
0135 
0136 
0137 def _FindAllMatches(regex, s):
0138   """Generates all matches of regex in string s."""
0139 
0140   r = re.compile(regex)
0141   return r.finditer(s)
0142 
0143 
0144 def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
0145   """Diagnoses the given disease by pattern matching.
0146 
0147   Can provide different diagnoses for different patterns.
0148 
0149   Args:
0150     short_name: Short name of the disease.
0151     long_name:  Long name of the disease.
0152     diagnoses:  A list of pairs (regex, pattern for formatting the diagnosis
0153                 for matching regex).
0154     msg:        Compiler's error messages.
0155   Yields:
0156     Tuples of the form
0157       (short name of disease, long name of disease, diagnosis).
0158   """
0159   for regex, diagnosis in diagnoses:
0160     if re.search(regex, msg):
0161       diagnosis = '%(file)s:%(line)s:' + diagnosis
0162       for m in _FindAllMatches(regex, msg):
0163         yield (short_name, long_name, diagnosis % m.groupdict())
0164 
0165 
0166 def _NeedToReturnReferenceDiagnoser(msg):
0167   """Diagnoses the NRR disease, given the error messages by the compiler."""
0168 
0169   gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
0170                + _GCC_FILE_LINE_RE + r'instantiated from here\n'
0171                r'.*gmock-actions\.h.*error: creating array with negative size')
0172   clang_regex = (r'error:.*array.*negative.*\r?\n'
0173                  r'(.*\n)*?' +
0174                  _CLANG_NON_GMOCK_FILE_LINE_RE +
0175                  r'note: in instantiation of function template specialization '
0176                  r'\'testing::internal::ReturnAction<(?P<type>.*)>'
0177                  r'::operator Action<.*>\' requested here')
0178   clang11_re = (r'use_ReturnRef_instead_of_Return_to_return_a_reference.*'
0179                 r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE)
0180 
0181   diagnosis = """
0182 You are using a Return() action in a function that returns a reference to
0183 %(type)s.  Please use ReturnRef() instead."""
0184   return _GenericDiagnoser('NRR', 'Need to Return Reference',
0185                            [(clang_regex, diagnosis),
0186                             (clang11_re, diagnosis % {'type': 'a type'}),
0187                             (gcc_regex, diagnosis % {'type': 'a type'})],
0188                            msg)
0189 
0190 
0191 def _NeedToReturnSomethingDiagnoser(msg):
0192   """Diagnoses the NRS disease, given the error messages by the compiler."""
0193 
0194   gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
0195                r'*gmock.*actions\.h.*error: void value not ignored)'
0196                r'|(error: control reaches end of non-void function)')
0197   clang_regex1 = (_CLANG_FILE_LINE_RE +
0198                   r'error: cannot initialize return object '
0199                   r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
0200                   r'with an rvalue of type \'void\'')
0201   clang_regex2 = (_CLANG_FILE_LINE_RE +
0202                   r'error: cannot initialize return object '
0203                   r'of type \'(?P<return_type>.*)\' '
0204                   r'with an rvalue of type \'void\'')
0205   diagnosis = """
0206 You are using an action that returns void, but it needs to return
0207 %(return_type)s.  Please tell it *what* to return.  Perhaps you can use
0208 the pattern DoAll(some_action, Return(some_value))?"""
0209   return _GenericDiagnoser(
0210       'NRS',
0211       'Need to Return Something',
0212       [(gcc_regex, diagnosis % {'return_type': '*something*'}),
0213        (clang_regex1, diagnosis),
0214        (clang_regex2, diagnosis)],
0215       msg)
0216 
0217 
0218 def _NeedToReturnNothingDiagnoser(msg):
0219   """Diagnoses the NRN disease, given the error messages by the compiler."""
0220 
0221   gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
0222                r'.*gmock-actions\.h.*error: instantiation of '
0223                r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
0224                r'as type \'void\'')
0225   clang_regex1 = (r'error: field has incomplete type '
0226                   r'\'Result\' \(aka \'void\'\)(\r)?\n'
0227                   r'(.*\n)*?' +
0228                   _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
0229                   r'of function template specialization '
0230                   r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
0231                   r'::operator Action<void \(.*\)>\' requested here')
0232   clang_regex2 = (r'error: field has incomplete type '
0233                   r'\'Result\' \(aka \'void\'\)(\r)?\n'
0234                   r'(.*\n)*?' +
0235                   _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
0236                   r'of function template specialization '
0237                   r'\'testing::internal::DoBothAction<.*>'
0238                   r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
0239                   r'requested here')
0240   diagnosis = """
0241 You are using an action that returns %(return_type)s, but it needs to return
0242 void.  Please use a void-returning action instead.
0243 
0244 All actions but the last in DoAll(...) must return void.  Perhaps you need
0245 to re-arrange the order of actions in a DoAll(), if you are using one?"""
0246   return _GenericDiagnoser(
0247       'NRN',
0248       'Need to Return Nothing',
0249       [(gcc_regex, diagnosis % {'return_type': '*something*'}),
0250        (clang_regex1, diagnosis),
0251        (clang_regex2, diagnosis)],
0252       msg)
0253 
0254 
0255 def _IncompleteByReferenceArgumentDiagnoser(msg):
0256   """Diagnoses the IBRA disease, given the error messages by the compiler."""
0257 
0258   gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
0259                r'.*gtest-printers\.h.*error: invalid application of '
0260                r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
0261 
0262   clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
0263                  r'\'sizeof\' to an incomplete type '
0264                  r'\'(?P<type>.*)( const)?\'\r?\n'
0265                  r'(.*\n)*?' +
0266                  _CLANG_NON_GMOCK_FILE_LINE_RE +
0267                  r'note: in instantiation of member function '
0268                  r'\'testing::internal2::TypeWithoutFormatter<.*>::'
0269                  r'PrintValue\' requested here')
0270   diagnosis = """
0271 In order to mock this function, Google Mock needs to see the definition
0272 of type "%(type)s" - declaration alone is not enough.  Either #include
0273 the header that defines it, or change the argument to be passed
0274 by pointer."""
0275 
0276   return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
0277                            [(gcc_regex, diagnosis),
0278                             (clang_regex, diagnosis)],
0279                            msg)
0280 
0281 
0282 def _OverloadedFunctionMatcherDiagnoser(msg):
0283   """Diagnoses the OFM disease, given the error messages by the compiler."""
0284 
0285   gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
0286                r'call to \'Truly\(<unresolved overloaded function type>\)')
0287   clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
0288                  r'call to \'Truly')
0289   diagnosis = """
0290 The argument you gave to Truly() is an overloaded function.  Please tell
0291 your compiler which overloaded version you want to use.
0292 
0293 For example, if you want to use the version whose signature is
0294   bool Foo(int n);
0295 you should write
0296   Truly(static_cast<bool (*)(int n)>(Foo))"""
0297   return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
0298                            [(gcc_regex, diagnosis),
0299                             (clang_regex, diagnosis)],
0300                            msg)
0301 
0302 
0303 def _OverloadedFunctionActionDiagnoser(msg):
0304   """Diagnoses the OFA disease, given the error messages by the compiler."""
0305 
0306   gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
0307                r'\'Invoke\(<unresolved overloaded function type>')
0308   clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
0309                  r'function for call to \'Invoke\'\r?\n'
0310                  r'(.*\n)*?'
0311                  r'.*\bgmock-generated-actions\.h:\d+:\d+:\s+'
0312                  r'note: candidate template ignored:\s+'
0313                  r'couldn\'t infer template argument \'FunctionImpl\'')
0314   diagnosis = """
0315 Function you are passing to Invoke is overloaded.  Please tell your compiler
0316 which overloaded version you want to use.
0317 
0318 For example, if you want to use the version whose signature is
0319   bool MyFunction(int n, double x);
0320 you should write something like
0321   Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
0322   return _GenericDiagnoser('OFA', 'Overloaded Function Action',
0323                            [(gcc_regex, diagnosis),
0324                             (clang_regex, diagnosis)],
0325                            msg)
0326 
0327 
0328 def _OverloadedMethodActionDiagnoser(msg):
0329   """Diagnoses the OMA disease, given the error messages by the compiler."""
0330 
0331   gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
0332                r'call to \'Invoke\(.+, <unresolved overloaded function '
0333                r'type>\)')
0334   clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
0335                  r'for call to \'Invoke\'\r?\n'
0336                  r'(.*\n)*?'
0337                  r'.*\bgmock-generated-actions\.h:\d+:\d+: '
0338                  r'note: candidate function template not viable: '
0339                  r'requires .*, but 2 (arguments )?were provided')
0340   diagnosis = """
0341 The second argument you gave to Invoke() is an overloaded method.  Please
0342 tell your compiler which overloaded version you want to use.
0343 
0344 For example, if you want to use the version whose signature is
0345   class Foo {
0346     ...
0347     bool Bar(int n, double x);
0348   };
0349 you should write something like
0350   Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
0351   return _GenericDiagnoser('OMA', 'Overloaded Method Action',
0352                            [(gcc_regex, diagnosis),
0353                             (clang_regex, diagnosis)],
0354                            msg)
0355 
0356 
0357 def _MockObjectPointerDiagnoser(msg):
0358   """Diagnoses the MOP disease, given the error messages by the compiler."""
0359 
0360   gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
0361                r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
0362                r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
0363   clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
0364                  r'\'(?P<class_name>.*?) *\' is a pointer; '
0365                  r'(did you mean|maybe you meant) to use \'->\'\?')
0366   diagnosis = """
0367 The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
0368 not a *pointer* to it.  Please write '*(%(mock_object)s)' instead of
0369 '%(mock_object)s' as your first argument.
0370 
0371 For example, given the mock class:
0372 
0373   class %(class_name)s : public ... {
0374     ...
0375     MOCK_METHOD0(%(method)s, ...);
0376   };
0377 
0378 and the following mock instance:
0379 
0380   %(class_name)s* mock_ptr = ...
0381 
0382 you should use the EXPECT_CALL like this:
0383 
0384   EXPECT_CALL(*mock_ptr, %(method)s(...));"""
0385 
0386   return _GenericDiagnoser(
0387       'MOP',
0388       'Mock Object Pointer',
0389       [(gcc_regex, diagnosis),
0390        (clang_regex, diagnosis % {'mock_object': 'mock_object',
0391                                   'method': 'method',
0392                                   'class_name': '%(class_name)s'})],
0393        msg)
0394 
0395 
0396 def _NeedToUseSymbolDiagnoser(msg):
0397   """Diagnoses the NUS disease, given the error messages by the compiler."""
0398 
0399   gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
0400                r'(was not declared in this scope|has not been declared)')
0401   clang_regex = (_CLANG_FILE_LINE_RE +
0402                  r'error: (use of undeclared identifier|unknown type name|'
0403                  r'no template named) \'(?P<symbol>[^\']+)\'')
0404   diagnosis = """
0405 '%(symbol)s' is defined by Google Mock in the testing namespace.
0406 Did you forget to write
0407   using testing::%(symbol)s;
0408 ?"""
0409   for m in (list(_FindAllMatches(gcc_regex, msg)) +
0410             list(_FindAllMatches(clang_regex, msg))):
0411     symbol = m.groupdict()['symbol']
0412     if symbol in _COMMON_GMOCK_SYMBOLS:
0413       yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
0414 
0415 
0416 def _NeedToUseReturnNullDiagnoser(msg):
0417   """Diagnoses the NRNULL disease, given the error messages by the compiler."""
0418 
0419   gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
0420                '::operator testing::Action<Func>\(\) const.*\n' +
0421                _GCC_FILE_LINE_RE + r'instantiated from here\n'
0422                r'.*error: no matching function for call to \'ImplicitCast_\('
0423                r'(:?long )?int&\)')
0424   clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
0425                  r'call to \'ImplicitCast_\'\r?\n'
0426                  r'(.*\n)*?' +
0427                  _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
0428                  r'of function template specialization '
0429                  r'\'testing::internal::ReturnAction<(int|long)>::operator '
0430                  r'Action<(?P<type>.*)\(\)>\' requested here')
0431   diagnosis = """
0432 You are probably calling Return(NULL) and the compiler isn't sure how to turn
0433 NULL into %(type)s. Use ReturnNull() instead.
0434 Note: the line number may be off; please fix all instances of Return(NULL)."""
0435   return _GenericDiagnoser(
0436       'NRNULL', 'Need to use ReturnNull',
0437       [(clang_regex, diagnosis),
0438        (gcc_regex, diagnosis % {'type': 'the right type'})],
0439       msg)
0440 
0441 
0442 def _TypeInTemplatedBaseDiagnoser(msg):
0443   """Diagnoses the TTB disease, given the error messages by the compiler."""
0444 
0445   # This version works when the type is used as the mock function's return
0446   # type.
0447   gcc_4_3_1_regex_type_in_retval = (
0448       r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
0449       r'error: a function call cannot appear in a constant-expression')
0450   gcc_4_4_0_regex_type_in_retval = (
0451       r'error: a function call cannot appear in a constant-expression'
0452       + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
0453   # This version works when the type is used as the mock function's sole
0454   # parameter type.
0455   gcc_regex_type_of_sole_param = (
0456       _GCC_FILE_LINE_RE +
0457       r'error: \'(?P<type>.+)\' was not declared in this scope\n'
0458       r'.*error: template argument 1 is invalid\n')
0459   # This version works when the type is used as a parameter of a mock
0460   # function that has multiple parameters.
0461   gcc_regex_type_of_a_param = (
0462       r'error: expected `;\' before \'::\' token\n'
0463       + _GCC_FILE_LINE_RE +
0464       r'error: \'(?P<type>.+)\' was not declared in this scope\n'
0465       r'.*error: template argument 1 is invalid\n'
0466       r'.*error: \'.+\' was not declared in this scope')
0467   clang_regex_type_of_retval_or_sole_param = (
0468       _CLANG_FILE_LINE_RE +
0469       r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
0470       r'(.*\n)*?'
0471       r'(?P=file):(?P=line):\d+: error: '
0472       r'non-friend class member \'Result\' cannot have a qualified name'
0473       )
0474   clang_regex_type_of_a_param = (
0475       _CLANG_FILE_LINE_RE +
0476       r'error: C\+\+ requires a type specifier for all declarations\n'
0477       r'(.*\n)*?'
0478       r'(?P=file):(?P=line):(?P=column): error: '
0479       r'C\+\+ requires a type specifier for all declarations'
0480       )
0481   clang_regex_unknown_type = (
0482       _CLANG_FILE_LINE_RE +
0483       r'error: unknown type name \'(?P<type>[^\']+)\''
0484       )
0485 
0486   diagnosis = """
0487 In a mock class template, types or typedefs defined in the base class
0488 template are *not* automatically visible.  This is how C++ works.  Before
0489 you can use a type or typedef named %(type)s defined in base class Base<T>, you
0490 need to make it visible.  One way to do it is:
0491 
0492   typedef typename Base<T>::%(type)s %(type)s;"""
0493 
0494   for diag in _GenericDiagnoser(
0495       'TTB', 'Type in Template Base',
0496       [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
0497        (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
0498        (gcc_regex_type_of_sole_param, diagnosis),
0499        (gcc_regex_type_of_a_param, diagnosis),
0500        (clang_regex_type_of_retval_or_sole_param, diagnosis),
0501        (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})],
0502       msg):
0503     yield diag
0504   # Avoid overlap with the NUS pattern.
0505   for m in _FindAllMatches(clang_regex_unknown_type, msg):
0506     type_ = m.groupdict()['type']
0507     if type_ not in _COMMON_GMOCK_SYMBOLS:
0508       yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict())
0509 
0510 
0511 def _WrongMockMethodMacroDiagnoser(msg):
0512   """Diagnoses the WMM disease, given the error messages by the compiler."""
0513 
0514   gcc_regex = (_GCC_FILE_LINE_RE +
0515                r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
0516                r'.*\n'
0517                r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
0518   clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
0519                  r'error:.*array.*negative.*r?\n'
0520                  r'(.*\n)*?'
0521                  r'(?P=file):(?P=line):(?P=column): error: too few arguments '
0522                  r'to function call, expected (?P<args>\d+), '
0523                  r'have (?P<wrong_args>\d+)')
0524   clang11_re = (_CLANG_NON_GMOCK_FILE_LINE_RE +
0525                 r'.*this_method_does_not_take_'
0526                 r'(?P<wrong_args>\d+)_argument.*')
0527   diagnosis = """
0528 You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
0529 %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
0530 MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
0531   return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
0532                            [(gcc_regex, diagnosis),
0533                             (clang11_re, diagnosis % {'wrong_args': 'm',
0534                                                       'args': 'n'}),
0535                             (clang_regex, diagnosis)],
0536                            msg)
0537 
0538 
0539 def _WrongParenPositionDiagnoser(msg):
0540   """Diagnoses the WPP disease, given the error messages by the compiler."""
0541 
0542   gcc_regex = (_GCC_FILE_LINE_RE +
0543                r'error:.*testing::internal::MockSpec<.* has no member named \''
0544                r'(?P<method>\w+)\'')
0545   clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
0546                  r'error: no member named \'(?P<method>\w+)\' in '
0547                  r'\'testing::internal::MockSpec<.*>\'')
0548   diagnosis = """
0549 The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
0550 ".%(method)s".  For example, you should write:
0551   EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
0552 instead of:
0553   EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
0554   return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
0555                            [(gcc_regex, diagnosis),
0556                             (clang_regex, diagnosis)],
0557                            msg)
0558 
0559 
0560 _DIAGNOSERS = [
0561     _IncompleteByReferenceArgumentDiagnoser,
0562     _MockObjectPointerDiagnoser,
0563     _NeedToReturnNothingDiagnoser,
0564     _NeedToReturnReferenceDiagnoser,
0565     _NeedToReturnSomethingDiagnoser,
0566     _NeedToUseReturnNullDiagnoser,
0567     _NeedToUseSymbolDiagnoser,
0568     _OverloadedFunctionActionDiagnoser,
0569     _OverloadedFunctionMatcherDiagnoser,
0570     _OverloadedMethodActionDiagnoser,
0571     _TypeInTemplatedBaseDiagnoser,
0572     _WrongMockMethodMacroDiagnoser,
0573     _WrongParenPositionDiagnoser,
0574     ]
0575 
0576 
0577 def Diagnose(msg):
0578   """Generates all possible diagnoses given the compiler error message."""
0579 
0580   msg = re.sub(r'\x1b\[[^m]*m', '', msg)  # Strips all color formatting.
0581   # Assuming the string is using the UTF-8 encoding, replaces the left and
0582   # the right single quote characters with apostrophes.
0583   msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg)
0584 
0585   diagnoses = []
0586   for diagnoser in _DIAGNOSERS:
0587     for diag in diagnoser(msg):
0588       diagnosis = '[%s - %s]\n%s' % diag
0589       if not diagnosis in diagnoses:
0590         diagnoses.append(diagnosis)
0591   return diagnoses
0592 
0593 
0594 def main():
0595   print ('Google Mock Doctor v%s - '
0596          'diagnoses problems in code using Google Mock.' % _VERSION)
0597 
0598   if sys.stdin.isatty():
0599     print ('Please copy and paste the compiler errors here.  Press c-D when '
0600            'you are done:')
0601   else:
0602     print ('Waiting for compiler errors on stdin . . .')
0603 
0604   msg = sys.stdin.read().strip()
0605   diagnoses = Diagnose(msg)
0606   count = len(diagnoses)
0607   if not count:
0608     print ("""
0609 Your compiler complained:
0610 8<------------------------------------------------------------
0611 %s
0612 ------------------------------------------------------------>8
0613 
0614 Uh-oh, I'm not smart enough to figure out what the problem is. :-(
0615 However...
0616 If you send your source code and the compiler's error messages to
0617 %s, you can be helped and I can get smarter --
0618 win-win for us!""" % (msg, _EMAIL))
0619   else:
0620     print ('------------------------------------------------------------')
0621     print ('Your code appears to have the following',)
0622     if count > 1:
0623       print ('%s diseases:' % (count,))
0624     else:
0625       print ('disease:')
0626     i = 0
0627     for d in diagnoses:
0628       i += 1
0629       if count > 1:
0630         print ('\n#%s:' % (i,))
0631       print (d)
0632     print ("""
0633 How did I do?  If you think I'm wrong or unhelpful, please send your
0634 source code and the compiler's error messages to %s.
0635 Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
0636            _EMAIL)
0637 
0638 
0639 if __name__ == '__main__':
0640   main()