Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # | 2 # |
| 3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved. | 3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved. |
| 4 # Copyright (C) 2009 Torch Mobile Inc. | 4 # Copyright (C) 2009 Torch Mobile Inc. |
| 5 # Copyright (C) 2009 Apple Inc. All rights reserved. | 5 # Copyright (C) 2009 Apple Inc. All rights reserved. |
| 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) | 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) |
| 7 # | 7 # |
| 8 # Redistribution and use in source and binary forms, with or without | 8 # Redistribution and use in source and binary forms, with or without |
| 9 # modification, are permitted provided that the following conditions are | 9 # modification, are permitted provided that the following conditions are |
| 10 # met: | 10 # met: |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 import math # for log | 40 import math # for log |
| 41 import os | 41 import os |
| 42 import os.path | 42 import os.path |
| 43 import re | 43 import re |
| 44 import sre_compile | 44 import sre_compile |
| 45 import string | 45 import string |
| 46 import sys | 46 import sys |
| 47 import unicodedata | 47 import unicodedata |
| 48 | 48 |
| 49 from webkitpy.common.memoized import memoized | 49 from webkitpy.common.memoized import memoized |
| 50 from webkitpy.common.system.filesystem import FileSystem | |
| 50 | 51 |
| 51 # The key to use to provide a class to fake loading a header file. | 52 # The key to use to provide a class to fake loading a header file. |
| 52 INCLUDE_IO_INJECTION_KEY = 'include_header_io' | 53 INCLUDE_IO_INJECTION_KEY = 'include_header_io' |
| 53 | 54 |
| 54 # Headers that we consider STL headers. | 55 # Headers that we consider STL headers. |
| 55 _STL_HEADERS = frozenset([ | 56 _STL_HEADERS = frozenset([ |
| 56 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', | 57 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', |
| 57 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', | 58 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', |
| 58 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', | 59 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', |
| 59 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', | 60 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', |
| (...skipping 3217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3277 error(line_number, 'runtime/bitfields', 5, | 3278 error(line_number, 'runtime/bitfields', 5, |
| 3278 'Please declare integral type bitfields with either signed or unsi gned.') | 3279 'Please declare integral type bitfields with either signed or unsi gned.') |
| 3279 | 3280 |
| 3280 check_identifier_name_in_declaration(filename, line_number, line, file_state , error) | 3281 check_identifier_name_in_declaration(filename, line_number, line, file_state , error) |
| 3281 | 3282 |
| 3282 # Check for unsigned int (should be just 'unsigned') | 3283 # Check for unsigned int (should be just 'unsigned') |
| 3283 if search(r'\bunsigned int\b', line): | 3284 if search(r'\bunsigned int\b', line): |
| 3284 error(line_number, 'runtime/unsigned', 1, | 3285 error(line_number, 'runtime/unsigned', 1, |
| 3285 'Omit int when using unsigned') | 3286 'Omit int when using unsigned') |
| 3286 | 3287 |
| 3287 # Check that we're not using static_cast<Text*>. | 3288 # Check for usage of static_cast<Classname*>. |
| 3288 if search(r'\bstatic_cast<Text\*>', line): | 3289 check_for_object_static_cast(filename, line_number, line, error) |
| 3289 error(line_number, 'readability/check', 4, | 3290 |
| 3290 'Consider using toText helper function in WebCore/dom/Text.h ' | |
| 3291 'instead of static_cast<Text*>') | |
| 3292 | 3291 |
| 3293 def check_identifier_name_in_declaration(filename, line_number, line, file_state , error): | 3292 def check_identifier_name_in_declaration(filename, line_number, line, file_state , error): |
| 3294 """Checks if identifier names contain any underscores. | 3293 """Checks if identifier names contain any underscores. |
| 3295 | 3294 |
| 3296 As identifiers in libraries we are using have a bunch of | 3295 As identifiers in libraries we are using have a bunch of |
| 3297 underscores, we only warn about the declarations of identifiers | 3296 underscores, we only warn about the declarations of identifiers |
| 3298 and don't check use of identifiers. | 3297 and don't check use of identifiers. |
| 3299 | 3298 |
| 3300 Args: | 3299 Args: |
| 3301 filename: The name of the current file. | 3300 filename: The name of the current file. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3414 return | 3413 return |
| 3415 # We should continue checking if this is a function | 3414 # We should continue checking if this is a function |
| 3416 # declaration because we need to check its arguments. | 3415 # declaration because we need to check its arguments. |
| 3417 # Also, we need to check multiple declarations. | 3416 # Also, we need to check multiple declarations. |
| 3418 if character_after_identifier != '(' and character_after_identifier != ' ,': | 3417 if character_after_identifier != '(' and character_after_identifier != ' ,': |
| 3419 return | 3418 return |
| 3420 | 3419 |
| 3421 number_of_identifiers += 1 | 3420 number_of_identifiers += 1 |
| 3422 line = line[matched.end():] | 3421 line = line[matched.end():] |
| 3423 | 3422 |
| 3423 | |
| 3424 def check_for_toFoo_definition(filename, pattern, error): | |
| 3425 """ Reports for using static_cast instead of toFoo convenience function. | |
| 3426 | |
| 3427 This function will output warnings to make sure you are actually using | |
| 3428 the added toFoo conversion functions rather than directly hard coding | |
| 3429 the static_cast<Classname*> call. For example, you should toHTMLELement(Node *) | |
| 3430 to convert Node* to HTMLElement*, instead of static_cast<HTMLElement*>(Node* ) | |
| 3431 | |
| 3432 Args: | |
| 3433 filename: The name of the header file in which to check for toFoo definiti on. | |
| 3434 pattern: The conversion function pattern to grep for. | |
| 3435 error: The function to call with any errors found. | |
| 3436 """ | |
| 3437 def get_abs_filepath(filename): | |
| 3438 fileSystem = FileSystem() | |
| 3439 _sep = 'src/third_party/WebKit' | |
|
inferno
2013/10/01 05:29:38
This will be overkill since we have ton of layout
r.kasibhatla
2013/10/01 09:53:46
Done.
| |
| 3440 base_dir = fileSystem.path_to_module(FileSystem.__module__).split(_sep, 1)[0] | |
| 3441 base_dir = ''.join((base_dir, _sep)) | |
| 3442 for root, dirs, names in os.walk(base_dir): | |
| 3443 if filename in names: | |
| 3444 return os.path.join(root, filename) | |
| 3445 return None | |
| 3446 | |
| 3447 def grep(lines, pattern, error): | |
| 3448 matches = [] | |
| 3449 function_state = None | |
| 3450 for line_number in xrange(lines.num_lines()): | |
| 3451 line = (lines.elided[line_number]).rstrip() | |
| 3452 try: | |
| 3453 if pattern in line: | |
| 3454 if not function_state: | |
| 3455 function_state = _FunctionState(1) | |
| 3456 detect_functions(lines, line_number, function_state, error) | |
| 3457 # Exclude the match of dummy conversion function. Dummy func tion is just to | |
| 3458 # catch invalid conversions and shouldn't be part of possibl e alternatives. | |
| 3459 result = re.search(r'%s(\s+)%s' % ("void", pattern), line) | |
| 3460 if not result: | |
| 3461 matches.append([line, function_state.body_start_position .row, function_state.end_position.row + 1]) | |
| 3462 function_state = None | |
| 3463 except UnicodeDecodeError: | |
| 3464 # There would be no non-ascii characters in the codebase ever. T he only exception | |
| 3465 # would be comments/copyright text which might have non-ascii ch aracters. Hence, | |
| 3466 # it is prefectly safe to catch the UnicodeDecodeError and just pass the line. | |
| 3467 pass | |
| 3468 | |
| 3469 return matches | |
| 3470 | |
| 3471 def check_in_mock_header(filename, matches=None, io=codecs): | |
| 3472 if not filename == 'Foo.h': | |
| 3473 return False | |
| 3474 | |
| 3475 io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs) | |
|
Dirk Pranke
2013/09/26 19:01:35
Ick. Can you file a separate bug to clean up all o
r.kasibhatla
2013/09/26 19:07:44
Sorry for re-asking, but should I remove usage of
| |
| 3476 header_file = None | |
| 3477 try: | |
| 3478 header_file = io.open(filename, 'r', 'utf8', 'replace') | |
| 3479 except IOError: | |
| 3480 return False | |
| 3481 line_number = 0 | |
| 3482 for line in header_file: | |
| 3483 line_number += 1 | |
| 3484 matched = re.search(r'\btoFoo\b', line) | |
| 3485 if matched: | |
| 3486 matches.append(['toFoo', line_number, line_number + 3]) | |
| 3487 return True | |
| 3488 | |
| 3489 # For unit testing only, avoid header search and lookup locally. | |
| 3490 matches = [] | |
| 3491 mock_def_found = check_in_mock_header(filename, matches) | |
| 3492 if mock_def_found: | |
| 3493 return matches | |
| 3494 | |
| 3495 # Regular style check flow. Search for actual header file & defs. | |
| 3496 file_path = get_abs_filepath(filename) | |
| 3497 if not file_path: | |
| 3498 return None | |
| 3499 try: | |
| 3500 f = open(file_path) | |
| 3501 clean_lines = CleansedLines(f.readlines()) | |
| 3502 finally: | |
| 3503 f.close() | |
| 3504 | |
| 3505 # Make a list of all genuine alternatives to static_cast. | |
| 3506 matches = grep(clean_lines, pattern, error) | |
| 3507 return matches | |
| 3508 | |
| 3509 | |
| 3510 def check_for_object_static_cast(processing_file, line_number, line, error): | |
| 3511 """Checks for a Cpp-style static cast on objects by looking for the pattern. | |
| 3512 | |
| 3513 Args: | |
| 3514 processing_file: The name of the processing file. | |
| 3515 line_number: The number of the line to check. | |
| 3516 line: The line of code to check. | |
| 3517 error: The function to call with any errors found. | |
| 3518 """ | |
| 3519 matched = search(r'\bstatic_cast<(\s*\w*:?:?\w+\s*\*+\s*)>', line) | |
| 3520 if not matched: | |
| 3521 return | |
| 3522 | |
| 3523 class_name = re.sub('[\*]', '', matched.group(1)) | |
| 3524 class_name = class_name.strip() | |
| 3525 # Ignore (for now) when the casting is to void*, | |
| 3526 if class_name == 'void': | |
| 3527 return | |
| 3528 | |
| 3529 namespace_pos = class_name.find(':') | |
| 3530 if not namespace_pos == -1: | |
| 3531 class_name = class_name[namespace_pos + 2:] | |
| 3532 | |
| 3533 header_file = ''.join((class_name, '.h')) | |
| 3534 matches = check_for_toFoo_definition(header_file, ''.join(('to', class_name) ), error) | |
| 3535 # Ignore (for now) if not able to find the header where toFoo might be defin ed. | |
| 3536 # TODO: Handle cases where Classname might be defined in some other header o r cpp file. | |
| 3537 if matches is None: | |
| 3538 return | |
| 3539 | |
| 3540 report_error = True | |
| 3541 # Ensure found static_cast instance is not from within toFoo definition itse lf. | |
| 3542 if (os.path.basename(processing_file) == header_file): | |
| 3543 for item in matches: | |
| 3544 if line_number in range(item[1], item[2]): | |
| 3545 report_error = False | |
| 3546 break | |
| 3547 | |
| 3548 if report_error: | |
| 3549 if len(matches): | |
| 3550 # toFoo is defined - enforce using it. | |
| 3551 # TODO: Suggest an appropriate toFoo from the alternatives present i n matches. | |
| 3552 error(line_number, 'runtime/casting', 4, | |
| 3553 'static_cast of class objects is not allowed. Use to%s defined in %s.' % | |
| 3554 (class_name, header_file)) | |
| 3555 else: | |
| 3556 # No toFoo defined - enforce definition & usage. | |
| 3557 # TODO: Automate the generation of toFoo() to avoid any slippages ev er. | |
| 3558 error(line_number, 'runtime/casting', 4, | |
| 3559 'static_cast of class objects is not allowed. Add to%s in %s a nd use it instead.' % | |
| 3560 (class_name, header_file)) | |
| 3561 | |
| 3562 | |
| 3424 def check_c_style_cast(line_number, line, raw_line, cast_type, pattern, | 3563 def check_c_style_cast(line_number, line, raw_line, cast_type, pattern, |
| 3425 error): | 3564 error): |
| 3426 """Checks for a C-style cast by looking for the pattern. | 3565 """Checks for a C-style cast by looking for the pattern. |
| 3427 | 3566 |
| 3428 This also handles sizeof(type) warnings, due to similarity of content. | 3567 This also handles sizeof(type) warnings, due to similarity of content. |
| 3429 | 3568 |
| 3430 Args: | 3569 Args: |
| 3431 line_number: The number of the line to check. | 3570 line_number: The number of the line to check. |
| 3432 line: The line of code to check. | 3571 line: The line of code to check. |
| 3433 raw_line: The raw line of code to check, with comments. | 3572 raw_line: The raw line of code to check, with comments. |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3913 self.handle_style_error, self.min_confidence) | 4052 self.handle_style_error, self.min_confidence) |
| 3914 | 4053 |
| 3915 | 4054 |
| 3916 # FIXME: Remove this function (requires refactoring unit tests). | 4055 # FIXME: Remove this function (requires refactoring unit tests). |
| 3917 def process_file_data(filename, file_extension, lines, error, min_confidence, un it_test_config): | 4056 def process_file_data(filename, file_extension, lines, error, min_confidence, un it_test_config): |
| 3918 global _unit_test_config | 4057 global _unit_test_config |
| 3919 _unit_test_config = unit_test_config | 4058 _unit_test_config = unit_test_config |
| 3920 checker = CppChecker(filename, file_extension, error, min_confidence) | 4059 checker = CppChecker(filename, file_extension, error, min_confidence) |
| 3921 checker.check(lines) | 4060 checker.check(lines) |
| 3922 _unit_test_config = {} | 4061 _unit_test_config = {} |
| OLD | NEW |