1 # Copyright (C) 2012 Intel Inc. All rights reserved. 2 # 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions 5 # are met: 6 # 1. Redistributions of source code must retain the above copyright 7 # notice, this list of conditions and the following disclaimer. 8 # 2. Redistributions in binary form must reproduce the above copyright 9 # notice, this list of conditions and the following disclaimer in the 10 # documentation and/or other materials provided with the distribution. 11 # 12 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 13 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 14 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 15 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 16 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 18 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 24 25 """Supports checking WebKit style in cmake files.(.cmake, CMakeLists.txt)""" 26 27 import re 28 29 from common import TabChecker 30 31 32 class CMakeChecker(object): 33 34 """Processes CMake lines for checking style.""" 35 36 # NO_SPACE_CMDS list are based on commands section of CMake document. 37 # Now it is generated from 38 # http://www.cmake.org/cmake/help/v2.8.10/cmake.html#section_Commands. 39 # Some commands are from default CMake modules such as pkg_check_modules. 40 # Please keep list in alphabet order. 41 # 42 # For commands in this list, spaces should not be added it and its 43 # parentheses. For eg, message("testing"), not message ("testing") 44 # 45 # The conditional commands like if, else, endif, foreach, endforeach, 46 # while, endwhile and break are listed in ONE_SPACE_CMDS 47 NO_SPACE_CMDS = [ 48 'add_custom_command', 'add_custom_target', 'add_definitions', 49 'add_dependencies', 'add_executable', 'add_library', 50 'add_subdirectory', 'add_test', 'aux_source_directory', 51 'build_command', 52 'cmake_minimum_required', 'cmake_policy', 'configure_file', 53 'create_test_sourcelist', 54 'define_property', 55 'enable_language', 'enable_testing', 'endfunction', 'endmacro', 56 'execute_process', 'export', 57 'file', 'find_file', 'find_library', 'find_package', 'find_path', 58 'find_program', 'fltk_wrap_ui', 'function', 59 'get_cmake_property', 'get_directory_property', 60 'get_filename_component', 'get_property', 'get_source_file_property', 61 'get_target_property', 'get_test_property', 62 'include', 'include_directories', 'include_external_msproject', 63 'include_regular_expression', 'install', 64 'link_directories', 'list', 'load_cache', 'load_command', 65 'macro', 'mark_as_advanced', 'math', 'message', 66 'option', 67 #From FindPkgConfig.cmake 68 'pkg_check_modules', 69 'project', 70 'qt_wrap_cpp', 'qt_wrap_ui', 71 'remove_definitions', 'return', 72 'separate_arguments', 'set', 'set_directory_properties', 'set_property', 73 'set_source_files_properties', 'set_target_properties', 74 'set_tests_properties', 'site_name', 'source_group', 'string', 75 'target_link_libraries', 'try_compile', 'try_run', 76 'unset', 77 'variable_watch', 78 ] 79 80 # CMake conditional commands, require one space between command and 81 # its parentheses, such as "if (", "foreach (", etc. 82 ONE_SPACE_CMDS = [ 83 'if', 'else', 'elseif', 'endif', 84 'foreach', 'endforeach', 85 'while', 'endwhile', 86 'break', 87 ] 88 89 def __init__(self, file_path, handle_style_error): 90 self._handle_style_error = handle_style_error 91 self._tab_checker = TabChecker(file_path, handle_style_error) 92 93 def check(self, lines): 94 self._tab_checker.check(lines) 95 self._num_lines = len(lines) 96 for l in xrange(self._num_lines): 97 self._process_line(l + 1, lines[l]) 98 99 def _process_line(self, line_number, line_content): 100 if re.match('(^|\ +)#', line_content): 101 # ignore comment line 102 return 103 l = line_content.expandtabs(4) 104 # check command like message( "testing") 105 if re.search('\(\ +', l): 106 self._handle_style_error(line_number, 'whitespace/parentheses', 5, 107 'No space after "("') 108 # check command like message("testing" ) 109 if re.search('\ +\)', l) and not re.search('^\ +\)$', l): 110 self._handle_style_error(line_number, 'whitespace/parentheses', 5, 111 'No space before ")"') 112 self._check_trailing_whitespace(line_number, l) 113 self._check_no_space_cmds(line_number, l) 114 self._check_one_space_cmds(line_number, l) 115 self._check_indent(line_number, line_content) 116 117 def _check_trailing_whitespace(self, line_number, line_content): 118 line_content = line_content.rstrip('\n') # chr(10), newline 119 line_content = line_content.rstrip('\r') # chr(13), carriage return 120 line_content = line_content.rstrip('\x0c') # chr(12), form feed, ^L 121 stripped = line_content.rstrip() 122 if line_content != stripped: 123 self._handle_style_error(line_number, 'whitespace/trailing', 5, 124 'No trailing spaces') 125 126 def _check_no_space_cmds(self, line_number, line_content): 127 # check command like "SET (" or "Set(" 128 for t in self.NO_SPACE_CMDS: 129 self._check_non_lowercase_cmd(line_number, line_content, t) 130 if re.search('(^|\ +)' + t.lower() + '\ +\(', line_content): 131 msg = 'No space between command "' + t.lower() + '" and its parentheses, should be "' + t + '("' 132 self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg) 133 134 def _check_one_space_cmds(self, line_number, line_content): 135 # check command like "IF (" or "if(" or "if (" or "If ()" 136 for t in self.ONE_SPACE_CMDS: 137 self._check_non_lowercase_cmd(line_number, line_content, t) 138 if re.search('(^|\ +)' + t.lower() + '(\(|\ \ +\()', line_content): 139 msg = 'One space between command "' + t.lower() + '" and its parentheses, should be "' + t + ' ("' 140 self._handle_style_error(line_number, 'whitespace/parentheses', 5, msg) 141 142 def _check_non_lowercase_cmd(self, line_number, line_content, cmd): 143 if re.search('(^|\ +)' + cmd + '\ *\(', line_content, flags=re.IGNORECASE) and \ 144 (not re.search('(^|\ +)' + cmd.lower() + '\ *\(', line_content)): 145 msg = 'Use lowercase command "' + cmd.lower() + '"' 146 self._handle_style_error(line_number, 'command/lowercase', 5, msg) 147 148 def _check_indent(self, line_number, line_content): 149 #TODO (halton): add indent checking 150 pass 151