verifiers.py (11510:b539c1a6e597) verifiers.py (11541:3d518944f0cc)
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

--- 171 unchanged lines hidden (view full) ---

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

--- 171 unchanged lines hidden (view full) ---

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:]

--- 61 unchanged lines hidden (view full) ---

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:]

--- 61 unchanged lines hidden (view full) ---

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) ]