From ed29e86c39cde1a77a8b3a4046d12f9b57fb72fb Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Tue, 3 Jul 2018 12:23:20 +0200 Subject: [PATCH 1/4] Tests for tool_lints --- .../compile-fail/feature-gate-tool_lints.rs | 12 ++++++++++++ src/test/compile-fail/tool_lints.rs | 18 ++++++++++++++++++ .../compile-fail/unknown-lint-tool-name.rs | 16 ++++++++++++++++ src/test/run-pass/tool_lints.rs | 15 +++++++++++++++ src/test/run-pass/tool_lints_2018_preview.rs | 16 ++++++++++++++++ src/test/ui/feature-gate-tool_lints.rs | 15 +++++++++++++++ src/test/ui/feature-gate-tool_lints.stderr | 11 +++++++++++ 7 files changed, 103 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-tool_lints.rs create mode 100644 src/test/compile-fail/tool_lints.rs create mode 100644 src/test/compile-fail/unknown-lint-tool-name.rs create mode 100644 src/test/run-pass/tool_lints.rs create mode 100644 src/test/run-pass/tool_lints_2018_preview.rs create mode 100644 src/test/ui/feature-gate-tool_lints.rs create mode 100644 src/test/ui/feature-gate-tool_lints.stderr diff --git a/src/test/compile-fail/feature-gate-tool_lints.rs b/src/test/compile-fail/feature-gate-tool_lints.rs new file mode 100644 index 00000000000..c311eb7ed7a --- /dev/null +++ b/src/test/compile-fail/feature-gate-tool_lints.rs @@ -0,0 +1,12 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental +fn main() {} diff --git a/src/test/compile-fail/tool_lints.rs b/src/test/compile-fail/tool_lints.rs new file mode 100644 index 00000000000..ea1efab4cb6 --- /dev/null +++ b/src/test/compile-fail/tool_lints.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Don't allow tool_lints, which aren't scoped + +#![feature(tool_lints)] +#![deny(unknown_lints)] + +#![deny(clippy)] //~ ERROR: unknown lint: `clippy` + +fn main() {} diff --git a/src/test/compile-fail/unknown-lint-tool-name.rs b/src/test/compile-fail/unknown-lint-tool-name.rs new file mode 100644 index 00000000000..173803d6030 --- /dev/null +++ b/src/test/compile-fail/unknown-lint-tool-name.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(tool_lints)] + +#![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`. + +#[allow(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`. +fn main() {} diff --git a/src/test/run-pass/tool_lints.rs b/src/test/run-pass/tool_lints.rs new file mode 100644 index 00000000000..24ec43b12f6 --- /dev/null +++ b/src/test/run-pass/tool_lints.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(tool_lints)] +#![deny(unknown_lints)] + +#[allow(clippy::almost_swapped)] +fn main() {} diff --git a/src/test/run-pass/tool_lints_2018_preview.rs b/src/test/run-pass/tool_lints_2018_preview.rs new file mode 100644 index 00000000000..6cd57eaa195 --- /dev/null +++ b/src/test/run-pass/tool_lints_2018_preview.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(tool_lints)] +#![feature(rust_2018_preview)] +#![deny(unknown_lints)] + +#[allow(clippy::almost_swapped)] +fn main() {} diff --git a/src/test/ui/feature-gate-tool_lints.rs b/src/test/ui/feature-gate-tool_lints.rs new file mode 100644 index 00000000000..3ef67982be9 --- /dev/null +++ b/src/test/ui/feature-gate-tool_lints.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[warn(clippy::decimal_literal_representation)] +//~^ ERROR scoped lint `clippy::decimal_literal_representation` is experimental +fn main() { + let a = 65_535; +} diff --git a/src/test/ui/feature-gate-tool_lints.stderr b/src/test/ui/feature-gate-tool_lints.stderr new file mode 100644 index 00000000000..8019b1e6a28 --- /dev/null +++ b/src/test/ui/feature-gate-tool_lints.stderr @@ -0,0 +1,11 @@ +error[E0658]: scoped lint `clippy::decimal_literal_representation` is experimental (see issue #44690) + --> $DIR/feature-gate-tool_lints.rs:11:8 + | +LL | #[warn(clippy::decimal_literal_representation)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(tool_lints)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From dddb8d2eba04610eca944a659c1906f78d210ab4 Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Tue, 3 Jul 2018 13:50:48 +0200 Subject: [PATCH 2/4] Implementation of tool lints --- src/librustc/diagnostics.rs | 1 + src/librustc/lint/levels.rs | 23 +++++++++++++++++++++++ src/libsyntax/attr/mod.rs | 11 +++++++++++ src/libsyntax/feature_gate.rs | 2 ++ 4 files changed, 37 insertions(+) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5fecf2b1535..5ace8397d9f 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2137,4 +2137,5 @@ register_diagnostics! { E0707, // multiple elided lifetimes used in arguments of `async fn` E0708, // `async` non-`move` closures with arguments are not currently supported E0709, // multiple different lifetimes used in arguments of `async fn` + E0710, // an unknown tool name found in scoped lint } diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 3393a2bf89d..6761b7b7492 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -22,6 +22,7 @@ use session::Session; use syntax::ast; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::Symbol; use util::nodemap::FxHashMap; @@ -221,6 +222,28 @@ impl<'a> LintLevelsBuilder<'a> { continue } }; + if word.is_scoped() { + if !self.sess.features_untracked().tool_lints { + feature_gate::emit_feature_err(&sess.parse_sess, + "tool_lints", + word.span, + feature_gate::GateIssue::Language, + &format!("scoped lint `{}` is experimental", + word.ident)); + } + + if !attr::is_known_lint_tool(word) { + span_err!( + sess, + word.span, + E0710, + "an unknown tool name found in scoped lint: `{}`.", + word.ident + ); + } + + continue + } let name = word.name(); match store.check_lint_name(&name.as_str()) { CheckLintNameResult::Ok(ids) => { diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 4e27d6c1525..f8db62083c7 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -90,6 +90,7 @@ pub fn is_known(attr: &Attribute) -> bool { } const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"]; +const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"]; pub fn is_known_tool(attr: &Attribute) -> bool { let tool_name = @@ -97,6 +98,12 @@ pub fn is_known_tool(attr: &Attribute) -> bool { RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref()) } +pub fn is_known_lint_tool(m_item: &MetaItem) -> bool { + let tool_name = + m_item.ident.segments.iter().next().expect("empty path in meta item").ident.name; + RUST_KNOWN_LINT_TOOL.contains(&tool_name.as_str().as_ref()) +} + impl NestedMetaItem { /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. pub fn meta_item(&self) -> Option<&MetaItem> { @@ -290,6 +297,10 @@ impl MetaItem { pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } + + pub fn is_scoped(&self) -> bool { + self.ident.segments.len() > 1 + } } impl Attribute { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2ae0e669fd0..d0837063514 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -458,6 +458,8 @@ declare_features! ( // Scoped attributes (active, tool_attributes, "1.25.0", Some(44690), None), + // Scoped lints + (active, tool_lints, "1.28.0", Some(44690), None), // allow irrefutable patterns in if-let and while-let statements (RFC 2086) (active, irrefutable_let_patterns, "1.27.0", Some(44495), None), From a9634fcd013a31842e551ba30c25e389a5d67bbd Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Tue, 3 Jul 2018 13:52:11 +0200 Subject: [PATCH 3/4] Unstable book documentation of tool lints --- .../src/language-features/tool-lints.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/tool-lints.md diff --git a/src/doc/unstable-book/src/language-features/tool-lints.md b/src/doc/unstable-book/src/language-features/tool-lints.md new file mode 100644 index 00000000000..5c0d33b5ab0 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/tool-lints.md @@ -0,0 +1,35 @@ +# `tool_lints` + +The tracking issue for this feature is: [#44690] + +[#44690]: https://github.com/rust-lang/rust/issues/44690 + +------------------------ + +Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of +certain tools. + +Currently `clippy` is the only available lint tool. + +It is recommended for lint tools to implement the scoped lints like this: + +- `#[_(TOOL_NAME::lintname)]`: for lint names +- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints +- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints + +## An example + +```rust +#![feature(tool_lints)] + +#![warn(clippy::pedantic)] + +#[allow(clippy::filter_map)] +fn main() { + let v = vec![0; 10]; + let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::>(); + println!("No filter_map()!"); +} +``` + +[^1]: Some defined lint groups can be excluded here. From c3949009adf7e8a039a1f467cbc6e6b5cf993303 Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Wed, 4 Jul 2018 14:25:33 +0200 Subject: [PATCH 4/4] Improving span of unknown lint tool error message --- src/librustc/lint/levels.rs | 8 ++++---- src/libsyntax/attr/mod.rs | 14 ++++++++------ src/test/compile-fail/unknown-lint-tool-name.rs | 4 ++-- src/test/ui/tool_lints.rs | 15 +++++++++++++++ src/test/ui/tool_lints.stderr | 9 +++++++++ 5 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/tool_lints.rs create mode 100644 src/test/ui/tool_lints.stderr diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 6761b7b7492..5bf15b10715 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -222,7 +222,7 @@ impl<'a> LintLevelsBuilder<'a> { continue } }; - if word.is_scoped() { + if let Some(lint_tool) = word.is_scoped() { if !self.sess.features_untracked().tool_lints { feature_gate::emit_feature_err(&sess.parse_sess, "tool_lints", @@ -232,12 +232,12 @@ impl<'a> LintLevelsBuilder<'a> { word.ident)); } - if !attr::is_known_lint_tool(word) { + if !attr::is_known_lint_tool(lint_tool) { span_err!( sess, - word.span, + lint_tool.span, E0710, - "an unknown tool name found in scoped lint: `{}`.", + "an unknown tool name found in scoped lint: `{}`", word.ident ); } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index f8db62083c7..d746ac3c577 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -98,10 +98,8 @@ pub fn is_known_tool(attr: &Attribute) -> bool { RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref()) } -pub fn is_known_lint_tool(m_item: &MetaItem) -> bool { - let tool_name = - m_item.ident.segments.iter().next().expect("empty path in meta item").ident.name; - RUST_KNOWN_LINT_TOOL.contains(&tool_name.as_str().as_ref()) +pub fn is_known_lint_tool(m_item: Ident) -> bool { + RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref()) } impl NestedMetaItem { @@ -298,8 +296,12 @@ impl MetaItem { self.meta_item_list().is_some() } - pub fn is_scoped(&self) -> bool { - self.ident.segments.len() > 1 + pub fn is_scoped(&self) -> Option { + if self.ident.segments.len() > 1 { + Some(self.ident.segments[0].ident) + } else { + None + } } } diff --git a/src/test/compile-fail/unknown-lint-tool-name.rs b/src/test/compile-fail/unknown-lint-tool-name.rs index 173803d6030..78b736edceb 100644 --- a/src/test/compile-fail/unknown-lint-tool-name.rs +++ b/src/test/compile-fail/unknown-lint-tool-name.rs @@ -10,7 +10,7 @@ #![feature(tool_lints)] -#![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`. +#![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar` -#[allow(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`. +#[allow(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar` fn main() {} diff --git a/src/test/ui/tool_lints.rs b/src/test/ui/tool_lints.rs new file mode 100644 index 00000000000..71f90b17c18 --- /dev/null +++ b/src/test/ui/tool_lints.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(tool_lints)] + +#[warn(foo::bar)] +//~^ ERROR an unknown tool name found in scoped lint: `foo::bar` +fn main() {} diff --git a/src/test/ui/tool_lints.stderr b/src/test/ui/tool_lints.stderr new file mode 100644 index 00000000000..16468df7370 --- /dev/null +++ b/src/test/ui/tool_lints.stderr @@ -0,0 +1,9 @@ +error[E0710]: an unknown tool name found in scoped lint: `foo::bar` + --> $DIR/tool_lints.rs:13:8 + | +LL | #[warn(foo::bar)] + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0710`.