diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 9aae188f9ecdf..02c0307e98cc8 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -208,7 +208,7 @@ impl Diagnostic { /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline it will only show the text message and not the text. /// - /// See `diagnostic::CodeSuggestion` for more information. + /// See `CodeSuggestion` for more information. pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { self.suggestions.push(CodeSuggestion { substitution_parts: vec![Substitution { @@ -235,7 +235,7 @@ impl Diagnostic { /// * may look like "to do xyz, use" or "to do xyz, use abc" /// * may contain a name of a function, variable or type, but not whole expressions /// - /// See `diagnostic::CodeSuggestion` for more information. + /// See `CodeSuggestion` for more information. pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { self.suggestions.push(CodeSuggestion { substitution_parts: vec![Substitution { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index daa132dbf6213..2f994de396c6f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -48,7 +48,7 @@ impl Emitter for EmitterWriter { sugg.substitution_parts[0].substitutions[0].find('\n').is_none() { let substitution = &sugg.substitution_parts[0].substitutions[0]; let msg = if substitution.len() == 0 || !sugg.show_code_when_inline { - // This substitution is only removal or we explicitely don't want to show the + // This substitution is only removal or we explicitly don't want to show the // code inline, don't show it format!("help: {}", sugg.msg) } else { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f3bf37c11a546..7f331418d4242 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -76,9 +76,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { if lit.span.ctxt() == SyntaxContext::empty() { - cx.span_lint(WHILE_TRUE, - e.span, - "denote infinite loops with loop { ... }"); + let msg = "denote infinite loops with `loop { ... }`"; + let mut err = cx.struct_span_lint(WHILE_TRUE, e.span, msg); + let condition_span = cx.tcx.sess.codemap().def_span(e.span); + err.span_suggestion_short(condition_span, + "use `loop`", + "loop".to_owned()); + err.emit(); } } } @@ -650,10 +654,11 @@ impl EarlyLintPass for DeprecatedAttr { ref name, ref reason, _) = g { - cx.span_lint(DEPRECATED, - attr.span, - &format!("use of deprecated attribute `{}`: {}. See {}", - name, reason, link)); + let msg = format!("use of deprecated attribute `{}`: {}. See {}", + name, reason, link); + let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg); + err.span_suggestion_short(attr.span, "remove this attribute", "".to_owned()); + err.emit(); } return; } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index b97920dd18b77..e2ade19b6e285 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -22,6 +22,7 @@ use syntax::attr; use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType}; use syntax::symbol::keywords; use syntax::ptr::P; +use syntax::print::pprust; use syntax::util::parser; use syntax_pos::Span; @@ -70,9 +71,13 @@ impl UnusedMut { let used_mutables = cx.tcx.used_mut_nodes.borrow(); for (_, v) in &mutables { if !v.iter().any(|e| used_mutables.contains(e)) { - cx.span_lint(UNUSED_MUT, - cx.tcx.hir.span(v[0]), - "variable does not need to be mutable"); + let binding_span = cx.tcx.hir.span(v[0]); + let mut_span = cx.tcx.sess.codemap().span_until_char(binding_span, ' '); + let mut err = cx.struct_span_lint(UNUSED_MUT, + binding_span, + "variable does not need to be mutable"); + err.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()); + err.emit(); } } } @@ -325,9 +330,40 @@ impl UnusedParens { let necessary = struct_lit_needs_parens && parser::contains_exterior_struct_lit(&inner); if !necessary { - cx.span_lint(UNUSED_PARENS, - value.span, - &format!("unnecessary parentheses around {}", msg)) + let span_msg = format!("unnecessary parentheses around {}", msg); + let mut err = cx.struct_span_lint(UNUSED_PARENS, + value.span, + &span_msg); + // Remove exactly one pair of parentheses (rather than naïvely + // stripping all paren characters) + let mut ate_left_paren = false; + let mut ate_right_paren = false; + let parens_removed = pprust::expr_to_string(value) + .trim_matches(|c| { + match c { + '(' => { + if ate_left_paren { + false + } else { + ate_left_paren = true; + true + } + }, + ')' => { + if ate_right_paren { + false + } else { + ate_right_paren = true; + true + } + }, + _ => false, + } + }).to_owned(); + err.span_suggestion_short(value.span, + "remove these parentheses", + parens_removed); + err.emit(); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e92a7484f3367..f6e85ed6725ce 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -824,7 +824,8 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("no_debug", Whitelisted, Gated( Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"), "no_debug", - "the `#[no_debug]` attribute is an experimental feature", + "the `#[no_debug]` attribute was an experimental feature that has been \ + deprecated due to lack of demand", cfg_fn!(no_debug))), ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable, "omit_gdb_pretty_printer_section", diff --git a/src/test/compile-fail/feature-gate-no-debug.rs b/src/test/compile-fail/feature-gate-no-debug.rs index 9815db6550d66..d21493de50a7f 100644 --- a/src/test/compile-fail/feature-gate-no-debug.rs +++ b/src/test/compile-fail/feature-gate-no-debug.rs @@ -10,5 +10,5 @@ #![allow(deprecated)] -#[no_debug] //~ ERROR the `#[no_debug]` attribute is +#[no_debug] //~ ERROR the `#[no_debug]` attribute was fn main() {} diff --git a/src/test/compile-fail/issue-1962.rs b/src/test/compile-fail/issue-1962.rs index db3e9c23b7621..9de3040bb616c 100644 --- a/src/test/compile-fail/issue-1962.rs +++ b/src/test/compile-fail/issue-1962.rs @@ -11,7 +11,7 @@ // compile-flags: -D while-true fn main() { let mut i = 0; - while true { //~ ERROR denote infinite loops with loop + while true { //~ ERROR denote infinite loops with `loop i += 1; if i == 5 { break; } } diff --git a/src/test/ui/lint/suggestions.rs b/src/test/ui/lint/suggestions.rs new file mode 100644 index 0000000000000..874124a7d3658 --- /dev/null +++ b/src/test/ui/lint/suggestions.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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(unused_mut)] // UI tests pass `-A unused`—see Issue #43896 +#![feature(no_debug)] + +#[no_debug] // should suggest removal of deprecated attribute +fn main() { + while true { // should suggest `loop` + let mut a = (1); // should suggest no `mut`, no parens + println!("{}", a); + } +} diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr new file mode 100644 index 0000000000000..5b2a4f589f738 --- /dev/null +++ b/src/test/ui/lint/suggestions.stderr @@ -0,0 +1,45 @@ +warning: unnecessary parentheses around assigned value + --> $DIR/suggestions.rs:17:21 + | +17 | let mut a = (1); // should suggest no `mut`, no parens + | ^^^ help: remove these parentheses + | + = note: #[warn(unused_parens)] on by default + +warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 + --> $DIR/suggestions.rs:14:1 + | +14 | #[no_debug] // should suggest removal of deprecated attribute + | ^^^^^^^^^^^ help: remove this attribute + | + = note: #[warn(deprecated)] on by default + +warning: denote infinite loops with `loop { ... }` + --> $DIR/suggestions.rs:16:5 + | +16 | while true { // should suggest `loop` + | ^--------- + | | + | _____help: use `loop` + | | +17 | | let mut a = (1); // should suggest no `mut`, no parens +18 | | println!("{}", a); +19 | | } + | |_____^ + | + = note: #[warn(while_true)] on by default + +warning: variable does not need to be mutable + --> $DIR/suggestions.rs:17:13 + | +17 | let mut a = (1); // should suggest no `mut`, no parens + | ---^^ + | | + | help: remove this `mut` + | +note: lint level defined here + --> $DIR/suggestions.rs:11:9 + | +11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896 + | ^^^^^^^^^^ + diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs new file mode 100644 index 0000000000000..d7cbd11472a64 --- /dev/null +++ b/src/test/ui/lint/unused_parens_json_suggestion.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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. + +// compile-flags: --error-format json + +// ignore-windows (see Issue #44968) + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +fn main() { + // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not + // the malformed `1 / (2 + 3` + let _a = (1 / (2 + 3)); +} diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr new file mode 100644 index 0000000000000..140224e081489 --- /dev/null +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -0,0 +1 @@ +{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":" let _a = 1 / (2 + 3);"}],"rendered":null} diff --git a/src/test/ui/path-lookahead.stderr b/src/test/ui/path-lookahead.stderr index 1d4ab35046b48..19e22b3f6f94f 100644 --- a/src/test/ui/path-lookahead.stderr +++ b/src/test/ui/path-lookahead.stderr @@ -2,7 +2,7 @@ warning: unnecessary parentheses around `return` value --> $DIR/path-lookahead.rs:18:10 | 18 | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses | = note: #[warn(unused_parens)] on by default