comparison contrib/check-code.py @ 14009:64de9ca66511

check-code: separate warnings to avoid repetitive str.startswith
author Idan Kamara <idankk86@gmail.com>
date Mon, 25 Apr 2011 13:03:26 +0300
parents bb391e0515ba
children 673abd432104
comparison
equal deleted inserted replaced
14008:da65edcac72a 14009:64de9ca66511
40 t = re.sub(r"\S", "x", m.group(2)) 40 t = re.sub(r"\S", "x", m.group(2))
41 return m.group(1) + t 41 return m.group(1) + t
42 42
43 43
44 testpats = [ 44 testpats = [
45 [
45 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"), 46 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
46 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"), 47 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
47 (r'^function', "don't use 'function', use old style"), 48 (r'^function', "don't use 'function', use old style"),
48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"), 49 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 (r'echo.*\\n', "don't use 'echo \\n', use printf"), 50 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
65 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"), 66 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
66 (r'^source\b', "don't use 'source', use '.'"), 67 (r'^source\b', "don't use 'source', use '.'"),
67 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"), 68 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
68 (r'ls\s+[^|-]+\s+-', "options to 'ls' must come before filenames"), 69 (r'ls\s+[^|-]+\s+-', "options to 'ls' must come before filenames"),
69 (r'[^>]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"), 70 (r'[^>]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
71 ],
72 # warnings
73 []
70 ] 74 ]
71 75
72 testfilters = [ 76 testfilters = [
73 (r"( *)(#([^\n]*\S)?)", repcomment), 77 (r"( *)(#([^\n]*\S)?)", repcomment),
74 (r"<<(\S+)((.|\n)*?\n\1)", rephere), 78 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
75 ] 79 ]
76 80
77 uprefix = r"^ \$ " 81 uprefix = r"^ \$ "
78 uprefixc = r"^ > " 82 uprefixc = r"^ > "
79 utestpats = [ 83 utestpats = [
84 [
80 (r'^(\S| $ ).*(\S\s+|^\s+)\n', "trailing whitespace on non-output"), 85 (r'^(\S| $ ).*(\S\s+|^\s+)\n', "trailing whitespace on non-output"),
81 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"), 86 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
82 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"), 87 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
83 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"), 88 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"),
84 (uprefix + r'.*\|\| echo.*(fail|error)', 89 (uprefix + r'.*\|\| echo.*(fail|error)',
85 "explicit exit code checks unnecessary"), 90 "explicit exit code checks unnecessary"),
86 (uprefix + r'set -e', "don't use set -e"), 91 (uprefix + r'set -e', "don't use set -e"),
87 (uprefixc + r'( *)\t', "don't use tabs to indent"), 92 (uprefixc + r'( *)\t', "don't use tabs to indent"),
88 ] 93 ],
89 94 # warnings
90 for p, m in testpats: 95 []
96 ]
97
98 for p, m in testpats[0] + testpats[1]:
91 if p.startswith('^'): 99 if p.startswith('^'):
92 p = uprefix + p[1:] 100 p = uprefix + p[1:]
93 else: 101 else:
94 p = uprefix + p 102 p = uprefix + p
95 utestpats.append((p, m)) 103 utestpats.append((p, m))
97 utestfilters = [ 105 utestfilters = [
98 (r"( *)(#([^\n]*\S)?)", repcomment), 106 (r"( *)(#([^\n]*\S)?)", repcomment),
99 ] 107 ]
100 108
101 pypats = [ 109 pypats = [
110 [
102 (r'^\s*def\s*\w+\s*\(.*,\s*\(', 111 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
103 "tuple parameter unpacking not available in Python 3+"), 112 "tuple parameter unpacking not available in Python 3+"),
104 (r'lambda\s*\(.*,.*\)', 113 (r'lambda\s*\(.*,.*\)',
105 "tuple parameter unpacking not available in Python 3+"), 114 "tuple parameter unpacking not available in Python 3+"),
106 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"), 115 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
110 (r'\S;\s*\n', "semicolon"), 119 (r'\S;\s*\n', "semicolon"),
111 (r'\w,\w', "missing whitespace after ,"), 120 (r'\w,\w', "missing whitespace after ,"),
112 (r'\w[+/*\-<>]\w', "missing whitespace in expression"), 121 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
113 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"), 122 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
114 (r'.{85}', "line too long"), 123 (r'.{85}', "line too long"),
115 (r'.{81}', "warning: line over 80 characters"),
116 (r'[^\n]\Z', "no trailing newline"), 124 (r'[^\n]\Z', "no trailing newline"),
117 (r'(\S\s+|^\s+)\n', "trailing whitespace"), 125 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
118 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"), 126 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
119 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"), 127 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
120 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+', 128 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
148 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', 156 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
149 "missing whitespace around operator"), 157 "missing whitespace around operator"),
150 (r'[^+=*!<>&| -](\s=|=\s)[^= ]', 158 (r'[^+=*!<>&| -](\s=|=\s)[^= ]',
151 "wrong whitespace around ="), 159 "wrong whitespace around ="),
152 (r'raise Exception', "don't raise generic exceptions"), 160 (r'raise Exception', "don't raise generic exceptions"),
161 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
162 (r' [=!]=\s+(True|False|None)',
163 "comparison with singleton, use 'is' or 'is not' instead"),
164 ],
165 # warnings
166 [
167 (r'.{81}', "warning: line over 80 characters"),
153 (r'^\s*except:$', "warning: naked except clause"), 168 (r'^\s*except:$', "warning: naked except clause"),
154 (r'ui\.(status|progress|write|note|warn)\([\'\"]x', 169 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
155 "warning: unwrapped ui message"), 170 "warning: unwrapped ui message"),
156 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), 171 ]
157 (r' [=!]=\s+(True|False|None)',
158 "comparison with singleton, use 'is' or 'is not' instead"),
159 ] 172 ]
160 173
161 pyfilters = [ 174 pyfilters = [
162 (r"""(?msx)(?P<comment>\#.*?$)| 175 (r"""(?msx)(?P<comment>\#.*?$)|
163 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!"))) 176 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
164 (?P<text>(([^\\]|\\.)*?)) 177 (?P<text>(([^\\]|\\.)*?))
165 (?P=quote))""", reppython), 178 (?P=quote))""", reppython),
166 ] 179 ]
167 180
168 cpats = [ 181 cpats = [
182 [
169 (r'//', "don't use //-style comments"), 183 (r'//', "don't use //-style comments"),
170 (r'^ ', "don't use spaces to indent"), 184 (r'^ ', "don't use spaces to indent"),
171 (r'\S\t', "don't use tabs except for indent"), 185 (r'\S\t', "don't use tabs except for indent"),
172 (r'(\S\s+|^\s+)\n', "trailing whitespace"), 186 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
173 (r'.{85}', "line too long"), 187 (r'.{85}', "line too long"),
180 (r'\w,\w', "missing whitespace after ,"), 194 (r'\w,\w', "missing whitespace after ,"),
181 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"), 195 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
182 (r'^#\s+\w', "use #foo, not # foo"), 196 (r'^#\s+\w', "use #foo, not # foo"),
183 (r'[^\n]\Z', "no trailing newline"), 197 (r'[^\n]\Z', "no trailing newline"),
184 (r'^\s*#import\b', "use only #include in standard C code"), 198 (r'^\s*#import\b', "use only #include in standard C code"),
199 ],
200 # warnings
201 []
185 ] 202 ]
186 203
187 cfilters = [ 204 cfilters = [
188 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment), 205 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
189 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote), 206 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
256 fp.close() 273 fp.close()
257 if "no-" + "check-code" in pre: 274 if "no-" + "check-code" in pre:
258 break 275 break
259 for p, r in filters: 276 for p, r in filters:
260 post = re.sub(p, r, post) 277 post = re.sub(p, r, post)
278 if warnings:
279 pats = pats[0] + pats[1]
280 else:
281 pats = pats[0]
261 # print post # uncomment to show filtered version 282 # print post # uncomment to show filtered version
262 z = enumerate(zip(pre.splitlines(), post.splitlines(True))) 283 z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
263 for n, l in z: 284 for n, l in z:
264 if "check-code" + "-ignore" in l[0]: 285 if "check-code" + "-ignore" in l[0]:
265 continue 286 continue
266 for p, msg in pats: 287 for p, msg in pats:
267 if not warnings and msg.startswith("warning"):
268 continue
269 if re.search(p, l[1]): 288 if re.search(p, l[1]):
270 bd = "" 289 bd = ""
271 if blame: 290 if blame:
272 bd = 'working directory' 291 bd = 'working directory'
273 if not blamecache: 292 if not blamecache: