diff --git a/src/conf.rs b/src/conf.rs index e275bd701..3b2a1dafa 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -73,16 +73,16 @@ impl From for ConfError { } macro_rules! define_Conf { - ($(($toml_name: tt, $rust_name: ident, $default: expr, $ty: ident),)+) => { + ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { /// Type used to store lint configuration. pub struct Conf { - $(pub $rust_name: $ty,)+ + $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ } impl Default for Conf { fn default() -> Conf { Conf { - $($rust_name: $default,)+ + $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ } } } @@ -94,12 +94,12 @@ macro_rules! define_Conf { match name.as_str() { $( define_Conf!(PAT $toml_name) => { - if let Some(value) = define_Conf!(CONV $ty, value) { + if let Some(value) = define_Conf!(CONV $($ty)+, value) { self.$rust_name = value; } else { return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), - stringify!($ty), + stringify!($($ty)+), value.type_str())); } }, @@ -117,12 +117,13 @@ macro_rules! define_Conf { // hack to convert tts (PAT $pat: pat) => { $pat }; (EXPR $e: expr) => { $e }; + (TY $ty: ty) => { $ty }; // how to read the value? (CONV i64, $value: expr) => { $value.as_integer() }; (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() }; (CONV String, $value: expr) => { $value.as_str().map(Into::into) }; - (CONV StringVec, $value: expr) => {{ + (CONV Vec, $value: expr) => {{ let slice = $value.as_slice(); if let Some(slice) = slice { @@ -137,16 +138,21 @@ macro_rules! define_Conf { None } }}; + + // provide a nicer syntax to declare the default value of `Vec` variables + (DEFAULT Vec, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; + (DEFAULT $ty: ty, $e: expr) => { $e }; } -/// To keep the `define_Conf!` macro simple -pub type StringVec = Vec; - define_Conf! { - ("blacklisted-names", blacklisted_names, vec!["foo".to_owned(), "bar".to_owned(), "baz".to_owned()], StringVec), - ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25, u64), - ("too-many-arguments-threshold", too_many_arguments_threshold, 6, u64), - ("type-complexity-threshold", type_complexity_threshold, 250, u64), + /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about + ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec), + /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have + ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), + /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have + ("too-many-arguments-threshold", too_many_arguments_threshold, 6 => u64), + /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have + ("type-complexity-threshold", type_complexity_threshold, 250 => u64), } /// Read the `toml` configuration file. The function will ignore “File not found” errors iif diff --git a/src/lib.rs b/src/lib.rs index 4c0a069a0..b69fdf70c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(type_macros)] #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] #![feature(iter_arith)] diff --git a/util/update_wiki.py b/util/update_wiki.py index d3467a410..a10b3549a 100755 --- a/util/update_wiki.py +++ b/util/update_wiki.py @@ -9,6 +9,8 @@ import sys level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''') +conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE) +confvar_re = re.compile(r'''/// Lint: (\w+). (.*).*\n *\("([^"]*)", (?:[^,]*), (.*) => (.*)\),''') def parse_path(p="src"): @@ -16,10 +18,23 @@ def parse_path(p="src"): for f in os.listdir(p): if f.endswith(".rs"): parse_file(d, os.path.join(p, f)) - return d + return (d, parse_conf(p)) -START = 0 -LINT = 1 + +def parse_conf(p): + c = {} + with open(p + '/conf.rs') as f: + f = f.read() + + m = re.search(conf_re, f) + m = m.groups()[0] + + m = re.findall(confvar_re, m) + + for (lint, doc, name, default, ty) in m: + c[lint.lower()] = (name, ty, doc, default) + + return c def parse_file(d, f): @@ -85,8 +100,14 @@ template = """\n# `%s` %s""" +conf_template = """ +**Configuration:** This lint has the following configuration variables: -def write_wiki_page(d, f): +* `%s: %s`: %s (defaults to `%s`). +""" + + +def write_wiki_page(d, c, f): keys = list(d.keys()) keys.sort() with open(f, "w") as w: @@ -102,8 +123,11 @@ def write_wiki_page(d, f): for k in keys: w.write(template % (k, d[k][0], "".join(d[k][1]))) + if k in c: + w.write(conf_template % c[k]) -def check_wiki_page(d, f): + +def check_wiki_page(d, c, f): errors = [] with open(f) as w: for line in w: @@ -122,11 +146,11 @@ def check_wiki_page(d, f): def main(): - d = parse_path() + (d, c) = parse_path() if "-c" in sys.argv: - check_wiki_page(d, "../rust-clippy.wiki/Home.md") + check_wiki_page(d, c, "../rust-clippy.wiki/Home.md") else: - write_wiki_page(d, "../rust-clippy.wiki/Home.md") + write_wiki_page(d, c, "../rust-clippy.wiki/Home.md") if __name__ == "__main__": main()