comparison contrib/check-code.py @ 15372:695ac6aca77f stable

check-code: fix issues with finding patterns in unified tests, fix tests - old-style patterns without ^ were getting improperly anchored - finditer was matching against beginning of line poorly - \s was matching newlines - [^x] was matching newlines so we: - remove earlier hacks for multiline matching - fix unified test anchoring by adding .* - replace \s with [ \t] - replace [^x] with [^\nx] - force all matches into multiline mode so ^ anchors work This uncovers a number of test issues that are then repaired.
author Matt Mackall <mpm@selenic.com>
date Thu, 27 Oct 2011 17:22:04 -0500
parents 572c22c88be6
children 3bece03bf3c6
comparison
equal deleted inserted replaced
15371:f26ed4ea46d8 15372:695ac6aca77f
43 43
44 testpats = [ 44 testpats = [
45 [ 45 [
46 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"), 46 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"), 47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 (r'(^|\n)function', "don't use 'function', use old style"), 48 (r'^function', "don't use 'function', use old style"),
49 (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"),
50 (r'echo.*\\n', "don't use 'echo \\n', use printf"), 50 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
51 (r'echo -n', "don't use 'echo -n', use printf"), 51 (r'echo -n', "don't use 'echo -n', use printf"),
52 (r'(^|\n)diff.*-\w*N', "don't use 'diff -N'"), 52 (r'^diff.*-\w*N', "don't use 'diff -N'"),
53 (r'(^| )wc[^|\n]*$', "filter wc output"), 53 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
54 (r'head -c', "don't use 'head -c', use 'dd'"), 54 (r'head -c', "don't use 'head -c', use 'dd'"),
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"), 55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
56 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"), 56 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"),
57 (r'printf.*\\x', "don't use printf \\x, use Python"), 57 (r'printf.*\\x', "don't use printf \\x, use Python"),
58 (r'\$\(.*\)', "don't use $(expr), use `expr`"), 58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"), 59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
60 (r'(^|\|\s*)grep (-\w\s+)*[^|\n]*[(|]\w', 60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
61 "use egrep for extended grep syntax"), 61 "use egrep for extended grep syntax"),
62 (r'/bin/', "don't use explicit paths for tools"), 62 (r'/bin/', "don't use explicit paths for tools"),
63 (r'\$PWD', "don't use $PWD, use `pwd`"), 63 (r'\$PWD', "don't use $PWD, use `pwd`"),
64 (r'[^\n]\Z', "no trailing newline"), 64 (r'[^\n]\Z', "no trailing newline"),
65 (r'export.*=', "don't export and assign at once"), 65 (r'export.*=', "don't export and assign at once"),
66 ('(^|\n)([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\\^', "^ must be quoted"), 66 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\\^', "^ must be quoted"),
67 (r'(^|\n)source\b', "don't use 'source', use '.'"), 67 (r'^source\b', "don't use 'source', use '.'"),
68 (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"),
69 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"), 69 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
70 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"), 70 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
71 (r'stop\(\)', "don't use 'stop' as a shell function name"), 71 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
72 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"), 72 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
73 ], 73 ],
74 # warnings 74 # warnings
75 [] 75 []
76 ] 76 ]
78 testfilters = [ 78 testfilters = [
79 (r"( *)(#([^\n]*\S)?)", repcomment), 79 (r"( *)(#([^\n]*\S)?)", repcomment),
80 (r"<<(\S+)((.|\n)*?\n\1)", rephere), 80 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
81 ] 81 ]
82 82
83 uprefix = r"(^|\n) \$\s*" 83 uprefix = r"^ \$ "
84 uprefixc = r"(^|\n) > " 84 uprefixc = r"^ > "
85 utestpats = [ 85 utestpats = [
86 [ 86 [
87 (r'(^|\n)(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"), 87 (r'^(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"),
88 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"), 88 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
89 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"), 89 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
90 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"), 90 (uprefix + r'.*\$\?', "explicit exit code checks unnecessary"),
91 (uprefix + r'.*\|\| echo.*(fail|error)', 91 (uprefix + r'.*\|\| echo.*(fail|error)',
92 "explicit exit code checks unnecessary"), 92 "explicit exit code checks unnecessary"),
97 [] 97 []
98 ] 98 ]
99 99
100 for i in [0, 1]: 100 for i in [0, 1]:
101 for p, m in testpats[i]: 101 for p, m in testpats[i]:
102 if p.startswith(r'(^|\n)'): 102 if p.startswith(r'^'):
103 p = uprefix + p[6:] 103 p = uprefix + p[1:]
104 else: 104 else:
105 p = uprefix + p 105 p = uprefix + ".*" + p
106 utestpats[i].append((p, m)) 106 utestpats[i].append((p, m))
107 107
108 utestfilters = [ 108 utestfilters = [
109 (r"( *)(#([^\n]*\S)?)", repcomment), 109 (r"( *)(#([^\n]*\S)?)", repcomment),
110 ] 110 ]
121 (r'^\s*\t', "don't use tabs"), 121 (r'^\s*\t', "don't use tabs"),
122 (r'\S;\s*\n', "semicolon"), 122 (r'\S;\s*\n', "semicolon"),
123 (r'\w,\w', "missing whitespace after ,"), 123 (r'\w,\w', "missing whitespace after ,"),
124 (r'\w[+/*\-<>]\w', "missing whitespace in expression"), 124 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
125 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"), 125 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
126 (r'(?m)(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n' 126 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
127 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'), 127 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
128 (r'.{85}', "line too long"), 128 (r'.{85}', "line too long"),
129 (r'(?m) x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'), 129 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
130 (r'[^\n]\Z', "no trailing newline"), 130 (r'[^\n]\Z', "no trailing newline"),
131 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), 131 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
132 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"), 132 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
133 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"), 133 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
134 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+', 134 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
342 print "Checking %s for %s" % (name, f) 342 print "Checking %s for %s" % (name, f)
343 343
344 prelines = None 344 prelines = None
345 errors = [] 345 errors = []
346 for p, msg in pats: 346 for p, msg in pats:
347 # fix-up regexes for multiline searches
348 po = p
349 # \s doesn't match \n
350 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
351 # [^...] doesn't match newline
352 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
353
354 #print po, '=>', p
355
347 pos = 0 356 pos = 0
348 n = 0 357 n = 0
349 for m in re.finditer(p, post): 358 for m in re.finditer(p, post, re.MULTILINE):
350 if prelines is None: 359 if prelines is None:
351 prelines = pre.splitlines() 360 prelines = pre.splitlines()
352 postlines = post.splitlines(True) 361 postlines = post.splitlines(True)
353 362
354 start = m.start() 363 start = m.start()