Skip to content

Commit 3f4330b

Browse files
committed
Rework clippy_utils::source.
1 parent 94aaebe commit 3f4330b

21 files changed

+1143
-412
lines changed

clippy_lints/src/cognitive_complexity.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_help;
33
use clippy_utils::res::MaybeDef;
4-
use clippy_utils::source::{IntoSpan, SpanExt};
4+
use clippy_utils::source::{SpanExt, StrExt};
55
use clippy_utils::visitors::for_each_expr_without_closures;
66
use clippy_utils::{LimitStack, get_async_fn_body, sym};
77
use core::ops::ControlFlow;
@@ -109,12 +109,11 @@ impl CognitiveComplexity {
109109
let fn_span = match kind {
110110
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
111111
FnKind::Closure => {
112-
let header_span = body_span.with_hi(decl.output.span().lo());
113-
if let Some(range) = header_span.map_range(cx, |_, src, range| {
114-
let mut idxs = src.get(range.clone())?.match_indices('|');
115-
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
112+
if let Some(sp) = body_span.map_range(cx, |scx, range| {
113+
scx.shrink_end_to(range, decl.output.span().lo())
114+
.and_then(|range| scx.map_range_text(range, |src| src.find_bounded_inclusive('|')))
116115
}) {
117-
range.with_ctxt(header_span.ctxt())
116+
sp
118117
} else {
119118
return;
120119
}

clippy_lints/src/collapsible_if.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_hir_and_then;
33
use clippy_utils::msrvs::Msrv;
4-
use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability};
4+
use clippy_utils::source::{SpanEditCx, SpanExt, StrExt, snippet, snippet_block_with_applicability};
55
use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text};
66
use rustc_ast::{BinOpKind, MetaItemInner};
77
use rustc_errors::Applicability;
@@ -113,15 +113,16 @@ impl CollapsibleIf {
113113
span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else")
114114
&& let Some(else_if_keyword_span) =
115115
span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if")
116+
&& let Some(else_keyword_span) =
117+
else_keyword_span.map_range(cx, SpanEditCx::with_leading_whitespace)
118+
&& let Some([else_open_bracket, else_closing_bracket]) =
119+
else_block.span.map_range(cx, |scx, range| {
120+
let [open, close] = scx.map_range_text(range, |src| src.get_prefix_suffix('{', '}'))?;
121+
let open = scx.with_leading_whitespace(open)?;
122+
let close = scx.with_leading_whitespace(close)?;
123+
Some([open, close])
124+
})
116125
{
117-
let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span();
118-
let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span();
119-
let else_closing_bracket = {
120-
let end = else_block.span.shrink_to_hi();
121-
end.with_lo(end.lo() - BytePos(1))
122-
.with_leading_whitespace(cx)
123-
.into_span()
124-
};
125126
let sugg = vec![
126127
// Remove the outer else block `else`
127128
(else_keyword_span, String::new()),
@@ -170,6 +171,12 @@ impl CollapsibleIf {
170171
&& self.eligible_condition(cx, check_inner)
171172
&& expr.span.eq_ctxt(inner.span)
172173
&& self.check_significant_tokens_and_expect_attrs(cx, then, inner, sym::collapsible_if)
174+
&& let Some([then_open_bracket, then_closing_bracket]) = then.span.map_range(cx, |scx, range| {
175+
let [open, close] = scx.map_range_text(range, |src| src.get_prefix_suffix('{', '}'))?;
176+
let open = scx.with_leading_whitespace(open)?;
177+
let close = scx.with_leading_whitespace(close)?;
178+
Some([open, close])
179+
})
173180
{
174181
span_lint_hir_and_then(
175182
cx,
@@ -178,13 +185,6 @@ impl CollapsibleIf {
178185
expr.span,
179186
"this `if` statement can be collapsed",
180187
|diag| {
181-
let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
182-
let then_closing_bracket = {
183-
let end = then.span.shrink_to_hi();
184-
end.with_lo(end.lo() - BytePos(1))
185-
.with_leading_whitespace(cx)
186-
.into_span()
187-
};
188188
let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span);
189189
let inner_if = inner_if_span.split_at(2).0;
190190
let mut sugg = vec![

clippy_lints/src/double_parens.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,11 @@ impl EarlyLintPass for DoubleParens {
104104

105105
/// Check that the span does indeed look like `( (..) )`
106106
fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool {
107-
if let Some(sfr) = inner.span.get_source_range(cx)
108-
// this is the same as `SourceFileRange::as_str`, but doesn't apply the range right away, because
109-
// we're interested in the source code outside it
110-
&& let Some(src) = sfr.sf.src.as_ref().map(|src| src.as_str())
111-
&& let Some((start, outer_after_inner)) = src.split_at_checked(sfr.range.end)
112-
&& let Some((outer_before_inner, inner)) = start.split_at_checked(sfr.range.start)
113-
&& outer_before_inner.trim_end().ends_with('(')
114-
&& inner.starts_with('(')
115-
&& inner.ends_with(')')
116-
&& outer_after_inner.trim_start().starts_with(')')
107+
if let Some((scx, range)) = inner.span.mk_edit_cx(cx)
108+
&& let Some(range) = scx.with_trailing_whitespace(range)
109+
&& let Some(range) = scx.with_leading_whitespace(range)
110+
&& let Some(range) = scx.with_trailing_match(range, ')')
111+
&& scx.with_leading_match(range, '(').is_some()
117112
{
118113
true
119114
} else {

clippy_lints/src/ifs/branches_sharing_code.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::res::MaybeResPath;
3-
use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet};
3+
use clippy_utils::source::{SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet};
44
use clippy_utils::ty::needs_ordered_drop;
55
use clippy_utils::visitors::for_each_expr_without_closures;
66
use clippy_utils::{
@@ -44,21 +44,18 @@ pub(super) fn check<'tcx>(
4444
let suggestion = reindent_multiline(&suggestion, true, cond_indent);
4545
(replace_span, suggestion)
4646
});
47-
let end_suggestion = res.end_span(last_block, sm).map(|span| {
47+
let end_suggestion = res.end_span(last_block, sm).and_then(|span| {
4848
let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None);
4949
let indent = indent_of(cx, expr.span.shrink_to_hi());
5050
let suggestion = "}\n".to_string() + &moved_snipped;
5151
let suggestion = reindent_multiline(&suggestion, true, indent);
5252

53-
let span = span.with_hi(last_block.span.hi());
54-
// Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
55-
let span = span
56-
.map_range(cx, |_, src, range| {
57-
(range.start > 4 && src.get(range.start - 4..range.start)? == " ")
58-
.then_some(range.start - 4..range.end)
59-
})
60-
.map_or(span, |range| range.with_ctxt(span.ctxt()));
61-
(span, suggestion.clone())
53+
span.map_range(cx, |scx, range| {
54+
let range = scx.extend_end_to(range, last_block.span.hi())?;
55+
// Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
56+
Some(scx.with_leading_match(range.clone(), " ").unwrap_or(range))
57+
})
58+
.map(|sp| (sp, suggestion))
6259
});
6360

6461
let (span, msg, end_span) = match (&start_suggestion, &end_suggestion) {

clippy_lints/src/implicit_hasher.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass;
1313
use rustc_span::Span;
1414

1515
use clippy_utils::diagnostics::span_lint_and_then;
16-
use clippy_utils::source::{IntoSpan, SpanExt, snippet};
16+
use clippy_utils::source::{SpanExt, snippet};
1717
use clippy_utils::sym;
1818

1919
declare_clippy_lint! {
@@ -118,16 +118,19 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
118118
return;
119119
}
120120

121-
let generics_suggestion_span = impl_.generics.span.substitute_dummy({
122-
let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| {
123-
Some(src.get(range.clone())?.find("impl")? + 4..range.end)
124-
});
125-
if let Some(range) = range {
126-
range.with_ctxt(item.span.ctxt())
121+
let generics_suggestion_span = if impl_.generics.span.is_dummy() {
122+
if let Some(sp) = item.span.map_range(cx, |scx, range| {
123+
scx.shrink_end_to(range, target.span().lo()).and_then(|range| {
124+
scx.map_range_text(range, |src| src.split_once("impl").map(|(_, x)| x))
125+
})
126+
}) {
127+
sp
127128
} else {
128129
return;
129130
}
130-
});
131+
} else {
132+
impl_.generics.span
133+
};
131134

132135
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
133136
for item in impl_.items.iter().map(|&item| cx.tcx.hir_impl_item(item)) {
@@ -164,19 +167,25 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
164167
if generics.span.from_expansion() {
165168
continue;
166169
}
167-
let generics_suggestion_span = generics.span.substitute_dummy({
168-
let range =
169-
(item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| {
170-
let (pre, post) = src.get(range.clone())?.split_once("fn")?;
171-
let pos = post.find('(')? + pre.len() + 2;
172-
Some(pos..pos)
173-
});
174-
if let Some(range) = range {
175-
range.with_ctxt(item.span.ctxt())
170+
171+
let generics_suggestion_span = if generics.span.is_dummy() {
172+
if let Some(sp) = item.span.map_range(cx, |scx, range| {
173+
scx.shrink_end_to(range, body.params[0].pat.span.lo())
174+
.and_then(|range| {
175+
scx.map_range_text(range, |src| {
176+
src.split_once("fn")
177+
.and_then(|(_, x)| x.split_once('('))
178+
.map(|(_, x)| x)
179+
})
180+
})
181+
}) {
182+
sp
176183
} else {
177184
return;
178185
}
179-
});
186+
} else {
187+
generics.span
188+
};
180189

181190
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
182191
ctr_vis.visit_body(body);

clippy_lints/src/ineffective_open_options.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,10 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
6868
match name.ident.name {
6969
sym::append => append = true,
7070
sym::write
71-
if let Some(range) = call_span.map_range(cx, |_, text, range| {
72-
if text.get(..range.start)?.ends_with('.') {
73-
Some(range.start - 1..range.end)
74-
} else {
75-
None
76-
}
77-
}) =>
71+
if let Some(sp) =
72+
call_span.map_range(cx, |scx, range| scx.with_leading_match(range, '.')) =>
7873
{
79-
write = Some(call_span.with_lo(range.start));
74+
write = Some(sp);
8075
},
8176
_ => {},
8277
}

clippy_lints/src/let_with_type_underscore.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::is_from_proc_macro;
3-
use clippy_utils::source::{IntoSpan, SpanExt};
3+
use clippy_utils::source::SpanExt;
44
use rustc_ast::{Local, TyKind};
55
use rustc_errors::Applicability;
66
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -34,12 +34,12 @@ impl EarlyLintPass for UnderscoreTyped {
3434
&& let sm = cx.sess().source_map()
3535
&& !local.span.in_external_macro(sm)
3636
&& !is_from_proc_macro(cx, &**ty)
37+
&& let Some(span_to_remove) = ty.span.map_range(cx, |scx, range| {
38+
scx.with_leading_whitespace(range)
39+
.and_then(|range| scx.with_leading_match(range, ':'))
40+
.and_then(|range| scx.with_leading_whitespace(range))
41+
})
3742
{
38-
let span_to_remove = sm
39-
.span_extend_to_prev_char_before(ty.span, ':', true)
40-
.with_leading_whitespace(cx)
41-
.into_span();
42-
4343
span_lint_and_then(
4444
cx,
4545
LET_WITH_TYPE_UNDERSCORE,

clippy_lints/src/lib.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
#![feature(array_windows)]
2-
#![feature(box_patterns)]
3-
#![feature(macro_metavar_expr_concat)]
4-
#![feature(f128)]
5-
#![feature(f16)]
6-
#![feature(if_let_guard)]
7-
#![feature(iter_intersperse)]
8-
#![feature(iter_partition_in_place)]
9-
#![feature(never_type)]
10-
#![feature(rustc_private)]
11-
#![feature(stmt_expr_attributes)]
12-
#![feature(unwrap_infallible)]
1+
#![feature(
2+
array_windows,
3+
box_patterns,
4+
f128,
5+
f16,
6+
if_let_guard,
7+
iter_intersperse,
8+
iter_partition_in_place,
9+
macro_metavar_expr_concat,
10+
never_type,
11+
rustc_private,
12+
stmt_expr_attributes,
13+
str_split_remainder,
14+
unwrap_infallible
15+
)]
1316
#![recursion_limit = "512"]
1417
#![allow(
1518
clippy::missing_docs_in_private_items,

clippy_lints/src/loops/unused_enumerate_index.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,8 @@ pub(super) fn check<'tcx>(
2626
&& !pat.span.from_expansion()
2727
&& !idx_pat.span.from_expansion()
2828
&& !inner_pat.span.from_expansion()
29-
&& let Some(enumerate_range) = enumerate_span.map_range(cx, |_, text, range| {
30-
text.get(..range.start)?
31-
.ends_with('.')
32-
.then_some(range.start - 1..range.end)
33-
})
29+
&& let Some(enumerate_span) = enumerate_span.map_range(cx, |scx, range| scx.with_leading_match(range, '.'))
3430
{
35-
let enumerate_span = Span::new(enumerate_range.start, enumerate_range.end, SyntaxContext::root(), None);
3631
span_lint_hir_and_then(
3732
cx,
3833
UNUSED_ENUMERATE_INDEX,

clippy_lints/src/methods/manual_inspect.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::msrvs::{self, Msrv};
33
use clippy_utils::res::{MaybeDef, MaybeResPath};
4-
use clippy_utils::source::{IntoSpan, SpanExt};
4+
use clippy_utils::source::{SpanEditCx, SpanExt, StrExt};
55
use clippy_utils::ty::get_field_by_name;
66
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
77
use clippy_utils::{ExprUseNode, expr_use_ctxt, sym};
@@ -100,18 +100,22 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
100100
let mut addr_of_edits = Vec::with_capacity(delayed.len());
101101
for x in delayed {
102102
match x {
103-
UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
103+
UseKind::Return(s) => {
104+
if let Some(sp) = s.map_range(cx, SpanEditCx::with_leading_whitespace) {
105+
edits.push((sp, String::new()));
106+
} else {
107+
return;
108+
}
109+
},
104110
UseKind::Borrowed(s) => {
105-
let range = s.map_range(cx, |_, src, range| {
106-
let src = src.get(range.clone())?;
107-
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
108-
trimmed.starts_with('&').then(|| {
109-
let pos = range.start + src.len() - trimmed.len();
110-
pos..pos + 1
111+
if let Some(sp) = s.map_range(cx, |scx, range| {
112+
scx.map_range_text(range, |src| {
113+
src.trim_start_matches([' ', '\t', '\n', '\r', '('])
114+
.split_prefix('&')
115+
.map(|[x, _]| x)
111116
})
112-
});
113-
if let Some(range) = range {
114-
addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
117+
}) {
118+
addr_of_edits.push((sp, String::new()));
115119
} else {
116120
requires_copy = true;
117121
requires_deref = true;
@@ -162,6 +166,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
162166
&& (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty))
163167
// This case could be handled, but a fair bit of care would need to be taken.
164168
&& (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env()))
169+
&& let Some(final_expr_span) = final_expr
170+
.span
171+
.map_range(cx, SpanEditCx::with_leading_whitespace)
165172
{
166173
if requires_deref {
167174
edits.push((param.span.shrink_to_lo(), "&".into()));
@@ -174,13 +181,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
174181
_ => return,
175182
};
176183
edits.push((name_span, edit.to_string()));
177-
edits.push((
178-
final_expr
179-
.span
180-
.with_leading_whitespace(cx)
181-
.with_ctxt(final_expr.span.ctxt()),
182-
String::new(),
183-
));
184+
edits.push((final_expr_span, String::new()));
184185
let app = if edits.iter().any(|(s, _)| s.from_expansion()) {
185186
Applicability::MaybeIncorrect
186187
} else {

0 commit comments

Comments
 (0)