blob: 4a41abfc682df01dbf7e5bb41f61deb3ab1c658d [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',
shiqiane35fdd92008-12-10 05:08:54 +0000105 'SetArgumentPointee',
106 'SetArrayArgument',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000107 'SetErrnoAndReturn',
108 'Throw',
109 'WithArg',
shiqiane35fdd92008-12-10 05:08:54 +0000110 'WithArgs',
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000111 'WithoutArgs',
shiqiane35fdd92008-12-10 05:08:54 +0000112
113 # Cardinalities
114 'AnyNumber',
115 'AtLeast',
116 'AtMost',
117 'Between',
118 'Exactly',
119
120 # Sequences
121 'InSequence',
122 'Sequence',
123
124 # Misc
125 'DefaultValue',
126 'Mock',
127 ]
128
vladlosev4c915512010-09-25 00:52:20 +0000129# Regex for matching source file path and line number in the compiler's errors.
130_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+'
131_CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
132_CLANG_NON_GMOCK_FILE_LINE_RE = (
133 r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000134
shiqiane35fdd92008-12-10 05:08:54 +0000135
136def _FindAllMatches(regex, s):
137 """Generates all matches of regex in string s."""
138
139 r = re.compile(regex)
140 return r.finditer(s)
141
142
vladlosev4c915512010-09-25 00:52:20 +0000143def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
shiqiane35fdd92008-12-10 05:08:54 +0000144 """Diagnoses the given disease by pattern matching.
145
vladlosev4c915512010-09-25 00:52:20 +0000146 Can provide different diagnoses for different patterns.
147
shiqiane35fdd92008-12-10 05:08:54 +0000148 Args:
149 short_name: Short name of the disease.
150 long_name: Long name of the disease.
vladlosev4c915512010-09-25 00:52:20 +0000151 diagnoses: A list of pairs (regex, pattern for formatting the diagnosis
152 for matching regex).
153 msg: Compiler's error messages.
shiqiane35fdd92008-12-10 05:08:54 +0000154 Yields:
155 Tuples of the form
156 (short name of disease, long name of disease, diagnosis).
157 """
vladlosev4c915512010-09-25 00:52:20 +0000158 for regex, diagnosis in diagnoses:
159 if re.search(regex, msg):
160 diagnosis = '%(file)s:%(line)s:' + diagnosis
161 for m in _FindAllMatches(regex, msg):
162 yield (short_name, long_name, diagnosis % m.groupdict())
shiqiane35fdd92008-12-10 05:08:54 +0000163
164
165def _NeedToReturnReferenceDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000166 """Diagnoses the NRR disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000167
vladlosev4c915512010-09-25 00:52:20 +0000168 gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
169 + _GCC_FILE_LINE_RE + r'instantiated from here\n'
170 r'.*gmock-actions\.h.*error: creating array with negative size')
171 clang_regex = (r'error: array size is negative\r?\n'
172 r'(.*\n)*?' +
173 _CLANG_NON_GMOCK_FILE_LINE_RE +
174 r'note: in instantiation of function template specialization '
175 r'\'testing::internal::ReturnAction<(?P<type>).*>'
176 r'::operator Action<.*>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000177 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000178You are using a Return() action in a function that returns a reference to
179%(type)s. Please use ReturnRef() instead."""
shiqiane35fdd92008-12-10 05:08:54 +0000180 return _GenericDiagnoser('NRR', 'Need to Return Reference',
vladlosev4c915512010-09-25 00:52:20 +0000181 [(clang_regex, diagnosis),
182 (gcc_regex, diagnosis % {'type': 'a type'})],
183 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000184
185
186def _NeedToReturnSomethingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000187 """Diagnoses the NRS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000188
vladlosev4c915512010-09-25 00:52:20 +0000189 gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
190 r'*gmock.*actions\.h.*error: void value not ignored)'
191 r'|(error: control reaches end of non-void function)')
192 clang_regex1 = (_CLANG_FILE_LINE_RE +
193 r'error: cannot initialize return object '
194 r'of type \'Result\' \(aka \'(?P<return_type>).*\'\) '
195 r'with an rvalue of type \'void\'')
196 clang_regex2 = (_CLANG_FILE_LINE_RE +
197 r'error: cannot initialize return object '
198 r'of type \'(?P<return_type>).*\' '
199 r'with an rvalue of type \'void\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000200 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000201You are using an action that returns void, but it needs to return
vladlosev4c915512010-09-25 00:52:20 +0000202%(return_type)s. Please tell it *what* to return. Perhaps you can use
zhanyong.wan16cf4732009-05-14 20:55:30 +0000203the pattern DoAll(some_action, Return(some_value))?"""
vladlosev4c915512010-09-25 00:52:20 +0000204 return _GenericDiagnoser(
205 'NRS',
206 'Need to Return Something',
207 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
208 (clang_regex1, diagnosis),
209 (clang_regex2, diagnosis)],
210 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000211
212
213def _NeedToReturnNothingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000214 """Diagnoses the NRN disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000215
vladlosev4c915512010-09-25 00:52:20 +0000216 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
217 r'.*gmock-actions\.h.*error: instantiation of '
218 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
219 r'as type \'void\'')
220 clang_regex1 = (r'error: field has incomplete type '
221 r'\'Result\' \(aka \'void\'\)(\r)?\n'
222 r'(.*\n)*?' +
223 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
224 r'of function template specialization '
225 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
226 r'::operator Action<void \(.*\)>\' requested here')
227 clang_regex2 = (r'error: field has incomplete type '
228 r'\'Result\' \(aka \'void\'\)(\r)?\n'
229 r'(.*\n)*?' +
230 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
231 r'of function template specialization '
232 r'\'testing::internal::DoBothAction<.*>'
233 r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
234 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000235 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000236You are using an action that returns %(return_type)s, but it needs to return
shiqiane35fdd92008-12-10 05:08:54 +0000237void. Please use a void-returning action instead.
238
239All actions but the last in DoAll(...) must return void. Perhaps you need
240to re-arrange the order of actions in a DoAll(), if you are using one?"""
vladlosev4c915512010-09-25 00:52:20 +0000241 return _GenericDiagnoser(
242 'NRN',
243 'Need to Return Nothing',
244 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
245 (clang_regex1, diagnosis),
246 (clang_regex2, diagnosis)],
247 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000248
249
250def _IncompleteByReferenceArgumentDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000251 """Diagnoses the IBRA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000252
vladlosev4c915512010-09-25 00:52:20 +0000253 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
254 r'.*gtest-printers\.h.*error: invalid application of '
255 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
256
257 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
258 r'\'sizeof\' to an incomplete type '
259 r'\'(?P<type>.*)( const)?\'\r?\n'
260 r'(.*\n)*?' +
261 _CLANG_NON_GMOCK_FILE_LINE_RE +
262 r'note: in instantiation of member function '
263 r'\'testing::internal::FunctionMocker<.*>::Invoke\' '
264 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000265 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000266In order to mock this function, Google Mock needs to see the definition
267of type "%(type)s" - declaration alone is not enough. Either #include
268the header that defines it, or change the argument to be passed
269by pointer."""
vladlosev4c915512010-09-25 00:52:20 +0000270
shiqiane35fdd92008-12-10 05:08:54 +0000271 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
vladlosev4c915512010-09-25 00:52:20 +0000272 [(gcc_regex, diagnosis),
273 (clang_regex, diagnosis)],
274 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000275
276
277def _OverloadedFunctionMatcherDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000278 """Diagnoses the OFM disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000279
vladlosev4c915512010-09-25 00:52:20 +0000280 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
281 r'call to \'Truly\(<unresolved overloaded function type>\)')
282 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
283 r'call to \'Truly')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000284 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000285The argument you gave to Truly() is an overloaded function. Please tell
vladlosev4c915512010-09-25 00:52:20 +0000286your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000287
288For example, if you want to use the version whose signature is
289 bool Foo(int n);
290you should write
291 Truly(static_cast<bool (*)(int n)>(Foo))"""
292 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
vladlosev4c915512010-09-25 00:52:20 +0000293 [(gcc_regex, diagnosis),
294 (clang_regex, diagnosis)],
295 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000296
297
298def _OverloadedFunctionActionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000299 """Diagnoses the OFA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000300
vladlosev4c915512010-09-25 00:52:20 +0000301 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
302 r'\'Invoke\(<unresolved overloaded function type>')
303 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
304 r'function for call to \'Invoke\'\r?\n'
305 r'(.*\n)*?'
306 r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+'
307 r'note: candidate template ignored:\s+'
308 r'couldn\'t infer template argument \'FunctionImpl\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000309 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000310Function you are passing to Invoke is overloaded. Please tell your compiler
shiqiane35fdd92008-12-10 05:08:54 +0000311which overloaded version you want to use.
312
313For example, if you want to use the version whose signature is
314 bool MyFunction(int n, double x);
315you should write something like
316 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
317 return _GenericDiagnoser('OFA', 'Overloaded Function Action',
vladlosev4c915512010-09-25 00:52:20 +0000318 [(gcc_regex, diagnosis),
319 (clang_regex, diagnosis)],
320 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000321
322
vladlosev4c915512010-09-25 00:52:20 +0000323def _OverloadedMethodActionDiagnoser(msg):
324 """Diagnoses the OMA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000325
vladlosev4c915512010-09-25 00:52:20 +0000326 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
327 r'call to \'Invoke\(.+, <unresolved overloaded function '
328 r'type>\)')
329 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
330 r'for call to \'Invoke\'\r?\n'
331 r'(.*\n)*?'
332 r'.*\bgmock-\w+-actions\.h:\d+:\d+: '
333 r'note: candidate function template not viable: '
334 r'requires 1 argument, but 2 were provided')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000335 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000336The second argument you gave to Invoke() is an overloaded method. Please
vladlosev4c915512010-09-25 00:52:20 +0000337tell your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000338
339For example, if you want to use the version whose signature is
340 class Foo {
341 ...
342 bool Bar(int n, double x);
343 };
344you should write something like
345 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
346 return _GenericDiagnoser('OMA', 'Overloaded Method Action',
vladlosev4c915512010-09-25 00:52:20 +0000347 [(gcc_regex, diagnosis),
348 (clang_regex, diagnosis)],
349 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000350
351
352def _MockObjectPointerDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000353 """Diagnoses the MOP disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000354
vladlosev4c915512010-09-25 00:52:20 +0000355 gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
356 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
357 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
358 clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
359 r'\'(?P<class_name>.*?) *\' is a pointer; '
360 r'maybe you meant to use \'->\'\?')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000361 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000362The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
363not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
364'%(mock_object)s' as your first argument.
365
366For example, given the mock class:
367
368 class %(class_name)s : public ... {
369 ...
370 MOCK_METHOD0(%(method)s, ...);
371 };
372
373and the following mock instance:
374
375 %(class_name)s* mock_ptr = ...
376
377you should use the EXPECT_CALL like this:
378
379 EXPECT_CALL(*mock_ptr, %(method)s(...));"""
shiqiane35fdd92008-12-10 05:08:54 +0000380
vladlosev4c915512010-09-25 00:52:20 +0000381 return _GenericDiagnoser(
382 'MOP',
383 'Mock Object Pointer',
384 [(gcc_regex, diagnosis),
385 (clang_regex, diagnosis % {'mock_object': 'mock_object',
386 'method': 'method',
387 'class_name': '%(class_name)s'})],
388 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000389
390
391def _NeedToUseSymbolDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000392 """Diagnoses the NUS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000393
vladlosev4c915512010-09-25 00:52:20 +0000394 gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
395 r'(was not declared in this scope|has not been declared)')
396 clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier '
397 r'\'(?P<symbol>.+)\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000398 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000399'%(symbol)s' is defined by Google Mock in the testing namespace.
400Did you forget to write
401 using testing::%(symbol)s;
402?"""
vladlosev4c915512010-09-25 00:52:20 +0000403 for m in (list(_FindAllMatches(gcc_regex, msg)) +
404 list(_FindAllMatches(clang_regex, msg))):
shiqiane35fdd92008-12-10 05:08:54 +0000405 symbol = m.groupdict()['symbol']
406 if symbol in _COMMON_GMOCK_SYMBOLS:
407 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
408
409
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000410def _NeedToUseReturnNullDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000411 """Diagnoses the NRNULL disease, given the error messages by the compiler."""
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000412
vladlosev4c915512010-09-25 00:52:20 +0000413 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
414 '::operator testing::Action<Func>\(\) const.*\n' +
415 _GCC_FILE_LINE_RE + r'instantiated from here\n'
416 r'.*error: no matching function for call to \'implicit_cast\('
417 r'long int&\)')
418 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
419 r'call to \'implicit_cast\'\r?\n'
420 r'(.*\n)*?' +
421 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
422 r'of function template specialization '
423 r'\'testing::internal::ReturnAction<long>::operator '
424 r'Action<(?P<type>.*)\(\)>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000425 diagnosis = """
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000426You are probably calling Return(NULL) and the compiler isn't sure how to turn
vladlosev4c915512010-09-25 00:52:20 +0000427NULL into %(type)s. Use ReturnNull() instead.
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000428Note: the line number may be off; please fix all instances of Return(NULL)."""
vladlosev4c915512010-09-25 00:52:20 +0000429 return _GenericDiagnoser(
430 'NRNULL', 'Need to use ReturnNull',
431 [(clang_regex, diagnosis),
432 (gcc_regex, diagnosis % {'type': 'the right type'})],
433 msg)
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000434
435
vladlosev4c915512010-09-25 00:52:20 +0000436def _TypeInTemplatedBaseDiagnoser(msg):
437 """Diagnoses the TTB disease, given the error messages by the compiler."""
438
439 # This version works when the type is used as the mock function's return
440 # type.
441 gcc_4_3_1_regex_type_in_retval = (
442 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
443 r'error: a function call cannot appear in a constant-expression')
444 gcc_4_4_0_regex_type_in_retval = (
445 r'error: a function call cannot appear in a constant-expression'
446 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
447 # This version works when the type is used as the mock function's sole
448 # parameter type.
449 gcc_regex_type_of_sole_param = (
450 _GCC_FILE_LINE_RE +
451 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
452 r'.*error: template argument 1 is invalid\n')
453 # This version works when the type is used as a parameter of a mock
454 # function that has multiple parameters.
455 gcc_regex_type_of_a_param = (
456 r'error: expected `;\' before \'::\' token\n'
457 + _GCC_FILE_LINE_RE +
458 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
459 r'.*error: template argument 1 is invalid\n'
460 r'.*error: \'.+\' was not declared in this scope')
461
462 diagnosis = """
zhanyong.wanb8243162009-06-04 05:48:20 +0000463In a mock class template, types or typedefs defined in the base class
464template are *not* automatically visible. This is how C++ works. Before
465you can use a type or typedef named %(type)s defined in base class Base<T>, you
466need to make it visible. One way to do it is:
467
468 typedef typename Base<T>::%(type)s %(type)s;"""
469
vladlosev4c915512010-09-25 00:52:20 +0000470 return _GenericDiagnoser(
471 'TTB', 'Type in Template Base',
472 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
473 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
474 (gcc_regex_type_of_sole_param, diagnosis),
475 (gcc_regex_type_of_a_param, diagnosis)],
476 msg)
zhanyong.wanb8243162009-06-04 05:48:20 +0000477
478
zhanyong.wan16cf4732009-05-14 20:55:30 +0000479def _WrongMockMethodMacroDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000480 """Diagnoses the WMM disease, given the error messages by the compiler."""
zhanyong.wan16cf4732009-05-14 20:55:30 +0000481
vladlosev4c915512010-09-25 00:52:20 +0000482 gcc_regex = (_GCC_FILE_LINE_RE +
483 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
484 r'.*\n'
485 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
486 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
487 r'error: array size is negative\r?\n'
488 r'(.*\n)*?'
489 r'(?P=file):(?P=line):(?P=column): error: too few arguments '
490 r'to function call, expected (?P<args>\d+), '
491 r'have (?P<wrong_args>\d+)')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000492 diagnosis = """
zhanyong.wan16cf4732009-05-14 20:55:30 +0000493You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
494%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
495MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
zhanyong.wanb8243162009-06-04 05:48:20 +0000496 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
vladlosev4c915512010-09-25 00:52:20 +0000497 [(gcc_regex, diagnosis),
498 (clang_regex, diagnosis)],
499 msg)
zhanyong.wan16cf4732009-05-14 20:55:30 +0000500
501
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000502def _WrongParenPositionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000503 """Diagnoses the WPP disease, given the error messages by the compiler."""
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000504
vladlosev4c915512010-09-25 00:52:20 +0000505 gcc_regex = (_GCC_FILE_LINE_RE +
506 r'error:.*testing::internal::MockSpec<.* has no member named \''
507 r'(?P<method>\w+)\'')
508 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
509 r'error: no member named \'(?P<method>\w+)\' in '
510 r'\'testing::internal::MockSpec<.*>\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000511 diagnosis = """
512The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
513".%(method)s". For example, you should write:
514 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
515instead of:
516 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
zhanyong.wanb8243162009-06-04 05:48:20 +0000517 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
vladlosev4c915512010-09-25 00:52:20 +0000518 [(gcc_regex, diagnosis),
519 (clang_regex, diagnosis)],
520 msg)
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000521
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000522
shiqiane35fdd92008-12-10 05:08:54 +0000523_DIAGNOSERS = [
524 _IncompleteByReferenceArgumentDiagnoser,
525 _MockObjectPointerDiagnoser,
526 _NeedToReturnNothingDiagnoser,
527 _NeedToReturnReferenceDiagnoser,
528 _NeedToReturnSomethingDiagnoser,
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000529 _NeedToUseReturnNullDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000530 _NeedToUseSymbolDiagnoser,
531 _OverloadedFunctionActionDiagnoser,
532 _OverloadedFunctionMatcherDiagnoser,
vladlosev4c915512010-09-25 00:52:20 +0000533 _OverloadedMethodActionDiagnoser,
534 _TypeInTemplatedBaseDiagnoser,
zhanyong.wan16cf4732009-05-14 20:55:30 +0000535 _WrongMockMethodMacroDiagnoser,
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000536 _WrongParenPositionDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000537 ]
538
539
540def Diagnose(msg):
vladlosev4c915512010-09-25 00:52:20 +0000541 """Generates all possible diagnoses given the compiler error message."""
542
543 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting.
shiqiane35fdd92008-12-10 05:08:54 +0000544
zhanyong.wan099e3b92009-12-09 17:58:37 +0000545 diagnoses = []
shiqiane35fdd92008-12-10 05:08:54 +0000546 for diagnoser in _DIAGNOSERS:
zhanyong.wan099e3b92009-12-09 17:58:37 +0000547 for diag in diagnoser(msg):
548 diagnosis = '[%s - %s]\n%s' % diag
549 if not diagnosis in diagnoses:
550 diagnoses.append(diagnosis)
551 return diagnoses
shiqiane35fdd92008-12-10 05:08:54 +0000552
553
554def main():
555 print ('Google Mock Doctor v%s - '
556 'diagnoses problems in code using Google Mock.' % _VERSION)
557
558 if sys.stdin.isatty():
559 print ('Please copy and paste the compiler errors here. Press c-D when '
560 'you are done:')
561 else:
562 print 'Waiting for compiler errors on stdin . . .'
563
564 msg = sys.stdin.read().strip()
zhanyong.wan099e3b92009-12-09 17:58:37 +0000565 diagnoses = Diagnose(msg)
shiqiane35fdd92008-12-10 05:08:54 +0000566 count = len(diagnoses)
567 if not count:
vladlosev662d8a22010-09-29 00:38:12 +0000568 print ("""
569Your compiler complained:
5708<------------------------------------------------------------
571%s
572------------------------------------------------------------>8
573
shiqiane35fdd92008-12-10 05:08:54 +0000574Uh-oh, I'm not smart enough to figure out what the problem is. :-(
575However...
vladlosev4c915512010-09-25 00:52:20 +0000576If you send your source code and the compiler's error messages to
vladlosev662d8a22010-09-29 00:38:12 +0000577%s, you can be helped and I can get smarter --
578win-win for us!""" % (msg, _EMAIL))
shiqiane35fdd92008-12-10 05:08:54 +0000579 else:
580 print '------------------------------------------------------------'
581 print 'Your code appears to have the following',
582 if count > 1:
583 print '%s diseases:' % (count,)
584 else:
585 print 'disease:'
586 i = 0
587 for d in diagnoses:
588 i += 1
589 if count > 1:
590 print '\n#%s:' % (i,)
591 print d
vladlosev662d8a22010-09-29 00:38:12 +0000592 print ("""
shiqiane35fdd92008-12-10 05:08:54 +0000593How did I do? If you think I'm wrong or unhelpful, please send your
vladlosev662d8a22010-09-29 00:38:12 +0000594source code and the compiler's error messages to %s.
595Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
596 _EMAIL)
shiqiane35fdd92008-12-10 05:08:54 +0000597
598
599if __name__ == '__main__':
600 main()