Пример #1
0
class TestExpectationsChecker(object):
    """Processes TestExpectations lines for validating the syntax."""

    categories = set(['test/expectations'])

    def _determine_port_from_expectations_path(self, host, expectations_path):
        # Pass a configuration to avoid calling default_configuration() when initializing the port (takes 0.5 seconds on a Mac Pro!).
        options = optparse.Values({'configuration': 'Release'})
        for port_name in host.port_factory.all_port_names():
            port = host.port_factory.get(port_name, options=options)
            for test_expectation_file in port.expectations_files():
                if test_expectation_file.replace(
                        port.path_from_webkit_base() + host.filesystem.sep,
                        '') == expectations_path:
                    return port
        return None

    def __init__(self, file_path, handle_style_error, host=None):
        self._file_path = file_path
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

        # FIXME: host should be a required parameter, not an optional one.
        host = host or Host()
        host.initialize_scm()

        self._port_obj = self._determine_port_from_expectations_path(
            host, file_path)

        # Suppress error messages of test_expectations module since they will be reported later.
        log = logging.getLogger(
            "webkitpy.layout_tests.layout_package.test_expectations")
        log.setLevel(logging.CRITICAL)

    def _handle_error_message(self, lineno, message, confidence):
        pass

    def check_test_expectations(self, expectations_str, tests=None):
        parser = TestExpectationParser(self._port_obj,
                                       tests,
                                       allow_rebaseline_modifier=False)
        expectations = parser.parse('expectations', expectations_str)

        level = 5
        for expectation_line in expectations:
            for warning in expectation_line.warnings:
                self._handle_style_error(expectation_line.line_number,
                                         'test/expectations', level, warning)

    def check_tabs(self, lines):
        self._tab_checker.check(lines)

    def check(self, lines):
        expectations = '\n'.join(lines)
        if self._port_obj:
            self.check_test_expectations(expectations_str=expectations,
                                         tests=None)

        # Warn tabs in lines as well
        self.check_tabs(lines)
Пример #2
0
class TestExpectationsChecker(object):
    """Processes TestExpectations lines for validating the syntax."""

    categories = set(['test/expectations'])

    def _determine_port_from_expectations_path(self, host, expectations_path):
        # Pass a configuration to avoid calling default_configuration() when initializing the port (takes 0.5 seconds on a Mac Pro!).
        options_wk1 = optparse.Values({'configuration': 'Release', 'webkit_test_runner': False})
        options_wk2 = optparse.Values({'configuration': 'Release', 'webkit_test_runner': True})
        for port_name in host.port_factory.all_port_names():
            ports = [host.port_factory.get(port_name, options=options_wk1), host.port_factory.get(port_name, options=options_wk2)]
            for port in ports:
                for test_expectation_file in port.expectations_files():
                    if test_expectation_file.replace(port.path_from_webkit_base() + host.filesystem.sep, '') == expectations_path:
                        return port
        return None

    def __init__(self, file_path, handle_style_error, host=None):
        self._file_path = file_path
        self._handle_style_error = handle_style_error
        self._handle_style_error.turn_off_line_filtering()
        self._tab_checker = TabChecker(file_path, handle_style_error)

        # FIXME: host should be a required parameter, not an optional one.
        host = host or Host()
        host._initialize_scm()

        self._port_obj = self._determine_port_from_expectations_path(host, file_path)

        # Suppress error messages of test_expectations module since they will be reported later.
        log = logging.getLogger("webkitpy.layout_tests.layout_package.test_expectations")
        log.setLevel(logging.CRITICAL)

    def _handle_error_message(self, lineno, message, confidence):
        pass

    def check_test_expectations(self, expectations_str, tests=None):
        parser = TestExpectationParser(self._port_obj, tests, False)
        expectations = parser.parse('expectations', expectations_str)

        level = 5
        for expectation_line in expectations:
            for warning in expectation_line.warnings:
                self._handle_style_error(expectation_line.line_number, 'test/expectations', level, warning)

    def check_tabs(self, lines):
        self._tab_checker.check(lines)

    def check(self, lines):
        expectations = '\n'.join(lines)
        if self._port_obj:
            self.check_test_expectations(expectations_str=expectations, tests=None)
        else:
            self._handle_style_error(1, 'test/expectations', 5,
                                     'No port uses path %s for test_expectations' % self._file_path)
        # Warn tabs in lines as well
        self.check_tabs(lines)
Пример #3
0
class TextChecker(object):
    """Processes text lines for checking style."""
    def __init__(self, file_path, handle_style_error):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
Пример #4
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""

    categories = set(['changelog/bugnumber', 'changelog/filechangedescriptionwhitespace'])

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if re.search("Unreviewed", line, re.IGNORECASE):
                break
            if re.search("build", line, re.IGNORECASE) and re.search("fix", line, re.IGNORECASE):
                break
        else:
            self.handle_style_error(first_line_checked,
                                    "changelog/bugnumber", 5,
                                    "ChangeLog entry has no bug number")
        # check file change descriptions for style violations
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            # filter file change descriptions
            if not re.match('\s*\*\s', line):
                continue
            if re.search(':\s*$', line) or re.search(':\s', line):
                continue
            self.handle_style_error(line_no,
                                    "changelog/filechangedescriptionwhitespace", 5,
                                    "Need whitespace between colon and description")


    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)
Пример #5
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""

    categories = set(
        ['changelog/bugnumber', 'changelog/filechangedescriptionwhitespace'])

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if re.search("Unreviewed", line, re.IGNORECASE):
                break
            if re.search("build", line, re.IGNORECASE) and re.search(
                    "fix", line, re.IGNORECASE):
                break
        else:
            self.handle_style_error(first_line_checked, "changelog/bugnumber",
                                    5, "ChangeLog entry has no bug number")
        # check file change descriptions for style violations
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            # filter file change descriptions
            if not re.match('\s*\*\s', line):
                continue
            if re.search(':\s*$', line) or re.search(':\s', line):
                continue
            self.handle_style_error(
                line_no, "changelog/filechangedescriptionwhitespace", 5,
                "Need whitespace between colon and description")

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)
Пример #6
0
class TextChecker(object):

    """Processes text lines for checking style."""

    def __init__(self, file_path, handle_style_error):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
