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 base_dir = fileSystem.path_to_module(FileSystem.__module__).split('WebKi
t', 1)[0] |
| 3440 base_dir = ''.join((base_dir, 'WebKit/Source')) |
| 3441 for root, dirs, names in os.walk(base_dir): |
| 3442 if filename in names: |
| 3443 return os.path.join(root, filename) |
| 3444 return None |
| 3445 |
| 3446 def grep(lines, pattern, error): |
| 3447 matches = [] |
| 3448 function_state = None |
| 3449 for line_number in xrange(lines.num_lines()): |
| 3450 line = (lines.elided[line_number]).rstrip() |
| 3451 try: |
| 3452 if pattern in line: |
| 3453 if not function_state: |
| 3454 function_state = _FunctionState(1) |
| 3455 detect_functions(lines, line_number, function_state, error) |
| 3456 # Exclude the match of dummy conversion function. Dummy func
tion is just to |
| 3457 # catch invalid conversions and shouldn't be part of possibl
e alternatives. |
| 3458 result = re.search(r'%s(\s+)%s' % ("void", pattern), line) |
| 3459 if not result: |
| 3460 matches.append([line, function_state.body_start_position
.row, function_state.end_position.row + 1]) |
| 3461 function_state = None |
| 3462 except UnicodeDecodeError: |
| 3463 # There would be no non-ascii characters in the codebase ever. T
he only exception |
| 3464 # would be comments/copyright text which might have non-ascii ch
aracters. Hence, |
| 3465 # it is prefectly safe to catch the UnicodeDecodeError and just
pass the line. |
| 3466 pass |
| 3467 |
| 3468 return matches |
| 3469 |
| 3470 def check_in_mock_header(filename, matches=None, io=codecs): |
| 3471 if not filename == 'Foo.h': |
| 3472 return False |
| 3473 |
| 3474 io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs) |
| 3475 header_file = None |
| 3476 try: |
| 3477 header_file = io.open(filename, 'r', 'utf8', 'replace') |
| 3478 except IOError: |
| 3479 return False |
| 3480 line_number = 0 |
| 3481 for line in header_file: |
| 3482 line_number += 1 |
| 3483 matched = re.search(r'\btoFoo\b', line) |
| 3484 if matched: |
| 3485 matches.append(['toFoo', line_number, line_number + 3]) |
| 3486 return True |
| 3487 |
| 3488 # For unit testing only, avoid header search and lookup locally. |
| 3489 matches = [] |
| 3490 mock_def_found = check_in_mock_header(filename, matches) |
| 3491 if mock_def_found: |
| 3492 return matches |
| 3493 |
| 3494 # Regular style check flow. Search for actual header file & defs. |
| 3495 file_path = get_abs_filepath(filename) |
| 3496 if not file_path: |
| 3497 return None |
| 3498 try: |
| 3499 f = open(file_path) |
| 3500 clean_lines = CleansedLines(f.readlines()) |
| 3501 finally: |
| 3502 f.close() |
| 3503 |
| 3504 # Make a list of all genuine alternatives to static_cast. |
| 3505 matches = grep(clean_lines, pattern, error) |
| 3506 return matches |
| 3507 |
| 3508 |
| 3509 def check_for_object_static_cast(processing_file, line_number, line, error): |
| 3510 """Checks for a Cpp-style static cast on objects by looking for the pattern. |
| 3511 |
| 3512 Args: |
| 3513 processing_file: The name of the processing file. |
| 3514 line_number: The number of the line to check. |
| 3515 line: The line of code to check. |
| 3516 error: The function to call with any errors found. |
| 3517 """ |
| 3518 matched = search(r'\bstatic_cast<(\s*\w*:?:?\w+\s*\*+\s*)>', line) |
| 3519 if not matched: |
| 3520 return |
| 3521 |
| 3522 class_name = re.sub('[\*]', '', matched.group(1)) |
| 3523 class_name = class_name.strip() |
| 3524 # Ignore (for now) when the casting is to void*, |
| 3525 if class_name == 'void': |
| 3526 return |
| 3527 |
| 3528 namespace_pos = class_name.find(':') |
| 3529 if not namespace_pos == -1: |
| 3530 class_name = class_name[namespace_pos + 2:] |
| 3531 |
| 3532 header_file = ''.join((class_name, '.h')) |
| 3533 matches = check_for_toFoo_definition(header_file, ''.join(('to', class_name)
), error) |
| 3534 # Ignore (for now) if not able to find the header where toFoo might be defin
ed. |
| 3535 # TODO: Handle cases where Classname might be defined in some other header o
r cpp file. |
| 3536 if matches is None: |
| 3537 return |
| 3538 |
| 3539 report_error = True |
| 3540 # Ensure found static_cast instance is not from within toFoo definition itse
lf. |
| 3541 if (os.path.basename(processing_file) == header_file): |
| 3542 for item in matches: |
| 3543 if line_number in range(item[1], item[2]): |
| 3544 report_error = False |
| 3545 break |
| 3546 |
| 3547 if report_error: |
| 3548 if len(matches): |
| 3549 # toFoo is defined - enforce using it. |
| 3550 # TODO: Suggest an appropriate toFoo from the alternatives present i
n matches. |
| 3551 error(line_number, 'runtime/casting', 4, |
| 3552 'static_cast of class objects is not allowed. Use to%s defined
in %s.' % |
| 3553 (class_name, header_file)) |
| 3554 else: |
| 3555 # No toFoo defined - enforce definition & usage. |
| 3556 # TODO: Automate the generation of toFoo() to avoid any slippages ev
er. |
| 3557 error(line_number, 'runtime/casting', 4, |
| 3558 'static_cast of class objects is not allowed. Add to%s in %s a
nd use it instead.' % |
| 3559 (class_name, header_file)) |
| 3560 |
| 3561 |
3424 def check_c_style_cast(line_number, line, raw_line, cast_type, pattern, | 3562 def check_c_style_cast(line_number, line, raw_line, cast_type, pattern, |
3425 error): | 3563 error): |
3426 """Checks for a C-style cast by looking for the pattern. | 3564 """Checks for a C-style cast by looking for the pattern. |
3427 | 3565 |
3428 This also handles sizeof(type) warnings, due to similarity of content. | 3566 This also handles sizeof(type) warnings, due to similarity of content. |
3429 | 3567 |
3430 Args: | 3568 Args: |
3431 line_number: The number of the line to check. | 3569 line_number: The number of the line to check. |
3432 line: The line of code to check. | 3570 line: The line of code to check. |
3433 raw_line: The raw line of code to check, with comments. | 3571 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) | 4051 self.handle_style_error, self.min_confidence) |
3914 | 4052 |
3915 | 4053 |
3916 # FIXME: Remove this function (requires refactoring unit tests). | 4054 # FIXME: Remove this function (requires refactoring unit tests). |
3917 def process_file_data(filename, file_extension, lines, error, min_confidence, un
it_test_config): | 4055 def process_file_data(filename, file_extension, lines, error, min_confidence, un
it_test_config): |
3918 global _unit_test_config | 4056 global _unit_test_config |
3919 _unit_test_config = unit_test_config | 4057 _unit_test_config = unit_test_config |
3920 checker = CppChecker(filename, file_extension, error, min_confidence) | 4058 checker = CppChecker(filename, file_extension, error, min_confidence) |
3921 checker.check(lines) | 4059 checker.check(lines) |
3922 _unit_test_config = {} | 4060 _unit_test_config = {} |
OLD | NEW |