1#!/usr/bin/env python 2# 3# Copyright (c) 2014, 2016 ARM Limited 4# All rights reserved 5# 6# The license below extends only to copyright in the software and shall 7# not be construed as granting a license to any other intellectual 8# property including but not limited to intellectual property relating 9# to a hardware implementation of the functionality of the software 10# licensed hereunder. You may use the software subject to the license 11# terms below provided that you ensure that this notice is replicated 12# unmodified and in its entirety in all distributions of the software, 13# modified or unmodified, in source code or in binary form. 14# 15# Copyright (c) 2006 The Regents of The University of Michigan 16# Copyright (c) 2007,2011 The Hewlett-Packard Development Company 17# Copyright (c) 2016 Advanced Micro Devices, Inc. 18# All rights reserved. 19# 20# Redistribution and use in source and binary forms, with or without 21# modification, are permitted provided that the following conditions are 22# met: redistributions of source code must retain the above copyright 23# notice, this list of conditions and the following disclaimer; 24# redistributions in binary form must reproduce the above copyright 25# notice, this list of conditions and the following disclaimer in the 26# documentation and/or other materials provided with the distribution; 27# neither the name of the copyright holders nor the names of its 28# contributors may be used to endorse or promote products derived from 29# this software without specific prior written permission. 30# 31# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42# 43# Authors: Nathan Binkert 44# Steve Reinhardt 45# Andreas Sandberg 46 47from abc import ABCMeta, abstractmethod 48from difflib import SequenceMatcher 49import inspect 50import os 51import re 52import sys 53 54import style 55import sort_includes 56from region import * 57from file_types import lang_type 58 59def _modified_regions(old, new): 60 try: 61 m = SequenceMatcher(a=old, b=new, autojunk=False) 62 except TypeError: 63 # autojunk was introduced in Python 2.7. We need a fallback 64 # mechanism to support old Python versions. 65 m = SequenceMatcher(a=old, b=new) 66 regions = Regions() 67 for tag, i1, i2, j1, j2 in m.get_opcodes(): 68 if tag != "equal": 69 regions.extend(Region(i1, i2)) 70 return regions 71 72 73class Verifier(object): 74 """Base class for style verifiers 75 76 Verifiers check for style violations and optionally fix such 77 violations. Implementations should either inherit from this class 78 (Verifier) if they need to work on entire files or LineVerifier if 79 they operate on a line-by-line basis. 80 81 Subclasses must define these class attributes: 82 languages = set of strings identifying applicable languages 83 test_name = long descriptive name of test, will be used in 84 messages such as "error in <foo>" or "invalid <foo>" 85 opt_name = short name used to generate command-line options to 86 control the test (--fix-<foo>, --ignore-<foo>, etc.) 87 88 """ 89 90 __metaclass__ = ABCMeta 91 92 def __init__(self, ui, opts, base=None): 93 self.ui = ui 94 self.base = base 95 96 # opt_name must be defined as a class attribute of derived classes. 97 # Check test-specific opts first as these have precedence. 98 self.opt_fix = opts.get('fix_' + self.opt_name, False) 99 self.opt_ignore = opts.get('ignore_' + self.opt_name, False) 100 self.opt_skip = opts.get('skip_' + self.opt_name, False) 101 # If no test-specific opts were set, then set based on "-all" opts. 102 if not (self.opt_fix or self.opt_ignore or self.opt_skip): 103 self.opt_fix = opts.get('fix_all', False) 104 self.opt_ignore = opts.get('ignore_all', False) 105 self.opt_skip = opts.get('skip_all', False) 106 107 def normalize_filename(self, name): 108 abs_name = os.path.abspath(name) 109 if self.base is None: 110 return abs_name 111 112 abs_base = os.path.abspath(self.base) 113 return os.path.relpath(abs_name, start=abs_base) 114 115 def open(self, filename, mode): 116 try: 117 f = file(filename, mode) 118 except OSError, msg: 119 print 'could not open file %s: %s' % (filename, msg) 120 return None 121 122 return f 123 124 def skip(self, filename): 125 # We never want to handle symlinks, so always skip them: If the location 126 # pointed to is a directory, skip it. If the location is a file inside 127 # the gem5 directory, it will be checked as a file, so symlink can be 128 # skipped. If the location is a file outside gem5, we don't want to 129 # check it anyway. 130 if os.path.islink(filename): 131 return True 132 return lang_type(filename) not in self.languages 133 134 def apply(self, filename, regions=all_regions): 135 """Possibly apply to specified regions of file 'filename'. 136 137 Verifier is skipped if --skip-<test> option was provided or if 138 file is not of an applicable type. Otherwise file is checked 139 and error messages printed. Errors are fixed or ignored if 140 the corresponding --fix-<test> or --ignore-<test> options were 141 provided. If neither, the user is prompted for an action. 142 143 Returns True to abort, False otherwise. 144 """ 145 if not (self.opt_skip or self.skip(filename)): 146 errors = self.check(filename, regions) 147 if errors and not self.opt_ignore: 148 if self.opt_fix: 149 self.fix(filename, regions) 150 else: 151 result = self.ui.prompt("(a)bort, (i)gnore, or (f)ix?", 152 'aif', 'a') 153 if result == 'f': 154 self.fix(filename, regions) 155 elif result == 'a': 156 return True # abort 157 158 return False 159 160 @abstractmethod 161 def check(self, filename, regions=all_regions): 162 """Check specified regions of file 'filename'. 163 164 Line-by-line checks can simply provide a check_line() method 165 that returns True if the line is OK and False if it has an 166 error. Verifiers that need a multi-line view (like 167 SortedIncludes) must override this entire function. 168 169 Returns a count of errors (0 if none), though actual non-zero 170 count value is not currently used anywhere. 171 """ 172 pass 173 174 @abstractmethod 175 def fix(self, filename, regions=all_regions): 176 """Fix specified regions of file 'filename'. 177 178 Line-by-line fixes can simply provide a fix_line() method that 179 returns the fixed line. Verifiers that need a multi-line view 180 (like SortedIncludes) must override this entire function. 181 """ 182 pass 183 184class LineVerifier(Verifier): 185 def check(self, filename, regions=all_regions): 186 f = self.open(filename, 'r') 187
| 1#!/usr/bin/env python 2# 3# Copyright (c) 2014, 2016 ARM Limited 4# All rights reserved 5# 6# The license below extends only to copyright in the software and shall 7# not be construed as granting a license to any other intellectual 8# property including but not limited to intellectual property relating 9# to a hardware implementation of the functionality of the software 10# licensed hereunder. You may use the software subject to the license 11# terms below provided that you ensure that this notice is replicated 12# unmodified and in its entirety in all distributions of the software, 13# modified or unmodified, in source code or in binary form. 14# 15# Copyright (c) 2006 The Regents of The University of Michigan 16# Copyright (c) 2007,2011 The Hewlett-Packard Development Company 17# Copyright (c) 2016 Advanced Micro Devices, Inc. 18# All rights reserved. 19# 20# Redistribution and use in source and binary forms, with or without 21# modification, are permitted provided that the following conditions are 22# met: redistributions of source code must retain the above copyright 23# notice, this list of conditions and the following disclaimer; 24# redistributions in binary form must reproduce the above copyright 25# notice, this list of conditions and the following disclaimer in the 26# documentation and/or other materials provided with the distribution; 27# neither the name of the copyright holders nor the names of its 28# contributors may be used to endorse or promote products derived from 29# this software without specific prior written permission. 30# 31# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42# 43# Authors: Nathan Binkert 44# Steve Reinhardt 45# Andreas Sandberg 46 47from abc import ABCMeta, abstractmethod 48from difflib import SequenceMatcher 49import inspect 50import os 51import re 52import sys 53 54import style 55import sort_includes 56from region import * 57from file_types import lang_type 58 59def _modified_regions(old, new): 60 try: 61 m = SequenceMatcher(a=old, b=new, autojunk=False) 62 except TypeError: 63 # autojunk was introduced in Python 2.7. We need a fallback 64 # mechanism to support old Python versions. 65 m = SequenceMatcher(a=old, b=new) 66 regions = Regions() 67 for tag, i1, i2, j1, j2 in m.get_opcodes(): 68 if tag != "equal": 69 regions.extend(Region(i1, i2)) 70 return regions 71 72 73class Verifier(object): 74 """Base class for style verifiers 75 76 Verifiers check for style violations and optionally fix such 77 violations. Implementations should either inherit from this class 78 (Verifier) if they need to work on entire files or LineVerifier if 79 they operate on a line-by-line basis. 80 81 Subclasses must define these class attributes: 82 languages = set of strings identifying applicable languages 83 test_name = long descriptive name of test, will be used in 84 messages such as "error in <foo>" or "invalid <foo>" 85 opt_name = short name used to generate command-line options to 86 control the test (--fix-<foo>, --ignore-<foo>, etc.) 87 88 """ 89 90 __metaclass__ = ABCMeta 91 92 def __init__(self, ui, opts, base=None): 93 self.ui = ui 94 self.base = base 95 96 # opt_name must be defined as a class attribute of derived classes. 97 # Check test-specific opts first as these have precedence. 98 self.opt_fix = opts.get('fix_' + self.opt_name, False) 99 self.opt_ignore = opts.get('ignore_' + self.opt_name, False) 100 self.opt_skip = opts.get('skip_' + self.opt_name, False) 101 # If no test-specific opts were set, then set based on "-all" opts. 102 if not (self.opt_fix or self.opt_ignore or self.opt_skip): 103 self.opt_fix = opts.get('fix_all', False) 104 self.opt_ignore = opts.get('ignore_all', False) 105 self.opt_skip = opts.get('skip_all', False) 106 107 def normalize_filename(self, name): 108 abs_name = os.path.abspath(name) 109 if self.base is None: 110 return abs_name 111 112 abs_base = os.path.abspath(self.base) 113 return os.path.relpath(abs_name, start=abs_base) 114 115 def open(self, filename, mode): 116 try: 117 f = file(filename, mode) 118 except OSError, msg: 119 print 'could not open file %s: %s' % (filename, msg) 120 return None 121 122 return f 123 124 def skip(self, filename): 125 # We never want to handle symlinks, so always skip them: If the location 126 # pointed to is a directory, skip it. If the location is a file inside 127 # the gem5 directory, it will be checked as a file, so symlink can be 128 # skipped. If the location is a file outside gem5, we don't want to 129 # check it anyway. 130 if os.path.islink(filename): 131 return True 132 return lang_type(filename) not in self.languages 133 134 def apply(self, filename, regions=all_regions): 135 """Possibly apply to specified regions of file 'filename'. 136 137 Verifier is skipped if --skip-<test> option was provided or if 138 file is not of an applicable type. Otherwise file is checked 139 and error messages printed. Errors are fixed or ignored if 140 the corresponding --fix-<test> or --ignore-<test> options were 141 provided. If neither, the user is prompted for an action. 142 143 Returns True to abort, False otherwise. 144 """ 145 if not (self.opt_skip or self.skip(filename)): 146 errors = self.check(filename, regions) 147 if errors and not self.opt_ignore: 148 if self.opt_fix: 149 self.fix(filename, regions) 150 else: 151 result = self.ui.prompt("(a)bort, (i)gnore, or (f)ix?", 152 'aif', 'a') 153 if result == 'f': 154 self.fix(filename, regions) 155 elif result == 'a': 156 return True # abort 157 158 return False 159 160 @abstractmethod 161 def check(self, filename, regions=all_regions): 162 """Check specified regions of file 'filename'. 163 164 Line-by-line checks can simply provide a check_line() method 165 that returns True if the line is OK and False if it has an 166 error. Verifiers that need a multi-line view (like 167 SortedIncludes) must override this entire function. 168 169 Returns a count of errors (0 if none), though actual non-zero 170 count value is not currently used anywhere. 171 """ 172 pass 173 174 @abstractmethod 175 def fix(self, filename, regions=all_regions): 176 """Fix specified regions of file 'filename'. 177 178 Line-by-line fixes can simply provide a fix_line() method that 179 returns the fixed line. Verifiers that need a multi-line view 180 (like SortedIncludes) must override this entire function. 181 """ 182 pass 183 184class LineVerifier(Verifier): 185 def check(self, filename, regions=all_regions): 186 f = self.open(filename, 'r') 187
|
| 188 lang = lang_type(filename) 189 assert lang in self.languages 190
|
188 errors = 0 189 for num,line in enumerate(f): 190 if num not in regions: 191 continue 192 line = line.rstrip('\n')
| 191 errors = 0 192 for num,line in enumerate(f): 193 if num not in regions: 194 continue 195 line = line.rstrip('\n')
|
193 if not self.check_line(line):
| 196 if not self.check_line(line, language=lang):
|
194 self.ui.write("invalid %s in %s:%d\n" % \ 195 (self.test_name, filename, num + 1)) 196 if self.ui.verbose: 197 self.ui.write(">>%s<<\n" % line[:-1]) 198 errors += 1
| 197 self.ui.write("invalid %s in %s:%d\n" % \ 198 (self.test_name, filename, num + 1)) 199 if self.ui.verbose: 200 self.ui.write(">>%s<<\n" % line[:-1]) 201 errors += 1
|
| 202 f.close()
|
199 return errors 200 201 def fix(self, filename, regions=all_regions): 202 f = self.open(filename, 'r+') 203
| 203 return errors 204 205 def fix(self, filename, regions=all_regions): 206 f = self.open(filename, 'r+') 207
|
| 208 lang = lang_type(filename) 209 assert lang in self.languages 210
|
204 lines = list(f) 205 206 f.seek(0) 207 f.truncate() 208 209 for i,line in enumerate(lines): 210 line = line.rstrip('\n') 211 if i in regions:
| 211 lines = list(f) 212 213 f.seek(0) 214 f.truncate() 215 216 for i,line in enumerate(lines): 217 line = line.rstrip('\n') 218 if i in regions:
|
212 line = self.fix_line(line)
| 219 line = self.fix_line(line, language=lang)
|
213 214 f.write(line) 215 f.write("\n") 216 f.close()
| 220 221 f.write(line) 222 f.write("\n") 223 f.close()
|
| 224 self.current_language = None
|
217
| 225
|
218
| |
219 @abstractmethod
| 226 @abstractmethod
|
220 def check_line(self, line):
| 227 def check_line(self, line, **kwargs):
|
221 pass 222 223 @abstractmethod
| 228 pass 229 230 @abstractmethod
|
224 def fix_line(self, line):
| 231 def fix_line(self, line, **kwargs):
|
225 pass 226 227class Whitespace(LineVerifier): 228 """Check whitespace. 229 230 Specifically: 231 - No tabs used for indent 232 - No trailing whitespace 233 """ 234
| 232 pass 233 234class Whitespace(LineVerifier): 235 """Check whitespace. 236 237 Specifically: 238 - No tabs used for indent 239 - No trailing whitespace 240 """ 241
|
235 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
| 242 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons', 243 'make', 'dts')) 244 trail_only = set(('make', 'dts')) 245
|
236 test_name = 'whitespace' 237 opt_name = 'white' 238 239 _lead = re.compile(r'^([ \t]+)') 240 _trail = re.compile(r'([ \t]+)$') 241
| 246 test_name = 'whitespace' 247 opt_name = 'white' 248 249 _lead = re.compile(r'^([ \t]+)') 250 _trail = re.compile(r'([ \t]+)$') 251
|
242 def check_line(self, line): 243 match = Whitespace._lead.search(line) 244 if match and match.group(1).find('\t') != -1: 245 return False
| |
246
| 252
|
| 253 def skip_lead(self, language): 254 return language in Whitespace.trail_only 255 256 def check_line(self, line, language): 257 if not self.skip_lead(language): 258 match = Whitespace._lead.search(line) 259 if match and match.group(1).find('\t') != -1: 260 return False 261
|
247 match = Whitespace._trail.search(line) 248 if match: 249 return False 250 251 return True 252
| 262 match = Whitespace._trail.search(line) 263 if match: 264 return False 265 266 return True 267
|
253 def fix_line(self, line): 254 if Whitespace._lead.search(line):
| 268 def fix_line(self, line, language): 269 if not self.skip_lead(language) and Whitespace._lead.search(line):
|
255 newline = '' 256 for i,c in enumerate(line): 257 if c == ' ': 258 newline += ' ' 259 elif c == '\t': 260 newline += ' ' * (tabsize - len(newline) % tabsize) 261 else: 262 newline += line[i:] 263 break 264 265 line = newline 266 267 return line.rstrip() 268 269 270class SortedIncludes(Verifier): 271 """Check for proper sorting of include statements""" 272 273 languages = sort_includes.default_languages 274 test_name = 'include file order' 275 opt_name = 'include' 276 277 def __init__(self, *args, **kwargs): 278 super(SortedIncludes, self).__init__(*args, **kwargs) 279 self.sort_includes = sort_includes.SortIncludes() 280 281 def check(self, filename, regions=all_regions): 282 f = self.open(filename, 'r') 283 norm_fname = self.normalize_filename(filename) 284 285 old = [ l.rstrip('\n') for l in f.xreadlines() ] 286 f.close() 287 288 if len(old) == 0: 289 return 0 290 291 language = lang_type(filename, old[0]) 292 new = list(self.sort_includes(old, norm_fname, language)) 293 294 modified = _modified_regions(old, new) & regions 295 296 if modified: 297 self.ui.write("invalid sorting of includes in %s\n" % (filename)) 298 if self.ui.verbose: 299 for start, end in modified.regions: 300 self.ui.write("bad region [%d, %d)\n" % (start, end)) 301 return 1 302 303 return 0 304 305 def fix(self, filename, regions=all_regions): 306 f = self.open(filename, 'r+') 307 308 old = f.readlines() 309 lines = [ l.rstrip('\n') for l in old ] 310 language = lang_type(filename, lines[0]) 311 sort_lines = list(self.sort_includes(lines, filename, language)) 312 new = ''.join(line + '\n' for line in sort_lines) 313 314 f.seek(0) 315 f.truncate() 316 317 for i,line in enumerate(sort_lines): 318 f.write(line) 319 f.write('\n') 320 f.close() 321 322 323class ControlSpace(LineVerifier): 324 """Check for exactly one space after if/while/for""" 325 326 languages = set(('C', 'C++')) 327 test_name = 'spacing after if/while/for' 328 opt_name = 'control' 329 330 _any_control = re.compile(r'\b(if|while|for)([ \t]*)\(') 331
| 270 newline = '' 271 for i,c in enumerate(line): 272 if c == ' ': 273 newline += ' ' 274 elif c == '\t': 275 newline += ' ' * (tabsize - len(newline) % tabsize) 276 else: 277 newline += line[i:] 278 break 279 280 line = newline 281 282 return line.rstrip() 283 284 285class SortedIncludes(Verifier): 286 """Check for proper sorting of include statements""" 287 288 languages = sort_includes.default_languages 289 test_name = 'include file order' 290 opt_name = 'include' 291 292 def __init__(self, *args, **kwargs): 293 super(SortedIncludes, self).__init__(*args, **kwargs) 294 self.sort_includes = sort_includes.SortIncludes() 295 296 def check(self, filename, regions=all_regions): 297 f = self.open(filename, 'r') 298 norm_fname = self.normalize_filename(filename) 299 300 old = [ l.rstrip('\n') for l in f.xreadlines() ] 301 f.close() 302 303 if len(old) == 0: 304 return 0 305 306 language = lang_type(filename, old[0]) 307 new = list(self.sort_includes(old, norm_fname, language)) 308 309 modified = _modified_regions(old, new) & regions 310 311 if modified: 312 self.ui.write("invalid sorting of includes in %s\n" % (filename)) 313 if self.ui.verbose: 314 for start, end in modified.regions: 315 self.ui.write("bad region [%d, %d)\n" % (start, end)) 316 return 1 317 318 return 0 319 320 def fix(self, filename, regions=all_regions): 321 f = self.open(filename, 'r+') 322 323 old = f.readlines() 324 lines = [ l.rstrip('\n') for l in old ] 325 language = lang_type(filename, lines[0]) 326 sort_lines = list(self.sort_includes(lines, filename, language)) 327 new = ''.join(line + '\n' for line in sort_lines) 328 329 f.seek(0) 330 f.truncate() 331 332 for i,line in enumerate(sort_lines): 333 f.write(line) 334 f.write('\n') 335 f.close() 336 337 338class ControlSpace(LineVerifier): 339 """Check for exactly one space after if/while/for""" 340 341 languages = set(('C', 'C++')) 342 test_name = 'spacing after if/while/for' 343 opt_name = 'control' 344 345 _any_control = re.compile(r'\b(if|while|for)([ \t]*)\(') 346
|
332 def check_line(self, line):
| 347 def check_line(self, line, **kwargs):
|
333 match = ControlSpace._any_control.search(line) 334 return not (match and match.group(2) != " ") 335
| 348 match = ControlSpace._any_control.search(line) 349 return not (match and match.group(2) != " ") 350
|
336 def fix_line(self, line):
| 351 def fix_line(self, line, **kwargs):
|
337 new_line = _any_control.sub(r'\1 (', line) 338 return new_line 339 340 341class LineLength(LineVerifier): 342 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 343 test_name = 'line length' 344 opt_name = 'length' 345
| 352 new_line = _any_control.sub(r'\1 (', line) 353 return new_line 354 355 356class LineLength(LineVerifier): 357 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 358 test_name = 'line length' 359 opt_name = 'length' 360
|
346 def check_line(self, line):
| 361 def check_line(self, line, **kwargs):
|
347 return style.normalized_len(line) <= 79 348
| 362 return style.normalized_len(line) <= 79 363
|
349 def fix(self, filename, regions=all_regions):
| 364 def fix(self, filename, regions=all_regions, **kwargs):
|
350 self.ui.write("Warning: cannot automatically fix overly long lines.\n") 351 352 def fix_line(self, line): 353 pass 354 355class ControlCharacters(LineVerifier): 356 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 357 test_name = 'control character' 358 opt_name = 'ascii' 359 360 valid = ('\n', '\t') 361 invalid = "".join([chr(i) for i in range(0, 0x20) if chr(i) not in valid]) 362
| 365 self.ui.write("Warning: cannot automatically fix overly long lines.\n") 366 367 def fix_line(self, line): 368 pass 369 370class ControlCharacters(LineVerifier): 371 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 372 test_name = 'control character' 373 opt_name = 'ascii' 374 375 valid = ('\n', '\t') 376 invalid = "".join([chr(i) for i in range(0, 0x20) if chr(i) not in valid]) 377
|
363 def check_line(self, line):
| 378 def check_line(self, line, **kwargs):
|
364 return self.fix_line(line) == line 365
| 379 return self.fix_line(line) == line 380
|
366 def fix_line(self, line):
| 381 def fix_line(self, line, **kwargs):
|
367 return line.translate(None, ControlCharacters.invalid) 368 369class BoolCompare(LineVerifier): 370 languages = set(('C', 'C++', 'python')) 371 test_name = 'boolean comparison' 372 opt_name = 'boolcomp' 373 374 regex = re.compile(r'\s*==\s*([Tt]rue|[Ff]alse)\b') 375
| 382 return line.translate(None, ControlCharacters.invalid) 383 384class BoolCompare(LineVerifier): 385 languages = set(('C', 'C++', 'python')) 386 test_name = 'boolean comparison' 387 opt_name = 'boolcomp' 388 389 regex = re.compile(r'\s*==\s*([Tt]rue|[Ff]alse)\b') 390
|
376 def check_line(self, line):
| 391 def check_line(self, line, **kwargs):
|
377 return self.regex.search(line) == None 378
| 392 return self.regex.search(line) == None 393
|
379 def fix_line(self, line):
| 394 def fix_line(self, line, **kwargs):
|
380 match = self.regex.search(line) 381 if match: 382 if match.group(1) in ('true', 'True'): 383 line = self.regex.sub('', line) 384 else: 385 self.ui.write("Warning: cannot automatically fix " 386 "comparisons with false/False.\n") 387 return line 388 389def is_verifier(cls): 390 """Determine if a class is a Verifier that can be instantiated""" 391 392 return inspect.isclass(cls) and issubclass(cls, Verifier) and \ 393 not inspect.isabstract(cls) 394 395# list of all verifier classes 396all_verifiers = [ v for n, v in \ 397 inspect.getmembers(sys.modules[__name__], is_verifier) ]
| 395 match = self.regex.search(line) 396 if match: 397 if match.group(1) in ('true', 'True'): 398 line = self.regex.sub('', line) 399 else: 400 self.ui.write("Warning: cannot automatically fix " 401 "comparisons with false/False.\n") 402 return line 403 404def is_verifier(cls): 405 """Determine if a class is a Verifier that can be instantiated""" 406 407 return inspect.isclass(cls) and issubclass(cls, Verifier) and \ 408 not inspect.isabstract(cls) 409 410# list of all verifier classes 411all_verifiers = [ v for n, v in \ 412 inspect.getmembers(sys.modules[__name__], is_verifier) ]
|