Пример #7
0
class JSChecker(object):
    """Processes JavaScript lines for checking style."""

    # FIXME: plug in a JavaScript parser to find syntax errors.
    categories = set(('js/syntax',))

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
Пример #8
0
class JSChecker(object):
    """Processes JavaScript lines for checking style."""

    # FIXME: plug in a JavaScript parser to find syntax errors.
    categories = set(('js/syntax', ))

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
    def assert_tab(self, input_lines, error_lines):
        """Assert when the given lines contain tabs."""
        self._error_lines = []

        def style_error_handler(line_number, category, confidence, message):
            self.assertEqual(category, 'whitespace/tab')
            self.assertEqual(confidence, 5)
            self.assertEqual(message, 'Line contains tab character.')
            self._error_lines.append(line_number)

        checker = TabChecker('', style_error_handler)
        checker.check(input_lines)
        self.assertEquals(self._error_lines, error_lines)
Пример #10
0
class TestExpectationsChecker(object):
    """Processes TestExpectations lines for validating the syntax."""

    categories = set(['test/expectations'])

    def __init__(self, file_path, handle_style_error, host=None):
        self._file_path = file_path
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

        # FIXME: host should be a required parameter, not an optional one.
        host = host or Host()
        host.initialize_scm()

        self._port_obj = host.port_factory.get()

        # Suppress error messages of test_expectations module since they will be reported later.
        log = logging.getLogger(
            "webkitpy.layout_tests.layout_package.test_expectations")
        log.setLevel(logging.CRITICAL)

    def _handle_error_message(self, lineno, message, confidence):
        pass

    def check_test_expectations(self, expectations_str, tests=None):
        parser = TestExpectationParser(self._port_obj,
                                       tests,
                                       is_lint_mode=True)
        expectations = parser.parse('expectations', expectations_str)

        level = 5
        for expectation_line in expectations:
            for warning in expectation_line.warnings:
                self._handle_style_error(expectation_line.line_numbers,
                                         'test/expectations', level, warning)

    def check_tabs(self, lines):
        self._tab_checker.check(lines)

    def check(self, lines):
        expectations = '\n'.join(lines)
        if self._port_obj:
            self.check_test_expectations(expectations_str=expectations,
                                         tests=None)

        # Warn tabs in lines as well
        self.check_tabs(lines)
Пример #11
0
class MessagesInChecker(object):
    """Processes .messages.in lines for checking style."""
    def __init__(self, file_path, handle_style_error):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        self.check_WTF_prefix(lines)

    def check_WTF_prefix(self, lines):
        comment = re.compile('^\s*#')
        for line_number, line in enumerate(lines):
            if not comment.match(line) and 'WTF::' in line:
                self.handle_style_error(line_number + 1,
                                        'build/messagesin/wtf', 5,
                                        'Line contains WTF:: prefix.')
Пример #12
0
class MessagesInChecker(object):

    """Processes .messages.in lines for checking style."""

    def __init__(self, file_path, handle_style_error):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        self.check_WTF_prefix(lines)

    def check_WTF_prefix(self, lines):
        comment = re.compile("^\s*#")
        for line_number, line in enumerate(lines):
            if not comment.match(line) and "WTF::" in line:
                self.handle_style_error(line_number + 1, "build/messagesin/wtf", 5, "Line contains WTF:: prefix.")
Пример #13
0
class TestExpectationsChecker(object):
    """Processes TestExpectations lines for validating the syntax."""

    categories = set(["test/expectations"])

    def __init__(self, file_path, handle_style_error, host=None):
        self._file_path = file_path
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

        # FIXME: host should be a required parameter, not an optional one.
        host = host or Host()
        host.initialize_scm()

        self._port_obj = host.port_factory.get()

        # Suppress error messages of test_expectations module since they will be reported later.
        log = logging.getLogger("webkitpy.layout_tests.layout_package.test_expectations")
        log.setLevel(logging.CRITICAL)

    def _handle_error_message(self, lineno, message, confidence):
        pass

    def check_test_expectations(self, expectations_str, tests=None):
        parser = TestExpectationParser(self._port_obj, tests, is_lint_mode=True)
        expectations = parser.parse("expectations", expectations_str)

        level = 5
        for expectation_line in expectations:
            for warning in expectation_line.warnings:
                self._handle_style_error(expectation_line.line_numbers, "test/expectations", level, warning)

    def check_tabs(self, lines):
        self._tab_checker.check(lines)

    def check(self, lines):
        expectations = "\n".join(lines)
        if self._port_obj:
            self.check_test_expectations(expectations_str=expectations, tests=None)

        # Warn tabs in lines as well
        self.check_tabs(lines)
