Skip to content

Commit e64493e

Browse files
committed
add new test and add conditional whitespace
1 parent b12c20c commit e64493e

File tree

4 files changed

+794
-29
lines changed

4 files changed

+794
-29
lines changed

src/librustc_lint/unused.rs

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use syntax::print::pprust;
1515
use syntax::symbol::{kw, sym};
1616
use syntax::symbol::Symbol;
1717
use syntax::util::parser;
18-
use syntax_pos::Span;
18+
use syntax_pos::{Span, BytePos};
1919

2020
use rustc::hir;
2121

@@ -353,31 +353,41 @@ declare_lint! {
353353
declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
354354

355355
impl UnusedParens {
356+
357+
fn is_expr_parens_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
358+
followed_by_block && match inner.node {
359+
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
360+
_ => parser::contains_exterior_struct_lit(&inner),
361+
}
362+
}
363+
356364
fn check_unused_parens_expr(&self,
357-
cx: &EarlyContext<'_>,
358-
value: &ast::Expr,
359-
msg: &str,
360-
followed_by_block: bool) {
365+
cx: &EarlyContext<'_>,
366+
value: &ast::Expr,
367+
msg: &str,
368+
followed_by_block: bool,
369+
left_pos: Option<BytePos>,
370+
right_pos: Option<BytePos>) {
361371
match value.node {
362372
ast::ExprKind::Paren(ref inner) => {
363-
let necessary = followed_by_block && match inner.node {
364-
ast::ExprKind::Ret(_) | ast::ExprKind::Break(..) => true,
365-
_ => parser::contains_exterior_struct_lit(&inner),
366-
};
367-
if !necessary {
373+
if !Self::is_expr_parens_necessary(inner, followed_by_block) {
368374
let expr_text = if let Ok(snippet) = cx.sess().source_map()
369375
.span_to_snippet(value.span) {
370376
snippet
371377
} else {
372378
pprust::expr_to_string(value)
373379
};
374-
Self::remove_outer_parens(cx, value.span, &expr_text, msg);
380+
let keep_space = (
381+
left_pos.map(|s| s >= value.span.lo()).unwrap_or(false),
382+
right_pos.map(|s| s <= value.span.hi()).unwrap_or(false),
383+
);
384+
Self::remove_outer_parens(cx, value.span, &expr_text, msg, keep_space);
375385
}
376386
}
377387
ast::ExprKind::Let(_, ref expr) => {
378388
// FIXME(#60336): Properly handle `let true = (false && true)`
379389
// actually needing the parenthesis.
380-
self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block);
390+
self.check_unused_parens_expr(cx, expr, "`let` head expression", followed_by_block, None, None);
381391
}
382392
_ => {}
383393
}
@@ -394,11 +404,11 @@ impl UnusedParens {
394404
} else {
395405
pprust::pat_to_string(value)
396406
};
397-
Self::remove_outer_parens(cx, value.span, &pattern_text, msg);
407+
Self::remove_outer_parens(cx, value.span, &pattern_text, msg, (false, false));
398408
}
399409
}
400410

