blob: 18c117fb03b43bf737e748232b73b80c242c444c [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.
131_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\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+')
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')
172 clang_regex = (r'error: array size is negative\r?\n'
173 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')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000178 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000179You are using a Return() action in a function that returns a reference to
180%(type)s. Please use ReturnRef() instead."""
shiqiane35fdd92008-12-10 05:08:54 +0000181 return _GenericDiagnoser('NRR', 'Need to Return Reference',
vladlosev4c915512010-09-25 00:52:20 +0000182 [(clang_regex, diagnosis),
183 (gcc_regex, diagnosis % {'type': 'a type'})],
184 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000185
186
187def _NeedToReturnSomethingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000188 """Diagnoses the NRS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000189
vladlosev4c915512010-09-25 00:52:20 +0000190 gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
191 r'*gmock.*actions\.h.*error: void value not ignored)'
192 r'|(error: control reaches end of non-void function)')
193 clang_regex1 = (_CLANG_FILE_LINE_RE +
194 r'error: cannot initialize return object '
195 r'of type \'Result\' \(aka \'(?P<return_type>).*\'\) '
196 r'with an rvalue of type \'void\'')
197 clang_regex2 = (_CLANG_FILE_LINE_RE +
198 r'error: cannot initialize return object '
199 r'of type \'(?P<return_type>).*\' '
200 r'with an rvalue of type \'void\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000201 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000202You are using an action that returns void, but it needs to return
vladlosev4c915512010-09-25 00:52:20 +0000203%(return_type)s. Please tell it *what* to return. Perhaps you can use
zhanyong.wan16cf4732009-05-14 20:55:30 +0000204the pattern DoAll(some_action, Return(some_value))?"""
vladlosev4c915512010-09-25 00:52:20 +0000205 return _GenericDiagnoser(
206 'NRS',
207 'Need to Return Something',
208 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
209 (clang_regex1, diagnosis),
210 (clang_regex2, diagnosis)],
211 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000212
213
214def _NeedToReturnNothingDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000215 """Diagnoses the NRN disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000216
vladlosev4c915512010-09-25 00:52:20 +0000217 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
218 r'.*gmock-actions\.h.*error: instantiation of '
219 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
220 r'as type \'void\'')
221 clang_regex1 = (r'error: field has incomplete type '
222 r'\'Result\' \(aka \'void\'\)(\r)?\n'
223 r'(.*\n)*?' +
224 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
225 r'of function template specialization '
226 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
227 r'::operator Action<void \(.*\)>\' requested here')
228 clang_regex2 = (r'error: field has incomplete type '
229 r'\'Result\' \(aka \'void\'\)(\r)?\n'
230 r'(.*\n)*?' +
231 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
232 r'of function template specialization '
233 r'\'testing::internal::DoBothAction<.*>'
234 r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
235 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000236 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000237You are using an action that returns %(return_type)s, but it needs to return
shiqiane35fdd92008-12-10 05:08:54 +0000238void. Please use a void-returning action instead.
239
240All actions but the last in DoAll(...) must return void. Perhaps you need
241to re-arrange the order of actions in a DoAll(), if you are using one?"""
vladlosev4c915512010-09-25 00:52:20 +0000242 return _GenericDiagnoser(
243 'NRN',
244 'Need to Return Nothing',
245 [(gcc_regex, diagnosis % {'return_type': '*something*'}),
246 (clang_regex1, diagnosis),
247 (clang_regex2, diagnosis)],
248 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000249
250
251def _IncompleteByReferenceArgumentDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000252 """Diagnoses the IBRA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000253
vladlosev4c915512010-09-25 00:52:20 +0000254 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
255 r'.*gtest-printers\.h.*error: invalid application of '
256 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
257
258 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
259 r'\'sizeof\' to an incomplete type '
260 r'\'(?P<type>.*)( const)?\'\r?\n'
261 r'(.*\n)*?' +
262 _CLANG_NON_GMOCK_FILE_LINE_RE +
263 r'note: in instantiation of member function '
264 r'\'testing::internal::FunctionMocker<.*>::Invoke\' '
265 r'requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000266 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000267In order to mock this function, Google Mock needs to see the definition
268of type "%(type)s" - declaration alone is not enough. Either #include
269the header that defines it, or change the argument to be passed
270by pointer."""
vladlosev4c915512010-09-25 00:52:20 +0000271
shiqiane35fdd92008-12-10 05:08:54 +0000272 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
vladlosev4c915512010-09-25 00:52:20 +0000273 [(gcc_regex, diagnosis),
274 (clang_regex, diagnosis)],
275 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000276
277
278def _OverloadedFunctionMatcherDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000279 """Diagnoses the OFM disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000280
vladlosev4c915512010-09-25 00:52:20 +0000281 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
282 r'call to \'Truly\(<unresolved overloaded function type>\)')
283 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
284 r'call to \'Truly')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000285 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000286The argument you gave to Truly() is an overloaded function. Please tell
vladlosev4c915512010-09-25 00:52:20 +0000287your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000288
289For example, if you want to use the version whose signature is
290 bool Foo(int n);
291you should write
292 Truly(static_cast<bool (*)(int n)>(Foo))"""
293 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
vladlosev4c915512010-09-25 00:52:20 +0000294 [(gcc_regex, diagnosis),
295 (clang_regex, diagnosis)],
296 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000297
298
299def _OverloadedFunctionActionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000300 """Diagnoses the OFA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000301
vladlosev4c915512010-09-25 00:52:20 +0000302 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
303 r'\'Invoke\(<unresolved overloaded function type>')
304 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
305 r'function for call to \'Invoke\'\r?\n'
306 r'(.*\n)*?'
307 r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+'
308 r'note: candidate template ignored:\s+'
309 r'couldn\'t infer template argument \'FunctionImpl\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000310 diagnosis = """
vladlosev4c915512010-09-25 00:52:20 +0000311Function you are passing to Invoke is overloaded. Please tell your compiler
shiqiane35fdd92008-12-10 05:08:54 +0000312which overloaded version you want to use.
313
314For example, if you want to use the version whose signature is
315 bool MyFunction(int n, double x);
316you should write something like
317 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
318 return _GenericDiagnoser('OFA', 'Overloaded Function Action',
vladlosev4c915512010-09-25 00:52:20 +0000319 [(gcc_regex, diagnosis),
320 (clang_regex, diagnosis)],
321 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000322
323
vladlosev4c915512010-09-25 00:52:20 +0000324def _OverloadedMethodActionDiagnoser(msg):
325 """Diagnoses the OMA disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000326
vladlosev4c915512010-09-25 00:52:20 +0000327 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
328 r'call to \'Invoke\(.+, <unresolved overloaded function '
329 r'type>\)')
330 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
331 r'for call to \'Invoke\'\r?\n'
332 r'(.*\n)*?'
333 r'.*\bgmock-\w+-actions\.h:\d+:\d+: '
334 r'note: candidate function template not viable: '
335 r'requires 1 argument, but 2 were provided')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000336 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000337The second argument you gave to Invoke() is an overloaded method. Please
vladlosev4c915512010-09-25 00:52:20 +0000338tell your compiler which overloaded version you want to use.
shiqiane35fdd92008-12-10 05:08:54 +0000339
340For example, if you want to use the version whose signature is
341 class Foo {
342 ...
343 bool Bar(int n, double x);
344 };
345you should write something like
346 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
347 return _GenericDiagnoser('OMA', 'Overloaded Method Action',
vladlosev4c915512010-09-25 00:52:20 +0000348 [(gcc_regex, diagnosis),
349 (clang_regex, diagnosis)],
350 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000351
352
353def _MockObjectPointerDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000354 """Diagnoses the MOP disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000355
vladlosev4c915512010-09-25 00:52:20 +0000356 gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
357 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
358 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
359 clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
360 r'\'(?P<class_name>.*?) *\' is a pointer; '
361 r'maybe you meant to use \'->\'\?')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000362 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000363The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
364not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
365'%(mock_object)s' as your first argument.
366
367For example, given the mock class:
368
369 class %(class_name)s : public ... {
370 ...
371 MOCK_METHOD0(%(method)s, ...);
372 };
373
374and the following mock instance:
375
376 %(class_name)s* mock_ptr = ...
377
378you should use the EXPECT_CALL like this:
379
380 EXPECT_CALL(*mock_ptr, %(method)s(...));"""
shiqiane35fdd92008-12-10 05:08:54 +0000381
vladlosev4c915512010-09-25 00:52:20 +0000382 return _GenericDiagnoser(
383 'MOP',
384 'Mock Object Pointer',
385 [(gcc_regex, diagnosis),
386 (clang_regex, diagnosis % {'mock_object': 'mock_object',
387 'method': 'method',
388 'class_name': '%(class_name)s'})],
389 msg)
shiqiane35fdd92008-12-10 05:08:54 +0000390
391
392def _NeedToUseSymbolDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000393 """Diagnoses the NUS disease, given the error messages by the compiler."""
shiqiane35fdd92008-12-10 05:08:54 +0000394
vladlosev4c915512010-09-25 00:52:20 +0000395 gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
396 r'(was not declared in this scope|has not been declared)')
397 clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier '
398 r'\'(?P<symbol>.+)\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000399 diagnosis = """
shiqiane35fdd92008-12-10 05:08:54 +0000400'%(symbol)s' is defined by Google Mock in the testing namespace.
401Did you forget to write
402 using testing::%(symbol)s;
403?"""
vladlosev4c915512010-09-25 00:52:20 +0000404 for m in (list(_FindAllMatches(gcc_regex, msg)) +
405 list(_FindAllMatches(clang_regex, msg))):
shiqiane35fdd92008-12-10 05:08:54 +0000406 symbol = m.groupdict()['symbol']
407 if symbol in _COMMON_GMOCK_SYMBOLS:
408 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
409
410
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000411def _NeedToUseReturnNullDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000412 """Diagnoses the NRNULL disease, given the error messages by the compiler."""
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000413
vladlosev4c915512010-09-25 00:52:20 +0000414 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
415 '::operator testing::Action<Func>\(\) const.*\n' +
416 _GCC_FILE_LINE_RE + r'instantiated from here\n'
417 r'.*error: no matching function for call to \'implicit_cast\('
418 r'long int&\)')
419 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
420 r'call to \'implicit_cast\'\r?\n'
421 r'(.*\n)*?' +
422 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
423 r'of function template specialization '
424 r'\'testing::internal::ReturnAction<long>::operator '
425 r'Action<(?P<type>.*)\(\)>\' requested here')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000426 diagnosis = """
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000427You are probably calling Return(NULL) and the compiler isn't sure how to turn
vladlosev4c915512010-09-25 00:52:20 +0000428NULL into %(type)s. Use ReturnNull() instead.
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000429Note: the line number may be off; please fix all instances of Return(NULL)."""
vladlosev4c915512010-09-25 00:52:20 +0000430 return _GenericDiagnoser(
431 'NRNULL', 'Need to use ReturnNull',
432 [(clang_regex, diagnosis),
433 (gcc_regex, diagnosis % {'type': 'the right type'})],
434 msg)
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000435
436
vladlosev4c915512010-09-25 00:52:20 +0000437def _TypeInTemplatedBaseDiagnoser(msg):
438 """Diagnoses the TTB disease, given the error messages by the compiler."""
439
440 # This version works when the type is used as the mock function's return
441 # type.
442 gcc_4_3_1_regex_type_in_retval = (
443 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
444 r'error: a function call cannot appear in a constant-expression')
445 gcc_4_4_0_regex_type_in_retval = (
446 r'error: a function call cannot appear in a constant-expression'
447 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
448 # This version works when the type is used as the mock function's sole
449 # parameter type.
450 gcc_regex_type_of_sole_param = (
451 _GCC_FILE_LINE_RE +
452 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
453 r'.*error: template argument 1 is invalid\n')
454 # This version works when the type is used as a parameter of a mock
455 # function that has multiple parameters.
456 gcc_regex_type_of_a_param = (
457 r'error: expected `;\' before \'::\' token\n'
458 + _GCC_FILE_LINE_RE +
459 r'error: \'(?P<type>.+)\' was not declared in this scope\n'
460 r'.*error: template argument 1 is invalid\n'
461 r'.*error: \'.+\' was not declared in this scope')
462
463 diagnosis = """
zhanyong.wanb8243162009-06-04 05:48:20 +0000464In a mock class template, types or typedefs defined in the base class
465template are *not* automatically visible. This is how C++ works. Before
466you can use a type or typedef named %(type)s defined in base class Base<T>, you
467need to make it visible. One way to do it is:
468
469 typedef typename Base<T>::%(type)s %(type)s;"""
470
vladlosev4c915512010-09-25 00:52:20 +0000471 return _GenericDiagnoser(
472 'TTB', 'Type in Template Base',
473 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
474 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
475 (gcc_regex_type_of_sole_param, diagnosis),
476 (gcc_regex_type_of_a_param, diagnosis)],
477 msg)
zhanyong.wanb8243162009-06-04 05:48:20 +0000478
479
zhanyong.wan16cf4732009-05-14 20:55:30 +0000480def _WrongMockMethodMacroDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000481 """Diagnoses the WMM disease, given the error messages by the compiler."""
zhanyong.wan16cf4732009-05-14 20:55:30 +0000482
vladlosev4c915512010-09-25 00:52:20 +0000483 gcc_regex = (_GCC_FILE_LINE_RE +
484 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
485 r'.*\n'
486 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
487 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
488 r'error: array size is negative\r?\n'
489 r'(.*\n)*?'
490 r'(?P=file):(?P=line):(?P=column): error: too few arguments '
491 r'to function call, expected (?P<args>\d+), '
492 r'have (?P<wrong_args>\d+)')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000493 diagnosis = """
zhanyong.wan16cf4732009-05-14 20:55:30 +0000494You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
495%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
496MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
zhanyong.wanb8243162009-06-04 05:48:20 +0000497 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
vladlosev4c915512010-09-25 00:52:20 +0000498 [(gcc_regex, diagnosis),
499 (clang_regex, diagnosis)],
500 msg)
zhanyong.wan16cf4732009-05-14 20:55:30 +0000501
502
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000503def _WrongParenPositionDiagnoser(msg):
vladlosev4c915512010-09-25 00:52:20 +0000504 """Diagnoses the WPP disease, given the error messages by the compiler."""
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000505
vladlosev4c915512010-09-25 00:52:20 +0000506 gcc_regex = (_GCC_FILE_LINE_RE +
507 r'error:.*testing::internal::MockSpec<.* has no member named \''
508 r'(?P<method>\w+)\'')
509 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
510 r'error: no member named \'(?P<method>\w+)\' in '
511 r'\'testing::internal::MockSpec<.*>\'')
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000512 diagnosis = """
513The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
514".%(method)s". For example, you should write:
515 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
516instead of:
517 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
zhanyong.wanb8243162009-06-04 05:48:20 +0000518 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
vladlosev4c915512010-09-25 00:52:20 +0000519 [(gcc_regex, diagnosis),
520 (clang_regex, diagnosis)],
521 msg)
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000522
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000523
shiqiane35fdd92008-12-10 05:08:54 +0000524_DIAGNOSERS = [
525 _IncompleteByReferenceArgumentDiagnoser,
526 _MockObjectPointerDiagnoser,
527 _NeedToReturnNothingDiagnoser,
528 _NeedToReturnReferenceDiagnoser,
529 _NeedToReturnSomethingDiagnoser,
zhanyong.wan5b95fa72009-01-27 22:28:45 +0000530 _NeedToUseReturnNullDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000531 _NeedToUseSymbolDiagnoser,
532 _OverloadedFunctionActionDiagnoser,
533 _OverloadedFunctionMatcherDiagnoser,
vladlosev4c915512010-09-25 00:52:20 +0000534 _OverloadedMethodActionDiagnoser,
535 _TypeInTemplatedBaseDiagnoser,
zhanyong.wan16cf4732009-05-14 20:55:30 +0000536 _WrongMockMethodMacroDiagnoser,
zhanyong.wan9413f2f2009-05-29 19:50:06 +0000537 _WrongParenPositionDiagnoser,
shiqiane35fdd92008-12-10 05:08:54 +0000538 ]
539
540
541def Diagnose(msg):
vladlosev4c915512010-09-25 00:52:20 +0000542 """Generates all possible diagnoses given the compiler error message."""
543
544 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting.
shiqiane35fdd92008-12-10 05:08:54 +0000545
zhanyong.wan099e3b92009-12-09 17:58:37 +0000546 diagnoses = []
shiqiane35fdd92008-12-10 05:08:54 +0000547 for diagnoser in _DIAGNOSERS:
zhanyong.wan099e3b92009-12-09 17:58:37 +0000548 for diag in diagnoser(msg):
549 diagnosis = '[%s - %s]\n%s' % diag
550 if not diagnosis in diagnoses:
551 diagnoses.append(diagnosis)
552 return diagnoses
shiqiane35fdd92008-12-10 05:08:54 +0000553
554
555def main():
556 print ('Google Mock Doctor v%s - '
557 'diagnoses problems in code using Google Mock.' % _VERSION)
558
559 if sys.stdin.isatty():
560 print ('Please copy and paste the compiler errors here. Press c-D when '
561 'you are done:')
562 else:
563 print 'Waiting for compiler errors on stdin . . .'
564
565 msg = sys.stdin.read().strip()
zhanyong.wan099e3b92009-12-09 17:58:37 +0000566 diagnoses = Diagnose(msg)
shiqiane35fdd92008-12-10 05:08:54 +0000567 count = len(diagnoses)
568 if not count:
vladlosev662d8a22010-09-29 00:38:12 +0000569 print ("""
570Your compiler complained:
5718<------------------------------------------------------------
572%s
573------------------------------------------------------------>8
574
shiqiane35fdd92008-12-10 05:08:54 +0000575Uh-oh, I'm not smart enough to figure out what the problem is. :-(
576However...
vladlosev4c915512010-09-25 00:52:20 +0000577If you send your source code and the compiler's error messages to
vladlosev662d8a22010-09-29 00:38:12 +0000578%s, you can be helped and I can get smarter --
579win-win for us!""" % (msg, _EMAIL))
shiqiane35fdd92008-12-10 05:08:54 +0000580 else:
581 print '------------------------------------------------------------'
582 print 'Your code appears to have the following',
583 if count > 1:
584 print '%s diseases:' % (count,)
585 else:
586 print 'disease:'
587 i = 0
588 for d in diagnoses:
589 i += 1
590 if count > 1:
591 print '\n#%s:' % (i,)
592 print d
vladlosev662d8a22010-09-29 00:38:12 +0000593 print ("""
shiqiane35fdd92008-12-10 05:08:54 +0000594How did I do? If you think I'm wrong or unhelpful, please send your
vladlosev662d8a22010-09-29 00:38:12 +0000595source code and the compiler's error messages to %s.
596Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
597 _EMAIL)
shiqiane35fdd92008-12-10 05:08:54 +0000598
599
600if __name__ == '__main__':
601 main()