Пример #14
0
class ChangeLogChecker(object):

    """Processes text lines for checking style."""

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if re.search("Unreviewed", line, re.IGNORECASE):
                break
            if re.search("build", line, re.IGNORECASE) and re.search("fix", line, re.IGNORECASE):
                break
        else:
            self.handle_style_error(first_line_checked,
                                    "changelog/bugnumber", 5,
                                    "ChangeLog entry has no bug number")

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)
Пример #15
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""
    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if re.search("Unreviewed", line, re.IGNORECASE):
                break
            if re.search("build", line, re.IGNORECASE) and re.search(
                    "fix", line, re.IGNORECASE):
                break
        else:
            self.handle_style_error(first_line_checked, "changelog/bugnumber",
                                    5, "ChangeLog entry has no bug number")

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)
Пример #16
0
class TestExpectationsChecker(object):
    """Processes TestExpectations lines for validating the syntax."""

    categories = set(['test/expectations'])

    def _determine_port_from_expectations_path(self, host, expectations_path):
        # Pass a configuration to avoid calling default_configuration() when initializing the port (takes 0.5 seconds on a Mac Pro!).
        options_wk1 = optparse.Values({'configuration': 'Release', 'webkit_test_runner': False})
        options_wk2 = optparse.Values({'configuration': 'Release', 'webkit_test_runner': True})
        for port_name in host.port_factory.all_port_names():
            ports = [host.port_factory.get(port_name, options=options_wk1), host.port_factory.get(port_name, options=options_wk2)]
            for port in ports:
                for test_expectation_file in port.expectations_files():
                    if test_expectation_file.replace(port.path_from_webkit_base() + host.filesystem.sep, '') == expectations_path:
                        return port
        return None

    def __init__(self, file_path, handle_style_error, host=None):
        self._file_path = file_path
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

        # FIXME: host should be a required parameter, not an optional one.
        host = host or Host()
        host.initialize_scm()

        self._port_obj = self._determine_port_from_expectations_path(host, file_path)

        # Suppress error messages of test_expectations module since they will be reported later.
        log = logging.getLogger("webkitpy.layout_tests.layout_package.test_expectations")
        log.setLevel(logging.CRITICAL)

    def _handle_error_message(self, lineno, message, confidence):
        pass

    def check_test_expectations(self, expectations_str, tests=None):
        parser = test_expectations.TestExpectationParser(self._port_obj, tests, allow_rebaseline_modifier=False)
        expectations = parser.parse('expectations', expectations_str)

        level = 5
        for expectation_line in expectations:
            for warning in expectation_line.warnings:
                self._handle_style_error(expectation_line.line_number, 'test/expectations', level, warning)

    def check_tabs(self, lines):
        self._tab_checker.check(lines)

    def check(self, lines):
        expectations = '\n'.join(lines)
        if self._port_obj:
            self.check_test_expectations(expectations_str=expectations, tests=None)

        # Warn tabs in lines as well
        self.check_tabs(lines)

    @staticmethod
    def _should_log_linter_warning(warning, files, cwd, host):
        abs_filename = host.filesystem.join(cwd, warning.filename)

        # Case 1, the line the warning was tied to is in our patch.
        if abs_filename in files and files[abs_filename] and warning.line_number in files[abs_filename]:
            return True

        for file, lines in warning.related_files.iteritems():
            abs_filename = host.filesystem.join(cwd, file)
            if abs_filename in files:
                # Case 2, a file associated with the warning is in our patch
                # Note that this will really only happen if you delete a test.
                if lines is None:
                    return True

                # Case 3, a line associated with the warning is in our patch.
                for line in lines:
                    if files[abs_filename] and line in files[abs_filename]:
                        return True
        return False

    @staticmethod
    def lint_test_expectations(files, configuration, cwd, increment_error_count=lambda: 0, line_numbers=None, host=Host()):
        error_count = 0
        files_linted = set()
        ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names()]
        for port in ports_to_lint:
            for expectations_file in port.expectations_dict().keys():
                style_error_handler = DefaultStyleErrorHandler(expectations_file, configuration, increment_error_count, line_numbers)

                try:
                    if expectations_file in files_linted:
                        continue
                    expectations = test_expectations.TestExpectations(
                        port,
                        expectations_to_lint={expectations_file: port.expectations_dict()[expectations_file]})
                    expectations.parse_all_expectations()
                except test_expectations.ParseError as e:
                    for warning in e.warnings:
                        if TestExpectationsChecker._should_log_linter_warning(warning, files, cwd, host):
                            style_error_handler(warning.line_number, 'test/expectations', 5, warning.error)
                            error_count += 1
                files_linted.add(expectations_file)
        return error_count