401-
fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &str) {
411+
fn remove_outer_parens(cx: &EarlyContext<'_>, span: Span, pattern: &str, msg: &str, keep_space: (bool, bool)) {
402412
let span_msg = format!("unnecessary parentheses around {}", msg);
403413
let mut err = cx.struct_span_lint(UNUSED_PARENS, span, &span_msg);
404414
let mut ate_left_paren = false;
@@ -427,9 +437,17 @@ impl UnusedParens {
427437
});
428438

429439
let replace = {
430-
let mut replace = String::from(" ");
431-
replace.push_str(parens_removed);
432-
replace.push(' ');
440+
let mut replace = if keep_space.0 {
441+
let mut s = String::from(" ");
442+
s.push_str(parens_removed);
443+
s
444+
} else {
445+
String::from(parens_removed)
446+
};
447+
448+
if keep_space.1 {
449+
replace.push(' ');
450+
}
433451
replace
434452
};
435453

@@ -446,14 +464,35 @@ impl UnusedParens {
446464
impl EarlyLintPass for UnusedParens {
447465
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
448466
use syntax::ast::ExprKind::*;
449-
let (value, msg, followed_by_block) = match e.node {
450-
If(ref cond, ..) => (cond, "`if` condition", true),
451-
While(ref cond, ..) => (cond, "`while` condition", true),
452-
ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
453-
Match(ref head, _) => (head, "`match` head expression", true),
454-
Ret(Some(ref value)) => (value, "`return` value", false),
455-
Assign(_, ref value) => (value, "assigned value", false),
456-
AssignOp(.., ref value) => (value, "assigned value", false),
467+
let (value, msg, followed_by_block, left_pos, right_pos) = match e.node {
468+
If(ref cond, ref block, ..) => {
469+
let left = e.span.lo() + syntax_pos::BytePos(2);
470+
let right = block.span.lo();
471+
(cond, "`if` condition", true, Some(left), Some(right))
472+
}
473+
474+
While(ref cond, ref block, ..) => {
475+
let left = e.span.lo() + syntax_pos::BytePos(5);
476+
let right = block.span.lo();
477+
(cond, "`while` condition", true, Some(left), Some(right))
478+
},
479+
480+
ForLoop(_, ref cond, ref block, ..) => {
481+
(cond, "`for` head expression", true, None, Some(block.span.lo()))
482+
}
483+
484+
Match(ref head, _) => {
485+
let left = e.span.lo() + syntax_pos::BytePos(5);
486+
(head, "`match` head expression", true, Some(left), None)
487+
}
488+
489+
Ret(Some(ref value)) => {
490+
let left = e.span.lo() + syntax_pos::BytePos(3);
491+
(value, "`return` value", false, Some(left), None)
492+
}
493+
494+
Assign(_, ref value) => (value, "assigned value", false, None, None),
495+
AssignOp(.., ref value) => (value, "assigned value", false, None, None),
457496
// either function/method call, or something this lint doesn't care about
458497
ref call_or_other => {
459498
let (args_to_check, call_kind) = match *call_or_other {
@@ -475,12 +514,12 @@ impl EarlyLintPass for UnusedParens {
475514
}
476515
let msg = format!("{} argument", call_kind);
477516
for arg in args_to_check {
478-
self.check_unused_parens_expr(cx, arg, &msg, false);
517+
self.check_unused_parens_expr(cx, arg, &msg, false, None, None);
479518
}
480519
return;
481520
}
482521
};
483-
self.check_unused_parens_expr(cx, &value, msg, followed_by_block);
522+
self.check_unused_parens_expr(cx, &value, msg, followed_by_block, left_pos, right_pos);
484523
}
485524

486525
fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
@@ -500,7 +539,7 @@ impl EarlyLintPass for UnusedParens {
500539
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
501540
if let ast::StmtKind::Local(ref local) = s.node {
502541
if let Some(ref value) = local.init {
503-
self.check_unused_parens_expr(cx, &value, "assigned value", false);
542+
self.check_unused_parens_expr(cx, &value, "assigned value", false, None, None);
504543
}
505544
}
506545
}

src/test/ui/lint/unused_parens_json_suggestion.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
}
8282
],
8383
"label": null,
84-
"suggested_replacement": " 1 / (2 + 3) ",
84+
"suggested_replacement": "1 / (2 + 3)",
8585
"suggestion_applicability": "MachineApplicable",
8686
"expansion": null
8787
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// compile-flags: --error-format pretty-json -Zunstable-options
2+
// build-pass
3+
4+
// The output for humans should just highlight the whole span without showing
5+
// the suggested replacement, but we also want to test that suggested
6+
// replacement only removes one set of parentheses, rather than naïvely
7+
// stripping away any starting or ending parenthesis characters—hence this
8+
// test of the JSON error format.
9+
10+
#![warn(unused_parens)]
11+
12+
fn main() {
13+
14+
let _b = false;
15+
16+
if (_b) {
17+
println!("hello");
18+
}
19+
20+
f();
21+
22+
}
23+
24+
fn f() -> bool {
25+
let c = false;
26+
27+
if(c) {
28+
println!("next");
29+
}
30+
31+
if (c){
32+
println!("prev");
33+
}
34+
35+
while (false && true){
36+
if (c) {
37+
println!("norm");
38+
}
39+
40+
}
41+
42+
while(true && false) {
43+
for i in (0 .. 3){
44+
println!("e~")
45+
}
46+
}
47+
48+
for i in (0 .. 3) {
49+
while (true && false) {
50+
println!("e~")
51+
}
52+
}
53+
54+
55+
loop {
56+
if (break { return true }) {
57+
}
58+
}
59+
false
60+
}

0 commit comments

Comments
 (0)