blob: 74992bc744810745c72ddd8bc20d9815af3c2abd [file] [log] [blame]
zhanyong.wana89034c2009-09-22 16:18:42 +00001#!/usr/bin/env python
shiqiane35fdd92008-12-10 05:08:54 +00002#
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
vladlosev4c915512010-09-25 00:52:20 +000032"""Converts compiler's errors in code using Google Mock to plain English."""
shiqiane35fdd92008-12-10 05:08:54 +000033
34__author__ = 'wan@google.com (Zhanyong Wan)'
35
36import re
37import sys
38
zhanyong.wanb8243162009-06-04 05:48:20 +000039_VERSION = '1.0.3'
shiqiane35fdd92008-12-10 05:08:54 +000040
vladlosev662d8a22010-09-29 00:38:12 +000041_EMAIL = 'googlemock@googlegroups.com'
42
shiqiane35fdd92008-12-10 05:08:54 +000043_COMMON_GMOCK_SYMBOLS = [
44 # Matchers
45 '_',
46 'A',
47 'AddressSatisfies',
48 'AllOf',
49 'An',
50 'AnyOf',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000051 'ContainerEq',
52 'Contains',
shiqiane35fdd92008-12-10 05:08:54 +000053 'ContainsRegex',
54 'DoubleEq',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000055 'ElementsAre',
56 'ElementsAreArray',
shiqiane35fdd92008-12-10 05:08:54 +000057 'EndsWith',
58 'Eq',
59 'Field',
60 'FloatEq',
61 'Ge',
62 'Gt',
63 'HasSubstr',
zhanyong.wan5b95fa72009-01-27 22:28:45 +000064 'IsInitializedProto',
shiqiane35fdd92008-12-10 05:08:54 +000065 'Le',
66 'Lt',
67 'MatcherCast',
zhanyong.wanb8243162009-06-04 05:48:20 +000068 'Matches',
shiqiane35fdd92008-12-10 05:08:54 +000069 'MatchesRegex',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000070 'NanSensitiveDoubleEq',
71 'NanSensitiveFloatEq',
shiqiane35fdd92008-12-10 05:08:54 +000072 'Ne',
73 'Not',
74 'NotNull',
75 'Pointee',
76 'Property',
77 'Ref',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000078 'ResultOf',
79 'SafeMatcherCast',
shiqiane35fdd92008-12-10 05:08:54 +000080 'StartsWith',
81 'StrCaseEq',
82 'StrCaseNe',
83 'StrEq',
84 'StrNe',
85 'Truly',
86 'TypedEq',
zhanyong.wanb8243162009-06-04 05:48:20 +000087 'Value',
shiqiane35fdd92008-12-10 05:08:54 +000088
89 # Actions
zhanyong.wan9413f2f2009-05-29 19:50:06 +000090 'Assign',
shiqiane35fdd92008-12-10 05:08:54 +000091 'ByRef',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000092 'DeleteArg',
shiqiane35fdd92008-12-10 05:08:54 +000093 'DoAll',
94 'DoDefault',
95 'IgnoreResult',
96 'Invoke',
97 'InvokeArgument',
98 'InvokeWithoutArgs',
99 'Return',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000100 'ReturnNew',
shiqiane35fdd92008-12-10 05:08:54 +0000101 'ReturnNull',
102 'ReturnRef',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000103 'SaveArg',
104 'SetArgReferee',
zhanyong.wan59214832010-10-05 05:58:51 +0000105 'SetArgPointee',
shiqiane35fdd92008-12-10 05:08:54 +0000106 'SetArgumentPointee',
107 'SetArrayArgument',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000108 'SetErrnoAndReturn',
109 'Throw',
110 'WithArg',
shiqiane35fdd92008-12-10 05:08:54 +0000111 'WithArgs',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000112 'WithoutArgs',
shiqiane35fdd92008-12-10 05:08:54 +0000113
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
vladlosev4c915512010-09-25 00:52:20 +0000130# Regex for matching source file path and line number in the compiler's errors.
vladlosev0fd83962011-09-28 18:32:59 +0000131_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
vladlosev4c915512010-09-25 00:52:20 +0000132_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+')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000135
shiqiane35fdd92008-12-10 05:08:54 +0000136
137def _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
vladlosev4c915512010-09-25 00:52:20 +0000144def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
shiqiane35fdd92008-12-10 05:08:54 +0000145 """Diagnoses the given disease by pattern matching.
146
vladlosev4c915512010-09-25 00:52:20 +0000147 Can provide different diagnoses for different patterns.
148
shiqiane35fdd92008-12-10 05:08:54 +0000149 Args:
150 short_name: Short name of the disease.
151 long_name: Long name of the disease.
vladlosev4c915512010-09-25 00:52:20 +0000152 diagnoses: A list of pairs (regex, pattern for formatting the diagnosis
153 for matching regex).
154 msg: Compiler's error messages.
shiqiane35fdd92008-12-10 05:08:54 +0000155 Yields:
156 Tuples of the form
157 (short name of disease, long name of disease, diagnosis).
158 """
vladlosev4c915512010-09-25 00:52:20 +0000159 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())
shiqiane35fdd92008-12-10 05:08:54 +0000164
165
166def _NeedToReturnReferenceDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000167 """Diagnoses the NRR disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000168
vladlosev4c915512010-09-25 00:52:20 +0000169 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')
zhanyong.wan5b61ce32011-02-01 00:00:03 +0000172 clang_regex = (r'error:.*array.*negative.*\r?\n'
vladlosev4c915512010-09-25 00:52:20 +0000173 r'(.*\n)*?' +
174 _CLANG_NON_GMOCK_FILE_LINE_RE +
175 r'note: in instantiation of function template specialization '
vladloseveca38cd2011-08-25 21:35:10 +0000176 r'\'testing::internal::ReturnAction<(?P<type>.*)>'
vladlosev4c915512010-09-25 00:52:20 +0000177 r'::operator Action<.*>\' requested here')
kosak6e87b782014-11-17 02:22:20 +0000178 clang11_re = (r'use_ReturnRef_instead_of_Return_to_return_a_reference.*'
179 r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE)
180
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000181 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000182You are using a Return() action in a function that returns a reference to
183%(type)s. Please use ReturnRef() instead."""
shiqiane35fdd92008-12-10 05:08:54 +0000184 return _GenericDiagnoser('NRR', 'Need to Return Reference',
vladlosev4c915512010-09-25 00:52:20 +0000185 [(clang_regex, diagnosis),
kosak6e87b782014-11-17 02:22:20 +0000186 (clang11_re, diagnosis % {'type': 'a type'}),
vladlosev4c915512010-09-25 00:52:20 +0000187 (gcc_regex, diagnosis % {'type': 'a type'})],
188 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000189
190
191def _NeedToReturnSomethingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000192 """Diagnoses the NRS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000193
vladlosev4c915512010-09-25 00:52:20 +0000194 gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
195 r'*gmock.*actions\.h.*error: void value not ignored)'
196 r'|(error: control reaches end of non-void function)')
197 clang_regex1 = (_CLANG_FILE_LINE_RE +
198 r'error: cannot initialize return object '
vladloseveca38cd2011-08-25 21:35:10 +0000199 r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
vladlosev4c915512010-09-25 00:52:20 +0000200 r'with an rvalue of type \'void\'')
201 clang_regex2 = (_CLANG_FILE_LINE_RE +
202 r'error: cannot initialize return object '
vladloseveca38cd2011-08-25 21:35:10 +0000203 r'of type \'(?P<return_type>.*)\' '
vladlosev4c915512010-09-25 00:52:20 +0000204 r'with an rvalue of type \'void\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000205 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000206You are using an action that returns void, but it needs to return
vladlosev4c915512010-09-25 00:52:20 +0000207%(return_type)s. Please tell it *what* to return. Perhaps you can use
zhanyong.wan16cf4732009-05-14 20:55:30 +0000208the pattern DoAll(some_action, Return(some_value))?"""
vladlosev4c915512010-09-25 00:52:20 +0000209 return _GenericDiagnoser(
210 'NRS',
211 'Need to Return Something',
212 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
213 (clang_regex1, diagnosis),
214 (clang_regex2, diagnosis)],
215 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000216
217
218def _NeedToReturnNothingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000219 """Diagnoses the NRN disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000220
vladlosev4c915512010-09-25 00:52:20 +0000221 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
222 r'.*gmock-actions\.h.*error: instantiation of '
223 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
224 r'as type \'void\'')
225 clang_regex1 = (r'error: field has incomplete type '
226 r'\'Result\' \(aka \'void\'\)(\r)?\n'
227 r'(.*\n)*?' +
228 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
229 r'of function template specialization '
230 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
231 r'::operator Action<void \(.*\)>\' requested here')
232 clang_regex2 = (r'error: field has incomplete type '
233 r'\'Result\' \(aka \'void\'\)(\r)?\n'
234 r'(.*\n)*?' +
235 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
236 r'of function template specialization '
237 r'\'testing::internal::DoBothAction<.*>'
238 r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
239 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000240 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000241You are using an action that returns %(return_type)s, but it needs to return
shiqiane35fdd92008-12-10 05:08:54 +0000242void. Please use a void-returning action instead.
243
244All actions but the last in DoAll(...) must return void. Perhaps you need
245to re-arrange the order of actions in a DoAll(), if you are using one?"""
vladlosev4c915512010-09-25 00:52:20 +0000246 return _GenericDiagnoser(
247 'NRN',
248 'Need to Return Nothing',
249 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
250 (clang_regex1, diagnosis),
251 (clang_regex2, diagnosis)],
252 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000253
254
255def _IncompleteByReferenceArgumentDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000256 """Diagnoses the IBRA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000257
vladlosev4c915512010-09-25 00:52:20 +0000258 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
259 r'.*gtest-printers\.h.*error: invalid application of '
260 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
261
262 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
263 r'\'sizeof\' to an incomplete type '
264 r'\'(?P<type>.*)( const)?\'\r?\n'
265 r'(.*\n)*?' +
266 _CLANG_NON_GMOCK_FILE_LINE_RE +
267 r'note: in instantiation of member function '
zhanyong.waned6c9272011-02-23 19:39:27 +0000268 r'\'testing::internal2::TypeWithoutFormatter<.*>::'
269 r'PrintValue\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000270 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000271In order to mock this function, Google Mock needs to see the definition
272of type "%(type)s" - declaration alone is not enough. Either #include
273the header that defines it, or change the argument to be passed
274by pointer."""
vladlosev4c915512010-09-25 00:52:20 +0000275
shiqiane35fdd92008-12-10 05:08:54 +0000276 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
vladlosev4c915512010-09-25 00:52:20 +0000277 [(gcc_regex, diagnosis),
278 (clang_regex, diagnosis)],
279 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000280
281
282def _OverloadedFunctionMatcherDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000283 """Diagnoses the OFM disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000284
vladlosev4c915512010-09-25 00:52:20 +0000285 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
286 r'call to \'Truly\(<unresolved overloaded function type>\)')
287 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
288 r'call to \'Truly')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000289 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000290The argument you gave to Truly() is an overloaded function. Please tell
vladlosev4c915512010-09-25 00:52:20 +0000291your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000292
293For example, if you want to use the version whose signature is
294 bool Foo(int n);
295you should write
296 Truly(static_cast<bool (*)(int n)>(Foo))"""
297 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
vladlosev4c915512010-09-25 00:52:20 +0000298 [(gcc_regex, diagnosis),
299 (clang_regex, diagnosis)],
300 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000301
302
303def _OverloadedFunctionActionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000304 """Diagnoses the OFA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000305
vladlosev4c915512010-09-25 00:52:20 +0000306 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
307 r'\'Invoke\(<unresolved overloaded function type>')
308 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
309 r'function for call to \'Invoke\'\r?\n'
310 r'(.*\n)*?'
kosak6e108722015-07-28 00:53:13 +0000311 r'.*\bgmock-generated-actions\.h:\d+:\d+:\s+'
vladlosev4c915512010-09-25 00:52:20 +0000312 r'note: candidate template ignored:\s+'
313 r'couldn\'t infer template argument \'FunctionImpl\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000314 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000315Function you are passing to Invoke is overloaded. Please tell your compiler
shiqiane35fdd92008-12-10 05:08:54 +0000316which overloaded version you want to use.
317
318For example, if you want to use the version whose signature is
319 bool MyFunction(int n, double x);
320you should write something like
321 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
322 return _GenericDiagnoser('OFA', 'Overloaded Function Action',
vladlosev4c915512010-09-25 00:52:20 +0000323 [(gcc_regex, diagnosis),
324 (clang_regex, diagnosis)],
325 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000326
327
vladlosev4c915512010-09-25 00:52:20 +0000328def _OverloadedMethodActionDiagnoser(msg):
329 """Diagnoses the OMA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000330
vladlosev4c915512010-09-25 00:52:20 +0000331 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
332 r'call to \'Invoke\(.+, <unresolved overloaded function '
333 r'type>\)')
334 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
335 r'for call to \'Invoke\'\r?\n'
336 r'(.*\n)*?'
kosak6e108722015-07-28 00:53:13 +0000337 r'.*\bgmock-generated-actions\.h:\d+:\d+: '
vladlosev4c915512010-09-25 00:52:20 +0000338 r'note: candidate function template not viable: '
zhanyong.wan2fd619e2012-05-31 20:40:56 +0000339 r'requires .*, but 2 (arguments )?were provided')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000340 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000341The second argument you gave to Invoke() is an overloaded method. Please
vladlosev4c915512010-09-25 00:52:20 +0000342tell your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000343
344For example, if you want to use the version whose signature is
345 class Foo {
346 ...
347 bool Bar(int n, double x);
348 };
349you should write something like
350 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
351 return _GenericDiagnoser('OMA', 'Overloaded Method Action',
vladlosev4c915512010-09-25 00:52:20 +0000352 [(gcc_regex, diagnosis),
353 (clang_regex, diagnosis)],
354 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000355
356
357def _MockObjectPointerDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000358 """Diagnoses the MOP disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000359
vladlosev4c915512010-09-25 00:52:20 +0000360 gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
361 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
362 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
363 clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
364 r'\'(?P<class_name>.*?) *\' is a pointer; '
kosak6305ff52015-04-28 22:36:31 +0000365 r'(did you mean|maybe you meant) to use \'->\'\?')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000366 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000367The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
368not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
369'%(mock_object)s' as your first argument.
370
371For example, given the mock class:
372
373 class %(class_name)s : public ... {
374 ...
375 MOCK_METHOD0(%(method)s, ...);
376 };
377
378and the following mock instance:
379
380 %(class_name)s* mock_ptr = ...
381
382you should use the EXPECT_CALL like this:
383
384 EXPECT_CALL(*mock_ptr, %(method)s(...));"""
shiqiane35fdd92008-12-10 05:08:54 +0000385
vladlosev4c915512010-09-25 00:52:20 +0000386 return _GenericDiagnoser(
387 'MOP',
388 'Mock Object Pointer',
389 [(gcc_regex, diagnosis),
390 (clang_regex, diagnosis % {'mock_object': 'mock_object',
391 'method': 'method',
392 'class_name': '%(class_name)s'})],
393 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000394
395
396def _NeedToUseSymbolDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000397 """Diagnoses the NUS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000398
vladlosev4c915512010-09-25 00:52:20 +0000399 gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
400 r'(was not declared in this scope|has not been declared)')
vladlosev787146b2011-08-16 00:51:14 +0000401 clang_regex = (_CLANG_FILE_LINE_RE +
vladloseveca38cd2011-08-25 21:35:10 +0000402 r'error: (use of undeclared identifier|unknown type name|'
403 r'no template named) \'(?P<symbol>[^\']+)\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000404 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000405'%(symbol)s' is defined by Google Mock in the testing namespace.
406Did you forget to write
407 using testing::%(symbol)s;
408?"""
vladlosev4c915512010-09-25 00:52:20 +0000409 for m in (list(_FindAllMatches(gcc_regex, msg)) +
410 list(_FindAllMatches(clang_regex, msg))):
shiqiane35fdd92008-12-10 05:08:54 +0000411 symbol = m.groupdict()['symbol']
412 if symbol in _COMMON_GMOCK_SYMBOLS:
413 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
414
415
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000416def _NeedToUseReturnNullDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000417 """Diagnoses the NRNULL disease, given the error messages by the compiler."""
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000418
vladlosev4c915512010-09-25 00:52:20 +0000419 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
420 '::operator testing::Action<Func>\(\) const.*\n' +
421 _GCC_FILE_LINE_RE + r'instantiated from here\n'
zhanyong.wan5b61ce32011-02-01 00:00:03 +0000422 r'.*error: no matching function for call to \'ImplicitCast_\('
jgm79a367e2012-04-10 16:02:11 +0000423 r'(:?long )?int&\)')
vladlosev4c915512010-09-25 00:52:20 +0000424 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
zhanyong.wan5b61ce32011-02-01 00:00:03 +0000425 r'call to \'ImplicitCast_\'\r?\n'
vladlosev4c915512010-09-25 00:52:20 +0000426 r'(.*\n)*?' +
427 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
428 r'of function template specialization '
vladlosevf44bdc72011-10-24 17:48:54 +0000429 r'\'testing::internal::ReturnAction<(int|long)>::operator '
vladlosev4c915512010-09-25 00:52:20 +0000430 r'Action<(?P<type>.*)\(\)>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000431 diagnosis = """
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000432You are probably calling Return(NULL) and the compiler isn't sure how to turn
vladlosev4c915512010-09-25 00:52:20 +0000433NULL into %(type)s. Use ReturnNull() instead.
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000434Note: the line number may be off; please fix all instances of Return(NULL)."""
vladlosev4c915512010-09-25 00:52:20 +0000435 return _GenericDiagnoser(
436 'NRNULL', 'Need to use ReturnNull',
437 [(clang_regex, diagnosis),
438 (gcc_regex, diagnosis % {'type': 'the right type'})],
439 msg)
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000440
441
vladlosev4c915512010-09-25 00:52:20 +0000442def _TypeInTemplatedBaseDiagnoser(msg):
443 """Diagnoses the TTB disease, given the error messages by the compiler."""
444
445 # This version works when the type is used as the mock function's return
446 # type.
447 gcc_4_3_1_regex_type_in_retval = (
448 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
449 r'error: a function call cannot appear in a constant-expression')
450 gcc_4_4_0_regex_type_in_retval = (
451 r'error: a function call cannot appear in a constant-expression'
452 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
453 # This version works when the type is used as the mock function's sole
454 # parameter type.
455 gcc_regex_type_of_sole_param = (
456 _GCC_FILE_LINE_RE +
457 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
458 r'.*error: template argument 1 is invalid\n')
459 # This version works when the type is used as a parameter of a mock
460 # function that has multiple parameters.
461 gcc_regex_type_of_a_param = (
462 r'error: expected `;\' before \'::\' token\n'
463 + _GCC_FILE_LINE_RE +
464 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
465 r'.*error: template argument 1 is invalid\n'
466 r'.*error: \'.+\' was not declared in this scope')
zhanyong.wana684b5a2010-12-02 23:30:50 +0000467 clang_regex_type_of_retval_or_sole_param = (
468 _CLANG_FILE_LINE_RE +
469 r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
470 r'(.*\n)*?'
vladlosev71d08622011-03-29 22:29:51 +0000471 r'(?P=file):(?P=line):\d+: error: '
zhanyong.wana684b5a2010-12-02 23:30:50 +0000472 r'non-friend class member \'Result\' cannot have a qualified name'
473 )
474 clang_regex_type_of_a_param = (
475 _CLANG_FILE_LINE_RE +
476 r'error: C\+\+ requires a type specifier for all declarations\n'
477 r'(.*\n)*?'
478 r'(?P=file):(?P=line):(?P=column): error: '
479 r'C\+\+ requires a type specifier for all declarations'
480 )
zhanyong.wan2fd619e2012-05-31 20:40:56 +0000481 clang_regex_unknown_type = (
482 _CLANG_FILE_LINE_RE +
483 r'error: unknown type name \'(?P<type>[^\']+)\''
484 )
vladlosev4c915512010-09-25 00:52:20 +0000485
486 diagnosis = """
zhanyong.wanb8243162009-06-04 05:48:20 +0000487In a mock class template, types or typedefs defined in the base class
488template are *not* automatically visible. This is how C++ works. Before
489you can use a type or typedef named %(type)s defined in base class Base<T>, you
490need to make it visible. One way to do it is:
491
492 typedef typename Base<T>::%(type)s %(type)s;"""
493
zhanyong.wan2fd619e2012-05-31 20:40:56 +0000494 for diag in _GenericDiagnoser(
vladlosev4c915512010-09-25 00:52:20 +0000495 'TTB', 'Type in Template Base',
496 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
497 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
498 (gcc_regex_type_of_sole_param, diagnosis),
zhanyong.wana684b5a2010-12-02 23:30:50 +0000499 (gcc_regex_type_of_a_param, diagnosis),
500 (clang_regex_type_of_retval_or_sole_param, diagnosis),
501 (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})],
zhanyong.wan2fd619e2012-05-31 20:40:56 +0000502 msg):
503 yield diag
504 # Avoid overlap with the NUS pattern.
505 for m in _FindAllMatches(clang_regex_unknown_type, msg):
506 type_ = m.groupdict()['type']
507 if type_ not in _COMMON_GMOCK_SYMBOLS:
508 yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict())
zhanyong.wanb8243162009-06-04 05:48:20 +0000509
510
zhanyong.wan16cf4732009-05-14 20:55:30 +0000511def _WrongMockMethodMacroDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000512 """Diagnoses the WMM disease, given the error messages by the compiler."""
zhanyong.wan16cf4732009-05-14 20:55:30 +0000513
vladlosev4c915512010-09-25 00:52:20 +0000514 gcc_regex = (_GCC_FILE_LINE_RE +
515 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
516 r'.*\n'
517 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
518 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
zhanyong.wan5b61ce32011-02-01 00:00:03 +0000519 r'error:.*array.*negative.*r?\n'
vladlosev4c915512010-09-25 00:52:20 +0000520 r'(.*\n)*?'
521 r'(?P=file):(?P=line):(?P=column): error: too few arguments '
522 r'to function call, expected (?P<args>\d+), '
523 r'have (?P<wrong_args>\d+)')
kosak6e87b782014-11-17 02:22:20 +0000524 clang11_re = (_CLANG_NON_GMOCK_FILE_LINE_RE +
525 r'.*this_method_does_not_take_'
526 r'(?P<wrong_args>\d+)_argument.*')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000527 diagnosis = """
zhanyong.wan16cf4732009-05-14 20:55:30 +0000528You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
529%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
530MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
zhanyong.wanb8243162009-06-04 05:48:20 +0000531 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
vladlosev4c915512010-09-25 00:52:20 +0000532 [(gcc_regex, diagnosis),
kosak6e87b782014-11-17 02:22:20 +0000533 (clang11_re, diagnosis % {'wrong_args': 'm',
534 'args': 'n'}),
vladlosev4c915512010-09-25 00:52:20 +0000535 (clang_regex, diagnosis)],
536 msg)
zhanyong.wan16cf4732009-05-14 20:55:30 +0000537
538
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000539def _WrongParenPositionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000540 """Diagnoses the WPP disease, given the error messages by the compiler."""
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000541
vladlosev4c915512010-09-25 00:52:20 +0000542 gcc_regex = (_GCC_FILE_LINE_RE +
543 r'error:.*testing::internal::MockSpec<.* has no member named \''
544 r'(?P<method>\w+)\'')
545 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
546 r'error: no member named \'(?P<method>\w+)\' in '
547 r'\'testing::internal::MockSpec<.*>\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000548 diagnosis = """
549The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
550".%(method)s". For example, you should write:
551 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
552instead of:
553 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
zhanyong.wanb8243162009-06-04 05:48:20 +0000554 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
vladlosev4c915512010-09-25 00:52:20 +0000555 [(gcc_regex, diagnosis),
556 (clang_regex, diagnosis)],
557 msg)
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000558
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000559
shiqiane35fdd92008-12-10 05:08:54 +0000560_DIAGNOSERS = [
561 _IncompleteByReferenceArgumentDiagnoser,
562 _MockObjectPointerDiagnoser,
563 _NeedToReturnNothingDiagnoser,
564 _NeedToReturnReferenceDiagnoser,
565 _NeedToReturnSomethingDiagnoser,
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000566 _NeedToUseReturnNullDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000567 _NeedToUseSymbolDiagnoser,
568 _OverloadedFunctionActionDiagnoser,
569 _OverloadedFunctionMatcherDiagnoser,
vladlosev4c915512010-09-25 00:52:20 +0000570 _OverloadedMethodActionDiagnoser,
571 _TypeInTemplatedBaseDiagnoser,
zhanyong.wan16cf4732009-05-14 20:55:30 +0000572 _WrongMockMethodMacroDiagnoser,
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000573 _WrongParenPositionDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000574 ]
575
576
577def Diagnose(msg):
vladlosev4c915512010-09-25 00:52:20 +0000578 """Generates all possible diagnoses given the compiler error message."""
579
580 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting.
vladlosev0fd83962011-09-28 18:32:59 +0000581 # Assuming the string is using the UTF-8 encoding, replaces the left and
582 # the right single quote characters with apostrophes.
583 msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg)
shiqiane35fdd92008-12-10 05:08:54 +0000584
zhanyong.wan099e3b92009-12-09 17:58:37 +0000585 diagnoses = []
shiqiane35fdd92008-12-10 05:08:54 +0000586 for diagnoser in _DIAGNOSERS:
zhanyong.wan099e3b92009-12-09 17:58:37 +0000587 for diag in diagnoser(msg):
588 diagnosis = '[%s - %s]\n%s' % diag
589 if not diagnosis in diagnoses:
590 diagnoses.append(diagnosis)
591 return diagnoses
shiqiane35fdd92008-12-10 05:08:54 +0000592
593
594def main():
595 print ('Google Mock Doctor v%s - '
596 'diagnoses problems in code using Google Mock.' % _VERSION)
597
598 if sys.stdin.isatty():
599 print ('Please copy and paste the compiler errors here. Press c-D when '
600 'you are done:')
601 else:
Sylac830d62015-08-30 08:57:48 +0200602 print ('Waiting for compiler errors on stdin . . .')
shiqiane35fdd92008-12-10 05:08:54 +0000603
604 msg = sys.stdin.read().strip()
zhanyong.wan099e3b92009-12-09 17:58:37 +0000605 diagnoses = Diagnose(msg)
shiqiane35fdd92008-12-10 05:08:54 +0000606 count = len(diagnoses)
607 if not count:
vladlosev662d8a22010-09-29 00:38:12 +0000608 print ("""
609Your compiler complained:
6108<------------------------------------------------------------
611%s
612------------------------------------------------------------>8
613
shiqiane35fdd92008-12-10 05:08:54 +0000614Uh-oh, I'm not smart enough to figure out what the problem is. :-(
615However...
vladlosev4c915512010-09-25 00:52:20 +0000616If you send your source code and the compiler's error messages to
vladlosev662d8a22010-09-29 00:38:12 +0000617%s, you can be helped and I can get smarter --
618win-win for us!""" % (msg, _EMAIL))
shiqiane35fdd92008-12-10 05:08:54 +0000619 else:
Sylac830d62015-08-30 08:57:48 +0200620 print ('------------------------------------------------------------')
621 print ('Your code appears to have the following',)
shiqiane35fdd92008-12-10 05:08:54 +0000622 if count > 1:
Sylac830d62015-08-30 08:57:48 +0200623 print ('%s diseases:' % (count,))
shiqiane35fdd92008-12-10 05:08:54 +0000624 else:
Sylac830d62015-08-30 08:57:48 +0200625 print ('disease:')
shiqiane35fdd92008-12-10 05:08:54 +0000626 i = 0
627 for d in diagnoses:
628 i += 1
629 if count > 1:
Sylac830d62015-08-30 08:57:48 +0200630 print ('\n#%s:' % (i,))
631 print (d)
vladlosev662d8a22010-09-29 00:38:12 +0000632 print ("""
shiqiane35fdd92008-12-10 05:08:54 +0000633How did I do? If you think I'm wrong or unhelpful, please send your
vladlosev662d8a22010-09-29 00:38:12 +0000634source code and the compiler's error messages to %s.
635Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
636 _EMAIL)
shiqiane35fdd92008-12-10 05:08:54 +0000637
638
639if __name__ == '__main__':
640 main()