blob: 1918cf6cf6cceb3fb3fa9c0d04101662968fd91f [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
41_COMMON_GMOCK_SYMBOLS = [
42 # Matchers
43 '_',
44 'A',
45 'AddressSatisfies',
46 'AllOf',
47 'An',
48 'AnyOf',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000049 'ContainerEq',
50 'Contains',
shiqiane35fdd92008-12-10 05:08:54 +000051 'ContainsRegex',
52 'DoubleEq',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000053 'ElementsAre',
54 'ElementsAreArray',
shiqiane35fdd92008-12-10 05:08:54 +000055 'EndsWith',
56 'Eq',
57 'Field',
58 'FloatEq',
59 'Ge',
60 'Gt',
61 'HasSubstr',
zhanyong.wan5b95fa72009-01-27 22:28:45 +000062 'IsInitializedProto',
shiqiane35fdd92008-12-10 05:08:54 +000063 'Le',
64 'Lt',
65 'MatcherCast',
zhanyong.wanb8243162009-06-04 05:48:20 +000066 'Matches',
shiqiane35fdd92008-12-10 05:08:54 +000067 'MatchesRegex',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000068 'NanSensitiveDoubleEq',
69 'NanSensitiveFloatEq',
shiqiane35fdd92008-12-10 05:08:54 +000070 'Ne',
71 'Not',
72 'NotNull',
73 'Pointee',
74 'Property',
75 'Ref',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000076 'ResultOf',
77 'SafeMatcherCast',
shiqiane35fdd92008-12-10 05:08:54 +000078 'StartsWith',
79 'StrCaseEq',
80 'StrCaseNe',
81 'StrEq',
82 'StrNe',
83 'Truly',
84 'TypedEq',
zhanyong.wanb8243162009-06-04 05:48:20 +000085 'Value',
shiqiane35fdd92008-12-10 05:08:54 +000086
87 # Actions
zhanyong.wan9413f2f2009-05-29 19:50:06 +000088 'Assign',
shiqiane35fdd92008-12-10 05:08:54 +000089 'ByRef',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000090 'DeleteArg',
shiqiane35fdd92008-12-10 05:08:54 +000091 'DoAll',
92 'DoDefault',
93 'IgnoreResult',
94 'Invoke',
95 'InvokeArgument',
96 'InvokeWithoutArgs',
97 'Return',
zhanyong.wan9413f2f2009-05-29 19:50:06 +000098 'ReturnNew',
shiqiane35fdd92008-12-10 05:08:54 +000099 'ReturnNull',
100 'ReturnRef',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000101 'SaveArg',
102 'SetArgReferee',
shiqiane35fdd92008-12-10 05:08:54 +0000103 'SetArgumentPointee',
104 'SetArrayArgument',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000105 'SetErrnoAndReturn',
106 'Throw',
107 'WithArg',
shiqiane35fdd92008-12-10 05:08:54 +0000108 'WithArgs',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000109 'WithoutArgs',
shiqiane35fdd92008-12-10 05:08:54 +0000110
111 # Cardinalities
112 'AnyNumber',
113 'AtLeast',
114 'AtMost',
115 'Between',
116 'Exactly',
117
118 # Sequences
119 'InSequence',
120 'Sequence',
121
122 # Misc
123 'DefaultValue',
124 'Mock',
125 ]
126
vladlosev4c915512010-09-25 00:52:20 +0000127# Regex for matching source file path and line number in the compiler's errors.
128_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+'
129_CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
130_CLANG_NON_GMOCK_FILE_LINE_RE = (
131 r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000132
shiqiane35fdd92008-12-10 05:08:54 +0000133
134def _FindAllMatches(regex, s):
135 """Generates all matches of regex in string s."""
136
137 r = re.compile(regex)
138 return r.finditer(s)
139
140
vladlosev4c915512010-09-25 00:52:20 +0000141def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
shiqiane35fdd92008-12-10 05:08:54 +0000142 """Diagnoses the given disease by pattern matching.
143
vladlosev4c915512010-09-25 00:52:20 +0000144 Can provide different diagnoses for different patterns.
145
shiqiane35fdd92008-12-10 05:08:54 +0000146 Args:
147 short_name: Short name of the disease.
148 long_name: Long name of the disease.
vladlosev4c915512010-09-25 00:52:20 +0000149 diagnoses: A list of pairs (regex, pattern for formatting the diagnosis
150 for matching regex).
151 msg: Compiler's error messages.
shiqiane35fdd92008-12-10 05:08:54 +0000152 Yields:
153 Tuples of the form
154 (short name of disease, long name of disease, diagnosis).
155 """
vladlosev4c915512010-09-25 00:52:20 +0000156 for regex, diagnosis in diagnoses:
157 if re.search(regex, msg):
158 diagnosis = '%(file)s:%(line)s:' + diagnosis
159 for m in _FindAllMatches(regex, msg):
160 yield (short_name, long_name, diagnosis % m.groupdict())
shiqiane35fdd92008-12-10 05:08:54 +0000161
162
163def _NeedToReturnReferenceDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000164 """Diagnoses the NRR disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000165
vladlosev4c915512010-09-25 00:52:20 +0000166 gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
167 + _GCC_FILE_LINE_RE + r'instantiated from here\n'
168 r'.*gmock-actions\.h.*error: creating array with negative size')
169 clang_regex = (r'error: array size is negative\r?\n'
170 r'(.*\n)*?' +
171 _CLANG_NON_GMOCK_FILE_LINE_RE +
172 r'note: in instantiation of function template specialization '
173 r'\'testing::internal::ReturnAction<(?P<type>).*>'
174 r'::operator Action<.*>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000175 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000176You are using a Return() action in a function that returns a reference to
177%(type)s. Please use ReturnRef() instead."""
shiqiane35fdd92008-12-10 05:08:54 +0000178 return _GenericDiagnoser('NRR', 'Need to Return Reference',
vladlosev4c915512010-09-25 00:52:20 +0000179 [(clang_regex, diagnosis),
180 (gcc_regex, diagnosis % {'type': 'a type'})],
181 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000182
183
184def _NeedToReturnSomethingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000185 """Diagnoses the NRS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000186
vladlosev4c915512010-09-25 00:52:20 +0000187 gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
188 r'*gmock.*actions\.h.*error: void value not ignored)'
189 r'|(error: control reaches end of non-void function)')
190 clang_regex1 = (_CLANG_FILE_LINE_RE +
191 r'error: cannot initialize return object '
192 r'of type \'Result\' \(aka \'(?P<return_type>).*\'\) '
193 r'with an rvalue of type \'void\'')
194 clang_regex2 = (_CLANG_FILE_LINE_RE +
195 r'error: cannot initialize return object '
196 r'of type \'(?P<return_type>).*\' '
197 r'with an rvalue of type \'void\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000198 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000199You are using an action that returns void, but it needs to return
vladlosev4c915512010-09-25 00:52:20 +0000200%(return_type)s. Please tell it *what* to return. Perhaps you can use
zhanyong.wan16cf4732009-05-14 20:55:30 +0000201the pattern DoAll(some_action, Return(some_value))?"""
vladlosev4c915512010-09-25 00:52:20 +0000202 return _GenericDiagnoser(
203 'NRS',
204 'Need to Return Something',
205 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
206 (clang_regex1, diagnosis),
207 (clang_regex2, diagnosis)],
208 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000209
210
211def _NeedToReturnNothingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000212 """Diagnoses the NRN disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000213
vladlosev4c915512010-09-25 00:52:20 +0000214 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
215 r'.*gmock-actions\.h.*error: instantiation of '
216 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
217 r'as type \'void\'')
218 clang_regex1 = (r'error: field has incomplete type '
219 r'\'Result\' \(aka \'void\'\)(\r)?\n'
220 r'(.*\n)*?' +
221 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
222 r'of function template specialization '
223 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
224 r'::operator Action<void \(.*\)>\' requested here')
225 clang_regex2 = (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::DoBothAction<.*>'
231 r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
232 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000233 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000234You are using an action that returns %(return_type)s, but it needs to return
shiqiane35fdd92008-12-10 05:08:54 +0000235void. Please use a void-returning action instead.
236
237All actions but the last in DoAll(...) must return void. Perhaps you need
238to re-arrange the order of actions in a DoAll(), if you are using one?"""
vladlosev4c915512010-09-25 00:52:20 +0000239 return _GenericDiagnoser(
240 'NRN',
241 'Need to Return Nothing',
242 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
243 (clang_regex1, diagnosis),
244 (clang_regex2, diagnosis)],
245 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000246
247
248def _IncompleteByReferenceArgumentDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000249 """Diagnoses the IBRA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000250
vladlosev4c915512010-09-25 00:52:20 +0000251 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
252 r'.*gtest-printers\.h.*error: invalid application of '
253 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
254
255 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
256 r'\'sizeof\' to an incomplete type '
257 r'\'(?P<type>.*)( const)?\'\r?\n'
258 r'(.*\n)*?' +
259 _CLANG_NON_GMOCK_FILE_LINE_RE +
260 r'note: in instantiation of member function '
261 r'\'testing::internal::FunctionMocker<.*>::Invoke\' '
262 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000263 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000264In order to mock this function, Google Mock needs to see the definition
265of type "%(type)s" - declaration alone is not enough. Either #include
266the header that defines it, or change the argument to be passed
267by pointer."""
vladlosev4c915512010-09-25 00:52:20 +0000268
shiqiane35fdd92008-12-10 05:08:54 +0000269 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
vladlosev4c915512010-09-25 00:52:20 +0000270 [(gcc_regex, diagnosis),
271 (clang_regex, diagnosis)],
272 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000273
274
275def _OverloadedFunctionMatcherDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000276 """Diagnoses the OFM disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000277
vladlosev4c915512010-09-25 00:52:20 +0000278 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
279 r'call to \'Truly\(<unresolved overloaded function type>\)')
280 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
281 r'call to \'Truly')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000282 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000283The argument you gave to Truly() is an overloaded function. Please tell
vladlosev4c915512010-09-25 00:52:20 +0000284your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000285
286For example, if you want to use the version whose signature is
287 bool Foo(int n);
288you should write
289 Truly(static_cast<bool (*)(int n)>(Foo))"""
290 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
vladlosev4c915512010-09-25 00:52:20 +0000291 [(gcc_regex, diagnosis),
292 (clang_regex, diagnosis)],
293 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000294
295
296def _OverloadedFunctionActionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000297 """Diagnoses the OFA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000298
vladlosev4c915512010-09-25 00:52:20 +0000299 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
300 r'\'Invoke\(<unresolved overloaded function type>')
301 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
302 r'function for call to \'Invoke\'\r?\n'
303 r'(.*\n)*?'
304 r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+'
305 r'note: candidate template ignored:\s+'
306 r'couldn\'t infer template argument \'FunctionImpl\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000307 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000308Function you are passing to Invoke is overloaded. Please tell your compiler
shiqiane35fdd92008-12-10 05:08:54 +0000309which overloaded version you want to use.
310
311For example, if you want to use the version whose signature is
312 bool MyFunction(int n, double x);
313you should write something like
314 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
315 return _GenericDiagnoser('OFA', 'Overloaded Function Action',
vladlosev4c915512010-09-25 00:52:20 +0000316 [(gcc_regex, diagnosis),
317 (clang_regex, diagnosis)],
318 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000319
320
vladlosev4c915512010-09-25 00:52:20 +0000321def _OverloadedMethodActionDiagnoser(msg):
322 """Diagnoses the OMA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000323
vladlosev4c915512010-09-25 00:52:20 +0000324 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
325 r'call to \'Invoke\(.+, <unresolved overloaded function '
326 r'type>\)')
327 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
328 r'for call to \'Invoke\'\r?\n'
329 r'(.*\n)*?'
330 r'.*\bgmock-\w+-actions\.h:\d+:\d+: '
331 r'note: candidate function template not viable: '
332 r'requires 1 argument, but 2 were provided')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000333 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000334The second argument you gave to Invoke() is an overloaded method. Please
vladlosev4c915512010-09-25 00:52:20 +0000335tell your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000336
337For example, if you want to use the version whose signature is
338 class Foo {
339 ...
340 bool Bar(int n, double x);
341 };
342you should write something like
343 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
344 return _GenericDiagnoser('OMA', 'Overloaded Method Action',
vladlosev4c915512010-09-25 00:52:20 +0000345 [(gcc_regex, diagnosis),
346 (clang_regex, diagnosis)],
347 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000348
349
350def _MockObjectPointerDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000351 """Diagnoses the MOP disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000352
vladlosev4c915512010-09-25 00:52:20 +0000353 gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
354 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
355 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
356 clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
357 r'\'(?P<class_name>.*?) *\' is a pointer; '
358 r'maybe you meant to use \'->\'\?')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000359 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000360The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
361not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
362'%(mock_object)s' as your first argument.
363
364For example, given the mock class:
365
366 class %(class_name)s : public ... {
367 ...
368 MOCK_METHOD0(%(method)s, ...);
369 };
370
371and the following mock instance:
372
373 %(class_name)s* mock_ptr = ...
374
375you should use the EXPECT_CALL like this:
376
377 EXPECT_CALL(*mock_ptr, %(method)s(...));"""
shiqiane35fdd92008-12-10 05:08:54 +0000378
vladlosev4c915512010-09-25 00:52:20 +0000379 return _GenericDiagnoser(
380 'MOP',
381 'Mock Object Pointer',
382 [(gcc_regex, diagnosis),
383 (clang_regex, diagnosis % {'mock_object': 'mock_object',
384 'method': 'method',
385 'class_name': '%(class_name)s'})],
386 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000387
388
389def _NeedToUseSymbolDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000390 """Diagnoses the NUS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000391
vladlosev4c915512010-09-25 00:52:20 +0000392 gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
393 r'(was not declared in this scope|has not been declared)')
394 clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier '
395 r'\'(?P<symbol>.+)\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000396 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000397'%(symbol)s' is defined by Google Mock in the testing namespace.
398Did you forget to write
399 using testing::%(symbol)s;
400?"""
vladlosev4c915512010-09-25 00:52:20 +0000401 for m in (list(_FindAllMatches(gcc_regex, msg)) +
402 list(_FindAllMatches(clang_regex, msg))):
shiqiane35fdd92008-12-10 05:08:54 +0000403 symbol = m.groupdict()['symbol']
404 if symbol in _COMMON_GMOCK_SYMBOLS:
405 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
406
407
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000408def _NeedToUseReturnNullDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000409 """Diagnoses the NRNULL disease, given the error messages by the compiler."""
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000410
vladlosev4c915512010-09-25 00:52:20 +0000411 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
412 '::operator testing::Action<Func>\(\) const.*\n' +
413 _GCC_FILE_LINE_RE + r'instantiated from here\n'
414 r'.*error: no matching function for call to \'implicit_cast\('
415 r'long int&\)')
416 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
417 r'call to \'implicit_cast\'\r?\n'
418 r'(.*\n)*?' +
419 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
420 r'of function template specialization '
421 r'\'testing::internal::ReturnAction<long>::operator '
422 r'Action<(?P<type>.*)\(\)>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000423 diagnosis = """
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000424You are probably calling Return(NULL) and the compiler isn't sure how to turn
vladlosev4c915512010-09-25 00:52:20 +0000425NULL into %(type)s. Use ReturnNull() instead.
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000426Note: the line number may be off; please fix all instances of Return(NULL)."""
vladlosev4c915512010-09-25 00:52:20 +0000427 return _GenericDiagnoser(
428 'NRNULL', 'Need to use ReturnNull',
429 [(clang_regex, diagnosis),
430 (gcc_regex, diagnosis % {'type': 'the right type'})],
431 msg)
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000432
433
vladlosev4c915512010-09-25 00:52:20 +0000434def _TypeInTemplatedBaseDiagnoser(msg):
435 """Diagnoses the TTB disease, given the error messages by the compiler."""
436
437 # This version works when the type is used as the mock function's return
438 # type.
439 gcc_4_3_1_regex_type_in_retval = (
440 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
441 r'error: a function call cannot appear in a constant-expression')
442 gcc_4_4_0_regex_type_in_retval = (
443 r'error: a function call cannot appear in a constant-expression'
444 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
445 # This version works when the type is used as the mock function's sole
446 # parameter type.
447 gcc_regex_type_of_sole_param = (
448 _GCC_FILE_LINE_RE +
449 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
450 r'.*error: template argument 1 is invalid\n')
451 # This version works when the type is used as a parameter of a mock
452 # function that has multiple parameters.
453 gcc_regex_type_of_a_param = (
454 r'error: expected `;\' before \'::\' token\n'
455 + _GCC_FILE_LINE_RE +
456 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
457 r'.*error: template argument 1 is invalid\n'
458 r'.*error: \'.+\' was not declared in this scope')
459
460 diagnosis = """
zhanyong.wanb8243162009-06-04 05:48:20 +0000461In a mock class template, types or typedefs defined in the base class
462template are *not* automatically visible. This is how C++ works. Before
463you can use a type or typedef named %(type)s defined in base class Base<T>, you
464need to make it visible. One way to do it is:
465
466 typedef typename Base<T>::%(type)s %(type)s;"""
467
vladlosev4c915512010-09-25 00:52:20 +0000468 return _GenericDiagnoser(
469 'TTB', 'Type in Template Base',
470 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
471 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
472 (gcc_regex_type_of_sole_param, diagnosis),
473 (gcc_regex_type_of_a_param, diagnosis)],
474 msg)
zhanyong.wanb8243162009-06-04 05:48:20 +0000475
476
zhanyong.wan16cf4732009-05-14 20:55:30 +0000477def _WrongMockMethodMacroDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000478 """Diagnoses the WMM disease, given the error messages by the compiler."""
zhanyong.wan16cf4732009-05-14 20:55:30 +0000479
vladlosev4c915512010-09-25 00:52:20 +0000480 gcc_regex = (_GCC_FILE_LINE_RE +
481 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
482 r'.*\n'
483 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
484 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
485 r'error: array size is negative\r?\n'
486 r'(.*\n)*?'
487 r'(?P=file):(?P=line):(?P=column): error: too few arguments '
488 r'to function call, expected (?P<args>\d+), '
489 r'have (?P<wrong_args>\d+)')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000490 diagnosis = """
zhanyong.wan16cf4732009-05-14 20:55:30 +0000491You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
492%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
493MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
zhanyong.wanb8243162009-06-04 05:48:20 +0000494 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
vladlosev4c915512010-09-25 00:52:20 +0000495 [(gcc_regex, diagnosis),
496 (clang_regex, diagnosis)],
497 msg)
zhanyong.wan16cf4732009-05-14 20:55:30 +0000498
499
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000500def _WrongParenPositionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000501 """Diagnoses the WPP disease, given the error messages by the compiler."""
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000502
vladlosev4c915512010-09-25 00:52:20 +0000503 gcc_regex = (_GCC_FILE_LINE_RE +
504 r'error:.*testing::internal::MockSpec<.* has no member named \''
505 r'(?P<method>\w+)\'')
506 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
507 r'error: no member named \'(?P<method>\w+)\' in '
508 r'\'testing::internal::MockSpec<.*>\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000509 diagnosis = """
510The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
511".%(method)s". For example, you should write:
512 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
513instead of:
514 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
zhanyong.wanb8243162009-06-04 05:48:20 +0000515 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
vladlosev4c915512010-09-25 00:52:20 +0000516 [(gcc_regex, diagnosis),
517 (clang_regex, diagnosis)],
518 msg)
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000519
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000520
shiqiane35fdd92008-12-10 05:08:54 +0000521_DIAGNOSERS = [
522 _IncompleteByReferenceArgumentDiagnoser,
523 _MockObjectPointerDiagnoser,
524 _NeedToReturnNothingDiagnoser,
525 _NeedToReturnReferenceDiagnoser,
526 _NeedToReturnSomethingDiagnoser,
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000527 _NeedToUseReturnNullDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000528 _NeedToUseSymbolDiagnoser,
529 _OverloadedFunctionActionDiagnoser,
530 _OverloadedFunctionMatcherDiagnoser,
vladlosev4c915512010-09-25 00:52:20 +0000531 _OverloadedMethodActionDiagnoser,
532 _TypeInTemplatedBaseDiagnoser,
zhanyong.wan16cf4732009-05-14 20:55:30 +0000533 _WrongMockMethodMacroDiagnoser,
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000534 _WrongParenPositionDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000535 ]
536
537
538def Diagnose(msg):
vladlosev4c915512010-09-25 00:52:20 +0000539 """Generates all possible diagnoses given the compiler error message."""
540
541 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting.
shiqiane35fdd92008-12-10 05:08:54 +0000542
zhanyong.wan099e3b92009-12-09 17:58:37 +0000543 diagnoses = []
shiqiane35fdd92008-12-10 05:08:54 +0000544 for diagnoser in _DIAGNOSERS:
zhanyong.wan099e3b92009-12-09 17:58:37 +0000545 for diag in diagnoser(msg):
546 diagnosis = '[%s - %s]\n%s' % diag
547 if not diagnosis in diagnoses:
548 diagnoses.append(diagnosis)
549 return diagnoses
shiqiane35fdd92008-12-10 05:08:54 +0000550
551
552def main():
553 print ('Google Mock Doctor v%s - '
554 'diagnoses problems in code using Google Mock.' % _VERSION)
555
556 if sys.stdin.isatty():
557 print ('Please copy and paste the compiler errors here. Press c-D when '
558 'you are done:')
559 else:
560 print 'Waiting for compiler errors on stdin . . .'
561
562 msg = sys.stdin.read().strip()
zhanyong.wan099e3b92009-12-09 17:58:37 +0000563 diagnoses = Diagnose(msg)
shiqiane35fdd92008-12-10 05:08:54 +0000564 count = len(diagnoses)
565 if not count:
566 print '\nGcc complained:'
567 print '8<------------------------------------------------------------'
568 print msg
569 print '------------------------------------------------------------>8'
570 print """
571Uh-oh, I'm not smart enough to figure out what the problem is. :-(
572However...
vladlosev4c915512010-09-25 00:52:20 +0000573If you send your source code and the compiler's error messages to
shiqiane35fdd92008-12-10 05:08:54 +0000574googlemock@googlegroups.com, you can be helped and I can get smarter --
575win-win for us!"""
576 else:
577 print '------------------------------------------------------------'
578 print 'Your code appears to have the following',
579 if count > 1:
580 print '%s diseases:' % (count,)
581 else:
582 print 'disease:'
583 i = 0
584 for d in diagnoses:
585 i += 1
586 if count > 1:
587 print '\n#%s:' % (i,)
588 print d
589 print """
590How did I do? If you think I'm wrong or unhelpful, please send your
vladlosev4c915512010-09-25 00:52:20 +0000591source code and compiler's error messages to googlemock@googlegroups.com.
592Then you can be helped and I can get smarter -- I promise I won't be upset!"""
shiqiane35fdd92008-12-10 05:08:54 +0000593
594
595if __name__ == '__main__':
596 main()