]> git.lizzy.rs Git - rust.git/blob - util/lintlib.py
Merge pull request #2458 from flip1995/suspicious_impl
[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 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
20 def parse_lints(lints, filepath):
21     last_comment = []
22     comment = True
23
24     with open(filepath) as fp:
25         for line in fp:
26             if comment:
27                 if line.startswith("/// "):
28                     last_comment.append(line[4:])
29                 elif line.startswith("///"):
30                     last_comment.append(line[3:])
31                 elif line.startswith("declare_lint!"):
32                     comment = False
33                     deprecated = False
34                     restriction = False
35                 elif line.startswith("declare_restriction_lint!"):
36                     comment = False
37                     deprecated = False
38                     restriction = True
39                 elif line.startswith("declare_deprecated_lint!"):
40                     comment = False
41                     deprecated = True
42                 else:
43                     last_comment = []
44             if not comment:
45                 m = lintname_re.search(line)
46                 if m:
47                     name = m.group(1).lower()
48
49                     if deprecated:
50                         level = "Deprecated"
51                     elif restriction:
52                         level = "Allow"
53                     else:
54                         while True:
55                             m = level_re.search(line)
56                             if m:
57                                 level = m.group(0)
58                                 break
59                             line = next(fp)
60
61                     log.info("found %s with level %s in %s",
62                              name, level, filepath)
63                     lints.append(Lint(name, level, last_comment, filepath))
64                     last_comment = []
65                     comment = True
66                 if "}" in line:
67                     log.warn("Warning: missing Lint-Name in %s", filepath)
68                     comment = True
69
70
71 def parse_configs(path):
72     configs = {}
73     with open(os.path.join(path, 'utils/conf.rs')) as fp:
74         contents = fp.read()
75
76     match = re.search(conf_re, contents)
77     confvars = re.findall(confvar_re, match.group(1))
78
79     for (lint, doc, name, default, ty) in confvars:
80         configs[lint.lower()] = Config(name.replace("_", "-"), ty, doc, default)
81
82     return configs
83
84
85 def parse_all(path="clippy_lints/src"):
86     lints = []
87     for filename in os.listdir(path):
88         if filename.endswith(".rs"):
89             parse_lints(lints, os.path.join(path, filename))
90     log.info("got %s lints", len(lints))
91
92     configs = parse_configs(path)
93     log.info("got %d configs", len(configs))
94
95     return lints, configs