1e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao#!/usr/bin/python
2e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao#
3e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao# Common lint functions applicable to multiple types of files.
4e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
5e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaoimport re
6e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
7e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaodef VerifyLineLength(filename, lines, max_length):
8e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """Checks to make sure the file has no lines with lines exceeding the length
9e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  limit.
10e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
11e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Args:
12e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    filename: the file under consideration as string
13e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lines: contents of the file as string array
14e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    max_length: maximum acceptable line length as number
15e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
16e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Returns:
17e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    A list of tuples with format [(filename, line number, msg), ...] with any
18e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    violations found.
19e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """
20e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  lint = []
21e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  line_num = 1
22e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  for line in lines:
23e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    length = len(line.rstrip('\n'))
24e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    if length > max_length:
25e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao      lint.append((filename, line_num,
26e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao                   'Line exceeds %d chars (%d)' % (max_length, length)))
27e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    line_num += 1
28e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  return lint
29e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
30e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaodef VerifyTabs(filename, lines):
31e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """Checks to make sure the file has no tab characters.
32e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
33e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Args:
34e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    filename: the file under consideration as string
35e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lines: contents of the file as string array
36e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
37e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Returns:
38e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    A list of tuples with format [(line_number, msg), ...] with any violations
39e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    found.
40e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """
41e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  lint = []
42e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  tab_re = re.compile(r'\t')
43e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  line_num = 1
44e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  for line in lines:
45e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    if tab_re.match(line.rstrip('\n')):
46e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao      lint.append((filename, line_num, 'Tab found instead of whitespace'))
47e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    line_num += 1
48e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  return lint
49e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
50e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
51e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaodef VerifyTrailingWhitespace(filename, lines):
52e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """Checks to make sure the file has no lines with trailing whitespace.
53e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
54e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Args:
55e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    filename: the file under consideration as string
56e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lines: contents of the file as string array
57e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
58e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Returns:
59e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    A list of tuples with format [(filename, line number, msg), ...] with any
60e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    violations found.
61e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """
62e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  lint = []
63e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  trailing_whitespace_re = re.compile(r'\s+$')
64e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  line_num = 1
65e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  for line in lines:
66e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    if trailing_whitespace_re.match(line.rstrip('\n')):
67e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao      lint.append((filename, line_num, 'Trailing whitespace'))
68e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    line_num += 1
69e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  return lint
70e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
71e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
72e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaoclass BaseLint:
73e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  def RunOnFile(filename, lines):
74e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    raise Exception('RunOnFile() unimplemented')
75e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
76e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
77e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liaodef RunLintOverAllFiles(linter, filenames):
78e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """Runs linter over the contents of all files.
79e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
80e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Args:
81e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lint: subclass of BaseLint, implementing RunOnFile()
82e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    filenames: list of all files whose contents will be linted
83e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
84e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  Returns:
85e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    A list of tuples with format [(filename, line number, msg), ...] with any
86e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    violations found.
87e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  """
88e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  lint = []
89e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  for filename in filenames:
90e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    file = open(filename, 'r')
91e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    if not file:
92e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao      print 'Cound not open %s' % filename
93e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao      continue
94e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lines = file.readlines()
95e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao    lint.extend(linter.RunOnFile(filename, lines))
96e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao
97e264f62ca09a8f65c87a46d562a4d0f9ec5d457Shih-wei Liao  return lint
98