| Index: Tools/Scripts/webkitpy/style/checkers/cpp.py
|
| diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py
|
| index 806f94134700e75ff5541c5ff758d7274f913969..9b6bbf9c34c99d5eae2ab487c37feeece5c32647 100644
|
| --- a/Tools/Scripts/webkitpy/style/checkers/cpp.py
|
| +++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py
|
| @@ -47,6 +47,7 @@ import sys
|
| import unicodedata
|
|
|
| from webkitpy.common.memoized import memoized
|
| +from webkitpy.common.system.filesystem import FileSystem
|
|
|
| # The key to use to provide a class to fake loading a header file.
|
| INCLUDE_IO_INJECTION_KEY = 'include_header_io'
|
| @@ -3284,11 +3285,9 @@ def check_language(filename, clean_lines, line_number, file_extension, include_s
|
| error(line_number, 'runtime/unsigned', 1,
|
| 'Omit int when using unsigned')
|
|
|
| - # Check that we're not using static_cast<Text*>.
|
| - if search(r'\bstatic_cast<Text\*>', line):
|
| - error(line_number, 'readability/check', 4,
|
| - 'Consider using toText helper function in WebCore/dom/Text.h '
|
| - 'instead of static_cast<Text*>')
|
| + # Check for usage of static_cast<Classname*>.
|
| + check_for_object_static_cast(filename, line_number, line, error)
|
| +
|
|
|
| def check_identifier_name_in_declaration(filename, line_number, line, file_state, error):
|
| """Checks if identifier names contain any underscores.
|
| @@ -3421,6 +3420,145 @@ def check_identifier_name_in_declaration(filename, line_number, line, file_state
|
| number_of_identifiers += 1
|
| line = line[matched.end():]
|
|
|
| +
|
| +def check_for_toFoo_definition(filename, pattern, error):
|
| + """ Reports for using static_cast instead of toFoo convenience function.
|
| +
|
| + This function will output warnings to make sure you are actually using
|
| + the added toFoo conversion functions rather than directly hard coding
|
| + the static_cast<Classname*> call. For example, you should toHTMLELement(Node*)
|
| + to convert Node* to HTMLElement*, instead of static_cast<HTMLElement*>(Node*)
|
| +
|
| + Args:
|
| + filename: The name of the header file in which to check for toFoo definition.
|
| + pattern: The conversion function pattern to grep for.
|
| + error: The function to call with any errors found.
|
| + """
|
| + def get_abs_filepath(filename):
|
| + fileSystem = FileSystem()
|
| + base_dir = fileSystem.path_to_module(FileSystem.__module__).split('WebKit', 1)[0]
|
| + base_dir = ''.join((base_dir, 'WebKit/Source'))
|
| + for root, dirs, names in os.walk(base_dir):
|
| + if filename in names:
|
| + return os.path.join(root, filename)
|
| + return None
|
| +
|
| + def grep(lines, pattern, error):
|
| + matches = []
|
| + function_state = None
|
| + for line_number in xrange(lines.num_lines()):
|
| + line = (lines.elided[line_number]).rstrip()
|
| + try:
|
| + if pattern in line:
|
| + if not function_state:
|
| + function_state = _FunctionState(1)
|
| + detect_functions(lines, line_number, function_state, error)
|
| + # Exclude the match of dummy conversion function. Dummy function is just to
|
| + # catch invalid conversions and shouldn't be part of possible alternatives.
|
| + result = re.search(r'%s(\s+)%s' % ("void", pattern), line)
|
| + if not result:
|
| + matches.append([line, function_state.body_start_position.row, function_state.end_position.row + 1])
|
| + function_state = None
|
| + except UnicodeDecodeError:
|
| + # There would be no non-ascii characters in the codebase ever. The only exception
|
| + # would be comments/copyright text which might have non-ascii characters. Hence,
|
| + # it is prefectly safe to catch the UnicodeDecodeError and just pass the line.
|
| + pass
|
| +
|
| + return matches
|
| +
|
| + def check_in_mock_header(filename, matches=None, io=codecs):
|
| + if not filename == 'Foo.h':
|
| + return False
|
| +
|
| + io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs)
|
| + header_file = None
|
| + try:
|
| + header_file = io.open(filename, 'r', 'utf8', 'replace')
|
| + except IOError:
|
| + return False
|
| + line_number = 0
|
| + for line in header_file:
|
| + line_number += 1
|
| + matched = re.search(r'\btoFoo\b', line)
|
| + if matched:
|
| + matches.append(['toFoo', line_number, line_number + 3])
|
| + return True
|
| +
|
| + # For unit testing only, avoid header search and lookup locally.
|
| + matches = []
|
| + mock_def_found = check_in_mock_header(filename, matches)
|
| + if mock_def_found:
|
| + return matches
|
| +
|
| + # Regular style check flow. Search for actual header file & defs.
|
| + file_path = get_abs_filepath(filename)
|
| + if not file_path:
|
| + return None
|
| + try:
|
| + f = open(file_path)
|
| + clean_lines = CleansedLines(f.readlines())
|
| + finally:
|
| + f.close()
|
| +
|
| + # Make a list of all genuine alternatives to static_cast.
|
| + matches = grep(clean_lines, pattern, error)
|
| + return matches
|
| +
|
| +
|
| +def check_for_object_static_cast(processing_file, line_number, line, error):
|
| + """Checks for a Cpp-style static cast on objects by looking for the pattern.
|
| +
|
| + Args:
|
| + processing_file: The name of the processing file.
|
| + line_number: The number of the line to check.
|
| + line: The line of code to check.
|
| + error: The function to call with any errors found.
|
| + """
|
| + matched = search(r'\bstatic_cast<(\s*\w*:?:?\w+\s*\*+\s*)>', line)
|
| + if not matched:
|
| + return
|
| +
|
| + class_name = re.sub('[\*]', '', matched.group(1))
|
| + class_name = class_name.strip()
|
| + # Ignore (for now) when the casting is to void*,
|
| + if class_name == 'void':
|
| + return
|
| +
|
| + namespace_pos = class_name.find(':')
|
| + if not namespace_pos == -1:
|
| + class_name = class_name[namespace_pos + 2:]
|
| +
|
| + header_file = ''.join((class_name, '.h'))
|
| + matches = check_for_toFoo_definition(header_file, ''.join(('to', class_name)), error)
|
| + # Ignore (for now) if not able to find the header where toFoo might be defined.
|
| + # TODO: Handle cases where Classname might be defined in some other header or cpp file.
|
| + if matches is None:
|
| + return
|
| +
|
| + report_error = True
|
| + # Ensure found static_cast instance is not from within toFoo definition itself.
|
| + if (os.path.basename(processing_file) == header_file):
|
| + for item in matches:
|
| + if line_number in range(item[1], item[2]):
|
| + report_error = False
|
| + break
|
| +
|
| + if report_error:
|
| + if len(matches):
|
| + # toFoo is defined - enforce using it.
|
| + # TODO: Suggest an appropriate toFoo from the alternatives present in matches.
|
| + error(line_number, 'runtime/casting', 4,
|
| + 'static_cast of class objects is not allowed. Use to%s defined in %s.' %
|
| + (class_name, header_file))
|
| + else:
|
| + # No toFoo defined - enforce definition & usage.
|
| + # TODO: Automate the generation of toFoo() to avoid any slippages ever.
|
| + error(line_number, 'runtime/casting', 4,
|
| + 'static_cast of class objects is not allowed. Add to%s in %s and use it instead.' %
|
| + (class_name, header_file))
|
| +
|
| +
|
| def check_c_style_cast(line_number, line, raw_line, cast_type, pattern,
|
| error):
|
| """Checks for a C-style cast by looking for the pattern.
|
|
|