diff --git a/src/doc.rs b/src/doc.rs index 9a6a86d41403..0ad238b55229 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -24,8 +24,16 @@ declare_lint! { "checks for the presence of `_`, `::` or camel-case outside ticks in documentation" } -#[derive(Copy,Clone)] -pub struct Doc; +#[derive(Clone)] +pub struct Doc { + valid_idents: Vec, +} + +impl Doc { + pub fn new(valid_idents: Vec) -> Self { + Doc { valid_idents: valid_idents } + } +} impl LintPass for Doc { fn get_lints(&self) -> LintArray { @@ -35,11 +43,11 @@ impl LintPass for Doc { impl EarlyLintPass for Doc { fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { - check_attrs(cx, &krate.attrs, krate.span); + check_attrs(cx, &self.valid_idents, &krate.attrs, krate.span); } fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { - check_attrs(cx, &item.attrs, item.span); + check_attrs(cx, &self.valid_idents, &item.attrs, item.span); } } @@ -73,7 +81,7 @@ fn collect_doc(attrs: &[ast::Attribute]) -> (Cow, Option) { } } -pub fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_span: Span) { +pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute], default_span: Span) { let (doc, span) = collect_doc(attrs); let span = span.unwrap_or(default_span); @@ -100,15 +108,19 @@ pub fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_s } if !in_ticks { - check_word(cx, word, span); + check_word(cx, valid_idents, word, span); } } } -fn check_word(cx: &EarlyContext, word: &str, span: Span) { +fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span) { /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { + if s.starts_with(|c: char| c.is_digit(10)) { + return false; + } + let s = if s.ends_with('s') { &s[..s.len()-1] } else { @@ -134,6 +146,10 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { // Or even as in `_foo bar_` which is emphasized. let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + if valid_idents.iter().any(|i| i == word) { + return; + } + if has_underscore(word) || word.contains("::") || is_camel_case(word) { span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word)); } diff --git a/src/lib.rs b/src/lib.rs index f3fc453cf69b..7ab48f462236 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,7 +233,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); - reg.register_early_lint_pass(box doc::Doc); + reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents)); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 2411e48997b3..e11a6c0d9c7c 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -149,6 +149,8 @@ define_Conf! { ("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: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks + ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB"] => Vec), /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64), /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index a7b316e1f823..635b33be9070 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -29,6 +29,18 @@ fn multiline_ticks() { fn test_emphasis() { } +/// This tests units. See also #835. +/// kiB MiB GiB TiB PiB EiB +/// kib Mib Gib Tib Pib Eib +/// kB MB GB TB PB EB +/// kb Mb Gb Tb Pb Eb +/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB +/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib +/// 32kB 32MB 32GB 32TB 32PB 32EB +/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb +fn test_units() { +} + /// This test has [a link with underscores][chunked-example] inside it. See #823. /// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). /// @@ -40,4 +52,5 @@ fn main() { foo_bar(); multiline_ticks(); test_emphasis(); + test_units(); }