Пример #17
0
class CMakeChecker(object):
    """Processes CMake lines for checking style."""

    # NO_SPACE_CMDS list are based on commands section of CMake document.
    # Now it is generated from
    # http://www.cmake.org/cmake/help/v2.8.10/cmake.html#section_Commands.
    # Some commands are from default CMake modules such as pkg_check_modules.
    # Please keep list in alphabet order.
    #
    # For commands in this list, spaces should not be added it and its
    # parentheses. For eg, message("testing"), not message ("testing")
    #
    # The conditional commands like if, else, endif, foreach, endforeach,
    # while, endwhile and break are listed in ONE_SPACE_CMDS
    NO_SPACE_CMDS = [
        'add_custom_command',
        'add_custom_target',
        'add_definitions',
        'add_dependencies',
        'add_executable',
        'add_library',
        'add_subdirectory',
        'add_test',
        'aux_source_directory',
        'build_command',
        'cmake_minimum_required',
        'cmake_policy',
        'configure_file',
        'create_test_sourcelist',
        'define_property',
        'enable_language',
        'enable_testing',
        'endfunction',
        'endmacro',
        'execute_process',
        'export',
        'file',
        'find_file',
        'find_library',
        'find_package',
        'find_path',
        'find_program',
        'fltk_wrap_ui',
        'function',
        'get_cmake_property',
        'get_directory_property',
        'get_filename_component',
        'get_property',
        'get_source_file_property',
        'get_target_property',
        'get_test_property',
        'include',
        'include_directories',
        'include_external_msproject',
        'include_regular_expression',
        'install',
        'link_directories',
        'list',
        'load_cache',
        'load_command',
        'macro',
        'mark_as_advanced',
        'math',
        'message',
        'option',
        #From FindPkgConfig.cmake
        'pkg_check_modules',
        'project',
        'remove_definitions',
        'return',
        'separate_arguments',
        'set',
        'set_directory_properties',
        'set_property',
        'set_source_files_properties',
        'set_target_properties',
        'set_tests_properties',
        'site_name',
        'source_group',
        'string',
        'target_link_libraries',
        'try_compile',
        'try_run',
        'unset',
        'variable_watch',
    ]

    # CMake conditional commands, require one space between command and
    # its parentheses, such as "if (", "foreach (", etc.
    ONE_SPACE_CMDS = [
        'if',
        'else',
        'elseif',
        'endif',
        'foreach',
        'endforeach',
        'while',
        'endwhile',
        'break',
    ]

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        for line_number, line in enumerate(lines, start=1):
            self._process_line(line_number, line)
        self._check_list_order(lines)

    def _process_line(self, line_number, line_content):
        if match('(^|\ +)#', line_content):
            # ignore comment line
            return
        l = line_content.expandtabs(4)
        # check command like message( "testing")
        if search('\(\ +', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space after "("')
        # check command like message("testing" )
        if search('\ +\)', l) and not search('^\ +\)$', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space before ")"')
        self._check_trailing_whitespace(line_number, l)
        self._check_no_space_cmds(line_number, l)
        self._check_one_space_cmds(line_number, l)
        self._check_indent(line_number, line_content)

    def _check_trailing_whitespace(self, line_number, line_content):
        line_content = line_content.rstrip('\n')  # chr(10), newline
        line_content = line_content.rstrip('\r')  # chr(13), carriage return
        line_content = line_content.rstrip('\x0c')  # chr(12), form feed, ^L
        stripped = line_content.rstrip()
        if line_content != stripped:
            self._handle_style_error(line_number, 'whitespace/trailing', 5,
                                     'No trailing spaces')

    def _check_no_space_cmds(self, line_number, line_content):
        # check command like "SET    (" or "Set("
        for t in self.NO_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if search('(^|\ +)' + t.lower() + '\ +\(', line_content):
                msg = 'No space between command "' + t.lower(
                ) + '" and its parentheses, should be "' + t + '("'
                self._handle_style_error(line_number, 'whitespace/parentheses',
                                         5, msg)

    def _check_one_space_cmds(self, line_number, line_content):
        # check command like "IF (" or "if(" or "if   (" or "If ()"
        for t in self.ONE_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if search('(^|\ +)' + t.lower() + '(\(|\ \ +\()', line_content):
                msg = 'One space between command "' + t.lower(
                ) + '" and its parentheses, should be "' + t + ' ("'
                self._handle_style_error(line_number, 'whitespace/parentheses',
                                         5, msg)

    def _check_non_lowercase_cmd(self, line_number, line_content, cmd):
        if searchIgnorecase('(^|\ +)' + cmd + '\ *\(', line_content) and \
           (not search('(^|\ +)' + cmd.lower() + '\ *\(', line_content)):
            msg = 'Use lowercase command "' + cmd.lower() + '"'
            self._handle_style_error(line_number, 'command/lowercase', 5, msg)

    def _check_indent(self, line_number, line_content):
        #TODO (halton): add indent checking
        pass

    def _check_list_order(self, lines):
        last_line = None

        for line_number, line in enumerate(lines, start=1):
            matched = search('\$\{.*\}', line)
            if matched:
                continue
            line = line.strip()

            if last_line == None:
                matched = match(
                    '(set\(|list\((APPEND|REMOVE_ITEM) )(?P<name>\w+)(?P<item>\s+\w+)?$',
                    line)
                if matched:
                    # FIXME: Add handling for include directories.
                    if 'INCLUDE_DIRECTORIES' in matched.group('name'):
                        continue
                    empty_lines_count = 0
                    last_line = ''
                    if matched.group('item'):
                        msg = 'First listitem "%s" should be in a new line.' % matched.group(
                            'item').strip()
                        self._handle_style_error(line_number,
                                                 'list/parentheses', 5, msg)
            else:
                matched = match('(?P<item>.+)?\)$', line)
                if matched:
                    last_line = None
                    if matched.group('item'):
                        msg = 'The parentheses after the last listitem "%s" should be in a new line.' % matched.group(
                            'item').strip()
                        self._handle_style_error(line_number,
                                                 'list/parentheses', 5, msg)
                elif line == '':
                    empty_lines_count += 1
                else:
                    last_line_path = self._list_item_path(last_line)
                    line_path = self._list_item_path(line)

                    if line == last_line:
                        msg = 'The item "%s" should be added only once to the list.' % line
                        self._handle_style_error(line_number, 'list/duplicate',
                                                 5, msg)
                    elif line_path < last_line_path or line_path == last_line_path and line < last_line:
                        msg = 'Alphabetical sorting problem. "%s" should be before "%s".' % (
                            line, last_line)
                        self._handle_style_error(line_number, 'list/order', 5,
                                                 msg)
                    elif last_line != '':
                        if line_path != last_line_path:
                            if empty_lines_count != 1:
                                msg = 'There should be exactly one empty line instead of %d between "%s" and "%s".' % (
                                    empty_lines_count, last_line, line)
                                self._handle_style_error(
                                    line_number, 'list/emptyline', 5, msg)
                        elif empty_lines_count != 0:
                            msg = 'There should be no empty line between "%s" and "%s".' % (
                                last_line, line)
                            self._handle_style_error(line_number,
                                                     'list/emptyline', 5, msg)

                    last_line = line
                    empty_lines_count = 0

    def _list_item_path(self, item):
        token = item.split('/')
        if len(token) < 2:
            return ''
        return '/'.join(token[:-1])
Пример #18
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""

    categories = set(['changelog/bugnumber', 'changelog/filechangedescriptionwhitespace'])

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if searchIgnorecase("Unreviewed", line):
                break
            if searchIgnorecase("build", line) and searchIgnorecase("fix", line):
                break
        else:
            self.handle_style_error(first_line_checked,
                                    "changelog/bugnumber", 5,
                                    "ChangeLog entry has no bug number")
        # check file change descriptions for style violations
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            # filter file change descriptions
            if not match('\s*\*\s', line):
                continue
            if search(':\s*$', line) or search(':\s', line):
                continue
            self.handle_style_error(line_no,
                                    "changelog/filechangedescriptionwhitespace", 5,
                                    "Need whitespace between colon and description")

        # check for a lingering "No new tests. (OOPS!)" left over from prepare-changeLog.
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            if match('\s*No new tests. \(OOPS!\)$', line):
                self.handle_style_error(line_no,
                                        "changelog/nonewtests", 5,
                                        "You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible.")

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)
Пример #19
0
class CMakeChecker(object):

    """Processes CMake lines for checking style."""

    # NO_SPACE_CMDS list are based on commands section of CMake document.
    # Now it is generated from
    # http://www.cmake.org/cmake/help/v2.8.10/cmake.html#section_Commands.
    # Some commands are from default CMake modules such as pkg_check_modules.
    # Please keep list in alphabet order.
    #
    # For commands in this list, spaces should not be added it and its
    # parentheses. For eg, message("testing"), not message ("testing")
    #
    # The conditional commands like if, else, endif, foreach, endforeach,
    # while, endwhile and break are listed in ONE_SPACE_CMDS
    NO_SPACE_CMDS = [
        'add_custom_command', 'add_custom_target', 'add_definitions',
        'add_dependencies', 'add_executable', 'add_library',
        'add_subdirectory', 'add_test', 'aux_source_directory',
        'build_command',
        'cmake_minimum_required', 'cmake_policy', 'configure_file',
        'create_test_sourcelist',
        'define_property',
        'enable_language', 'enable_testing', 'endfunction', 'endmacro',
        'execute_process', 'export',
        'file', 'find_file', 'find_library', 'find_package', 'find_path',
        'find_program', 'fltk_wrap_ui', 'function',
        'get_cmake_property', 'get_directory_property',
        'get_filename_component', 'get_property', 'get_source_file_property',
        'get_target_property', 'get_test_property',
        'include', 'include_directories', 'include_external_msproject',
        'include_regular_expression', 'install',
        'link_directories', 'list', 'load_cache', 'load_command',
        'macro', 'mark_as_advanced', 'math', 'message',
        'option',
        #From FindPkgConfig.cmake
        'pkg_check_modules',
        'project',
        'qt_wrap_cpp', 'qt_wrap_ui',
        'remove_definitions', 'return',
        'separate_arguments', 'set', 'set_directory_properties', 'set_property',
        'set_source_files_properties', 'set_target_properties',
        'set_tests_properties', 'site_name', 'source_group', 'string',
        'target_link_libraries', 'try_compile', 'try_run',
        'unset',
        'variable_watch',
    ]

    # CMake conditional commands, require one space between command and
    # its parentheses, such as "if (", "foreach (", etc.
    ONE_SPACE_CMDS = [
        'if', 'else', 'elseif', 'endif',
        'foreach', 'endforeach',
        'while', 'endwhile',
        'break',
    ]

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        self._num_lines = len(lines)
        for l in xrange(self._num_lines):
            self._process_line(l + 1, lines[l])

    def _process_line(self, line_number, line_content):
        if re.match('(^|\ +)#', line_content):
            # ignore comment line
            return
        l = line_content.expandtabs(4)
        # check command like message( "testing")
        if re.search('\(\ +', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space after "("')
        # check command like message("testing" )
        if re.search('\ +\)', l) and not re.search('^\ +\)$', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space before ")"')
        self._check_trailing_whitespace(line_number, l)
        self._check_no_space_cmds(line_number, l)
        self._check_one_space_cmds(line_number, l)
        self._check_indent(line_number, line_content)

    def _check_trailing_whitespace(self, line_number, line_content):
        line_content = line_content.rstrip('\n')    # chr(10), newline
        line_content = line_content.rstrip('\r')    # chr(13), carriage return
        line_content = line_content.rstrip('\x0c')  # chr(12), form feed, ^L
        stripped = line_content.rstrip()
        if line_content != stripped:
            self._handle_style_error(line_number, 'whitespace/trailing', 5,
                                     'No trailing spaces')

    def _check_no_space_cmds(self, line_number, line_content):
        # check command like "SET    (" or "Set("
        for t in self.NO_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if re.search('(^|\ +)' + t.lower() + '\ +\(', line_content):
                msg = 'No space between command "' + t.lower() + '" and its parentheses, should be "' + t + '("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_one_space_cmds(self, line_number, line_content):
        # check command like "IF (" or "if(" or "if   (" or "If ()"
        for t in self.ONE_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if re.search('(^|\ +)' + t.lower() + '(\(|\ \ +\()', line_content):
                msg = 'One space between command "' + t.lower() + '" and its parentheses, should be "' + t + ' ("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_non_lowercase_cmd(self, line_number, line_content, cmd):
        if re.search('(^|\ +)' + cmd + '\ *\(', line_content, flags=re.IGNORECASE) and \
           (not re.search('(^|\ +)' + cmd.lower() + '\ *\(', line_content)):
            msg = 'Use lowercase command "' + cmd.lower() + '"'
            self._handle_style_error(line_number, 'command/lowercase', 5, msg)

    def _check_indent(self, line_number, line_content):
        #TODO (halton): add indent checking
        pass
Пример #20
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""

    categories = set(['changelog/bugnumber', 'changelog/filechangedescriptionwhitespace'])

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if searchIgnorecase("Unreviewed", line):
                break
            if searchIgnorecase("build", line) and searchIgnorecase("fix", line):
                break
        else:
            self.handle_style_error(first_line_checked,
                                    "changelog/bugnumber", 5,
                                    "ChangeLog entry has no bug number")
        # check file change descriptions for style violations
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            # filter file change descriptions
            if not match('\s*\*\s', line):
                continue
            if search(':\s*$', line) or search(':\s', line):
                continue
            self.handle_style_error(line_no,
                                    "changelog/filechangedescriptionwhitespace", 5,
                                    "Need whitespace between colon and description")

        # check for a lingering "No new tests (OOPS!)." left over from prepare-changeLog.
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            if match('\s*No new tests \(OOPS!\)\.$', line):
                self.handle_style_error(line_no,
                                        "changelog/nonewtests", 5,
                                        "You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible.")

        self.check_for_unwanted_security_phrases(first_line_checked, entry_lines)

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)

    def contains_phrase_in_first_line_or_across_two_lines(self, phrase, line1, line2):
        return searchIgnorecase(phrase, line1) or ((not searchIgnorecase(phrase, line2)) and searchIgnorecase(phrase, line1 + " " + line2))

    def check_for_unwanted_security_phrases(self, first_line_checked, lines):
        unwanted_security_phrases = [
            "arbitrary code execution", "buffer overflow", "buffer overrun",
            "buffer underrun", "dangling pointer", "double free", "fuzzer", "fuzzing", "fuzz test",
            "invalid cast", "jsfunfuzz", "malicious", "memory corruption", "security bug",
            "security flaw", "use after free", "use-after-free", "UXSS",
            "WTFCrashWithSecurityImplication",
            "spoof",  # Captures spoof, spoofed, spoofing
            "vulnerab",  # Captures vulnerable, vulnerability, vulnerabilities
        ]

        lines_with_single_spaces = []
        for line in lines:
            lines_with_single_spaces.append(" ".join(line.split()))

        found_unwanted_security_phrases = []
        last_index = len(lines_with_single_spaces) - 1
        first_line_number_with_unwanted_phrase = maxsize
        for unwanted_phrase in unwanted_security_phrases:
            for line_index, line in enumerate(lines_with_single_spaces):
                next_line = "" if line_index >= last_index else lines_with_single_spaces[line_index + 1]
                if self.contains_phrase_in_first_line_or_across_two_lines(unwanted_phrase, line, next_line):
                    found_unwanted_security_phrases.append(unwanted_phrase)
                    first_line_number_with_unwanted_phrase = min(first_line_number_with_unwanted_phrase, first_line_checked + line_index)

        if len(found_unwanted_security_phrases) > 0:
            self.handle_style_error(first_line_number_with_unwanted_phrase,
                                    "changelog/unwantedsecurityterms", 3,
                                    "Please consider whether the use of security-sensitive phrasing could help someone exploit WebKit: {}".format(", ".join(found_unwanted_security_phrases)))
Пример #21
0
class ChangeLogChecker(object):
    """Processes text lines for checking style."""

    categories = set(
        ['changelog/bugnumber', 'changelog/filechangedescriptionwhitespace'])

    def __init__(self, file_path, handle_style_error, should_line_be_checked):
        self.file_path = file_path
        self.handle_style_error = handle_style_error
        self.should_line_be_checked = should_line_be_checked
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check_entry(self, first_line_checked, entry_lines):
        if not entry_lines:
            return
        for line in entry_lines:
            if parse_bug_id_from_changelog(line):
                break
            if searchIgnorecase("Unreviewed", line):
                break
            if searchIgnorecase("build", line) and searchIgnorecase(
                    "fix", line):
                break
        else:
            self.handle_style_error(first_line_checked, "changelog/bugnumber",
                                    5, "ChangeLog entry has no bug number")
        # check file change descriptions for style violations
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            # filter file change descriptions
            if not match('\s*\*\s', line):
                continue
            if search(':\s*$', line) or search(':\s', line):
                continue
            self.handle_style_error(
                line_no, "changelog/filechangedescriptionwhitespace", 5,
                "Need whitespace between colon and description")

        # check for a lingering "No new tests (OOPS!)." left over from prepare-changeLog.
        line_no = first_line_checked - 1
        for line in entry_lines:
            line_no = line_no + 1
            if match('\s*No new tests \(OOPS!\)\.$', line):
                self.handle_style_error(
                    line_no, "changelog/nonewtests", 5,
                    "You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible."
                )

        self.check_for_unwanted_security_phrases(first_line_checked,
                                                 entry_lines)

    def check(self, lines):
        self._tab_checker.check(lines)
        first_line_checked = 0
        entry_lines = []

        for line_index, line in enumerate(lines):
            if not self.should_line_be_checked(line_index + 1):
                # If we transitioned from finding changed lines to
                # unchanged lines, then we are done.
                if first_line_checked:
                    break
                continue
            if not first_line_checked:
                first_line_checked = line_index + 1
            entry_lines.append(line)

        self.check_entry(first_line_checked, entry_lines)

    def contains_phrase_in_first_line_or_across_two_lines(
            self, phrase, line1, line2):
        return searchIgnorecase(phrase, line1) or (
            (not searchIgnorecase(phrase, line2))
            and searchIgnorecase(phrase, line1 + " " + line2))

    def check_for_unwanted_security_phrases(self, first_line_checked, lines):
        unwanted_security_phrases = [
            "arbitrary code execution",
            "buffer overflow",
            "buffer overrun",
            "buffer underrun",
            "dangling pointer",
            "double free",
            "fuzzer",
            "fuzzing",
            "fuzz test",
            "invalid cast",
            "jsfunfuzz",
            "malicious",
            "memory corruption",
            "security bug",
            "security flaw",
            "use after free",
            "use-after-free",
            "UXSS",
            "WTFCrashWithSecurityImplication",
            "spoof",  # Captures spoof, spoofed, spoofing
            "vulnerab",  # Captures vulnerable, vulnerability, vulnerabilities
        ]

        lines_with_single_spaces = []
        for line in lines:
            lines_with_single_spaces.append(" ".join(line.split()))

        found_unwanted_security_phrases = []
        last_index = len(lines_with_single_spaces) - 1
        first_line_number_with_unwanted_phrase = maxsize
        for unwanted_phrase in unwanted_security_phrases:
            for line_index, line in enumerate(lines_with_single_spaces):
                next_line = "" if line_index >= last_index else lines_with_single_spaces[
                    line_index + 1]
                if self.contains_phrase_in_first_line_or_across_two_lines(
                        unwanted_phrase, line, next_line):
                    found_unwanted_security_phrases.append(unwanted_phrase)
                    first_line_number_with_unwanted_phrase = min(
                        first_line_number_with_unwanted_phrase,
                        first_line_checked + line_index)

        if len(found_unwanted_security_phrases) > 0:
            self.handle_style_error(
                first_line_number_with_unwanted_phrase,
                "changelog/unwantedsecurityterms", 3,
                "Please consider whether the use of security-sensitive phrasing could help someone exploit WebKit: {}"
                .format(", ".join(found_unwanted_security_phrases)))
Пример #22
0
class CMakeChecker(object):

    """Processes CMake lines for checking style."""

    # NO_SPACE_CMDS list are based on commands section of CMake document.
    # Now it is generated from
    # http://www.cmake.org/cmake/help/v2.8.10/cmake.html#section_Commands.
    # Some commands are from default CMake modules such as pkg_check_modules.
    # Please keep list in alphabet order.
    #
    # For commands in this list, spaces should not be added it and its
    # parentheses. For eg, message("testing"), not message ("testing")
    #
    # The conditional commands like if, else, endif, foreach, endforeach,
    # while, endwhile and break are listed in ONE_SPACE_CMDS
    NO_SPACE_CMDS = [
        'add_custom_command', 'add_custom_target', 'add_definitions',
        'add_dependencies', 'add_executable', 'add_library',
        'add_subdirectory', 'add_test', 'aux_source_directory',
        'build_command',
        'cmake_minimum_required', 'cmake_policy', 'configure_file',
        'create_test_sourcelist',
        'define_property',
        'enable_language', 'enable_testing', 'endfunction', 'endmacro',
        'execute_process', 'export',
        'file', 'find_file', 'find_library', 'find_package', 'find_path',
        'find_program', 'fltk_wrap_ui', 'function',
        'get_cmake_property', 'get_directory_property',
        'get_filename_component', 'get_property', 'get_source_file_property',
        'get_target_property', 'get_test_property',
        'include', 'include_directories', 'include_external_msproject',
        'include_regular_expression', 'install',
        'link_directories', 'list', 'load_cache', 'load_command',
        'macro', 'mark_as_advanced', 'math', 'message',
        'option',
        #From FindPkgConfig.cmake
        'pkg_check_modules',
        'project',
        'qt_wrap_cpp', 'qt_wrap_ui',
        'remove_definitions', 'return',
        'separate_arguments', 'set', 'set_directory_properties', 'set_property',
        'set_source_files_properties', 'set_target_properties',
        'set_tests_properties', 'site_name', 'source_group', 'string',
        'target_link_libraries', 'try_compile', 'try_run',
        'unset',
        'variable_watch',
    ]

    # CMake conditional commands, require one space between command and
    # its parentheses, such as "if (", "foreach (", etc.
    ONE_SPACE_CMDS = [
        'if', 'else', 'elseif', 'endif',
        'foreach', 'endforeach',
        'while', 'endwhile',
        'break',
    ]

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        self._num_lines = len(lines)
        for l in xrange(self._num_lines):
            self._process_line(l + 1, lines[l])

    def _process_line(self, line_number, line_content):
        if re.match('(^|\ +)#', line_content):
            # ignore comment line
            return
        l = line_content.expandtabs(4)
        # check command like message( "testing")
        if re.search('\(\ +', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space after "("')
        # check command like message("testing" )
        if re.search('\ +\)', l) and not re.search('^\ +\)$', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space before ")"')
        self._check_trailing_whitespace(line_number, l)
        self._check_no_space_cmds(line_number, l)
        self._check_one_space_cmds(line_number, l)
        self._check_indent(line_number, line_content)

    def _check_trailing_whitespace(self, line_number, line_content):
        line_content = line_content.rstrip('\n')    # chr(10), newline
        line_content = line_content.rstrip('\r')    # chr(13), carriage return
        line_content = line_content.rstrip('\x0c')  # chr(12), form feed, ^L
        stripped = line_content.rstrip()
        if line_content != stripped:
            self._handle_style_error(line_number, 'whitespace/trailing', 5,
                                     'No trailing spaces')

    def _check_no_space_cmds(self, line_number, line_content):
        # check command like "SET    (" or "Set("
        for t in self.NO_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if re.search('(^|\ +)' + t.lower() + '\ +\(', line_content):
                msg = 'No space between command "' + t.lower() + '" and its parentheses, should be "' + t + '("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_one_space_cmds(self, line_number, line_content):
        # check command like "IF (" or "if(" or "if   (" or "If ()"
        for t in self.ONE_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if re.search('(^|\ +)' + t.lower() + '(\(|\ \ +\()', line_content):
                msg = 'One space between command "' + t.lower() + '" and its parentheses, should be "' + t + ' ("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_non_lowercase_cmd(self, line_number, line_content, cmd):
        if re.search('(^|\ +)' + cmd + '\ *\(', line_content, flags=re.IGNORECASE) and \
           (not re.search('(^|\ +)' + cmd.lower() + '\ *\(', line_content)):
            msg = 'Use lowercase command "' + cmd.lower() + '"'
            self._handle_style_error(line_number, 'command/lowercase', 5, msg)

    def _check_indent(self, line_number, line_content):
        #TODO (halton): add indent checking
        pass
Пример #23
0
class CMakeChecker(object):

    """Processes CMake lines for checking style."""

    # NO_SPACE_CMDS list are based on commands section of CMake document.
    # Now it is generated from
    # http://www.cmake.org/cmake/help/v2.8.10/cmake.html#section_Commands.
    # Some commands are from default CMake modules such as pkg_check_modules.
    # Please keep list in alphabet order.
    #
    # For commands in this list, spaces should not be added it and its
    # parentheses. For eg, message("testing"), not message ("testing")
    #
    # The conditional commands like if, else, endif, foreach, endforeach,
    # while, endwhile and break are listed in ONE_SPACE_CMDS
    NO_SPACE_CMDS = [
        'add_custom_command', 'add_custom_target', 'add_definitions',
        'add_dependencies', 'add_executable', 'add_library',
        'add_subdirectory', 'add_test', 'aux_source_directory',
        'build_command',
        'cmake_minimum_required', 'cmake_policy', 'configure_file',
        'create_test_sourcelist',
        'define_property',
        'enable_language', 'enable_testing', 'endfunction', 'endmacro',
        'execute_process', 'export',
        'file', 'find_file', 'find_library', 'find_package', 'find_path',
        'find_program', 'fltk_wrap_ui', 'function',
        'get_cmake_property', 'get_directory_property',
        'get_filename_component', 'get_property', 'get_source_file_property',
        'get_target_property', 'get_test_property',
        'include', 'include_directories', 'include_external_msproject',
        'include_regular_expression', 'install',
        'link_directories', 'list', 'load_cache', 'load_command',
        'macro', 'mark_as_advanced', 'math', 'message',
        'option',
        #From FindPkgConfig.cmake
        'pkg_check_modules',
        'project',
        'remove_definitions', 'return',
        'separate_arguments', 'set', 'set_directory_properties', 'set_property',
        'set_source_files_properties', 'set_target_properties',
        'set_tests_properties', 'site_name', 'source_group', 'string',
        'target_link_libraries', 'try_compile', 'try_run',
        'unset',
        'variable_watch',
    ]

    # CMake conditional commands, require one space between command and
    # its parentheses, such as "if (", "foreach (", etc.
    ONE_SPACE_CMDS = [
        'if', 'else', 'elseif', 'endif',
        'foreach', 'endforeach',
        'while', 'endwhile',
        'break',
    ]

    def __init__(self, file_path, handle_style_error):
        self._handle_style_error = handle_style_error
        self._tab_checker = TabChecker(file_path, handle_style_error)

    def check(self, lines):
        self._tab_checker.check(lines)
        for line_number, line in enumerate(lines, start=1):
            self._process_line(line_number, line)
        self._check_list_order(lines)

    def _process_line(self, line_number, line_content):
        if match('(^|\ +)#', line_content):
            # ignore comment line
            return
        l = line_content.expandtabs(4)
        # check command like message( "testing")
        if search('\(\ +', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space after "("')
        # check command like message("testing" )
        if search('\ +\)', l) and not search('^\ +\)$', l):
            self._handle_style_error(line_number, 'whitespace/parentheses', 5,
                                     'No space before ")"')
        self._check_trailing_whitespace(line_number, l)
        self._check_no_space_cmds(line_number, l)
        self._check_one_space_cmds(line_number, l)
        self._check_indent(line_number, line_content)

    def _check_trailing_whitespace(self, line_number, line_content):
        line_content = line_content.rstrip('\n')    # chr(10), newline
        line_content = line_content.rstrip('\r')    # chr(13), carriage return
        line_content = line_content.rstrip('\x0c')  # chr(12), form feed, ^L
        stripped = line_content.rstrip()
        if line_content != stripped:
            self._handle_style_error(line_number, 'whitespace/trailing', 5,
                                     'No trailing spaces')

    def _check_no_space_cmds(self, line_number, line_content):
        # check command like "SET    (" or "Set("
        for t in self.NO_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if search('(^|\ +)' + t.lower() + '\ +\(', line_content):
                msg = 'No space between command "' + t.lower() + '" and its parentheses, should be "' + t + '("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_one_space_cmds(self, line_number, line_content):
        # check command like "IF (" or "if(" or "if   (" or "If ()"
        for t in self.ONE_SPACE_CMDS:
            self._check_non_lowercase_cmd(line_number, line_content, t)
            if search('(^|\ +)' + t.lower() + '(\(|\ \ +\()', line_content):
                msg = 'One space between command "' + t.lower() + '" and its parentheses, should be "' + t + ' ("'
                self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg)

    def _check_non_lowercase_cmd(self, line_number, line_content, cmd):
        if searchIgnorecase('(^|\ +)' + cmd + '\ *\(', line_content) and \
           (not search('(^|\ +)' + cmd.lower() + '\ *\(', line_content)):
            msg = 'Use lowercase command "' + cmd.lower() + '"'
            self._handle_style_error(line_number, 'command/lowercase', 5, msg)

    def _check_indent(self, line_number, line_content):
        #TODO (halton): add indent checking
        pass

    def _check_list_order(self, lines):
        last_line = None

        for line_number, line in enumerate(lines, start=1):
            matched = search('\$\{.*\}', line)
            if matched:
                continue
            line = line.strip()

            if last_line == None:
                matched = match('(set\(|list\((APPEND|REMOVE_ITEM) )(?P<name>\w+)(?P<item>\s+\w+)?$', line)
                if matched:
                    # FIXME: Add handling for include directories.
                    if 'INCLUDE_DIRECTORIES' in matched.group('name'):
                        continue
                    empty_lines_count = 0
                    last_line = ''
                    if matched.group('item'):
                        msg = 'First listitem "%s" should be in a new line.' % matched.group('item').strip()
                        self._handle_style_error(line_number, 'list/parentheses', 5, msg)
            else:
                matched = match('(?P<item>.+)?\)$', line)
                if matched:
                    last_line = None
                    if matched.group('item'):
                        msg = 'The parentheses after the last listitem "%s" should be in a new line.' % matched.group('item').strip()
                        self._handle_style_error(line_number, 'list/parentheses', 5, msg)
                elif line == '':
                    empty_lines_count += 1
                else:
                    last_line_path = self._list_item_path(last_line)
                    line_path = self._list_item_path(line)

                    if line == last_line:
                        msg = 'The item "%s" should be added only once to the list.' % line
                        self._handle_style_error(line_number, 'list/duplicate', 5, msg)
                    elif line_path < last_line_path or line_path == last_line_path and line < last_line:
                        msg = 'Alphabetical sorting problem. "%s" should be before "%s".' % (line, last_line)
                        self._handle_style_error(line_number, 'list/order', 5, msg)
                    elif last_line != '':
                        if line_path != last_line_path:
                            if empty_lines_count != 1:
                                msg = 'There should be exactly one empty line instead of %d between "%s" and "%s".' % (empty_lines_count, last_line, line)
                                self._handle_style_error(line_number, 'list/emptyline', 5, msg)
                        elif empty_lines_count != 0:
                            msg = 'There should be no empty line between "%s" and "%s".' % (last_line, line)
                            self._handle_style_error(line_number, 'list/emptyline', 5, msg)

                    last_line = line
                    empty_lines_count = 0

    def _list_item_path(self, item):
        token = item.split('/')
        if len(token) < 2:
            return ''
        return '/'.join(token[:-1])