Skip to content

Commit 3d43826

Browse files
committed
Auto merge of #8305 - camsteffen:util-cleanup, r=flip1995
Factor out several utils, add `path_def_id` changelog: none This is generally an effort to reduce the total number of utils. `path_def_id` is added which I believe is more "cross-cutting" and also complements `path_to_local`. Best reviewed one commit at a time. Added: * `path_def_id` * `path_res` Removed: * `is_qpath_def_path` * `match_any_diagnostic_items` * `expr_path_res` * `single_segment_path` * `differing_macro_contexts` * `is_ty_param_lang_item` * `is_ty_param_diagnostic_item` * `get_qpath_generics` Renamed: * `path_to_res` to `def_path_res` * `get_qpath_generic_tys` to `qpath_generic_tys` CC `@Jarcho` since this relates to some of your work and you may have input.
2 parents 8dc719c + bd583d9 commit 3d43826

29 files changed

+249
-309
lines changed

clippy_lints/src/blocks_in_if_conditions.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
2+
use clippy_utils::get_parent_expr;
23
use clippy_utils::higher;
34
use clippy_utils::source::snippet_block_with_applicability;
45
use clippy_utils::ty::implements_trait;
5-
use clippy_utils::{differing_macro_contexts, get_parent_expr};
66
use if_chain::if_chain;
77
use rustc_errors::Applicability;
88
use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
9797
if let Some(ex) = &block.expr {
9898
// don't dig into the expression here, just suggest that they remove
9999
// the block
100-
if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) {
100+
if expr.span.from_expansion() || ex.span.from_expansion() {
101101
return;
102102
}
103103
let mut applicability = Applicability::MachineApplicable;
@@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
122122
}
123123
} else {
124124
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
125-
if span.from_expansion() || differing_macro_contexts(expr.span, span) {
125+
if span.from_expansion() || expr.span.from_expansion() {
126126
return;
127127
}
128128
// move block higher

clippy_lints/src/disallowed_methods.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
7777
fn check_crate(&mut self, cx: &LateContext<'_>) {
7878
for (index, conf) in self.conf_disallowed.iter().enumerate() {
7979
let segs: Vec<_> = conf.path().split("::").collect();
80-
if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
80+
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
8181
self.disallowed.insert(id, index);
8282
}
8383
}

clippy_lints/src/disallowed_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
9696
),
9797
};
9898
let segs: Vec<_> = path.split("::").collect();
99-
match clippy_utils::path_to_res(cx, &segs) {
99+
match clippy_utils::def_path_res(cx, &segs) {
100100
Res::Def(_, id) => {
101101
self.def_ids.insert(id, reason);
102102
},

clippy_lints/src/formatting.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
2-
use clippy_utils::differing_macro_contexts;
32
use clippy_utils::source::snippet_opt;
43
use if_chain::if_chain;
54
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
@@ -135,7 +134,7 @@ impl EarlyLintPass for Formatting {
135134
/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
136135
fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
137136
if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind {
138-
if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() {
137+
if !lhs.span.from_expansion() && !rhs.span.from_expansion() {
139138
let eq_span = lhs.span.between(rhs.span);
140139
if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
141140
if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
@@ -165,7 +164,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
165164
fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
166165
if_chain! {
167166
if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind;
168-
if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion();
167+
if !lhs.span.from_expansion() && !rhs.span.from_expansion();
169168
// span between BinOp LHS and RHS
170169
let binop_span = lhs.span.between(rhs.span);
171170
// if RHS is an UnOp
@@ -206,8 +205,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
206205
if_chain! {
207206
if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
208207
if is_block(else_) || is_if(else_);
209-
if !differing_macro_contexts(then.span, else_.span);
210-
if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span);
208+
if !then.span.from_expansion() && !else_.span.from_expansion();
209+
if !in_external_macro(cx.sess(), expr.span);
211210

212211
// workaround for rust-lang/rust#43081
213212
if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
@@ -268,7 +267,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
268267
for element in array {
269268
if_chain! {
270269
if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
271-
if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span);
270+
if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt();
272271
let space_span = lhs.span.between(op.span);
273272
if let Some(space_snippet) = snippet_opt(cx, space_span);
274273
let lint_span = lhs.span.with_lo(lhs.span.hi());
@@ -291,8 +290,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
291290

292291
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
293292
if_chain! {
294-
if !differing_macro_contexts(first.span, second.span);
295-
if !first.span.from_expansion();
293+
if !first.span.from_expansion() && !second.span.from_expansion();
296294
if let ExprKind::If(cond_expr, ..) = &first.kind;
297295
if is_block(second) || is_if(second);
298296

clippy_lints/src/implicit_hasher.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_typeck::hir_ty_to_ty;
1717
use if_chain::if_chain;
1818

1919
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
20-
use clippy_utils::differing_macro_contexts;
2120
use clippy_utils::source::{snippet, snippet_opt};
2221
use clippy_utils::ty::is_type_diagnostic_item;
2322

@@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
123122
vis.visit_ty(impl_.self_ty);
124123

125124
for target in &vis.found {
126-
if differing_macro_contexts(item.span, target.span()) {
125+
if item.span.ctxt() != target.span().ctxt() {
127126
return;
128127
}
129128

clippy_lints/src/infinite_iter.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint;
22
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
3-
use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths};
3+
use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths};
44
use rustc_hir::{BorrowKind, Expr, ExprKind};
55
use rustc_lint::{LateContext, LateLintPass};
66
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -167,13 +167,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
167167
},
168168
ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
169169
ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
170-
ExprKind::Call(path, _) => {
171-
if let ExprKind::Path(ref qpath) = path.kind {
172-
is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into()
173-
} else {
174-
Finite
175-
}
176-
},
170+
ExprKind::Call(path, _) => path_def_id(cx, path)
171+
.map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
172+
.into(),
177173
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
178174
_ => Finite,
179175
}

clippy_lints/src/loops/single_element_loop.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use super::SINGLE_ELEMENT_LOOP;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
3-
use clippy_utils::single_segment_path;
4-
use clippy_utils::source::{indent_of, snippet};
3+
use clippy_utils::source::{indent_of, snippet_with_applicability};
54
use if_chain::if_chain;
65
use rustc_errors::Applicability;
7-
use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind};
6+
use rustc_hir::{BorrowKind, Expr, ExprKind, Pat};
87
use rustc_lint::LateContext;
98

109
pub(super) fn check<'tcx>(
@@ -16,33 +15,30 @@ pub(super) fn check<'tcx>(
1615
) {
1716
let arg_expr = match arg.kind {
1817
ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
19-
ExprKind::MethodCall(method, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => {
20-
&args[0]
21-
},
18+
ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg,
2219
_ => return,
2320
};
2421
if_chain! {
25-
if let PatKind::Binding(.., target, _) = pat.kind;
2622
if let ExprKind::Array([arg_expression]) = arg_expr.kind;
27-
if let ExprKind::Path(ref list_item) = arg_expression.kind;
28-
if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name);
2923
if let ExprKind::Block(block, _) = body.kind;
3024
if !block.stmts.is_empty();
31-
3225
then {
33-
let mut block_str = snippet(cx, block.span, "..").into_owned();
26+
let mut applicability = Applicability::MachineApplicable;
27+
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
28+
let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
29+
let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
3430
block_str.remove(0);
3531
block_str.pop();
36-
32+
let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
3733

3834
span_lint_and_sugg(
3935
cx,
4036
SINGLE_ELEMENT_LOOP,
4137
expr.span,
4238
"for loop over a single element",
4339
"try",
44-
format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str),
45-
Applicability::MachineApplicable
40+
format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str),
41+
applicability,
4642
)
4743
}
4844
}

clippy_lints/src/matches.rs

+35-27
Original file line numberDiff line numberDiff line change
@@ -1860,22 +1860,22 @@ where
18601860
mod redundant_pattern_match {
18611861
use super::REDUNDANT_PATTERN_MATCHING;
18621862
use clippy_utils::diagnostics::span_lint_and_then;
1863-
use clippy_utils::higher;
18641863
use clippy_utils::source::snippet;
18651864
use clippy_utils::sugg::Sugg;
18661865
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
1867-
use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
1866+
use clippy_utils::{higher, match_def_path};
1867+
use clippy_utils::{is_lang_ctor, is_trait_method, paths};
18681868
use if_chain::if_chain;
18691869
use rustc_ast::ast::LitKind;
18701870
use rustc_data_structures::fx::FxHashSet;
18711871
use rustc_errors::Applicability;
1872-
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
1872+
use rustc_hir::LangItem::{OptionNone, PollPending};
18731873
use rustc_hir::{
18741874
intravisit::{walk_expr, Visitor},
18751875
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
18761876
};
18771877
use rustc_lint::LateContext;
1878-
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
1878+
use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
18791879
use rustc_span::sym;
18801880

18811881
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -2051,28 +2051,31 @@ mod redundant_pattern_match {
20512051
has_else: bool,
20522052
) {
20532053
// also look inside refs
2054-
let mut kind = &let_pat.kind;
20552054
// if we have &None for example, peel it so we can detect "if let None = x"
2056-
if let PatKind::Ref(inner, _mutability) = kind {
2057-
kind = &inner.kind;
2058-
}
2055+
let check_pat = match let_pat.kind {
2056+
PatKind::Ref(inner, _mutability) => inner,
2057+
_ => let_pat,
2058+
};
20592059
let op_ty = cx.typeck_results().expr_ty(let_expr);
20602060
// Determine which function should be used, and the type contained by the corresponding
20612061
// variant.
2062-
let (good_method, inner_ty) = match kind {
2063-
PatKind::TupleStruct(ref path, [sub_pat], _) => {
2062+
let (good_method, inner_ty) = match check_pat.kind {
2063+
PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
20642064
if let PatKind::Wild = sub_pat.kind {
2065-
if is_lang_ctor(cx, path, ResultOk) {
2065+
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
2066+
let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
2067+
let lang_items = cx.tcx.lang_items();
2068+
if Some(id) == lang_items.result_ok_variant() {
20662069
("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
2067-
} else if is_lang_ctor(cx, path, ResultErr) {
2070+
} else if Some(id) == lang_items.result_err_variant() {
20682071
("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
2069-
} else if is_lang_ctor(cx, path, OptionSome) {
2072+
} else if Some(id) == lang_items.option_some_variant() {
20702073
("is_some()", op_ty)
2071-
} else if is_lang_ctor(cx, path, PollReady) {
2074+
} else if Some(id) == lang_items.poll_ready_variant() {
20722075
("is_ready()", op_ty)
2073-
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
2076+
} else if match_def_path(cx, id, &paths::IPADDR_V4) {
20742077
("is_ipv4()", op_ty)
2075-
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
2078+
} else if match_def_path(cx, id, &paths::IPADDR_V6) {
20762079
("is_ipv6()", op_ty)
20772080
} else {
20782081
return;
@@ -2272,17 +2275,22 @@ mod redundant_pattern_match {
22722275
should_be_left: &'a str,
22732276
should_be_right: &'a str,
22742277
) -> Option<&'a str> {
2275-
let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
2276-
&& is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
2277-
{
2278-
(&(*arms[0].body).kind, &(*arms[1].body).kind)
2279-
} else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
2280-
&& is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
2281-
{
2282-
(&(*arms[1].body).kind, &(*arms[0].body).kind)
2283-
} else {
2284-
return None;
2285-
};
2278+
let left_id = cx
2279+
.typeck_results()
2280+
.qpath_res(path_left, arms[0].pat.hir_id)
2281+
.opt_def_id()?;
2282+
let right_id = cx
2283+
.typeck_results()
2284+
.qpath_res(path_right, arms[1].pat.hir_id)
2285+
.opt_def_id()?;
2286+
let body_node_pair =
2287+
if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
2288+
(&(*arms[0].body).kind, &(*arms[1].body).kind)
2289+
} else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
2290+
(&(*arms[1].body).kind, &(*arms[0].body).kind)
2291+
} else {
2292+
return None;
2293+
};
22862294

22872295
match body_node_pair {
22882296
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {

clippy_lints/src/methods/chars_cmp.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet_with_applicability;
3-
use clippy_utils::{method_chain_args, single_segment_path};
3+
use clippy_utils::{method_chain_args, path_def_id};
44
use if_chain::if_chain;
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_lint::LateContext;
88
use rustc_lint::Lint;
9-
use rustc_middle::ty;
10-
use rustc_span::sym;
9+
use rustc_middle::ty::{self, DefIdTree};
1110

1211
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
1312
pub(super) fn check(
@@ -19,11 +18,9 @@ pub(super) fn check(
1918
) -> bool {
2019
if_chain! {
2120
if let Some(args) = method_chain_args(info.chain, chain_methods);
22-
if let hir::ExprKind::Call(fun, arg_char) = info.other.kind;
23-
if arg_char.len() == 1;
24-
if let hir::ExprKind::Path(ref qpath) = fun.kind;
25-
if let Some(segment) = single_segment_path(qpath);
26-
if segment.ident.name == sym::Some;
21+
if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
22+
if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
23+
if Some(id) == cx.tcx.lang_items().option_some_variant();
2724
then {
2825
let mut applicability = Applicability::MachineApplicable;
2926
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
@@ -42,7 +39,7 @@ pub(super) fn check(
4239
if info.eq { "" } else { "!" },
4340
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
4441
suggest,
45-
snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
42+
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
4643
applicability,
4744
);
4845

clippy_lints/src/methods/manual_saturating_arithmetic.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::is_qpath_def_path;
32
use clippy_utils::source::snippet_with_applicability;
3+
use clippy_utils::{match_def_path, path_def_id};
44
use if_chain::if_chain;
55
use rustc_ast::ast;
66
use rustc_errors::Applicability;
@@ -93,12 +93,12 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<M
9393
let ty_str = ty.to_string();
9494

9595
// `std::T::MAX` `std::T::MIN` constants
96-
if let hir::ExprKind::Path(path) = &expr.kind {
97-
if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MAX"][..]) {
96+
if let Some(id) = path_def_id(cx, expr) {
97+
if match_def_path(cx, id, &["core", &ty_str, "MAX"]) {
9898
return Some(MinMax::Max);
9999
}
100100

101-
if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MIN"][..]) {
101+
if match_def_path(cx, id, &["core", &ty_str, "MIN"]) {
102102
return Some(MinMax::Min);
103103
}
104104
}

clippy_lints/src/methods/option_map_or_none.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet;
33
use clippy_utils::ty::is_type_diagnostic_item;
4-
use clippy_utils::{is_lang_ctor, single_segment_path};
4+
use clippy_utils::{is_lang_ctor, path_def_id};
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_hir::LangItem::{OptionNone, OptionSome};
88
use rustc_lint::LateContext;
9+
use rustc_middle::ty::DefIdTree;
910
use rustc_span::symbol::sym;
1011

1112
use super::OPTION_MAP_OR_NONE;
@@ -76,13 +77,11 @@ pub(super) fn check<'tcx>(
7677
if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind;
7778
let arg_snippet = snippet(cx, span, "..");
7879
let body = cx.tcx.hir().body(id);
79-
if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value);
80-
if arg_char.len() == 1;
81-
if let hir::ExprKind::Path(ref qpath) = func.kind;
82-
if let Some(segment) = single_segment_path(qpath);
83-
if segment.ident.name == sym::Some;
80+
if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value);
81+
if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
82+
if Some(id) == cx.tcx.lang_items().option_some_variant();
8483
then {
85-
let func_snippet = snippet(cx, arg_char[0].span, "..");
84+
let func_snippet = snippet(cx, arg_char.span, "..");
8685
let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
8786
`map(..)` instead";
8887
return span_lint_and_sugg(

0 commit comments

Comments
 (0)