From 8a4c34a5b7f084f64ab20a4120c61521a1a2b662 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 9 Aug 2024 09:04:18 -0400 Subject: [PATCH] Start removing `snippet_opt` --- clippy_lints/src/booleans.rs | 33 +++++++------ clippy_lints/src/borrow_deref_ref.rs | 7 +-- clippy_lints/src/format.rs | 4 +- clippy_lints/src/format_args.rs | 4 +- clippy_lints/src/from_over_into.rs | 12 ++--- clippy_lints/src/int_plus_one.rs | 6 +-- clippy_lints/src/items_after_test_module.rs | 9 ++-- clippy_lints/src/large_stack_frames.rs | 4 +- clippy_lints/src/len_zero.rs | 4 +- clippy_lints/src/literal_representation.rs | 6 +-- clippy_lints/src/manual_float_methods.rs | 4 +- clippy_lints/src/manual_hash_one.rs | 6 +-- clippy_lints/src/manual_non_exhaustive.rs | 6 +-- clippy_lints/src/manual_range_patterns.rs | 6 +-- .../src/methods/unnecessary_iter_cloned.rs | 8 +-- .../src/misc_early/unneeded_field_pattern.rs | 27 +++++----- .../src/missing_enforced_import_rename.rs | 4 +- clippy_lints/src/needless_if.rs | 4 +- clippy_lints/src/needless_late_init.rs | 11 +++-- clippy_lints/src/no_effect.rs | 47 +++++++++--------- clippy_lints/src/nonstandard_macro_braces.rs | 6 +-- .../src/operators/assign_op_pattern.rs | 6 +-- .../src/operators/misrefactored_assign_op.rs | 6 ++- .../src/operators/needless_bitwise_bool.rs | 6 +-- clippy_lints/src/operators/ptr_eq.rs | 6 +-- clippy_lints/src/unit_types/unit_arg.rs | 20 ++++---- .../src/utils/format_args_collector.rs | 49 ++++++------------- clippy_utils/src/attrs.rs | 38 +++++++------- clippy_utils/src/hir_utils.rs | 18 +++---- 29 files changed, 177 insertions(+), 190 deletions(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a2f48c18170..e933fdf1d6e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition( let suggestion = match (left.kind, right.kind) { (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (ExprKind::Unary(UnOp::Not, left_sub), _) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right.span) else { + let Some(right) = right.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (_, ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left.span) else { return }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(left) = left.span.get_source_text(cx) else { + return; + }; + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; @@ -313,8 +315,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { self.output.push_str(&str); } else { self.output.push('!'); - let snip = snippet_opt(self.cx, terminal.span)?; - self.output.push_str(&snip); + self.output.push_str(&terminal.span.get_source_text(self.cx)?); } }, True | False | Not(_) => { @@ -345,8 +346,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } }, &Term(n) => { - let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?; - self.output.push_str(&snip); + self.output.push_str( + &self.terminals[n as usize] + .span + .source_callsite() + .get_source_text(self.cx)?, + ); }, } Some(()) @@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { _ => None, } .and_then(|op| { - let lhs_snippet = snippet_opt(cx, lhs.span)?; - let rhs_snippet = snippet_opt(cx, rhs.span)?; + let lhs_snippet = lhs.span.get_source_text(cx)?; + let rhs_snippet = rhs.span.get_source_text(cx)?; if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { @@ -399,7 +404,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) + .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?))) }, _ => None, } diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index bd123a725a7..cba8224b84c 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; use rustc_errors::Applicability; @@ -73,6 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { } }) && !is_from_proc_macro(cx, e) + && let Some(deref_text) = deref_target.span.get_source_text(cx) { span_lint_and_then( cx, @@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to reborrow, try removing `&*`", - snippet_opt(cx, deref_target.span).unwrap(), + deref_text.as_str(), Applicability::MachineApplicable, ); @@ -98,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to deref, try using `&**`", - format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), + format!("&**{deref_text}"), Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index c14bd38a1f2..4dedff69b9a 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { + let Some(snippet) = format_args.span.get_source_text(cx) else { return; }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 823992767e5..020c0c5440d 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -7,7 +7,7 @@ use clippy_utils::macros::{ find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, }; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use itertools::Itertools; use rustc_ast::{ @@ -407,7 +407,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) + && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index b6c8437fb8f..5e9098474dc 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ @@ -178,8 +178,8 @@ fn convert_to_from( return None; }; - let from = snippet_opt(cx, self_ty.span)?; - let into = snippet_opt(cx, target_ty.span)?; + let from = self_ty.span.get_source_text(cx)?; + let into = target_ty.span.get_source_text(cx)?; let return_type = matches!(sig.decl.output, FnRetTy::Return(_)) .then_some(String::from("Self")) @@ -190,10 +190,10 @@ fn convert_to_from( (into_trait_seg.ident.span, String::from("From")), // impl Into for U -> impl Into for U // ~ ~ - (target_ty.span, from.clone()), + (target_ty.span, from.to_owned()), // impl Into for U -> impl Into for T // ~ ~ - (self_ty.span, into), + (self_ty.span, into.to_owned()), // fn into(self) -> T -> fn from(self) -> T // ~~~~ ~~~~ (impl_item.ident.span, String::from("from")), @@ -223,7 +223,7 @@ fn convert_to_from( } for span in finder.upper { - suggestions.push((span, from.clone())); + suggestions.push((span, from.to_owned())); } for span in finder.lower { suggestions.push((span, String::from("val"))); diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 941caaab1f1..fc575bff7e6 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -130,8 +130,8 @@ impl IntPlusOne { BinOpKind::Le => "<", _ => return None, }; - if let Some(snippet) = snippet_opt(cx, node.span) { - if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { + if let Some(snippet) = node.span.get_source_text(cx) { + if let Some(other_side_snippet) = other_side.span.get_source_text(cx) { let rec = match side { Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 3614fb8cc96..8caa484bb99 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; @@ -93,11 +93,14 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(prev) = mod_pos.checked_sub(1) && let prev = cx.tcx.hir().item(module.item_ids[prev]) && let items_span = last.span.with_lo(test_mod.span.hi()) - && let Some(items) = snippet_opt(cx, items_span) + && let Some(items) = items_span.get_source_text(cx) { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", - vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], + vec![ + (prev.span.shrink_to_hi(), items.to_owned()), + (items_span, String::new()), + ], Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 4abf7edc9b4..d2bdf194ada 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -3,7 +3,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { // TODO: Is there a cleaner, robust way to ask this question? // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = snippet_opt(cx, local_span) + if let Some(name) = local_span.get_source_text(cx) && is_ident(&name) { // If the local is an ordinary named variable, diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 4c737371bd2..0bc7fc2dd9d 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; @@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { - let Some(snippet) = snippet_opt(cx, span) else { + let Some(snippet) = span.get_source_text(cx) else { return span; }; if has_enclosing_paren(snippet) { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index f51c593b2de..81f2a03fb55 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -225,7 +225,7 @@ impl LiteralDigitGrouping { } fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if let Some(src) = snippet_opt(cx, span) + if let Some(src) = span.get_source_text(cx) && let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) { @@ -439,7 +439,7 @@ impl DecimalLiteralRepresentation { // Lint integral literals. if let Ok(lit_kind) = LitKind::from_token_lit(lit) && let LitKind::Int(val, _) = lit_kind - && let Some(src) = snippet_opt(cx, span) + && let Some(src) = span.get_source_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal && val >= u128::from(self.threshold) diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 6bdc79129a9..9d3ddab60bb 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(&const_1) && is_neg_infinity(&const_2) || is_neg_infinity(&const_1) && is_infinity(&const_2)) - && let Some(local_snippet) = snippet_opt(cx, first.span) + && let Some(local_snippet) = first.span.get_source_text(cx) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 1c568b1b74f..11716a539ab 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; @@ -107,8 +107,8 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, "manual implementation of `BuildHasher::hash_one`", |diag| { - if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) - && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + if let Some(build_hasher) = build_hasher.span.get_source_text(cx) + && let Some(hashed_value) = hashed_value.span.get_source_text(cx) { diag.multipart_suggestion( "try", diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 28cfe22835a..6b1d90483cc 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; @@ -124,7 +124,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { |diag| { if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = snippet_opt(cx, header_span) + && let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { "this seems like a manual implementation of the non-exhaustive pattern", |diag| { let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = snippet_opt(cx, header_span) { + if let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, "add the attribute", diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 07d4abbf5cd..9afb2b5bc84 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns { pat.span, "this OR pattern can be rewritten using a range", |diag| { - if let Some(min) = snippet_opt(cx, min.span) - && let Some(max) = snippet_opt(cx, max.span) + if let Some(min) = min.span.get_source_text(cx) + && let Some(max) = max.span.get_source_text(cx) { diag.span_suggestion( pat.span, diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 70885e46e95..4d18bc7ac77 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -1,7 +1,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; @@ -40,7 +40,7 @@ pub fn check_for_loop_iter( && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { // Issue 12098 // https://github.com/rust-lang/rust-clippy/issues/12098 @@ -100,7 +100,7 @@ pub fn check_for_loop_iter( && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") && iter_item_ty == into_iter_item_ty - && let Some(collection_snippet) = snippet_opt(cx, collection.span) + && let Some(collection_snippet) = collection.span.get_source_text(cx) { collection_snippet } else { @@ -122,7 +122,7 @@ pub fn check_for_loop_iter( } else { Applicability::MachineApplicable }; - diag.span_suggestion(expr.span, "use", snippet, applicability); + diag.span_suggestion(expr.span, "use", snippet.to_owned(), applicability); if !references_to_binding.is_empty() { diag.multipart_suggestion( "remove any references to the binding", diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 6db03adf44a..33ab94e00a5 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; +use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; @@ -45,19 +46,6 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` instead", ); } else { - let mut normal = vec![]; - - for field in pfields { - match field.pat.kind { - PatKind::Wild => {}, - _ => { - if let Some(n) = snippet_opt(cx, field.span) { - normal.push(n); - } - }, - } - } - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, @@ -65,7 +53,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { field.span, "you matched a field with a wildcard pattern, consider using `..` instead", |diag| { - diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", "))); + diag.help(format!( + "try with `{type_name} {{ {}, .. }}`", + pfields + .iter() + .filter_map(|f| match f.pat.kind { + PatKind::Wild => None, + _ => f.span.get_source_text(cx), + }) + .format(", "), + )); }, ); } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index cdf6645b3df..59f29d242ab 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::def_path_def_ids; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; @@ -73,7 +73,7 @@ impl LateLintPass<'_> for ImportRename { && let Some(name) = self.renames.get(&id) // Remove semicolon since it is not present for nested imports && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') - && let Some(snip) = snippet_opt(cx, span_without_semi) + && let Some(snip) = span_without_semi.get_source_text(cx) && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 1d6233d432a..8e14fbf2f80 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -57,7 +57,7 @@ impl LateLintPass<'_> for NeedlessIf { src.bytes() .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) }) - && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && let Some(cond_snippet) = cond.span.get_source_text(cx) && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 4bfc30fa5cf..46cdb82130f 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; @@ -236,7 +236,7 @@ fn first_usage<'tcx>( }) } -fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { +fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { let span = local.span.with_hi(match local.ty { // let : ; // ~~~~~~~~~~~~~~~ @@ -246,7 +246,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - snippet_opt(cx, span) + span.get_source_text(cx) } fn check<'tcx>( @@ -275,7 +275,10 @@ fn check<'tcx>( |diag| { diag.multipart_suggestion( format!("move the declaration `{binding_name}` here"), - vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)], + vec![ + (local_stmt.span, String::new()), + (assign.lhs_span, let_snippet.to_owned()), + ], Applicability::MachineApplicable, ); }, diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 8232e69db39..b181791699a 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::has_drop; use clippy_utils::{ in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, @@ -268,34 +268,31 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { - if is_inside_always_const_context(cx.tcx, expr.hir_id) { - return; + if !is_inside_always_const_context(cx.tcx, expr.hir_id) + && let [arr, func] = &*reduced + && let Some(arr) = arr.span.get_source_text(cx) + && let Some(func) = func.span.get_source_text(cx) + { + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + format!("assert!({arr}.len() > {func});"), + Applicability::MaybeIncorrect, + ); + }, + ); } - let snippet = - if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { - format!("assert!({arr}.len() > {func});") - } else { - return; - }; - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be written as", - snippet, - Applicability::MaybeIncorrect, - ); - }, - ); } else { let mut snippet = String::new(); for e in reduced { - if let Some(snip) = snippet_opt(cx, e.span) { + if let Some(snip) = e.span.get_source_text(cx) { snippet.push_str(&snip); snippet.push(';'); } else { diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 2aaf1e6ff46..51ba29d7389 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::types::MacroMatcher; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -34,7 +34,7 @@ declare_clippy_lint! { } /// The (callsite span, (open brace, close brace), source snippet) -type MacroInfo = (Span, (char, char), String); +type MacroInfo = (Span, (char, char), SourceText); pub struct MacroBraces { macro_braces: FxHashMap, @@ -94,7 +94,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = snippet_opt(cx, span_call_site) + && let Some(snip) = span_call_site.get_source_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && snip.starts_with(&format!("{name}!")) diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 641d881d974..11c97b4ef00 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; @@ -46,8 +46,8 @@ pub(super) fn check<'tcx>( expr.span, "manual implementation of an assign operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = - (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs.span.get_source_text(cx) { diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 311cbd050a1..8daedd1c901 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -42,7 +42,9 @@ fn lint_misrefactored_assign_op( expr.span, "variable appears on both sides of an assignment operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs_other.span.get_source_text(cx) + { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index ab5fb178700..9d8e833ef6d 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -24,8 +24,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp e.span, "use of bitwise operator instead of lazy operator between booleans", |diag| { - if let Some(lhs_snip) = snippet_opt(cx, lhs.span) - && let Some(rhs_snip) = snippet_opt(cx, rhs.span) + if let Some(lhs_snip) = lhs.span.get_source_text(cx) + && let Some(rhs_snip) = rhs.span.get_source_text(cx) { let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 607930561e0..861564d5456 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -22,8 +22,8 @@ pub(super) fn check<'tcx>( if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left) && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right) - && let Some(left_snip) = snippet_opt(cx, left_var.span) - && let Some(right_snip) = snippet_opt(cx, right_var.span) + && let Some(left_snip) = left_var.span.get_source_text(cx) + && let Some(right_snip) = right_var.span.get_source_text(cx) { let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_sugg( diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index afc53e6f32d..978d49f09c3 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; @@ -79,7 +79,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp && block.expr.is_none() && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind - && let Some(snip) = snippet_opt(cx, last_expr.span) + && let Some(snip) = last_expr.span.get_source_text(cx) { Some((last_stmt.span, snip)) } else { @@ -90,24 +90,24 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp db.span_suggestion( span, "remove the semicolon from the last statement in the block", - sugg, + sugg.as_str(), Applicability::MaybeIncorrect, ); or = "or "; applicability = Applicability::MaybeIncorrect; }); - let arg_snippets: Vec = args_to_recover + let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - let arg_snippets_without_empty_blocks: Vec = args_to_recover + let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - if let Some(call_snippet) = snippet_opt(cx, expr.span) { + if let Some(call_snippet) = expr.span.get_source_text(cx) { let sugg = fmt_stmts_and_call( cx, expr, @@ -161,8 +161,8 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[impl AsRef], - non_empty_block_args_snippets: &[impl AsRef], + args_snippets: &[SourceText], + non_empty_block_args_snippets: &[SourceText], ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); let call_snippet_with_replacements = args_snippets diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 5acfd35fd6a..f50ce6c99de 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; @@ -75,38 +75,21 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { // `format!("{} {} {c}", "one", "two", c = "three")` // ^^ ^^ ^^^^^^ - let between_spans = once(args.span) + !once(args.span) .chain(argument_span) .tuple_windows() - .map(|(start, end)| start.between(end)); - - for between_span in between_spans { - let mut seen_comma = false; - - let Some(snippet) = snippet_opt(cx, between_span) else { - return true; - }; - for token in tokenize(&snippet) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => seen_comma = true, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates that we crossed a macro boundary - // - // `println!(some_proc_macro!("input {}"), a)` - // ^^^ between_span - // `println!("{}", val!(x))` - // ^^^^^^^ between_span - _ => return true, - } - } - - if !seen_comma { - return true; - } - } - - false + .map(|(start, end)| start.between(end)) + .all(|sp| { + sp.check_source_text(cx, |src| { + // text should be either `, name` or `, name =` + let mut iter = tokenize(src).filter(|t| { + !matches!( + t.kind, + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace + ) + }); + iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma)) + && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq)) + }) + }) } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index d2200bcf710..42c8b218d14 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -7,7 +7,7 @@ use rustc_session::Session; use rustc_span::{sym, Span}; use std::str::FromStr; -use crate::source::snippet_opt; +use crate::source::SpanRangeExt; use crate::tokenize_with_text; /// Deprecation status of attributes known by Clippy. @@ -179,25 +179,23 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks if the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); + s.check_source_text(cx, |src| { + let mut iter = tokenize_with_text(src); - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + { + return true; + } } - } - false + false + }) } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index b0a668329e9..f61ef9ac1b0 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -588,10 +588,9 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' // block with an empty span. ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]), // `{}` => `()` - ([], None) => match snippet_opt(cx, block.span) { - // Don't reduce if there are any tokens contained in the braces - Some(snip) - if tokenize(&snip) + ([], None) + if block.span.check_source_text(cx, |src| { + tokenize(src) .map(|t| t.kind) .filter(|t| { !matches!( @@ -599,11 +598,10 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace ) }) - .ne([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) => - { - kind - }, - _ => &ExprKind::Tup(&[]), + .eq([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) + }) => + { + &ExprKind::Tup(&[]) }, ([], Some(expr)) => match expr.kind { // `{ return .. }` => `return ..`