1#!/usr/bin/env python 2# 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 32"""Converts compiler's errors in code using Google Mock to plain English.""" 33 34__author__ = 'wan@google.com (Zhanyong Wan)' 35 36import re 37import sys 38 39_VERSION = '1.0.3' 40 41_EMAIL = 'googlemock@googlegroups.com' 42 43_COMMON_GMOCK_SYMBOLS = [ 44 # Matchers 45 '_', 46 'A', 47 'AddressSatisfies', 48 'AllOf', 49 'An', 50 'AnyOf', 51 'ContainerEq', 52 'Contains', 53 'ContainsRegex', 54 'DoubleEq', 55 'ElementsAre', 56 'ElementsAreArray', 57 'EndsWith', 58 'Eq', 59 'Field', 60 'FloatEq', 61 'Ge', 62 'Gt', 63 'HasSubstr', 64 'IsInitializedProto', 65 'Le', 66 'Lt', 67 'MatcherCast', 68 'Matches', 69 'MatchesRegex', 70 'NanSensitiveDoubleEq', 71 'NanSensitiveFloatEq', 72 'Ne', 73 'Not', 74 'NotNull', 75 'Pointee', 76 'Property', 77 'Ref', 78 'ResultOf', 79 'SafeMatcherCast', 80 'StartsWith', 81 'StrCaseEq', 82 'StrCaseNe', 83 'StrEq', 84 'StrNe', 85 'Truly', 86 'TypedEq', 87 'Value', 88 89 # Actions 90 'Assign', 91 'ByRef', 92 'DeleteArg', 93 'DoAll', 94 'DoDefault', 95 'IgnoreResult', 96 'Invoke', 97 'InvokeArgument', 98 'InvokeWithoutArgs', 99 'Return', 100 'ReturnNew', 101 'ReturnNull', 102 'ReturnRef', 103 'SaveArg', 104 'SetArgReferee', 105 'SetArgPointee', 106 'SetArgumentPointee', 107 'SetArrayArgument', 108 'SetErrnoAndReturn', 109 'Throw', 110 'WithArg', 111 'WithArgs', 112 'WithoutArgs', 113 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 130# 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+):(\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+') 135 136 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 144def _GenericDiagnoser(short_name, long_name, diagnoses, msg): 145 """Diagnoses the given disease by pattern matching. 146 147 Can provide different diagnoses for different patterns. 148 149 Args: 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 153 for matching regex). 154 msg: Compiler's error messages. 155 Yields: 156 Tuples of the form 157 (short name of disease, long name of disease, diagnosis). 158 """ 159 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()) 164 165 166def _NeedToReturnReferenceDiagnoser(msg): 167 """Diagnoses the NRR disease, given the error messages by the compiler.""" 168 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' 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') 178 clang11_re = (r'use_ReturnRef_instead_of_Return_to_return_a_reference.*' 179 r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE) 180 181 diagnosis = """ 182You are using a Return() action in a function that returns a reference to 183%(type)s. Please use ReturnRef() instead.""" 184 return _GenericDiagnoser('NRR', 'Need to Return Reference', 185 [(clang_regex, diagnosis), 186 (clang11_re, diagnosis % {'type': 'a type'}), 187 (gcc_regex, diagnosis % {'type': 'a type'})], 188 msg) 189 190 191def _NeedToReturnSomethingDiagnoser(msg): 192 """Diagnoses the NRS disease, given the error messages by the compiler.""" 193 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\'') 205 diagnosis = """ 206You 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 208the pattern DoAll(some_action, Return(some_value))?""" 209 return _GenericDiagnoser( 210 'NRS', 211 'Need to Return Something', 212 [(gcc_regex, diagnosis % {'return_type': '*something*'}), 213 (clang_regex1, diagnosis), 214 (clang_regex2, diagnosis)], 215 msg) 216 217 218def _NeedToReturnNothingDiagnoser(msg): 219 """Diagnoses the NRN disease, given the error messages by the compiler.""" 220 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_\' ' 224 r'as type \'void\'') 225 clang_regex1 = (r'error: field has incomplete type ' 226 r'\'Result\' \(aka \'void\'\)(\r)?\n' 227 r'(.*\n)*?' + 228 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 229 r'of function template specialization ' 230 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>' 231 r'::operator Action<void \(.*\)>\' requested here') 232 clang_regex2 = (r'error: field has incomplete type ' 233 r'\'Result\' \(aka \'void\'\)(\r)?\n' 234 r'(.*\n)*?' + 235 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 236 r'of function template specialization ' 237 r'\'testing::internal::DoBothAction<.*>' 238 r'::operator Action<(?P<return_type>.*) \(.*\)>\' ' 239 r'requested here') 240 diagnosis = """ 241You are using an action that returns %(return_type)s, but it needs to return 242void. Please use a void-returning action instead. 243 244All actions but the last in DoAll(...) must return void. Perhaps you need 245to re-arrange the order of actions in a DoAll(), if you are using one?""" 246 return _GenericDiagnoser( 247 'NRN', 248 'Need to Return Nothing', 249 [(gcc_regex, diagnosis % {'return_type': '*something*'}), 250 (clang_regex1, diagnosis), 251 (clang_regex2, diagnosis)], 252 msg) 253 254 255def _IncompleteByReferenceArgumentDiagnoser(msg): 256 """Diagnoses the IBRA disease, given the error messages by the compiler.""" 257 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>.*)\'') 261 262 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of ' 263 r'\'sizeof\' to an incomplete type ' 264 r'\'(?P<type>.*)( const)?\'\r?\n' 265 r'(.*\n)*?' + 266 _CLANG_NON_GMOCK_FILE_LINE_RE + 267 r'note: in instantiation of member function ' 268 r'\'testing::internal2::TypeWithoutFormatter<.*>::' 269 r'PrintValue\' requested here') 270 diagnosis = """ 271In order to mock this function, Google Mock needs to see the definition 272of type "%(type)s" - declaration alone is not enough. Either #include 273the header that defines it, or change the argument to be passed 274by pointer.""" 275 276 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', 277 [(gcc_regex, diagnosis), 278 (clang_regex, diagnosis)], 279 msg) 280 281 282def _OverloadedFunctionMatcherDiagnoser(msg): 283 """Diagnoses the OFM disease, given the error messages by the compiler.""" 284 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 ' 288 r'call to \'Truly') 289 diagnosis = """ 290The argument you gave to Truly() is an overloaded function. Please tell 291your compiler which overloaded version you want to use. 292 293For example, if you want to use the version whose signature is 294 bool Foo(int n); 295you should write 296 Truly(static_cast<bool (*)(int n)>(Foo))""" 297 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher', 298 [(gcc_regex, diagnosis), 299 (clang_regex, diagnosis)], 300 msg) 301 302 303def _OverloadedFunctionActionDiagnoser(msg): 304 """Diagnoses the OFA disease, given the error messages by the compiler.""" 305 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' 310 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\'') 314 diagnosis = """ 315Function you are passing to Invoke is overloaded. Please tell your compiler 316which overloaded version you want to use. 317 318For example, if you want to use the version whose signature is 319 bool MyFunction(int n, double x); 320you should write something like 321 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))""" 322 return _GenericDiagnoser('OFA', 'Overloaded Function Action', 323 [(gcc_regex, diagnosis), 324 (clang_regex, diagnosis)], 325 msg) 326 327 328def _OverloadedMethodActionDiagnoser(msg): 329 """Diagnoses the OMA disease, given the error messages by the compiler.""" 330 331 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for ' 332 r'call to \'Invoke\(.+, <unresolved overloaded function ' 333 r'type>\)') 334 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function ' 335 r'for call to \'Invoke\'\r?\n' 336 r'(.*\n)*?' 337 r'.*\bgmock-generated-actions\.h:\d+:\d+: ' 338 r'note: candidate function template not viable: ' 339 r'requires .*, but 2 (arguments )?were provided') 340 diagnosis = """ 341The second argument you gave to Invoke() is an overloaded method. Please 342tell your compiler which overloaded version you want to use. 343 344For example, if you want to use the version whose signature is 345 class Foo { 346 ... 347 bool Bar(int n, double x); 348 }; 349you should write something like 350 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))""" 351 return _GenericDiagnoser('OMA', 'Overloaded Method Action', 352 [(gcc_regex, diagnosis), 353 (clang_regex, diagnosis)], 354 msg) 355 356 357def _MockObjectPointerDiagnoser(msg): 358 """Diagnoses the MOP disease, given the error messages by the compiler.""" 359 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 \'->\'\?') 366 diagnosis = """ 367The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, 368not a *pointer* to it. Please write '*(%(mock_object)s)' instead of 369'%(mock_object)s' as your first argument. 370 371For example, given the mock class: 372 373 class %(class_name)s : public ... { 374 ... 375 MOCK_METHOD0(%(method)s, ...); 376 }; 377 378and the following mock instance: 379 380 %(class_name)s* mock_ptr = ... 381 382you should use the EXPECT_CALL like this: 383 384 EXPECT_CALL(*mock_ptr, %(method)s(...));""" 385 386 return _GenericDiagnoser( 387 'MOP', 388 'Mock Object Pointer', 389 [(gcc_regex, diagnosis), 390 (clang_regex, diagnosis % {'mock_object': 'mock_object', 391 'method': 'method', 392 'class_name': '%(class_name)s'})], 393 msg) 394 395 396def _NeedToUseSymbolDiagnoser(msg): 397 """Diagnoses the NUS disease, given the error messages by the compiler.""" 398 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>[^\']+)\'') 404 diagnosis = """ 405'%(symbol)s' is defined by Google Mock in the testing namespace. 406Did you forget to write 407 using testing::%(symbol)s; 408?""" 409 for m in (list(_FindAllMatches(gcc_regex, msg)) + 410 list(_FindAllMatches(clang_regex, msg))): 411 symbol = m.groupdict()['symbol'] 412 if symbol in _COMMON_GMOCK_SYMBOLS: 413 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) 414 415 416def _NeedToUseReturnNullDiagnoser(msg): 417 """Diagnoses the NRNULL disease, given the error messages by the compiler.""" 418 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_\(' 423 r'(:?long )?int&\)') 424 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' 425 r'call to \'ImplicitCast_\'\r?\n' 426 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') 431 diagnosis = """ 432You are probably calling Return(NULL) and the compiler isn't sure how to turn 433NULL into %(type)s. Use ReturnNull() instead. 434Note: the line number may be off; please fix all instances of Return(NULL).""" 435 return _GenericDiagnoser( 436 'NRNULL', 'Need to use ReturnNull', 437 [(clang_regex, diagnosis), 438 (gcc_regex, diagnosis % {'type': 'the right type'})], 439 msg) 440 441 442def _TypeInTemplatedBaseDiagnoser(msg): 443 """Diagnoses the TTB disease, given the error messages by the compiler.""" 444 445 # This version works when the type is used as the mock function's return 446 # type. 447 gcc_4_3_1_regex_type_in_retval = ( 448 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE + 449 r'error: a function call cannot appear in a constant-expression') 450 gcc_4_4_0_regex_type_in_retval = ( 451 r'error: a function call cannot appear in a constant-expression' 452 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n') 453 # This version works when the type is used as the mock function's sole 454 # parameter type. 455 gcc_regex_type_of_sole_param = ( 456 _GCC_FILE_LINE_RE + 457 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 458 r'.*error: template argument 1 is invalid\n') 459 # This version works when the type is used as a parameter of a mock 460 # function that has multiple parameters. 461 gcc_regex_type_of_a_param = ( 462 r'error: expected `;\' before \'::\' token\n' 463 + _GCC_FILE_LINE_RE + 464 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 465 r'.*error: template argument 1 is invalid\n' 466 r'.*error: \'.+\' was not declared in this scope') 467 clang_regex_type_of_retval_or_sole_param = ( 468 _CLANG_FILE_LINE_RE + 469 r'error: use of undeclared identifier \'(?P<type>.*)\'\n' 470 r'(.*\n)*?' 471 r'(?P=file):(?P=line):\d+: error: ' 472 r'non-friend class member \'Result\' cannot have a qualified name' 473 ) 474 clang_regex_type_of_a_param = ( 475 _CLANG_FILE_LINE_RE + 476 r'error: C\+\+ requires a type specifier for all declarations\n' 477 r'(.*\n)*?' 478 r'(?P=file):(?P=line):(?P=column): error: ' 479 r'C\+\+ requires a type specifier for all declarations' 480 ) 481 clang_regex_unknown_type = ( 482 _CLANG_FILE_LINE_RE + 483 r'error: unknown type name \'(?P<type>[^\']+)\'' 484 ) 485 486 diagnosis = """ 487In a mock class template, types or typedefs defined in the base class 488template are *not* automatically visible. This is how C++ works. Before 489you can use a type or typedef named %(type)s defined in base class Base<T>, you 490need to make it visible. One way to do it is: 491 492 typedef typename Base<T>::%(type)s %(type)s;""" 493 494 for diag in _GenericDiagnoser( 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'})], 502 msg): 503 yield diag 504 # Avoid overlap with the NUS pattern. 505 for m in _FindAllMatches(clang_regex_unknown_type, msg): 506 type_ = m.groupdict()['type'] 507 if type_ not in _COMMON_GMOCK_SYMBOLS: 508 yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict()) 509 510 511def _WrongMockMethodMacroDiagnoser(msg): 512 """Diagnoses the WMM disease, given the error messages by the compiler.""" 513 514 gcc_regex = (_GCC_FILE_LINE_RE + 515 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n' 516 r'.*\n' 517 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>') 518 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + 519 r'error:.*array.*negative.*r?\n' 520 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.*') 527 diagnosis = """ 528You are using MOCK_METHOD%(wrong_args)s to define a mock method that has 529%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, 530MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" 531 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', 532 [(gcc_regex, diagnosis), 533 (clang11_re, diagnosis % {'wrong_args': 'm', 534 'args': 'n'}), 535 (clang_regex, diagnosis)], 536 msg) 537 538 539def _WrongParenPositionDiagnoser(msg): 540 """Diagnoses the WPP disease, given the error messages by the compiler.""" 541 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<.*>\'') 548 diagnosis = """ 549The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* 550".%(method)s". For example, you should write: 551 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...); 552instead of: 553 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" 554 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position', 555 [(gcc_regex, diagnosis), 556 (clang_regex, diagnosis)], 557 msg) 558 559 560_DIAGNOSERS = [ 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, 574 ] 575 576 577def Diagnose(msg): 578 """Generates all possible diagnoses given the compiler error message.""" 579 580 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting. 581 # Assuming the string is using the UTF-8 encoding, replaces the left and 582 # the right single quote characters with apostrophes. 583 msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg) 584 585 diagnoses = [] 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) 591 return diagnoses 592 593 594def main(): 595 print ('Google Mock Doctor v%s - ' 596 'diagnoses problems in code using Google Mock.' % _VERSION) 597 598 if sys.stdin.isatty(): 599 print ('Please copy and paste the compiler errors here. Press c-D when ' 600 'you are done:') 601 else: 602 print ('Waiting for compiler errors on stdin . . .') 603 604 msg = sys.stdin.read().strip() 605 diagnoses = Diagnose(msg) 606 count = len(diagnoses) 607 if not count: 608 print (""" 609Your compiler complained: 6108<------------------------------------------------------------ 611%s 612------------------------------------------------------------>8 613 614Uh-oh, I'm not smart enough to figure out what the problem is. :-( 615However... 616If you send your source code and the compiler's error messages to 617%s, you can be helped and I can get smarter -- 618win-win for us!""" % (msg, _EMAIL)) 619 else: 620 print ('------------------------------------------------------------') 621 print ('Your code appears to have the following',) 622 if count > 1: 623 print ('%s diseases:' % (count,)) 624 else: 625 print ('disease:') 626 i = 0 627 for d in diagnoses: 628 i += 1 629 if count > 1: 630 print ('\n#%s:' % (i,)) 631 print (d) 632 print (""" 633How did I do? If you think I'm wrong or unhelpful, please send your 634source code and the compiler's error messages to %s. 635Then you can be helped and I can get smarter -- I promise I won't be upset!""" % 636 _EMAIL) 637 638 639if __name__ == '__main__': 640 main() 641