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 diagnosis = """ 179You are using a Return() action in a function that returns a reference to 180%(type)s. Please use ReturnRef() instead.""" 181 return _GenericDiagnoser('NRR', 'Need to Return Reference', 182 [(clang_regex, diagnosis), 183 (gcc_regex, diagnosis % {'type': 'a type'})], 184 msg) 185 186 187def _NeedToReturnSomethingDiagnoser(msg): 188 """Diagnoses the NRS disease, given the error messages by the compiler.""" 189 190 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\'') 201 diagnosis = """ 202You are using an action that returns void, but it needs to return 203%(return_type)s. Please tell it *what* to return. Perhaps you can use 204the pattern DoAll(some_action, Return(some_value))?""" 205 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) 212 213 214def _NeedToReturnNothingDiagnoser(msg): 215 """Diagnoses the NRN disease, given the error messages by the compiler.""" 216 217 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') 236 diagnosis = """ 237You are using an action that returns %(return_type)s, but it needs to return 238void. 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?""" 242 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) 249 250 251def _IncompleteByReferenceArgumentDiagnoser(msg): 252 """Diagnoses the IBRA disease, given the error messages by the compiler.""" 253 254 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::internal2::TypeWithoutFormatter<.*>::' 265 r'PrintValue\' requested here') 266 diagnosis = """ 267In 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.""" 271 272 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', 273 [(gcc_regex, diagnosis), 274 (clang_regex, diagnosis)], 275 msg) 276 277 278def _OverloadedFunctionMatcherDiagnoser(msg): 279 """Diagnoses the OFM disease, given the error messages by the compiler.""" 280 281 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') 285 diagnosis = """ 286The argument you gave to Truly() is an overloaded function. Please tell 287your compiler which overloaded version you want to use. 288 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', 294 [(gcc_regex, diagnosis), 295 (clang_regex, diagnosis)], 296 msg) 297 298 299def _OverloadedFunctionActionDiagnoser(msg): 300 """Diagnoses the OFA disease, given the error messages by the compiler.""" 301 302 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\'') 310 diagnosis = """ 311Function you are passing to Invoke is overloaded. Please tell your compiler 312which 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', 319 [(gcc_regex, diagnosis), 320 (clang_regex, diagnosis)], 321 msg) 322 323 324def _OverloadedMethodActionDiagnoser(msg): 325 """Diagnoses the OMA disease, given the error messages by the compiler.""" 326 327 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 .*, but 2 (arguments )?were provided') 336 diagnosis = """ 337The second argument you gave to Invoke() is an overloaded method. Please 338tell your compiler which overloaded version you want to use. 339 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', 348 [(gcc_regex, diagnosis), 349 (clang_regex, diagnosis)], 350 msg) 351 352 353def _MockObjectPointerDiagnoser(msg): 354 """Diagnoses the MOP disease, given the error messages by the compiler.""" 355 356 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 \'->\'\?') 362 diagnosis = """ 363The 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(...));""" 381 382 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) 390 391 392def _NeedToUseSymbolDiagnoser(msg): 393 """Diagnoses the NUS disease, given the error messages by the compiler.""" 394 395 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 + 398 r'error: (use of undeclared identifier|unknown type name|' 399 r'no template named) \'(?P<symbol>[^\']+)\'') 400 diagnosis = """ 401'%(symbol)s' is defined by Google Mock in the testing namespace. 402Did you forget to write 403 using testing::%(symbol)s; 404?""" 405 for m in (list(_FindAllMatches(gcc_regex, msg)) + 406 list(_FindAllMatches(clang_regex, msg))): 407 symbol = m.groupdict()['symbol'] 408 if symbol in _COMMON_GMOCK_SYMBOLS: 409 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) 410 411 412def _NeedToUseReturnNullDiagnoser(msg): 413 """Diagnoses the NRNULL disease, given the error messages by the compiler.""" 414 415 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>' 416 '::operator testing::Action<Func>\(\) const.*\n' + 417 _GCC_FILE_LINE_RE + r'instantiated from here\n' 418 r'.*error: no matching function for call to \'ImplicitCast_\(' 419 r'(:?long )?int&\)') 420 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' 421 r'call to \'ImplicitCast_\'\r?\n' 422 r'(.*\n)*?' + 423 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 424 r'of function template specialization ' 425 r'\'testing::internal::ReturnAction<(int|long)>::operator ' 426 r'Action<(?P<type>.*)\(\)>\' requested here') 427 diagnosis = """ 428You are probably calling Return(NULL) and the compiler isn't sure how to turn 429NULL into %(type)s. Use ReturnNull() instead. 430Note: the line number may be off; please fix all instances of Return(NULL).""" 431 return _GenericDiagnoser( 432 'NRNULL', 'Need to use ReturnNull', 433 [(clang_regex, diagnosis), 434 (gcc_regex, diagnosis % {'type': 'the right type'})], 435 msg) 436 437 438def _TypeInTemplatedBaseDiagnoser(msg): 439 """Diagnoses the TTB disease, given the error messages by the compiler.""" 440 441 # This version works when the type is used as the mock function's return 442 # type. 443 gcc_4_3_1_regex_type_in_retval = ( 444 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE + 445 r'error: a function call cannot appear in a constant-expression') 446 gcc_4_4_0_regex_type_in_retval = ( 447 r'error: a function call cannot appear in a constant-expression' 448 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n') 449 # This version works when the type is used as the mock function's sole 450 # parameter type. 451 gcc_regex_type_of_sole_param = ( 452 _GCC_FILE_LINE_RE + 453 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 454 r'.*error: template argument 1 is invalid\n') 455 # This version works when the type is used as a parameter of a mock 456 # function that has multiple parameters. 457 gcc_regex_type_of_a_param = ( 458 r'error: expected `;\' before \'::\' token\n' 459 + _GCC_FILE_LINE_RE + 460 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 461 r'.*error: template argument 1 is invalid\n' 462 r'.*error: \'.+\' was not declared in this scope') 463 clang_regex_type_of_retval_or_sole_param = ( 464 _CLANG_FILE_LINE_RE + 465 r'error: use of undeclared identifier \'(?P<type>.*)\'\n' 466 r'(.*\n)*?' 467 r'(?P=file):(?P=line):\d+: error: ' 468 r'non-friend class member \'Result\' cannot have a qualified name' 469 ) 470 clang_regex_type_of_a_param = ( 471 _CLANG_FILE_LINE_RE + 472 r'error: C\+\+ requires a type specifier for all declarations\n' 473 r'(.*\n)*?' 474 r'(?P=file):(?P=line):(?P=column): error: ' 475 r'C\+\+ requires a type specifier for all declarations' 476 ) 477 clang_regex_unknown_type = ( 478 _CLANG_FILE_LINE_RE + 479 r'error: unknown type name \'(?P<type>[^\']+)\'' 480 ) 481 482 diagnosis = """ 483In a mock class template, types or typedefs defined in the base class 484template are *not* automatically visible. This is how C++ works. Before 485you can use a type or typedef named %(type)s defined in base class Base<T>, you 486need to make it visible. One way to do it is: 487 488 typedef typename Base<T>::%(type)s %(type)s;""" 489 490 for diag in _GenericDiagnoser( 491 'TTB', 'Type in Template Base', 492 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}), 493 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}), 494 (gcc_regex_type_of_sole_param, diagnosis), 495 (gcc_regex_type_of_a_param, diagnosis), 496 (clang_regex_type_of_retval_or_sole_param, diagnosis), 497 (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})], 498 msg): 499 yield diag 500 # Avoid overlap with the NUS pattern. 501 for m in _FindAllMatches(clang_regex_unknown_type, msg): 502 type_ = m.groupdict()['type'] 503 if type_ not in _COMMON_GMOCK_SYMBOLS: 504 yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict()) 505 506 507def _WrongMockMethodMacroDiagnoser(msg): 508 """Diagnoses the WMM disease, given the error messages by the compiler.""" 509 510 gcc_regex = (_GCC_FILE_LINE_RE + 511 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n' 512 r'.*\n' 513 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>') 514 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + 515 r'error:.*array.*negative.*r?\n' 516 r'(.*\n)*?' 517 r'(?P=file):(?P=line):(?P=column): error: too few arguments ' 518 r'to function call, expected (?P<args>\d+), ' 519 r'have (?P<wrong_args>\d+)') 520 diagnosis = """ 521You are using MOCK_METHOD%(wrong_args)s to define a mock method that has 522%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, 523MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" 524 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', 525 [(gcc_regex, diagnosis), 526 (clang_regex, diagnosis)], 527 msg) 528 529 530def _WrongParenPositionDiagnoser(msg): 531 """Diagnoses the WPP disease, given the error messages by the compiler.""" 532 533 gcc_regex = (_GCC_FILE_LINE_RE + 534 r'error:.*testing::internal::MockSpec<.* has no member named \'' 535 r'(?P<method>\w+)\'') 536 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + 537 r'error: no member named \'(?P<method>\w+)\' in ' 538 r'\'testing::internal::MockSpec<.*>\'') 539 diagnosis = """ 540The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* 541".%(method)s". For example, you should write: 542 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...); 543instead of: 544 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" 545 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position', 546 [(gcc_regex, diagnosis), 547 (clang_regex, diagnosis)], 548 msg) 549 550 551_DIAGNOSERS = [ 552 _IncompleteByReferenceArgumentDiagnoser, 553 _MockObjectPointerDiagnoser, 554 _NeedToReturnNothingDiagnoser, 555 _NeedToReturnReferenceDiagnoser, 556 _NeedToReturnSomethingDiagnoser, 557 _NeedToUseReturnNullDiagnoser, 558 _NeedToUseSymbolDiagnoser, 559 _OverloadedFunctionActionDiagnoser, 560 _OverloadedFunctionMatcherDiagnoser, 561 _OverloadedMethodActionDiagnoser, 562 _TypeInTemplatedBaseDiagnoser, 563 _WrongMockMethodMacroDiagnoser, 564 _WrongParenPositionDiagnoser, 565 ] 566 567 568def Diagnose(msg): 569 """Generates all possible diagnoses given the compiler error message.""" 570 571 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting. 572 # Assuming the string is using the UTF-8 encoding, replaces the left and 573 # the right single quote characters with apostrophes. 574 msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg) 575 576 diagnoses = [] 577 for diagnoser in _DIAGNOSERS: 578 for diag in diagnoser(msg): 579 diagnosis = '[%s - %s]\n%s' % diag 580 if not diagnosis in diagnoses: 581 diagnoses.append(diagnosis) 582 return diagnoses 583 584 585def main(): 586 print ('Google Mock Doctor v%s - ' 587 'diagnoses problems in code using Google Mock.' % _VERSION) 588 589 if sys.stdin.isatty(): 590 print ('Please copy and paste the compiler errors here. Press c-D when ' 591 'you are done:') 592 else: 593 print 'Waiting for compiler errors on stdin . . .' 594 595 msg = sys.stdin.read().strip() 596 diagnoses = Diagnose(msg) 597 count = len(diagnoses) 598 if not count: 599 print (""" 600Your compiler complained: 6018<------------------------------------------------------------ 602%s 603------------------------------------------------------------>8 604 605Uh-oh, I'm not smart enough to figure out what the problem is. :-( 606However... 607If you send your source code and the compiler's error messages to 608%s, you can be helped and I can get smarter -- 609win-win for us!""" % (msg, _EMAIL)) 610 else: 611 print '------------------------------------------------------------' 612 print 'Your code appears to have the following', 613 if count > 1: 614 print '%s diseases:' % (count,) 615 else: 616 print 'disease:' 617 i = 0 618 for d in diagnoses: 619 i += 1 620 if count > 1: 621 print '\n#%s:' % (i,) 622 print d 623 print (""" 624How did I do? If you think I'm wrong or unhelpful, please send your 625source code and the compiler's error messages to %s. 626Then you can be helped and I can get smarter -- I promise I won't be upset!""" % 627 _EMAIL) 628 629 630if __name__ == '__main__': 631 main() 632