32 """Converts compiler's errors in code using Google Mock to plain English."""
34 __author__ =
'wan@google.com (Zhanyong Wan)'
41 _EMAIL =
'googlemock@googlegroups.com'
43 _COMMON_GMOCK_SYMBOLS = [
70 'NanSensitiveDoubleEq',
71 'NanSensitiveFloatEq',
106 'SetArgumentPointee',
131 _GCC_FILE_LINE_RE =
r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
132 _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+')
138 """Generates all matches of regex in string s."""
140 r = re.compile(regex)
145 """Diagnoses the given disease by pattern matching.
147 Can provide different diagnoses for different patterns.
150 short_name: Short name of the disease.
151 long_name: Long name of the disease.
152 diagnoses: A list of pairs (regex, pattern for formatting the diagnosis
154 msg: Compiler's error messages.
157 (short name of disease, long name of disease, diagnosis).
159 for regex, diagnosis
in diagnoses:
160 if re.search(regex, msg):
161 diagnosis =
'%(file)s:%(line)s:' + diagnosis
163 yield (short_name, long_name, diagnosis % m.groupdict())
167 """Diagnoses the NRR disease, given the error messages by the compiler."""
169 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')
172 clang_regex = (
r'error:.*array.*negative.*\r?\n'
174 _CLANG_NON_GMOCK_FILE_LINE_RE +
175 r'note: in instantiation of function template specialization '
176 r'\'testing::internal::ReturnAction<(?P<type>.*)>'
177 r'::operator Action<.*>\' requested here')
178 clang11_re = (
r'use_ReturnRef_instead_of_Return_to_return_a_reference.*'
179 r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE)
182 You are using a Return() action in a function that returns a reference to
183 %(type)s. Please use ReturnRef() instead."""
185 [(clang_regex, diagnosis),
186 (clang11_re, diagnosis % {
'type':
'a type'}),
187 (gcc_regex, diagnosis % {
'type':
'a type'})],
192 """Diagnoses the NRS disease, given the error messages by the compiler."""
194 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 '
199 r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
200 r'with an rvalue of type \'void\'')
201 clang_regex2 = (_CLANG_FILE_LINE_RE +
202 r'error: cannot initialize return object '
203 r'of type \'(?P<return_type>.*)\' '
204 r'with an rvalue of type \'void\'')
206 You are using an action that returns void, but it needs to return
207 %(return_type)s. Please tell it *what* to return. Perhaps you can use
208 the pattern DoAll(some_action, Return(some_value))?"""
211 'Need to Return Something',
212 [(gcc_regex, diagnosis % {
'return_type':
'*something*'}),
213 (clang_regex1, diagnosis),
214 (clang_regex2, diagnosis)],
219 """Diagnoses the NRN disease, given the error messages by the compiler."""
221 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_\' '
225 clang_regex1 = (
r'error: field has incomplete type '
226 r'\'Result\' \(aka \'void\'\)(\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'
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>.*) \(.*\)>\' '
241 You are using an action that returns %(return_type)s, but it needs to return
242 void. Please use a void-returning action instead.
244 All actions but the last in DoAll(...) must return void. Perhaps you need
245 to re-arrange the order of actions in a DoAll(), if you are using one?"""
248 'Need to Return Nothing',
249 [(gcc_regex, diagnosis % {
'return_type':
'*something*'}),
250 (clang_regex1, diagnosis),
251 (clang_regex2, diagnosis)],
256 """Diagnoses the IBRA disease, given the error messages by the compiler."""
258 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>.*)\'')
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'
266 _CLANG_NON_GMOCK_FILE_LINE_RE +
267 r'note: in instantiation of member function '
268 r'\'testing::internal2::TypeWithoutFormatter<.*>::'
269 r'PrintValue\' requested here')
271 In order to mock this function, Google Mock needs to see the definition
272 of type "%(type)s" - declaration alone is not enough. Either #include
273 the header that defines it, or change the argument to be passed
277 [(gcc_regex, diagnosis),
278 (clang_regex, diagnosis)],
283 """Diagnoses the OFM disease, given the error messages by the compiler."""
285 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 '
290 The argument you gave to Truly() is an overloaded function. Please tell
291 your compiler which overloaded version you want to use.
293 For example, if you want to use the version whose signature is
296 Truly(static_cast<bool (*)(int n)>(Foo))"""
298 [(gcc_regex, diagnosis),
299 (clang_regex, diagnosis)],
304 """Diagnoses the OFA disease, given the error messages by the compiler."""
306 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'
311 r'.*\bgmock-generated-actions\.h:\d+:\d+:\s+'
312 r'note: candidate template ignored:\s+'
313 r'couldn\'t infer template argument \'FunctionImpl\'')
315 Function you are passing to Invoke is overloaded. Please tell your compiler
316 which overloaded version you want to use.
318 For example, if you want to use the version whose signature is
319 bool MyFunction(int n, double x);
320 you should write something like
321 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
323 [(gcc_regex, diagnosis),
324 (clang_regex, diagnosis)],
329 """Diagnoses the OMA disease, given the error messages by the compiler."""
331 gcc_regex = (_GCC_FILE_LINE_RE +
r'error: no matching function for '
332 r'call to \'Invoke\(.+, <unresolved overloaded function '
334 clang_regex = (_CLANG_FILE_LINE_RE +
r'error: no matching function '
335 r'for call to \'Invoke\'\r?\n'
337 r'.*\bgmock-generated-actions\.h:\d+:\d+: '
338 r'note: candidate function template not viable: '
339 r'requires .*, but 2 (arguments )?were provided')
341 The second argument you gave to Invoke() is an overloaded method. Please
342 tell your compiler which overloaded version you want to use.
344 For example, if you want to use the version whose signature is
347 bool Bar(int n, double x);
349 you should write something like
350 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
352 [(gcc_regex, diagnosis),
353 (clang_regex, diagnosis)],
358 """Diagnoses the MOP disease, given the error messages by the compiler."""
360 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; '
365 r'(did you mean|maybe you meant) to use \'->\'\?')
367 The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
368 not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
369 '%(mock_object)s' as your first argument.
371 For example, given the mock class:
373 class %(class_name)s : public ... {
375 MOCK_METHOD0(%(method)s, ...);
378 and the following mock instance:
380 %(class_name)s* mock_ptr = ...
382 you should use the EXPECT_CALL like this:
384 EXPECT_CALL(*mock_ptr, %(method)s(...));"""
388 'Mock Object Pointer',
389 [(gcc_regex, diagnosis),
390 (clang_regex, diagnosis % {
'mock_object':
'mock_object',
392 'class_name':
'%(class_name)s'})],
397 """Diagnoses the NUS disease, given the error messages by the compiler."""
399 gcc_regex = (_GCC_FILE_LINE_RE +
r'error: \'(?P<symbol>.+)\' '
400 r'(was not declared in this scope|has not been declared)')
401 clang_regex = (_CLANG_FILE_LINE_RE +
402 r'error: (use of undeclared identifier|unknown type name|'
403 r'no template named) \'(?P<symbol>[^\']+)\'')
405 '%(symbol)s' is defined by Google Mock in the testing namespace.
406 Did you forget to write
407 using testing::%(symbol)s;
411 symbol = m.groupdict()[
'symbol']
412 if symbol
in _COMMON_GMOCK_SYMBOLS:
413 yield (
'NUS',
'Need to Use Symbol', diagnosis % m.groupdict())
417 """Diagnoses the NRNULL disease, given the error messages by the compiler."""
419 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'
422 r'.*error: no matching function for call to \'ImplicitCast_\('
424 clang_regex = (
r'\bgmock-actions.h:.* error: no matching function for '
425 r'call to \'ImplicitCast_\'\r?\n'
427 _CLANG_NON_GMOCK_FILE_LINE_RE +
r'note: in instantiation '
428 r'of function template specialization '
429 r'\'testing::internal::ReturnAction<(int|long)>::operator '
430 r'Action<(?P<type>.*)\(\)>\' requested here')
432 You are probably calling Return(NULL) and the compiler isn't sure how to turn
433 NULL into %(type)s. Use ReturnNull() instead.
434 Note: the line number may be off; please fix all instances of Return(NULL)."""
436 'NRNULL',
'Need to use ReturnNull',
437 [(clang_regex, diagnosis),
438 (gcc_regex, diagnosis % {
'type':
'the right type'})],
443 """Diagnoses the TTB disease, given the error messages by the compiler."""
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')
455 gcc_regex_type_of_sole_param = (
457 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
458 r'.*error: template argument 1 is invalid\n')
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')
467 clang_regex_type_of_retval_or_sole_param = (
468 _CLANG_FILE_LINE_RE +
469 r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
471 r'(?P=file):(?P=line):\d+: error: '
472 r'non-friend class member \'Result\' cannot have a qualified name'
474 clang_regex_type_of_a_param = (
475 _CLANG_FILE_LINE_RE +
476 r'error: C\+\+ requires a type specifier for all declarations\n'
478 r'(?P=file):(?P=line):(?P=column): error: '
479 r'C\+\+ requires a type specifier for all declarations'
481 clang_regex_unknown_type = (
482 _CLANG_FILE_LINE_RE +
483 r'error: unknown type name \'(?P<type>[^\']+)\''
487 In a mock class template, types or typedefs defined in the base class
488 template are *not* automatically visible. This is how C++ works. Before
489 you can use a type or typedef named %(type)s defined in base class Base<T>, you
490 need to make it visible. One way to do it is:
492 typedef typename Base<T>::%(type)s %(type)s;"""
495 '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),
499 (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'})],
506 type_ = m.groupdict()[
'type']
507 if type_
not in _COMMON_GMOCK_SYMBOLS:
508 yield (
'TTB',
'Type in Template Base', diagnosis % m.groupdict())
512 """Diagnoses the WMM disease, given the error messages by the compiler."""
514 gcc_regex = (_GCC_FILE_LINE_RE +
515 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
517 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
518 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
519 r'error:.*array.*negative.*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+)')
524 clang11_re = (_CLANG_NON_GMOCK_FILE_LINE_RE +
525 r'.*this_method_does_not_take_'
526 r'(?P<wrong_args>\d+)_argument.*')
528 You 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,
530 MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
532 [(gcc_regex, diagnosis),
533 (clang11_re, diagnosis % {
'wrong_args':
'm',
535 (clang_regex, diagnosis)],
540 """Diagnoses the WPP disease, given the error messages by the compiler."""
542 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<.*>\'')
549 The 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(...);
553 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
555 [(gcc_regex, diagnosis),
556 (clang_regex, diagnosis)],
561 _IncompleteByReferenceArgumentDiagnoser,
562 _MockObjectPointerDiagnoser,
563 _NeedToReturnNothingDiagnoser,
564 _NeedToReturnReferenceDiagnoser,
565 _NeedToReturnSomethingDiagnoser,
566 _NeedToUseReturnNullDiagnoser,
567 _NeedToUseSymbolDiagnoser,
568 _OverloadedFunctionActionDiagnoser,
569 _OverloadedFunctionMatcherDiagnoser,
570 _OverloadedMethodActionDiagnoser,
571 _TypeInTemplatedBaseDiagnoser,
572 _WrongMockMethodMacroDiagnoser,
573 _WrongParenPositionDiagnoser,
578 """Generates all possible diagnoses given the compiler error message."""
580 msg = re.sub(
r'\x1b\[[^m]*m',
'', msg)
583 msg = re.sub(
r'(\xe2\x80\x98|\xe2\x80\x99)',
"'", msg)
586 for diagnoser
in _DIAGNOSERS:
587 for diag
in diagnoser(msg):
588 diagnosis =
'[%s - %s]\n%s' % diag
589 if not diagnosis
in diagnoses:
590 diagnoses.append(diagnosis)
595 print (
'Google Mock Doctor v%s - '
596 'diagnoses problems in code using Google Mock.' % _VERSION)
598 if sys.stdin.isatty():
599 print (
'Please copy and paste the compiler errors here. Press c-D when '
602 print (
'Waiting for compiler errors on stdin . . .')
604 msg = sys.stdin.read().strip()
606 count = len(diagnoses)
609 Your compiler complained:
610 8<------------------------------------------------------------
612 ------------------------------------------------------------>8
614 Uh-oh, I'm not smart enough to figure out what the problem is. :-(
616 If you send your source code and the compiler's error messages to
617 %s, you can be helped and I can get smarter --
618 win-win for us!""" % (msg, _EMAIL))
620 print (
'------------------------------------------------------------')
621 print (
'Your code appears to have the following',)
623 print (
'%s diseases:' % (count,))
630 print (
'\n#%s:' % (i,))
633 How did I do? If you think I'm wrong or unhelpful, please send your
634 source code and the compiler's error messages to %s.
635 Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
639 if __name__ ==
'__main__':