about summary refs log tree commit diff
path: root/src/tools/clippy/util/lintlib.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/util/lintlib.py')
-rw-r--r--src/tools/clippy/util/lintlib.py114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/tools/clippy/util/lintlib.py b/src/tools/clippy/util/lintlib.py
new file mode 100644
index 00000000000..d0d9beb9b2d
--- /dev/null
+++ b/src/tools/clippy/util/lintlib.py
@@ -0,0 +1,114 @@
+# Common utils for the several housekeeping scripts.
+
+import os
+import re
+import collections
+
+import logging as log
+log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
+
+Lint = collections.namedtuple('Lint', 'name level doc sourcefile group')
+Config = collections.namedtuple('Config', 'name ty doc default')
+
+lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
+group_re = re.compile(r'''\s*([a-z_][a-z_0-9]+)''')
+conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
+confvar_re = re.compile(
+    r'''/// Lint: ([\w,\s]+)\. (.*)\n\s*\([^,]+,\s+"([^"]+)":\s+([^,]+),\s+([^\.\)]+).*\),''', re.MULTILINE)
+comment_re = re.compile(r'''\s*/// ?(.*)''')
+
+lint_levels = {
+    "correctness": 'Deny',
+    "style": 'Warn',
+    "complexity": 'Warn',
+    "perf": 'Warn',
+    "restriction": 'Allow',
+    "pedantic": 'Allow',
+    "nursery": 'Allow',
+    "cargo": 'Allow',
+}
+
+
+def parse_lints(lints, filepath):
+    comment = []
+    clippy = False
+    deprecated = False
+    name = ""
+
+    with open(filepath) as fp:
+        for line in fp:
+            if clippy or deprecated:
+                m = lintname_re.search(line)
+                if m:
+                    name = m.group(1).lower()
+                    line = next(fp)
+
+                    if deprecated:
+                        level = "Deprecated"
+                        group = "deprecated"
+                    else:
+                        while True:
+                            g = group_re.search(line)
+                            if g:
+                                group = g.group(1).lower()
+                                level = lint_levels.get(group, None)
+                                break
+                            line = next(fp)
+
+                    if level is None:
+                        continue
+
+                    log.info("found %s with level %s in %s",
+                             name, level, filepath)
+                    lints.append(Lint(name, level, comment, filepath, group))
+                    comment = []
+
+                    clippy = False
+                    deprecated = False
+                    name = ""
+                else:
+                    m = comment_re.search(line)
+                    if m:
+                        comment.append(m.group(1))
+            elif line.startswith("declare_clippy_lint!"):
+                clippy = True
+                deprecated = False
+            elif line.startswith("declare_deprecated_lint!"):
+                clippy = False
+                deprecated = True
+            elif line.startswith("declare_lint!"):
+                import sys
+                print(
+                    "don't use `declare_lint!` in Clippy, "
+                    "use `declare_clippy_lint!` instead"
+                )
+                sys.exit(42)
+
+
+def parse_configs(path):
+    configs = {}
+    with open(os.path.join(path, 'utils/conf.rs')) as fp:
+        contents = fp.read()
+
+    match = re.search(conf_re, contents)
+    confvars = re.findall(confvar_re, match.group(1))
+
+    for (lints, doc, name, ty, default) in confvars:
+        for lint in lints.split(','):
+            configs[lint.strip().lower()] = Config(name.replace("_", "-"), ty, doc, default)
+    return configs
+
+
+def parse_all(path="clippy_lints/src"):
+    lints = []
+    for root, dirs, files in os.walk(path):
+        for fn in files:
+            if fn.endswith('.rs'):
+                parse_lints(lints, os.path.join(root, fn))
+
+    log.info("got %s lints", len(lints))
+
+    configs = parse_configs(path)
+    log.info("got %d configs", len(configs))
+
+    return lints, configs