From c209fc9349ff750dc983ecfe23d8e0bb74f002df Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Fri, 5 Oct 2018 09:06:05 -0700 Subject: [PATCH 1/6] Fix string_lit_as_bytes lint for macros Prior to this change, string_lit_as_bytes would trigger for constructs like `include_str!("filename").as_bytes()` and would recommend fixing it by rewriting as `binclude_str!("filename")`. This change updates the lint to act as an EarlyLintPass lint. It then differentiates between string literals and macros that have bytes yielding alternatives. Closes #3205 --- clippy_lints/src/strings.rs | 39 +++++++++++++++++++++++++++++-------- tests/ui/strings.rs | 8 +++++--- tests/ui/strings.stderr | 12 ------------ 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index f4798842205..9b6478fb9cd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -92,7 +92,14 @@ impl LintPass for StringAdd { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if let ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) = e.node { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref left, + _, + ) = e.node + { if is_string(cx, left) { if !is_allowed(cx, STRING_ADD_ASSIGN, e.id) { let parent = get_parent_expr(cx, e); @@ -132,13 +139,15 @@ fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool { fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool { match src.node { - ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), + ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref left, + _, + ) => SpanlessEq::new(cx).eq_expr(target, left), ExprKind::Block(ref block, _) => { - block.stmts.is_empty() - && block - .expr - .as_ref() - .map_or(false, |expr| is_add(cx, expr, target)) + block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) }, _ => false, } @@ -162,7 +171,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { if path.ident.name == "as_bytes" { if let ExprKind::Lit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { - if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) { + let callsite = snippet(cx, args[0].span.source_callsite(), ""); + let expanded = format!("\"{}\"", lit_content.as_str()); + if callsite.starts_with("include_str!") { + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `as_bytes()` on `include_str!(..)`", + "consider using `include_bytes!(..)` instead", + snippet(cx, args[0].span, r#""foo""#).replacen("include_str", "include_bytes", 1), + ); + } else if callsite == expanded + && lit_content.as_str().chars().all(|c| c.is_ascii()) + && !in_macro(args[0].span) + { span_lint_and_sugg( cx, STRING_LIT_AS_BYTES, diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 7bc4e6515f6..6693776a961 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -10,10 +10,10 @@ - #[warn(clippy::string_add)] #[allow(clippy::string_add_assign)] -fn add_only() { // ignores assignment distinction +fn add_only() { + // ignores assignment distinction let mut x = "".to_owned(); for _ in 1..3 { @@ -63,6 +63,8 @@ fn str_lit_as_bytes() { let ubs = "☃".as_bytes(); let strify = stringify!(foobar).as_bytes(); + + let includestr = include_str!("entry.rs").as_bytes(); } fn main() { @@ -72,6 +74,6 @@ fn main() { // the add is only caught for `String` let mut x = 1; - ; x = x + 1; +; x = x + 1; assert_eq!(2, x); } diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index bcdf91568d2..8a93733732e 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -60,17 +60,5 @@ error: calling `as_bytes()` on a string literal | = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` -error: calling `as_bytes()` on a string literal - --> $DIR/strings.rs:65:18 - | -65 | let strify = stringify!(foobar).as_bytes(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `bstringify!(foobar)` - -error: manual implementation of an assign operation - --> $DIR/strings.rs:75:7 - | -75 | ; x = x + 1; - | ^^^^^^^^^ help: replace it with: `x += 1` - error: aborting due to 11 previous errors From f9020bb2dded44e97fd997ab71ab4edf6d88033b Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Wed, 24 Oct 2018 11:49:39 -0400 Subject: [PATCH 2/6] fix: extra semicolon, only create callsite once --- clippy_lints/src/strings.rs | 2 +- tests/ui/strings.rs | 5 ++++- tests/ui/strings.stderr | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 9b6478fb9cd..fe3d461ab43 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { if path.ident.name == "as_bytes" { if let ExprKind::Lit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { - let callsite = snippet(cx, args[0].span.source_callsite(), ""); + let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); let expanded = format!("\"{}\"", lit_content.as_str()); if callsite.starts_with("include_str!") { span_lint_and_sugg( diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 6693776a961..d2062b356dc 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -59,6 +59,8 @@ fn both() { fn str_lit_as_bytes() { let bs = "hello there".as_bytes(); + let bs = r###"raw string with three ### in it and some " ""###.as_bytes(); + // no warning, because this cannot be written as a byte string literal: let ubs = "☃".as_bytes(); @@ -67,6 +69,7 @@ fn str_lit_as_bytes() { let includestr = include_str!("entry.rs").as_bytes(); } +#[allow(clippy::assign_op_pattern)] fn main() { add_only(); add_assign_only(); @@ -74,6 +77,6 @@ fn main() { // the add is only caught for `String` let mut x = 1; -; x = x + 1; + x = x + 1; assert_eq!(2, x); } diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index 8a93733732e..2496270ba0d 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -60,5 +60,3 @@ error: calling `as_bytes()` on a string literal | = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` -error: aborting due to 11 previous errors - From 19ac2e94c6cb12ae4f9fb410f165e2aa5309e124 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Fri, 26 Oct 2018 09:10:20 -0700 Subject: [PATCH 3/6] fix: correctly reconstruct raw strings --- clippy_lints/src/strings.rs | 12 ++++++++---- tests/ui/strings.stderr | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index fe3d461ab43..e07b1649a46 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -7,7 +7,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; @@ -164,15 +163,20 @@ impl LintPass for StringLitAsBytes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - use crate::syntax::ast::LitKind; + use crate::syntax::ast::{LitKind, StrStyle}; use crate::utils::{in_macro, snippet}; if let ExprKind::MethodCall(ref path, _, ref args) = e.node { if path.ident.name == "as_bytes" { if let ExprKind::Lit(ref lit) = args[0].node { - if let LitKind::Str(ref lit_content, _) = lit.node { + if let LitKind::Str(ref lit_content, style) = lit.node { let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); - let expanded = format!("\"{}\"", lit_content.as_str()); + let expanded = if let StrStyle::Raw(n) = style { + let term = (0..n).map(|_| '#').collect::<String>(); + format!("r{0}\"{1}\"{0}", term, lit_content.as_str()) + } else { + format!("\"{}\"", lit_content.as_str()) + }; if callsite.starts_with("include_str!") { span_lint_and_sugg( cx, diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index 2496270ba0d..21115d8e97e 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -60,3 +60,17 @@ error: calling `as_bytes()` on a string literal | = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` +error: calling `as_bytes()` on a string literal + --> $DIR/strings.rs:62:14 + | +62 | let bs = r###"raw string with three ### in it and some " ""###.as_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with three ### in it and some " ""###` + +error: calling `as_bytes()` on `include_str!(..)` + --> $DIR/strings.rs:69:22 + | +69 | let includestr = include_str!("entry.rs").as_bytes(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry.rs")` + +error: aborting due to 11 previous errors + From aa7bcb9074f3a7235e43d1da910d80248e53357d Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Sat, 27 Oct 2018 11:01:27 +0200 Subject: [PATCH 4/6] Don't expand macro in identity_conversion suggestion --- clippy_lints/src/identity_conversion.rs | 5 +++-- clippy_lints/src/utils/mod.rs | 6 ++++++ tests/ui/identity_conversion.rs | 1 + tests/ui/identity_conversion.stderr | 8 +++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index e9761616696..00ce58f00b0 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -12,7 +12,7 @@ use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; use crate::syntax::ast::NodeId; -use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, span_lint_and_then}; +use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then}; use crate::utils::{opt_def_id, paths, resolve_node}; use crate::rustc_errors::Applicability; @@ -72,7 +72,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { let a = cx.tables.expr_ty(e); let b = cx.tables.expr_ty(&args[0]); if same_tys(cx, a, b) { - let sugg = snippet(cx, args[0].span, "<expr>").into_owned(); + let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string(); + span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| { db.span_suggestion_with_applicability( e.span, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 1a8db837f32..5ff246630e0 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -362,6 +362,12 @@ pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) } +/// Same as `snippet`, but should only be used when it's clear that the input span is +/// not a macro argument. +pub fn snippet_with_macro_callsite<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + snippet(cx, span.source_callsite(), default) +} + /// Convert a span to a code snippet. Returns `None` if not available. pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> { cx.sess().source_map().span_to_snippet(span).ok() diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs index 9384c9eb206..b5cb92c6d5a 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/identity_conversion.rs @@ -53,4 +53,5 @@ fn main() { let _ = String::from(format!("A: {:04}", 123)); let _ = "".lines().into_iter(); let _ = vec![1, 2, 3].into_iter().into_iter(); + let _: String = format!("Hello {}", "world").into(); } diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/identity_conversion.stderr index 2ac74191931..15bef8b125e 100644 --- a/tests/ui/identity_conversion.stderr +++ b/tests/ui/identity_conversion.stderr @@ -58,5 +58,11 @@ error: identical conversion 55 | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` -error: aborting due to 9 previous errors +error: identical conversion + --> $DIR/identity_conversion.rs:56:21 + | +56 | let _: String = format!("Hello {}", "world").into(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` + +error: aborting due to 10 previous errors From af1548f58f2a9a356a7c122f2fba25c816492a91 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Sat, 27 Oct 2018 14:45:02 +0200 Subject: [PATCH 5/6] Don't expand macro in single_match suggestion --- clippy_lints/src/matches.rs | 3 +- clippy_lints/src/utils/mod.rs | 5 +++- tests/ui/matches.stderr | 2 +- tests/ui/single_match.rs | 9 ++++++ tests/ui/single_match.stderr | 52 +++++++++++++++++++++-------------- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index e46615f4da2..4a704c3d52e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -19,7 +19,8 @@ use crate::syntax::ast::LitKind; use crate::syntax::source_map::Span; use crate::utils::paths; use crate::utils::{expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, - remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty}; + remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, + span_note_and_lint, walk_ptrs_ty}; use crate::utils::sugg::Sugg; use crate::consts::{constant, Constant}; use crate::rustc_errors::Applicability; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 5ff246630e0..72a6bda26c3 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -406,7 +406,10 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>( ) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.unwrap_or_default(); - if let ExprKind::Block(_, _) = expr.node { + if in_macro(expr.span) { + Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + } + else if let ExprKind::Block(_, _) = expr.node { Cow::Owned(format!("{}{}", code, string)) } else if string.is_empty() { Cow::Owned(format!("{{ {} }}", code)) diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index bed903faf1a..b5f1f2ab0e7 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -33,7 +33,7 @@ error: you seem to be trying to use match for destructuring a single pattern. Co 51 | | &(v, 1) => println!("{}", v), 52 | | _ => println!("none"), 53 | | } - | |_____^ help: try this: `if let &(v, 1) = tup { $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ; } else { $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ; }` + | |_____^ help: try this: `if let &(v, 1) = tup { println!("{}", v) } else { println!("none") }` error: you don't need to add `&` to all patterns --> $DIR/matches.rs:50:5 diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 5c7cae249b4..dca68e179e7 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -23,6 +23,15 @@ fn single_match(){ _ => () }; + let x = Some(1u8); + match x { + // Note the missing block braces. + // We suggest `if let Some(y) = x { .. }` because the macro + // is expanded before we can do anything. + Some(y) => println!("{:?}", y), + _ => () + } + let z = (1u8,1u8); match z { (2...3, 7...9) => dummy(), diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 74448391ca5..df614ad201d 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -12,38 +12,50 @@ error: you seem to be trying to use match for destructuring a single pattern. Co error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:27:5 | -27 | / match z { -28 | | (2...3, 7...9) => dummy(), -29 | | _ => {} -30 | | }; +27 | / match x { +28 | | // Note the missing block braces. +29 | | // We suggest `if let Some(y) = x { .. }` because the macro +30 | | // is expanded before we can do anything. +31 | | Some(y) => println!("{:?}", y), +32 | | _ => () +33 | | } + | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` + +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match.rs:36:5 + | +36 | / match z { +37 | | (2...3, 7...9) => dummy(), +38 | | _ => {} +39 | | }; | |_____^ help: try this: `if let (2...3, 7...9) = z { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:53:5 + --> $DIR/single_match.rs:62:5 | -53 | / match x { -54 | | Some(y) => dummy(), -55 | | None => () -56 | | }; +62 | / match x { +63 | | Some(y) => dummy(), +64 | | None => () +65 | | }; | |_____^ help: try this: `if let Some(y) = x { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:58:5 + --> $DIR/single_match.rs:67:5 | -58 | / match y { -59 | | Ok(y) => dummy(), -60 | | Err(..) => () -61 | | }; +67 | / match y { +68 | | Ok(y) => dummy(), +69 | | Err(..) => () +70 | | }; | |_____^ help: try this: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:65:5 + --> $DIR/single_match.rs:74:5 | -65 | / match c { -66 | | Cow::Borrowed(..) => dummy(), -67 | | Cow::Owned(..) => (), -68 | | }; +74 | / match c { +75 | | Cow::Borrowed(..) => dummy(), +76 | | Cow::Owned(..) => (), +77 | | }; | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors From 840e50e97f023c2d0bfeb0222d094fa407f12f2f Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Sat, 27 Oct 2018 15:37:56 +0200 Subject: [PATCH 6/6] Don't expand macro in or_fun_call suggestion --- clippy_lints/src/methods/mod.rs | 8 ++++---- tests/ui/methods.stderr | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 01f97264d0b..8d0cd32e23b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -21,7 +21,7 @@ use crate::utils::sugg; use crate::utils::{ get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type, - match_var, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet, span_lint, + match_var, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_macro_callsite, span_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; use if_chain::if_chain; @@ -1062,9 +1062,9 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa } let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(), - (false, true) => snippet(cx, fun_span, ".."), + (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), + (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), + (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."), }; let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 307814824ea..896b15481bb 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -297,7 +297,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/methods.rs:339:14 | 339 | with_vec.unwrap_or(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| < [ _ ] > :: into_vec ( box [ $ ( $ x ) , * ] ))` + | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| vec![])` error: use of `unwrap_or` followed by a function call --> $DIR/methods.rs:344:21