@@ 4269-4384 (lines=116) @@ | ||
4266 | return (None, -1) |
|
4267 | ||
4268 | ||
4269 | def CheckCheck(filename, clean_lines, linenum, error): |
|
4270 | """Checks the use of CHECK and EXPECT macros. |
|
4271 | ||
4272 | Args: |
|
4273 | filename: The name of the current file. |
|
4274 | clean_lines: A CleansedLines instance containing the file. |
|
4275 | linenum: The number of the line to check. |
|
4276 | error: The function to call with any errors found. |
|
4277 | """ |
|
4278 | ||
4279 | # Decide the set of replacement macros that should be suggested |
|
4280 | lines = clean_lines.elided |
|
4281 | (check_macro, start_pos) = FindCheckMacro(lines[linenum]) |
|
4282 | if not check_macro: |
|
4283 | return |
|
4284 | ||
4285 | # Find end of the boolean expression by matching parentheses |
|
4286 | (last_line, end_line, end_pos) = CloseExpression( |
|
4287 | clean_lines, linenum, start_pos) |
|
4288 | if end_pos < 0: |
|
4289 | return |
|
4290 | ||
4291 | # If the check macro is followed by something other than a |
|
4292 | # semicolon, assume users will log their own custom error messages |
|
4293 | # and don't suggest any replacements. |
|
4294 | if not Match(r'\s*;', last_line[end_pos:]): |
|
4295 | return |
|
4296 | ||
4297 | if linenum == end_line: |
|
4298 | expression = lines[linenum][start_pos + 1:end_pos - 1] |
|
4299 | else: |
|
4300 | expression = lines[linenum][start_pos + 1:] |
|
4301 | for i in xrange(linenum + 1, end_line): |
|
4302 | expression += lines[i] |
|
4303 | expression += last_line[0:end_pos - 1] |
|
4304 | ||
4305 | # Parse expression so that we can take parentheses into account. |
|
4306 | # This avoids false positives for inputs like "CHECK((a < 4) == b)", |
|
4307 | # which is not replaceable by CHECK_LE. |
|
4308 | lhs = '' |
|
4309 | rhs = '' |
|
4310 | operator = None |
|
4311 | while expression: |
|
4312 | matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' |
|
4313 | r'==|!=|>=|>|<=|<|\()(.*)$', expression) |
|
4314 | if matched: |
|
4315 | token = matched.group(1) |
|
4316 | if token == '(': |
|
4317 | # Parenthesized operand |
|
4318 | expression = matched.group(2) |
|
4319 | (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) |
|
4320 | if end < 0: |
|
4321 | return # Unmatched parenthesis |
|
4322 | lhs += '(' + expression[0:end] |
|
4323 | expression = expression[end:] |
|
4324 | elif token in ('&&', '||'): |
|
4325 | # Logical and/or operators. This means the expression |
|
4326 | # contains more than one term, for example: |
|
4327 | # CHECK(42 < a && a < b); |
|
4328 | # |
|
4329 | # These are not replaceable with CHECK_LE, so bail out early. |
|
4330 | return |
|
4331 | elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): |
|
4332 | # Non-relational operator |
|
4333 | lhs += token |
|
4334 | expression = matched.group(2) |
|
4335 | else: |
|
4336 | # Relational operator |
|
4337 | operator = token |
|
4338 | rhs = matched.group(2) |
|
4339 | break |
|
4340 | else: |
|
4341 | # Unparenthesized operand. Instead of appending to lhs one character |
|
4342 | # at a time, we do another regular expression match to consume several |
|
4343 | # characters at once if possible. Trivial benchmark shows that this |
|
4344 | # is more efficient when the operands are longer than a single |
|
4345 | # character, which is generally the case. |
|
4346 | matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) |
|
4347 | if not matched: |
|
4348 | matched = Match(r'^(\s*\S)(.*)$', expression) |
|
4349 | if not matched: |
|
4350 | break |
|
4351 | lhs += matched.group(1) |
|
4352 | expression = matched.group(2) |
|
4353 | ||
4354 | # Only apply checks if we got all parts of the boolean expression |
|
4355 | if not (lhs and operator and rhs): |
|
4356 | return |
|
4357 | ||
4358 | # Check that rhs do not contain logical operators. We already know |
|
4359 | # that lhs is fine since the loop above parses out && and ||. |
|
4360 | if rhs.find('&&') > -1 or rhs.find('||') > -1: |
|
4361 | return |
|
4362 | ||
4363 | # At least one of the operands must be a constant literal. This is |
|
4364 | # to avoid suggesting replacements for unprintable things like |
|
4365 | # CHECK(variable != iterator) |
|
4366 | # |
|
4367 | # The following pattern matches decimal, hex integers, strings, and |
|
4368 | # characters (in that order). |
|
4369 | lhs = lhs.strip() |
|
4370 | rhs = rhs.strip() |
|
4371 | match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' |
|
4372 | if Match(match_constant, lhs) or Match(match_constant, rhs): |
|
4373 | # Note: since we know both lhs and rhs, we can provide a more |
|
4374 | # descriptive error message like: |
|
4375 | # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) |
|
4376 | # Instead of: |
|
4377 | # Consider using CHECK_EQ instead of CHECK(a == b) |
|
4378 | # |
|
4379 | # We are still keeping the less descriptive message because if lhs |
|
4380 | # or rhs gets long, the error message might become unreadable. |
|
4381 | error(filename, linenum, 'readability/check', 2, |
|
4382 | 'Consider using %s instead of %s(a %s b)' % ( |
|
4383 | _CHECK_REPLACEMENT[check_macro][operator], |
|
4384 | check_macro, operator)) |
|
4385 | ||
4386 | ||
4387 | def CheckAltTokens(filename, clean_lines, linenum, error): |
@@ 4269-4384 (lines=116) @@ | ||
4266 | return (None, -1) |
|
4267 | ||
4268 | ||
4269 | def CheckCheck(filename, clean_lines, linenum, error): |
|
4270 | """Checks the use of CHECK and EXPECT macros. |
|
4271 | ||
4272 | Args: |
|
4273 | filename: The name of the current file. |
|
4274 | clean_lines: A CleansedLines instance containing the file. |
|
4275 | linenum: The number of the line to check. |
|
4276 | error: The function to call with any errors found. |
|
4277 | """ |
|
4278 | ||
4279 | # Decide the set of replacement macros that should be suggested |
|
4280 | lines = clean_lines.elided |
|
4281 | (check_macro, start_pos) = FindCheckMacro(lines[linenum]) |
|
4282 | if not check_macro: |
|
4283 | return |
|
4284 | ||
4285 | # Find end of the boolean expression by matching parentheses |
|
4286 | (last_line, end_line, end_pos) = CloseExpression( |
|
4287 | clean_lines, linenum, start_pos) |
|
4288 | if end_pos < 0: |
|
4289 | return |
|
4290 | ||
4291 | # If the check macro is followed by something other than a |
|
4292 | # semicolon, assume users will log their own custom error messages |
|
4293 | # and don't suggest any replacements. |
|
4294 | if not Match(r'\s*;', last_line[end_pos:]): |
|
4295 | return |
|
4296 | ||
4297 | if linenum == end_line: |
|
4298 | expression = lines[linenum][start_pos + 1:end_pos - 1] |
|
4299 | else: |
|
4300 | expression = lines[linenum][start_pos + 1:] |
|
4301 | for i in xrange(linenum + 1, end_line): |
|
4302 | expression += lines[i] |
|
4303 | expression += last_line[0:end_pos - 1] |
|
4304 | ||
4305 | # Parse expression so that we can take parentheses into account. |
|
4306 | # This avoids false positives for inputs like "CHECK((a < 4) == b)", |
|
4307 | # which is not replaceable by CHECK_LE. |
|
4308 | lhs = '' |
|
4309 | rhs = '' |
|
4310 | operator = None |
|
4311 | while expression: |
|
4312 | matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' |
|
4313 | r'==|!=|>=|>|<=|<|\()(.*)$', expression) |
|
4314 | if matched: |
|
4315 | token = matched.group(1) |
|
4316 | if token == '(': |
|
4317 | # Parenthesized operand |
|
4318 | expression = matched.group(2) |
|
4319 | (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) |
|
4320 | if end < 0: |
|
4321 | return # Unmatched parenthesis |
|
4322 | lhs += '(' + expression[0:end] |
|
4323 | expression = expression[end:] |
|
4324 | elif token in ('&&', '||'): |
|
4325 | # Logical and/or operators. This means the expression |
|
4326 | # contains more than one term, for example: |
|
4327 | # CHECK(42 < a && a < b); |
|
4328 | # |
|
4329 | # These are not replaceable with CHECK_LE, so bail out early. |
|
4330 | return |
|
4331 | elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): |
|
4332 | # Non-relational operator |
|
4333 | lhs += token |
|
4334 | expression = matched.group(2) |
|
4335 | else: |
|
4336 | # Relational operator |
|
4337 | operator = token |
|
4338 | rhs = matched.group(2) |
|
4339 | break |
|
4340 | else: |
|
4341 | # Unparenthesized operand. Instead of appending to lhs one character |
|
4342 | # at a time, we do another regular expression match to consume several |
|
4343 | # characters at once if possible. Trivial benchmark shows that this |
|
4344 | # is more efficient when the operands are longer than a single |
|
4345 | # character, which is generally the case. |
|
4346 | matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) |
|
4347 | if not matched: |
|
4348 | matched = Match(r'^(\s*\S)(.*)$', expression) |
|
4349 | if not matched: |
|
4350 | break |
|
4351 | lhs += matched.group(1) |
|
4352 | expression = matched.group(2) |
|
4353 | ||
4354 | # Only apply checks if we got all parts of the boolean expression |
|
4355 | if not (lhs and operator and rhs): |
|
4356 | return |
|
4357 | ||
4358 | # Check that rhs do not contain logical operators. We already know |
|
4359 | # that lhs is fine since the loop above parses out && and ||. |
|
4360 | if rhs.find('&&') > -1 or rhs.find('||') > -1: |
|
4361 | return |
|
4362 | ||
4363 | # At least one of the operands must be a constant literal. This is |
|
4364 | # to avoid suggesting replacements for unprintable things like |
|
4365 | # CHECK(variable != iterator) |
|
4366 | # |
|
4367 | # The following pattern matches decimal, hex integers, strings, and |
|
4368 | # characters (in that order). |
|
4369 | lhs = lhs.strip() |
|
4370 | rhs = rhs.strip() |
|
4371 | match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' |
|
4372 | if Match(match_constant, lhs) or Match(match_constant, rhs): |
|
4373 | # Note: since we know both lhs and rhs, we can provide a more |
|
4374 | # descriptive error message like: |
|
4375 | # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) |
|
4376 | # Instead of: |
|
4377 | # Consider using CHECK_EQ instead of CHECK(a == b) |
|
4378 | # |
|
4379 | # We are still keeping the less descriptive message because if lhs |
|
4380 | # or rhs gets long, the error message might become unreadable. |
|
4381 | error(filename, linenum, 'readability/check', 2, |
|
4382 | 'Consider using %s instead of %s(a %s b)' % ( |
|
4383 | _CHECK_REPLACEMENT[check_macro][operator], |
|
4384 | check_macro, operator)) |
|
4385 | ||
4386 | ||
4387 | def CheckAltTokens(filename, clean_lines, linenum, error): |