]> git.lizzy.rs Git - rust.git/blob - util/lintlib.py
1fddcbdc3fad026b76ce2d50079ec6d1d2241f1a
[rust.git] / util / lintlib.py
1 # Common utils for the several housekeeping scripts.
2
3 import os
4 import re
5 import collections
6
7 import logging as log
8 log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
9
10 Lint = collections.namedtuple('Lint', 'name level doc sourcefile')
11 Config = collections.namedtuple('Config', 'name ty doc default')
12
13 lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
14 level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''')
15 group_re = re.compile(r'''([a-z_][a-z_0-9]+)''')
16 conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
17 confvar_re = re.compile(
18     r'''/// Lint: (\w+). (.*).*\n\s*\([^,]+,\s+"([^"]+)",\s+([^=\)]+)=>\s+(.*)\),''', re.MULTILINE)
19
20 lint_levels = {
21     "correctness": 'Deny',
22     "style": 'Warn',
23     "complexity": 'Warn',
24     "perf": 'Warn',
25     "restriction": 'Allow',
26     "pedantic": 'Allow',
27     "nursery": 'Allow',
28 }
29
30 def parse_lints(lints, filepath):
31     last_comment = []
32     comment = True
33     clippy = False
34     deprecated = False
35     name = ""
36
37     with open(filepath) as fp:
38         for line in fp:
39             if comment:
40                 if line.startswith("/// "):
41                     last_comment.append(line[4:])
42                 elif line.startswith("///"):
43                     last_comment.append(line[3:])
44                 elif line.startswith("declare_lint!"):
45                     import sys
46                     print "don't use `declare_lint!` in clippy, use `declare_clippy_lint!` instead"
47                     sys.exit(42)
48                 elif line.startswith("declare_clippy_lint!"):
49                     comment = False
50                     deprecated = False
51                     clippy = True
52                     name = ""
53                 elif line.startswith("declare_deprecated_lint!"):
54                     comment = False
55                     deprecated = True
56                     clippy = False
57                 else:
58                     last_comment = []
59             if not comment:
60                 if name:
61                     g = group_re.search(line)
62                     if g:
63                         group = g.group(1).lower()
64                         level = lint_levels[group]
65                         log.info("found %s with level %s in %s",
66                                 name, level, filepath)
67                         lints.append(Lint(name, level, last_comment, filepath, group))
68                         last_comment = []
69                         comment = True
70                 else:
71                     m = lintname_re.search(line)
72                     if m:
73                         name = m.group(1).lower()
74
75                         if deprecated:
76                             level = "Deprecated"
77                         else:
78                             while True:
79                                 m = level_re.search(line)
80                                 if m:
81                                     level = m.group(0)
82                                     break
83                                 line = next(fp)
84                         if not clippy:
85                             log.info("found %s with level %s in %s",
86                                     name, level, filepath)
87                             lints.append(Lint(name, level, last_comment, filepath, "deprecated"))
88                             last_comment = []
89                             comment = True
90                     if "}" in line:
91                         log.warn("Warning: missing Lint-Name in %s", filepath)
92                         comment = True
93
94
95 def parse_configs(path):
96     configs = {}
97     with open(os.path.join(path, 'utils/conf.rs')) as fp:
98         contents = fp.read()
99
100     match = re.search(conf_re, contents)
101     confvars = re.findall(confvar_re, match.group(1))
102
103     for (lint, doc, name, default, ty) in confvars:
104         configs[lint.lower()] = Config(name.replace("_", "-"), ty, doc, default)
105
106     return configs
107
108
109 def parse_all(path="clippy_lints/src"):
110     lints = []
111     for filename in os.listdir(path):
112         if filename.endswith(".rs"):
113             parse_lints(lints, os.path.join(path, filename))
114     log.info("got %s lints", len(lints))
115
116     configs = parse_configs(path)
117     log.info("got %d configs", len(configs))
118
119     return lints, configs