113481Sgiacomo.travaglini@arm.com#!/usr/bin/env python
213481Sgiacomo.travaglini@arm.com#
313481Sgiacomo.travaglini@arm.com# Copyright 2008, Google Inc.
413481Sgiacomo.travaglini@arm.com# All rights reserved.
513481Sgiacomo.travaglini@arm.com#
613481Sgiacomo.travaglini@arm.com# Redistribution and use in source and binary forms, with or without
713481Sgiacomo.travaglini@arm.com# modification, are permitted provided that the following conditions are
813481Sgiacomo.travaglini@arm.com# met:
913481Sgiacomo.travaglini@arm.com#
1013481Sgiacomo.travaglini@arm.com#     * Redistributions of source code must retain the above copyright
1113481Sgiacomo.travaglini@arm.com# notice, this list of conditions and the following disclaimer.
1213481Sgiacomo.travaglini@arm.com#     * Redistributions in binary form must reproduce the above
1313481Sgiacomo.travaglini@arm.com# copyright notice, this list of conditions and the following disclaimer
1413481Sgiacomo.travaglini@arm.com# in the documentation and/or other materials provided with the
1513481Sgiacomo.travaglini@arm.com# distribution.
1613481Sgiacomo.travaglini@arm.com#     * Neither the name of Google Inc. nor the names of its
1713481Sgiacomo.travaglini@arm.com# contributors may be used to endorse or promote products derived from
1813481Sgiacomo.travaglini@arm.com# this software without specific prior written permission.
1913481Sgiacomo.travaglini@arm.com#
2013481Sgiacomo.travaglini@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2113481Sgiacomo.travaglini@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2213481Sgiacomo.travaglini@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2313481Sgiacomo.travaglini@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2413481Sgiacomo.travaglini@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2513481Sgiacomo.travaglini@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2613481Sgiacomo.travaglini@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2713481Sgiacomo.travaglini@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2813481Sgiacomo.travaglini@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2913481Sgiacomo.travaglini@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3013481Sgiacomo.travaglini@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3113481Sgiacomo.travaglini@arm.com
3213481Sgiacomo.travaglini@arm.com"""Converts compiler's errors in code using Google Mock to plain English."""
3313481Sgiacomo.travaglini@arm.com
3413481Sgiacomo.travaglini@arm.com__author__ = 'wan@google.com (Zhanyong Wan)'
3513481Sgiacomo.travaglini@arm.com
3613481Sgiacomo.travaglini@arm.comimport re
3713481Sgiacomo.travaglini@arm.comimport sys
3813481Sgiacomo.travaglini@arm.com
3913481Sgiacomo.travaglini@arm.com_VERSION = '1.0.3'
4013481Sgiacomo.travaglini@arm.com
4113481Sgiacomo.travaglini@arm.com_EMAIL = 'googlemock@googlegroups.com'
4213481Sgiacomo.travaglini@arm.com
4313481Sgiacomo.travaglini@arm.com_COMMON_GMOCK_SYMBOLS = [
4413481Sgiacomo.travaglini@arm.com    # Matchers
4513481Sgiacomo.travaglini@arm.com    '_',
4613481Sgiacomo.travaglini@arm.com    'A',
4713481Sgiacomo.travaglini@arm.com    'AddressSatisfies',
4813481Sgiacomo.travaglini@arm.com    'AllOf',
4913481Sgiacomo.travaglini@arm.com    'An',
5013481Sgiacomo.travaglini@arm.com    'AnyOf',
5113481Sgiacomo.travaglini@arm.com    'ContainerEq',
5213481Sgiacomo.travaglini@arm.com    'Contains',
5313481Sgiacomo.travaglini@arm.com    'ContainsRegex',
5413481Sgiacomo.travaglini@arm.com    'DoubleEq',
5513481Sgiacomo.travaglini@arm.com    'ElementsAre',
5613481Sgiacomo.travaglini@arm.com    'ElementsAreArray',
5713481Sgiacomo.travaglini@arm.com    'EndsWith',
5813481Sgiacomo.travaglini@arm.com    'Eq',
5913481Sgiacomo.travaglini@arm.com    'Field',
6013481Sgiacomo.travaglini@arm.com    'FloatEq',
6113481Sgiacomo.travaglini@arm.com    'Ge',
6213481Sgiacomo.travaglini@arm.com    'Gt',
6313481Sgiacomo.travaglini@arm.com    'HasSubstr',
6413481Sgiacomo.travaglini@arm.com    'IsInitializedProto',
6513481Sgiacomo.travaglini@arm.com    'Le',
6613481Sgiacomo.travaglini@arm.com    'Lt',
6713481Sgiacomo.travaglini@arm.com    'MatcherCast',
6813481Sgiacomo.travaglini@arm.com    'Matches',
6913481Sgiacomo.travaglini@arm.com    'MatchesRegex',
7013481Sgiacomo.travaglini@arm.com    'NanSensitiveDoubleEq',
7113481Sgiacomo.travaglini@arm.com    'NanSensitiveFloatEq',
7213481Sgiacomo.travaglini@arm.com    'Ne',
7313481Sgiacomo.travaglini@arm.com    'Not',
7413481Sgiacomo.travaglini@arm.com    'NotNull',
7513481Sgiacomo.travaglini@arm.com    'Pointee',
7613481Sgiacomo.travaglini@arm.com    'Property',
7713481Sgiacomo.travaglini@arm.com    'Ref',
7813481Sgiacomo.travaglini@arm.com    'ResultOf',
7913481Sgiacomo.travaglini@arm.com    'SafeMatcherCast',
8013481Sgiacomo.travaglini@arm.com    'StartsWith',
8113481Sgiacomo.travaglini@arm.com    'StrCaseEq',
8213481Sgiacomo.travaglini@arm.com    'StrCaseNe',
8313481Sgiacomo.travaglini@arm.com    'StrEq',
8413481Sgiacomo.travaglini@arm.com    'StrNe',
8513481Sgiacomo.travaglini@arm.com    'Truly',
8613481Sgiacomo.travaglini@arm.com    'TypedEq',
8713481Sgiacomo.travaglini@arm.com    'Value',
8813481Sgiacomo.travaglini@arm.com
8913481Sgiacomo.travaglini@arm.com    # Actions
9013481Sgiacomo.travaglini@arm.com    'Assign',
9113481Sgiacomo.travaglini@arm.com    'ByRef',
9213481Sgiacomo.travaglini@arm.com    'DeleteArg',
9313481Sgiacomo.travaglini@arm.com    'DoAll',
9413481Sgiacomo.travaglini@arm.com    'DoDefault',
9513481Sgiacomo.travaglini@arm.com    'IgnoreResult',
9613481Sgiacomo.travaglini@arm.com    'Invoke',
9713481Sgiacomo.travaglini@arm.com    'InvokeArgument',
9813481Sgiacomo.travaglini@arm.com    'InvokeWithoutArgs',
9913481Sgiacomo.travaglini@arm.com    'Return',
10013481Sgiacomo.travaglini@arm.com    'ReturnNew',
10113481Sgiacomo.travaglini@arm.com    'ReturnNull',
10213481Sgiacomo.travaglini@arm.com    'ReturnRef',
10313481Sgiacomo.travaglini@arm.com    'SaveArg',
10413481Sgiacomo.travaglini@arm.com    'SetArgReferee',
10513481Sgiacomo.travaglini@arm.com    'SetArgPointee',
10613481Sgiacomo.travaglini@arm.com    'SetArgumentPointee',
10713481Sgiacomo.travaglini@arm.com    'SetArrayArgument',
10813481Sgiacomo.travaglini@arm.com    'SetErrnoAndReturn',
10913481Sgiacomo.travaglini@arm.com    'Throw',
11013481Sgiacomo.travaglini@arm.com    'WithArg',
11113481Sgiacomo.travaglini@arm.com    'WithArgs',
11213481Sgiacomo.travaglini@arm.com    'WithoutArgs',
11313481Sgiacomo.travaglini@arm.com
11413481Sgiacomo.travaglini@arm.com    # Cardinalities
11513481Sgiacomo.travaglini@arm.com    'AnyNumber',
11613481Sgiacomo.travaglini@arm.com    'AtLeast',
11713481Sgiacomo.travaglini@arm.com    'AtMost',
11813481Sgiacomo.travaglini@arm.com    'Between',
11913481Sgiacomo.travaglini@arm.com    'Exactly',
12013481Sgiacomo.travaglini@arm.com
12113481Sgiacomo.travaglini@arm.com    # Sequences
12213481Sgiacomo.travaglini@arm.com    'InSequence',
12313481Sgiacomo.travaglini@arm.com    'Sequence',
12413481Sgiacomo.travaglini@arm.com
12513481Sgiacomo.travaglini@arm.com    # Misc
12613481Sgiacomo.travaglini@arm.com    'DefaultValue',
12713481Sgiacomo.travaglini@arm.com    'Mock',
12813481Sgiacomo.travaglini@arm.com    ]
12913481Sgiacomo.travaglini@arm.com
13013481Sgiacomo.travaglini@arm.com# Regex for matching source file path and line number in the compiler's errors.
13113481Sgiacomo.travaglini@arm.com_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
13213481Sgiacomo.travaglini@arm.com_CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
13313481Sgiacomo.travaglini@arm.com_CLANG_NON_GMOCK_FILE_LINE_RE = (
13413481Sgiacomo.travaglini@arm.com    r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
13513481Sgiacomo.travaglini@arm.com
13613481Sgiacomo.travaglini@arm.com
13713481Sgiacomo.travaglini@arm.comdef _FindAllMatches(regex, s):
13813481Sgiacomo.travaglini@arm.com  """Generates all matches of regex in string s."""
13913481Sgiacomo.travaglini@arm.com
14013481Sgiacomo.travaglini@arm.com  r = re.compile(regex)
14113481Sgiacomo.travaglini@arm.com  return r.finditer(s)
14213481Sgiacomo.travaglini@arm.com
14313481Sgiacomo.travaglini@arm.com
14413481Sgiacomo.travaglini@arm.comdef _GenericDiagnoser(short_name, long_name, diagnoses, msg):
14513481Sgiacomo.travaglini@arm.com  """Diagnoses the given disease by pattern matching.
14613481Sgiacomo.travaglini@arm.com
14713481Sgiacomo.travaglini@arm.com  Can provide different diagnoses for different patterns.
14813481Sgiacomo.travaglini@arm.com
14913481Sgiacomo.travaglini@arm.com  Args:
15013481Sgiacomo.travaglini@arm.com    short_name: Short name of the disease.
15113481Sgiacomo.travaglini@arm.com    long_name:  Long name of the disease.
15213481Sgiacomo.travaglini@arm.com    diagnoses:  A list of pairs (regex, pattern for formatting the diagnosis
15313481Sgiacomo.travaglini@arm.com                for matching regex).
15413481Sgiacomo.travaglini@arm.com    msg:        Compiler's error messages.
15513481Sgiacomo.travaglini@arm.com  Yields:
15613481Sgiacomo.travaglini@arm.com    Tuples of the form
15713481Sgiacomo.travaglini@arm.com      (short name of disease, long name of disease, diagnosis).
15813481Sgiacomo.travaglini@arm.com  """
15913481Sgiacomo.travaglini@arm.com  for regex, diagnosis in diagnoses:
16013481Sgiacomo.travaglini@arm.com    if re.search(regex, msg):
16113481Sgiacomo.travaglini@arm.com      diagnosis = '%(file)s:%(line)s:' + diagnosis
16213481Sgiacomo.travaglini@arm.com      for m in _FindAllMatches(regex, msg):
16313481Sgiacomo.travaglini@arm.com        yield (short_name, long_name, diagnosis % m.groupdict())
16413481Sgiacomo.travaglini@arm.com
16513481Sgiacomo.travaglini@arm.com
16613481Sgiacomo.travaglini@arm.comdef _NeedToReturnReferenceDiagnoser(msg):
16713481Sgiacomo.travaglini@arm.com  """Diagnoses the NRR disease, given the error messages by the compiler."""
16813481Sgiacomo.travaglini@arm.com
16913481Sgiacomo.travaglini@arm.com  gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
17013481Sgiacomo.travaglini@arm.com               + _GCC_FILE_LINE_RE + r'instantiated from here\n'
17113481Sgiacomo.travaglini@arm.com               r'.*gmock-actions\.h.*error: creating array with negative size')
17213481Sgiacomo.travaglini@arm.com  clang_regex = (r'error:.*array.*negative.*\r?\n'
17313481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?' +
17413481Sgiacomo.travaglini@arm.com                 _CLANG_NON_GMOCK_FILE_LINE_RE +
17513481Sgiacomo.travaglini@arm.com                 r'note: in instantiation of function template specialization '
17613481Sgiacomo.travaglini@arm.com                 r'\'testing::internal::ReturnAction<(?P<type>.*)>'
17713481Sgiacomo.travaglini@arm.com                 r'::operator Action<.*>\' requested here')
17813481Sgiacomo.travaglini@arm.com  clang11_re = (r'use_ReturnRef_instead_of_Return_to_return_a_reference.*'
17913481Sgiacomo.travaglini@arm.com                r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE)
18013481Sgiacomo.travaglini@arm.com
18113481Sgiacomo.travaglini@arm.com  diagnosis = """
18213481Sgiacomo.travaglini@arm.comYou are using a Return() action in a function that returns a reference to
18313481Sgiacomo.travaglini@arm.com%(type)s.  Please use ReturnRef() instead."""
18413481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('NRR', 'Need to Return Reference',
18513481Sgiacomo.travaglini@arm.com                           [(clang_regex, diagnosis),
18613481Sgiacomo.travaglini@arm.com                            (clang11_re, diagnosis % {'type': 'a type'}),
18713481Sgiacomo.travaglini@arm.com                            (gcc_regex, diagnosis % {'type': 'a type'})],
18813481Sgiacomo.travaglini@arm.com                           msg)
18913481Sgiacomo.travaglini@arm.com
19013481Sgiacomo.travaglini@arm.com
19113481Sgiacomo.travaglini@arm.comdef _NeedToReturnSomethingDiagnoser(msg):
19213481Sgiacomo.travaglini@arm.com  """Diagnoses the NRS disease, given the error messages by the compiler."""
19313481Sgiacomo.travaglini@arm.com
19413481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
19513481Sgiacomo.travaglini@arm.com               r'*gmock.*actions\.h.*error: void value not ignored)'
19613481Sgiacomo.travaglini@arm.com               r'|(error: control reaches end of non-void function)')
19713481Sgiacomo.travaglini@arm.com  clang_regex1 = (_CLANG_FILE_LINE_RE +
19813481Sgiacomo.travaglini@arm.com                  r'error: cannot initialize return object '
19913481Sgiacomo.travaglini@arm.com                  r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
20013481Sgiacomo.travaglini@arm.com                  r'with an rvalue of type \'void\'')
20113481Sgiacomo.travaglini@arm.com  clang_regex2 = (_CLANG_FILE_LINE_RE +
20213481Sgiacomo.travaglini@arm.com                  r'error: cannot initialize return object '
20313481Sgiacomo.travaglini@arm.com                  r'of type \'(?P<return_type>.*)\' '
20413481Sgiacomo.travaglini@arm.com                  r'with an rvalue of type \'void\'')
20513481Sgiacomo.travaglini@arm.com  diagnosis = """
20613481Sgiacomo.travaglini@arm.comYou are using an action that returns void, but it needs to return
20713481Sgiacomo.travaglini@arm.com%(return_type)s.  Please tell it *what* to return.  Perhaps you can use
20813481Sgiacomo.travaglini@arm.comthe pattern DoAll(some_action, Return(some_value))?"""
20913481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser(
21013481Sgiacomo.travaglini@arm.com      'NRS',
21113481Sgiacomo.travaglini@arm.com      'Need to Return Something',
21213481Sgiacomo.travaglini@arm.com      [(gcc_regex, diagnosis % {'return_type': '*something*'}),
21313481Sgiacomo.travaglini@arm.com       (clang_regex1, diagnosis),
21413481Sgiacomo.travaglini@arm.com       (clang_regex2, diagnosis)],
21513481Sgiacomo.travaglini@arm.com      msg)
21613481Sgiacomo.travaglini@arm.com
21713481Sgiacomo.travaglini@arm.com
21813481Sgiacomo.travaglini@arm.comdef _NeedToReturnNothingDiagnoser(msg):
21913481Sgiacomo.travaglini@arm.com  """Diagnoses the NRN disease, given the error messages by the compiler."""
22013481Sgiacomo.travaglini@arm.com
22113481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
22213481Sgiacomo.travaglini@arm.com               r'.*gmock-actions\.h.*error: instantiation of '
22313481Sgiacomo.travaglini@arm.com               r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
22413481Sgiacomo.travaglini@arm.com               r'as type \'void\'')
22513481Sgiacomo.travaglini@arm.com  clang_regex1 = (r'error: field has incomplete type '
22613481Sgiacomo.travaglini@arm.com                  r'\'Result\' \(aka \'void\'\)(\r)?\n'
22713481Sgiacomo.travaglini@arm.com                  r'(.*\n)*?' +
22813481Sgiacomo.travaglini@arm.com                  _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
22913481Sgiacomo.travaglini@arm.com                  r'of function template specialization '
23013481Sgiacomo.travaglini@arm.com                  r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
23113481Sgiacomo.travaglini@arm.com                  r'::operator Action<void \(.*\)>\' requested here')
23213481Sgiacomo.travaglini@arm.com  clang_regex2 = (r'error: field has incomplete type '
23313481Sgiacomo.travaglini@arm.com                  r'\'Result\' \(aka \'void\'\)(\r)?\n'
23413481Sgiacomo.travaglini@arm.com                  r'(.*\n)*?' +
23513481Sgiacomo.travaglini@arm.com                  _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
23613481Sgiacomo.travaglini@arm.com                  r'of function template specialization '
23713481Sgiacomo.travaglini@arm.com                  r'\'testing::internal::DoBothAction<.*>'
23813481Sgiacomo.travaglini@arm.com                  r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
23913481Sgiacomo.travaglini@arm.com                  r'requested here')
24013481Sgiacomo.travaglini@arm.com  diagnosis = """
24113481Sgiacomo.travaglini@arm.comYou are using an action that returns %(return_type)s, but it needs to return
24213481Sgiacomo.travaglini@arm.comvoid.  Please use a void-returning action instead.
24313481Sgiacomo.travaglini@arm.com
24413481Sgiacomo.travaglini@arm.comAll actions but the last in DoAll(...) must return void.  Perhaps you need
24513481Sgiacomo.travaglini@arm.comto re-arrange the order of actions in a DoAll(), if you are using one?"""
24613481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser(
24713481Sgiacomo.travaglini@arm.com      'NRN',
24813481Sgiacomo.travaglini@arm.com      'Need to Return Nothing',
24913481Sgiacomo.travaglini@arm.com      [(gcc_regex, diagnosis % {'return_type': '*something*'}),
25013481Sgiacomo.travaglini@arm.com       (clang_regex1, diagnosis),
25113481Sgiacomo.travaglini@arm.com       (clang_regex2, diagnosis)],
25213481Sgiacomo.travaglini@arm.com      msg)
25313481Sgiacomo.travaglini@arm.com
25413481Sgiacomo.travaglini@arm.com
25513481Sgiacomo.travaglini@arm.comdef _IncompleteByReferenceArgumentDiagnoser(msg):
25613481Sgiacomo.travaglini@arm.com  """Diagnoses the IBRA disease, given the error messages by the compiler."""
25713481Sgiacomo.travaglini@arm.com
25813481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
25913481Sgiacomo.travaglini@arm.com               r'.*gtest-printers\.h.*error: invalid application of '
26013481Sgiacomo.travaglini@arm.com               r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
26113481Sgiacomo.travaglini@arm.com
26213481Sgiacomo.travaglini@arm.com  clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
26313481Sgiacomo.travaglini@arm.com                 r'\'sizeof\' to an incomplete type '
26413481Sgiacomo.travaglini@arm.com                 r'\'(?P<type>.*)( const)?\'\r?\n'
26513481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?' +
26613481Sgiacomo.travaglini@arm.com                 _CLANG_NON_GMOCK_FILE_LINE_RE +
26713481Sgiacomo.travaglini@arm.com                 r'note: in instantiation of member function '
26813481Sgiacomo.travaglini@arm.com                 r'\'testing::internal2::TypeWithoutFormatter<.*>::'
26913481Sgiacomo.travaglini@arm.com                 r'PrintValue\' requested here')
27013481Sgiacomo.travaglini@arm.com  diagnosis = """
27113481Sgiacomo.travaglini@arm.comIn order to mock this function, Google Mock needs to see the definition
27213481Sgiacomo.travaglini@arm.comof type "%(type)s" - declaration alone is not enough.  Either #include
27313481Sgiacomo.travaglini@arm.comthe header that defines it, or change the argument to be passed
27413481Sgiacomo.travaglini@arm.comby pointer."""
27513481Sgiacomo.travaglini@arm.com
27613481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
27713481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
27813481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
27913481Sgiacomo.travaglini@arm.com                           msg)
28013481Sgiacomo.travaglini@arm.com
28113481Sgiacomo.travaglini@arm.com
28213481Sgiacomo.travaglini@arm.comdef _OverloadedFunctionMatcherDiagnoser(msg):
28313481Sgiacomo.travaglini@arm.com  """Diagnoses the OFM disease, given the error messages by the compiler."""
28413481Sgiacomo.travaglini@arm.com
28513481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
28613481Sgiacomo.travaglini@arm.com               r'call to \'Truly\(<unresolved overloaded function type>\)')
28713481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
28813481Sgiacomo.travaglini@arm.com                 r'call to \'Truly')
28913481Sgiacomo.travaglini@arm.com  diagnosis = """
29013481Sgiacomo.travaglini@arm.comThe argument you gave to Truly() is an overloaded function.  Please tell
29113481Sgiacomo.travaglini@arm.comyour compiler which overloaded version you want to use.
29213481Sgiacomo.travaglini@arm.com
29313481Sgiacomo.travaglini@arm.comFor example, if you want to use the version whose signature is
29413481Sgiacomo.travaglini@arm.com  bool Foo(int n);
29513481Sgiacomo.travaglini@arm.comyou should write
29613481Sgiacomo.travaglini@arm.com  Truly(static_cast<bool (*)(int n)>(Foo))"""
29713481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
29813481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
29913481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
30013481Sgiacomo.travaglini@arm.com                           msg)
30113481Sgiacomo.travaglini@arm.com
30213481Sgiacomo.travaglini@arm.com
30313481Sgiacomo.travaglini@arm.comdef _OverloadedFunctionActionDiagnoser(msg):
30413481Sgiacomo.travaglini@arm.com  """Diagnoses the OFA disease, given the error messages by the compiler."""
30513481Sgiacomo.travaglini@arm.com
30613481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
30713481Sgiacomo.travaglini@arm.com               r'\'Invoke\(<unresolved overloaded function type>')
30813481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
30913481Sgiacomo.travaglini@arm.com                 r'function for call to \'Invoke\'\r?\n'
31013481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?'
31113481Sgiacomo.travaglini@arm.com                 r'.*\bgmock-generated-actions\.h:\d+:\d+:\s+'
31213481Sgiacomo.travaglini@arm.com                 r'note: candidate template ignored:\s+'
31313481Sgiacomo.travaglini@arm.com                 r'couldn\'t infer template argument \'FunctionImpl\'')
31413481Sgiacomo.travaglini@arm.com  diagnosis = """
31513481Sgiacomo.travaglini@arm.comFunction you are passing to Invoke is overloaded.  Please tell your compiler
31613481Sgiacomo.travaglini@arm.comwhich overloaded version you want to use.
31713481Sgiacomo.travaglini@arm.com
31813481Sgiacomo.travaglini@arm.comFor example, if you want to use the version whose signature is
31913481Sgiacomo.travaglini@arm.com  bool MyFunction(int n, double x);
32013481Sgiacomo.travaglini@arm.comyou should write something like
32113481Sgiacomo.travaglini@arm.com  Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
32213481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('OFA', 'Overloaded Function Action',
32313481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
32413481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
32513481Sgiacomo.travaglini@arm.com                           msg)
32613481Sgiacomo.travaglini@arm.com
32713481Sgiacomo.travaglini@arm.com
32813481Sgiacomo.travaglini@arm.comdef _OverloadedMethodActionDiagnoser(msg):
32913481Sgiacomo.travaglini@arm.com  """Diagnoses the OMA disease, given the error messages by the compiler."""
33013481Sgiacomo.travaglini@arm.com
33113481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
33213481Sgiacomo.travaglini@arm.com               r'call to \'Invoke\(.+, <unresolved overloaded function '
33313481Sgiacomo.travaglini@arm.com               r'type>\)')
33413481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
33513481Sgiacomo.travaglini@arm.com                 r'for call to \'Invoke\'\r?\n'
33613481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?'
33713481Sgiacomo.travaglini@arm.com                 r'.*\bgmock-generated-actions\.h:\d+:\d+: '
33813481Sgiacomo.travaglini@arm.com                 r'note: candidate function template not viable: '
33913481Sgiacomo.travaglini@arm.com                 r'requires .*, but 2 (arguments )?were provided')
34013481Sgiacomo.travaglini@arm.com  diagnosis = """
34113481Sgiacomo.travaglini@arm.comThe second argument you gave to Invoke() is an overloaded method.  Please
34213481Sgiacomo.travaglini@arm.comtell your compiler which overloaded version you want to use.
34313481Sgiacomo.travaglini@arm.com
34413481Sgiacomo.travaglini@arm.comFor example, if you want to use the version whose signature is
34513481Sgiacomo.travaglini@arm.com  class Foo {
34613481Sgiacomo.travaglini@arm.com    ...
34713481Sgiacomo.travaglini@arm.com    bool Bar(int n, double x);
34813481Sgiacomo.travaglini@arm.com  };
34913481Sgiacomo.travaglini@arm.comyou should write something like
35013481Sgiacomo.travaglini@arm.com  Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
35113481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('OMA', 'Overloaded Method Action',
35213481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
35313481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
35413481Sgiacomo.travaglini@arm.com                           msg)
35513481Sgiacomo.travaglini@arm.com
35613481Sgiacomo.travaglini@arm.com
35713481Sgiacomo.travaglini@arm.comdef _MockObjectPointerDiagnoser(msg):
35813481Sgiacomo.travaglini@arm.com  """Diagnoses the MOP disease, given the error messages by the compiler."""
35913481Sgiacomo.travaglini@arm.com
36013481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
36113481Sgiacomo.travaglini@arm.com               r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
36213481Sgiacomo.travaglini@arm.com               r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
36313481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
36413481Sgiacomo.travaglini@arm.com                 r'\'(?P<class_name>.*?) *\' is a pointer; '
36513481Sgiacomo.travaglini@arm.com                 r'(did you mean|maybe you meant) to use \'->\'\?')
36613481Sgiacomo.travaglini@arm.com  diagnosis = """
36713481Sgiacomo.travaglini@arm.comThe first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
36813481Sgiacomo.travaglini@arm.comnot a *pointer* to it.  Please write '*(%(mock_object)s)' instead of
36913481Sgiacomo.travaglini@arm.com'%(mock_object)s' as your first argument.
37013481Sgiacomo.travaglini@arm.com
37113481Sgiacomo.travaglini@arm.comFor example, given the mock class:
37213481Sgiacomo.travaglini@arm.com
37313481Sgiacomo.travaglini@arm.com  class %(class_name)s : public ... {
37413481Sgiacomo.travaglini@arm.com    ...
37513481Sgiacomo.travaglini@arm.com    MOCK_METHOD0(%(method)s, ...);
37613481Sgiacomo.travaglini@arm.com  };
37713481Sgiacomo.travaglini@arm.com
37813481Sgiacomo.travaglini@arm.comand the following mock instance:
37913481Sgiacomo.travaglini@arm.com
38013481Sgiacomo.travaglini@arm.com  %(class_name)s* mock_ptr = ...
38113481Sgiacomo.travaglini@arm.com
38213481Sgiacomo.travaglini@arm.comyou should use the EXPECT_CALL like this:
38313481Sgiacomo.travaglini@arm.com
38413481Sgiacomo.travaglini@arm.com  EXPECT_CALL(*mock_ptr, %(method)s(...));"""
38513481Sgiacomo.travaglini@arm.com
38613481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser(
38713481Sgiacomo.travaglini@arm.com      'MOP',
38813481Sgiacomo.travaglini@arm.com      'Mock Object Pointer',
38913481Sgiacomo.travaglini@arm.com      [(gcc_regex, diagnosis),
39013481Sgiacomo.travaglini@arm.com       (clang_regex, diagnosis % {'mock_object': 'mock_object',
39113481Sgiacomo.travaglini@arm.com                                  'method': 'method',
39213481Sgiacomo.travaglini@arm.com                                  'class_name': '%(class_name)s'})],
39313481Sgiacomo.travaglini@arm.com       msg)
39413481Sgiacomo.travaglini@arm.com
39513481Sgiacomo.travaglini@arm.com
39613481Sgiacomo.travaglini@arm.comdef _NeedToUseSymbolDiagnoser(msg):
39713481Sgiacomo.travaglini@arm.com  """Diagnoses the NUS disease, given the error messages by the compiler."""
39813481Sgiacomo.travaglini@arm.com
39913481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
40013481Sgiacomo.travaglini@arm.com               r'(was not declared in this scope|has not been declared)')
40113481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_FILE_LINE_RE +
40213481Sgiacomo.travaglini@arm.com                 r'error: (use of undeclared identifier|unknown type name|'
40313481Sgiacomo.travaglini@arm.com                 r'no template named) \'(?P<symbol>[^\']+)\'')
40413481Sgiacomo.travaglini@arm.com  diagnosis = """
40513481Sgiacomo.travaglini@arm.com'%(symbol)s' is defined by Google Mock in the testing namespace.
40613481Sgiacomo.travaglini@arm.comDid you forget to write
40713481Sgiacomo.travaglini@arm.com  using testing::%(symbol)s;
40813481Sgiacomo.travaglini@arm.com?"""
40913481Sgiacomo.travaglini@arm.com  for m in (list(_FindAllMatches(gcc_regex, msg)) +
41013481Sgiacomo.travaglini@arm.com            list(_FindAllMatches(clang_regex, msg))):
41113481Sgiacomo.travaglini@arm.com    symbol = m.groupdict()['symbol']
41213481Sgiacomo.travaglini@arm.com    if symbol in _COMMON_GMOCK_SYMBOLS:
41313481Sgiacomo.travaglini@arm.com      yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
41413481Sgiacomo.travaglini@arm.com
41513481Sgiacomo.travaglini@arm.com
41613481Sgiacomo.travaglini@arm.comdef _NeedToUseReturnNullDiagnoser(msg):
41713481Sgiacomo.travaglini@arm.com  """Diagnoses the NRNULL disease, given the error messages by the compiler."""
41813481Sgiacomo.travaglini@arm.com
41913481Sgiacomo.travaglini@arm.com  gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
42013481Sgiacomo.travaglini@arm.com               '::operator testing::Action<Func>\(\) const.*\n' +
42113481Sgiacomo.travaglini@arm.com               _GCC_FILE_LINE_RE + r'instantiated from here\n'
42213481Sgiacomo.travaglini@arm.com               r'.*error: no matching function for call to \'ImplicitCast_\('
42313481Sgiacomo.travaglini@arm.com               r'(:?long )?int&\)')
42413481Sgiacomo.travaglini@arm.com  clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
42513481Sgiacomo.travaglini@arm.com                 r'call to \'ImplicitCast_\'\r?\n'
42613481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?' +
42713481Sgiacomo.travaglini@arm.com                 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
42813481Sgiacomo.travaglini@arm.com                 r'of function template specialization '
42913481Sgiacomo.travaglini@arm.com                 r'\'testing::internal::ReturnAction<(int|long)>::operator '
43013481Sgiacomo.travaglini@arm.com                 r'Action<(?P<type>.*)\(\)>\' requested here')
43113481Sgiacomo.travaglini@arm.com  diagnosis = """
43213481Sgiacomo.travaglini@arm.comYou are probably calling Return(NULL) and the compiler isn't sure how to turn
43313481Sgiacomo.travaglini@arm.comNULL into %(type)s. Use ReturnNull() instead.
43413481Sgiacomo.travaglini@arm.comNote: the line number may be off; please fix all instances of Return(NULL)."""
43513481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser(
43613481Sgiacomo.travaglini@arm.com      'NRNULL', 'Need to use ReturnNull',
43713481Sgiacomo.travaglini@arm.com      [(clang_regex, diagnosis),
43813481Sgiacomo.travaglini@arm.com       (gcc_regex, diagnosis % {'type': 'the right type'})],
43913481Sgiacomo.travaglini@arm.com      msg)
44013481Sgiacomo.travaglini@arm.com
44113481Sgiacomo.travaglini@arm.com
44213481Sgiacomo.travaglini@arm.comdef _TypeInTemplatedBaseDiagnoser(msg):
44313481Sgiacomo.travaglini@arm.com  """Diagnoses the TTB disease, given the error messages by the compiler."""
44413481Sgiacomo.travaglini@arm.com
44513481Sgiacomo.travaglini@arm.com  # This version works when the type is used as the mock function's return
44613481Sgiacomo.travaglini@arm.com  # type.
44713481Sgiacomo.travaglini@arm.com  gcc_4_3_1_regex_type_in_retval = (
44813481Sgiacomo.travaglini@arm.com      r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
44913481Sgiacomo.travaglini@arm.com      r'error: a function call cannot appear in a constant-expression')
45013481Sgiacomo.travaglini@arm.com  gcc_4_4_0_regex_type_in_retval = (
45113481Sgiacomo.travaglini@arm.com      r'error: a function call cannot appear in a constant-expression'
45213481Sgiacomo.travaglini@arm.com      + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
45313481Sgiacomo.travaglini@arm.com  # This version works when the type is used as the mock function's sole
45413481Sgiacomo.travaglini@arm.com  # parameter type.
45513481Sgiacomo.travaglini@arm.com  gcc_regex_type_of_sole_param = (
45613481Sgiacomo.travaglini@arm.com      _GCC_FILE_LINE_RE +
45713481Sgiacomo.travaglini@arm.com      r'error: \'(?P<type>.+)\' was not declared in this scope\n'
45813481Sgiacomo.travaglini@arm.com      r'.*error: template argument 1 is invalid\n')
45913481Sgiacomo.travaglini@arm.com  # This version works when the type is used as a parameter of a mock
46013481Sgiacomo.travaglini@arm.com  # function that has multiple parameters.
46113481Sgiacomo.travaglini@arm.com  gcc_regex_type_of_a_param = (
46213481Sgiacomo.travaglini@arm.com      r'error: expected `;\' before \'::\' token\n'
46313481Sgiacomo.travaglini@arm.com      + _GCC_FILE_LINE_RE +
46413481Sgiacomo.travaglini@arm.com      r'error: \'(?P<type>.+)\' was not declared in this scope\n'
46513481Sgiacomo.travaglini@arm.com      r'.*error: template argument 1 is invalid\n'
46613481Sgiacomo.travaglini@arm.com      r'.*error: \'.+\' was not declared in this scope')
46713481Sgiacomo.travaglini@arm.com  clang_regex_type_of_retval_or_sole_param = (
46813481Sgiacomo.travaglini@arm.com      _CLANG_FILE_LINE_RE +
46913481Sgiacomo.travaglini@arm.com      r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
47013481Sgiacomo.travaglini@arm.com      r'(.*\n)*?'
47113481Sgiacomo.travaglini@arm.com      r'(?P=file):(?P=line):\d+: error: '
47213481Sgiacomo.travaglini@arm.com      r'non-friend class member \'Result\' cannot have a qualified name'
47313481Sgiacomo.travaglini@arm.com      )
47413481Sgiacomo.travaglini@arm.com  clang_regex_type_of_a_param = (
47513481Sgiacomo.travaglini@arm.com      _CLANG_FILE_LINE_RE +
47613481Sgiacomo.travaglini@arm.com      r'error: C\+\+ requires a type specifier for all declarations\n'
47713481Sgiacomo.travaglini@arm.com      r'(.*\n)*?'
47813481Sgiacomo.travaglini@arm.com      r'(?P=file):(?P=line):(?P=column): error: '
47913481Sgiacomo.travaglini@arm.com      r'C\+\+ requires a type specifier for all declarations'
48013481Sgiacomo.travaglini@arm.com      )
48113481Sgiacomo.travaglini@arm.com  clang_regex_unknown_type = (
48213481Sgiacomo.travaglini@arm.com      _CLANG_FILE_LINE_RE +
48313481Sgiacomo.travaglini@arm.com      r'error: unknown type name \'(?P<type>[^\']+)\''
48413481Sgiacomo.travaglini@arm.com      )
48513481Sgiacomo.travaglini@arm.com
48613481Sgiacomo.travaglini@arm.com  diagnosis = """
48713481Sgiacomo.travaglini@arm.comIn a mock class template, types or typedefs defined in the base class
48813481Sgiacomo.travaglini@arm.comtemplate are *not* automatically visible.  This is how C++ works.  Before
48913481Sgiacomo.travaglini@arm.comyou can use a type or typedef named %(type)s defined in base class Base<T>, you
49013481Sgiacomo.travaglini@arm.comneed to make it visible.  One way to do it is:
49113481Sgiacomo.travaglini@arm.com
49213481Sgiacomo.travaglini@arm.com  typedef typename Base<T>::%(type)s %(type)s;"""
49313481Sgiacomo.travaglini@arm.com
49413481Sgiacomo.travaglini@arm.com  for diag in _GenericDiagnoser(
49513481Sgiacomo.travaglini@arm.com      'TTB', 'Type in Template Base',
49613481Sgiacomo.travaglini@arm.com      [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
49713481Sgiacomo.travaglini@arm.com       (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
49813481Sgiacomo.travaglini@arm.com       (gcc_regex_type_of_sole_param, diagnosis),
49913481Sgiacomo.travaglini@arm.com       (gcc_regex_type_of_a_param, diagnosis),
50013481Sgiacomo.travaglini@arm.com       (clang_regex_type_of_retval_or_sole_param, diagnosis),
50113481Sgiacomo.travaglini@arm.com       (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})],
50213481Sgiacomo.travaglini@arm.com      msg):
50313481Sgiacomo.travaglini@arm.com    yield diag
50413481Sgiacomo.travaglini@arm.com  # Avoid overlap with the NUS pattern.
50513481Sgiacomo.travaglini@arm.com  for m in _FindAllMatches(clang_regex_unknown_type, msg):
50613481Sgiacomo.travaglini@arm.com    type_ = m.groupdict()['type']
50713481Sgiacomo.travaglini@arm.com    if type_ not in _COMMON_GMOCK_SYMBOLS:
50813481Sgiacomo.travaglini@arm.com      yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict())
50913481Sgiacomo.travaglini@arm.com
51013481Sgiacomo.travaglini@arm.com
51113481Sgiacomo.travaglini@arm.comdef _WrongMockMethodMacroDiagnoser(msg):
51213481Sgiacomo.travaglini@arm.com  """Diagnoses the WMM disease, given the error messages by the compiler."""
51313481Sgiacomo.travaglini@arm.com
51413481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE +
51513481Sgiacomo.travaglini@arm.com               r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
51613481Sgiacomo.travaglini@arm.com               r'.*\n'
51713481Sgiacomo.travaglini@arm.com               r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
51813481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
51913481Sgiacomo.travaglini@arm.com                 r'error:.*array.*negative.*r?\n'
52013481Sgiacomo.travaglini@arm.com                 r'(.*\n)*?'
52113481Sgiacomo.travaglini@arm.com                 r'(?P=file):(?P=line):(?P=column): error: too few arguments '
52213481Sgiacomo.travaglini@arm.com                 r'to function call, expected (?P<args>\d+), '
52313481Sgiacomo.travaglini@arm.com                 r'have (?P<wrong_args>\d+)')
52413481Sgiacomo.travaglini@arm.com  clang11_re = (_CLANG_NON_GMOCK_FILE_LINE_RE +
52513481Sgiacomo.travaglini@arm.com                r'.*this_method_does_not_take_'
52613481Sgiacomo.travaglini@arm.com                r'(?P<wrong_args>\d+)_argument.*')
52713481Sgiacomo.travaglini@arm.com  diagnosis = """
52813481Sgiacomo.travaglini@arm.comYou are using MOCK_METHOD%(wrong_args)s to define a mock method that has
52913481Sgiacomo.travaglini@arm.com%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
53013481Sgiacomo.travaglini@arm.comMOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
53113481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
53213481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
53313481Sgiacomo.travaglini@arm.com                            (clang11_re, diagnosis % {'wrong_args': 'm',
53413481Sgiacomo.travaglini@arm.com                                                      'args': 'n'}),
53513481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
53613481Sgiacomo.travaglini@arm.com                           msg)
53713481Sgiacomo.travaglini@arm.com
53813481Sgiacomo.travaglini@arm.com
53913481Sgiacomo.travaglini@arm.comdef _WrongParenPositionDiagnoser(msg):
54013481Sgiacomo.travaglini@arm.com  """Diagnoses the WPP disease, given the error messages by the compiler."""
54113481Sgiacomo.travaglini@arm.com
54213481Sgiacomo.travaglini@arm.com  gcc_regex = (_GCC_FILE_LINE_RE +
54313481Sgiacomo.travaglini@arm.com               r'error:.*testing::internal::MockSpec<.* has no member named \''
54413481Sgiacomo.travaglini@arm.com               r'(?P<method>\w+)\'')
54513481Sgiacomo.travaglini@arm.com  clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
54613481Sgiacomo.travaglini@arm.com                 r'error: no member named \'(?P<method>\w+)\' in '
54713481Sgiacomo.travaglini@arm.com                 r'\'testing::internal::MockSpec<.*>\'')
54813481Sgiacomo.travaglini@arm.com  diagnosis = """
54913481Sgiacomo.travaglini@arm.comThe closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
55013481Sgiacomo.travaglini@arm.com".%(method)s".  For example, you should write:
55113481Sgiacomo.travaglini@arm.com  EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
55213481Sgiacomo.travaglini@arm.cominstead of:
55313481Sgiacomo.travaglini@arm.com  EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
55413481Sgiacomo.travaglini@arm.com  return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
55513481Sgiacomo.travaglini@arm.com                           [(gcc_regex, diagnosis),
55613481Sgiacomo.travaglini@arm.com                            (clang_regex, diagnosis)],
55713481Sgiacomo.travaglini@arm.com                           msg)
55813481Sgiacomo.travaglini@arm.com
55913481Sgiacomo.travaglini@arm.com
56013481Sgiacomo.travaglini@arm.com_DIAGNOSERS = [
56113481Sgiacomo.travaglini@arm.com    _IncompleteByReferenceArgumentDiagnoser,
56213481Sgiacomo.travaglini@arm.com    _MockObjectPointerDiagnoser,
56313481Sgiacomo.travaglini@arm.com    _NeedToReturnNothingDiagnoser,
56413481Sgiacomo.travaglini@arm.com    _NeedToReturnReferenceDiagnoser,
56513481Sgiacomo.travaglini@arm.com    _NeedToReturnSomethingDiagnoser,
56613481Sgiacomo.travaglini@arm.com    _NeedToUseReturnNullDiagnoser,
56713481Sgiacomo.travaglini@arm.com    _NeedToUseSymbolDiagnoser,
56813481Sgiacomo.travaglini@arm.com    _OverloadedFunctionActionDiagnoser,
56913481Sgiacomo.travaglini@arm.com    _OverloadedFunctionMatcherDiagnoser,
57013481Sgiacomo.travaglini@arm.com    _OverloadedMethodActionDiagnoser,
57113481Sgiacomo.travaglini@arm.com    _TypeInTemplatedBaseDiagnoser,
57213481Sgiacomo.travaglini@arm.com    _WrongMockMethodMacroDiagnoser,
57313481Sgiacomo.travaglini@arm.com    _WrongParenPositionDiagnoser,
57413481Sgiacomo.travaglini@arm.com    ]
57513481Sgiacomo.travaglini@arm.com
57613481Sgiacomo.travaglini@arm.com
57713481Sgiacomo.travaglini@arm.comdef Diagnose(msg):
57813481Sgiacomo.travaglini@arm.com  """Generates all possible diagnoses given the compiler error message."""
57913481Sgiacomo.travaglini@arm.com
58013481Sgiacomo.travaglini@arm.com  msg = re.sub(r'\x1b\[[^m]*m', '', msg)  # Strips all color formatting.
58113481Sgiacomo.travaglini@arm.com  # Assuming the string is using the UTF-8 encoding, replaces the left and
58213481Sgiacomo.travaglini@arm.com  # the right single quote characters with apostrophes.
58313481Sgiacomo.travaglini@arm.com  msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg)
58413481Sgiacomo.travaglini@arm.com
58513481Sgiacomo.travaglini@arm.com  diagnoses = []
58613481Sgiacomo.travaglini@arm.com  for diagnoser in _DIAGNOSERS:
58713481Sgiacomo.travaglini@arm.com    for diag in diagnoser(msg):
58813481Sgiacomo.travaglini@arm.com      diagnosis = '[%s - %s]\n%s' % diag
58913481Sgiacomo.travaglini@arm.com      if not diagnosis in diagnoses:
59013481Sgiacomo.travaglini@arm.com        diagnoses.append(diagnosis)
59113481Sgiacomo.travaglini@arm.com  return diagnoses
59213481Sgiacomo.travaglini@arm.com
59313481Sgiacomo.travaglini@arm.com
59413481Sgiacomo.travaglini@arm.comdef main():
59513481Sgiacomo.travaglini@arm.com  print ('Google Mock Doctor v%s - '
59613481Sgiacomo.travaglini@arm.com         'diagnoses problems in code using Google Mock.' % _VERSION)
59713481Sgiacomo.travaglini@arm.com
59813481Sgiacomo.travaglini@arm.com  if sys.stdin.isatty():
59913481Sgiacomo.travaglini@arm.com    print ('Please copy and paste the compiler errors here.  Press c-D when '
60013481Sgiacomo.travaglini@arm.com           'you are done:')
60113481Sgiacomo.travaglini@arm.com  else:
60213481Sgiacomo.travaglini@arm.com    print ('Waiting for compiler errors on stdin . . .')
60313481Sgiacomo.travaglini@arm.com
60413481Sgiacomo.travaglini@arm.com  msg = sys.stdin.read().strip()
60513481Sgiacomo.travaglini@arm.com  diagnoses = Diagnose(msg)
60613481Sgiacomo.travaglini@arm.com  count = len(diagnoses)
60713481Sgiacomo.travaglini@arm.com  if not count:
60813481Sgiacomo.travaglini@arm.com    print ("""
60913481Sgiacomo.travaglini@arm.comYour compiler complained:
61013481Sgiacomo.travaglini@arm.com8<------------------------------------------------------------
61113481Sgiacomo.travaglini@arm.com%s
61213481Sgiacomo.travaglini@arm.com------------------------------------------------------------>8
61313481Sgiacomo.travaglini@arm.com
61413481Sgiacomo.travaglini@arm.comUh-oh, I'm not smart enough to figure out what the problem is. :-(
61513481Sgiacomo.travaglini@arm.comHowever...
61613481Sgiacomo.travaglini@arm.comIf you send your source code and the compiler's error messages to
61713481Sgiacomo.travaglini@arm.com%s, you can be helped and I can get smarter --
61813481Sgiacomo.travaglini@arm.comwin-win for us!""" % (msg, _EMAIL))
61913481Sgiacomo.travaglini@arm.com  else:
62013481Sgiacomo.travaglini@arm.com    print ('------------------------------------------------------------')
62113481Sgiacomo.travaglini@arm.com    print ('Your code appears to have the following',)
62213481Sgiacomo.travaglini@arm.com    if count > 1:
62313481Sgiacomo.travaglini@arm.com      print ('%s diseases:' % (count,))
62413481Sgiacomo.travaglini@arm.com    else:
62513481Sgiacomo.travaglini@arm.com      print ('disease:')
62613481Sgiacomo.travaglini@arm.com    i = 0
62713481Sgiacomo.travaglini@arm.com    for d in diagnoses:
62813481Sgiacomo.travaglini@arm.com      i += 1
62913481Sgiacomo.travaglini@arm.com      if count > 1:
63013481Sgiacomo.travaglini@arm.com        print ('\n#%s:' % (i,))
63113481Sgiacomo.travaglini@arm.com      print (d)
63213481Sgiacomo.travaglini@arm.com    print ("""
63313481Sgiacomo.travaglini@arm.comHow did I do?  If you think I'm wrong or unhelpful, please send your
63413481Sgiacomo.travaglini@arm.comsource code and the compiler's error messages to %s.
63513481Sgiacomo.travaglini@arm.comThen you can be helped and I can get smarter -- I promise I won't be upset!""" %
63613481Sgiacomo.travaglini@arm.com           _EMAIL)
63713481Sgiacomo.travaglini@arm.com
63813481Sgiacomo.travaglini@arm.com
63913481Sgiacomo.travaglini@arm.comif __name__ == '__main__':
64013481Sgiacomo.travaglini@arm.com  main()
641