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