Skip to content

Commit 8e690e3

Browse files
committed
Rework clippy_utils::source.
1 parent 24c92cf commit 8e690e3

20 files changed

+972
-388
lines changed

clippy_lints/src/cognitive_complexity.rs

Lines changed: 11 additions & 9 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;
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,15 +109,17 @@ 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)
116-
}) {
117-
range.with_ctxt(header_span.ctxt())
118-
} else {
112+
let Some(s) = body_span.map_range(cx, |range| {
113+
range
114+
.set_end_if_within(decl.output.span().lo())?
115+
.edit_range(|src, range| {
116+
let mut idxs = src.get(range.clone())?.match_indices('|');
117+
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
118+
})
119+
}) else {
119120
return;
120-
}
121+
};
122+
s
121123
},
122124
};
123125

clippy_lints/src/collapsible_if.rs

Lines changed: 15 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::{SourceFileRange, SpanExt, 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,15 @@ 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, SourceFileRange::add_leading_whitespace)
118+
&& let Some(else_open_bracket) = else_block
119+
.span
120+
.map_range(cx, |range| range.set_to_prefix('{')?.add_leading_whitespace())
121+
&& let Some(else_closing_bracket) = else_block
122+
.span
123+
.map_range(cx, |range| range.set_to_suffix('}')?.add_leading_whitespace())
116124
{
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-
};
125125
let sugg = vec![
126126
// Remove the outer else block `else`
127127
(else_keyword_span, String::new()),
@@ -170,6 +170,12 @@ impl CollapsibleIf {
170170
&& self.eligible_condition(cx, check_inner)
171171
&& expr.span.eq_ctxt(inner.span)
172172
&& self.check_significant_tokens_and_expect_attrs(cx, then, inner, sym::collapsible_if)
173+
&& let Some(then_open_bracket) = then
174+
.span
175+
.map_range(cx, |range| range.set_to_prefix('{')?.add_leading_whitespace())
176+
&& let Some(then_closing_bracket) = then
177+
.span
178+
.map_range(cx, |range| range.set_to_suffix('}')?.add_leading_whitespace())
173179
{
174180
span_lint_hir_and_then(
175181
cx,
@@ -178,13 +184,6 @@ impl CollapsibleIf {
178184
expr.span,
179185
"this `if` statement can be collapsed",
180186
|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-
};
188187
let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span);
189188
let inner_if = inner_if_span.split_at(2).0;
190189
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(mut src) = inner.span.get_source_range(cx)
108+
&& let Some(src) = src.add_trailing_whitespace()
109+
&& let Some(src) = src.add_leading_whitespace()
110+
&& let Some(src) = src.add_leading_match('(')
111+
&& src.add_trailing_match(')').is_some()
117112
{
118113
true
119114
} else {

clippy_lints/src/ifs/branches_sharing_code.rs

Lines changed: 11 additions & 9 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,23 @@ 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());
5453
// 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)
54+
let span = span.map_range(cx, |range| {
55+
range.set_end_if_after(last_block.span.hi())?.edit_range(|src, range| {
56+
if src.get(..range.start)?.ends_with(" ") {
57+
Some(range.start - 4..range.end)
58+
} else {
59+
Some(range)
60+
}
5961
})
60-
.map_or(span, |range| range.with_ctxt(span.ctxt()));
61-
(span, suggestion.clone())
62+
})?;
63+
Some((span, suggestion))
6264
});
6365

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

clippy_lints/src/implicit_hasher.rs

Lines changed: 16 additions & 22 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! {
@@ -117,17 +117,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
117117
if !item.span.eq_ctxt(target.span()) {
118118
return;
119119
}
120-
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())
127-
} else {
128-
return;
129-
}
130-
});
120+
let Some(generics_span) = item.span.map_range(cx, |file| {
121+
file.set_end_if_within(target.span().lo())?
122+
.edit_range(|src, range| Some(src.get(range.clone())?.find("impl")? + 4..range.end))
123+
}) else {
124+
return;
125+
};
126+
let generics_suggestion_span = impl_.generics.span.substitute_dummy(generics_span);
131127

132128
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
133129
for item in impl_.items.iter().map(|&item| cx.tcx.hir_impl_item(item)) {
@@ -164,19 +160,17 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
164160
if generics.span.from_expansion() {
165161
continue;
166162
}
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| {
163+
let Some(generics_span) = item.span.map_range(cx, |file| {
164+
file.set_end_if_within(body.params[0].pat.span.lo())?
165+
.edit_range(|src, range| {
170166
let (pre, post) = src.get(range.clone())?.split_once("fn")?;
171167
let pos = post.find('(')? + pre.len() + 2;
172168
Some(pos..pos)
173-
});
174-
if let Some(range) = range {
175-
range.with_ctxt(item.span.ctxt())
176-
} else {
177-
return;
178-
}
179-
});
169+
})
170+
}) else {
171+
return;
172+
};
173+
let generics_suggestion_span = generics.span.substitute_dummy(generics_span);
180174

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

clippy_lints/src/ineffective_open_options.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,15 @@ 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-
}
71+
if let Some(call_span) = call_span.map_range(cx, |range| {
72+
range.add_leading_whitespace()?.edit_range(|text, range| {
73+
text.get(..range.start)?
74+
.ends_with('.')
75+
.then_some(range.start.wrapping_sub(1)..range.end)
76+
})
7777
}) =>
7878
{
79-
write = Some(call_span.with_lo(range.start));
79+
write = Some(call_span);
8080
},
8181
_ => {},
8282
}

clippy_lints/src/let_with_type_underscore.rs

Lines changed: 7 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,13 @@ 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) =
38+
ty.span.map_range(sm, |src| {
39+
src.add_leading_whitespace()?
40+
.add_leading_match(':')?
41+
.add_leading_whitespace()
42+
})
3743
{
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-
4344
span_lint_and_then(
4445
cx,
4546
LET_WITH_TYPE_UNDERSCORE,

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, |src| src.add_leading_match('.'))
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: 22 additions & 21 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::{SourceFileRange, SpanExt};
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};
@@ -91,7 +91,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
9191
})
9292
.is_none();
9393

94-
if ret_count != 0 {
94+
if !can_lint || ret_count != 0 {
9595
// A return expression that didn't return the original value was found.
9696
return;
9797
}
@@ -100,18 +100,25 @@ 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(s) = s.map_range(cx, SourceFileRange::add_leading_whitespace) {
105+
edits.push((s, 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(s) = s.map_range(cx, |range| {
112+
range.edit_range(|src, range| {
113+
let src = src.get(range.clone())?;
114+
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
115+
trimmed.starts_with('&').then(|| {
116+
let pos = range.start + src.len() - trimmed.len();
117+
pos..pos + 1
118+
})
111119
})
112-
});
113-
if let Some(range) = range {
114-
addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
120+
}) {
121+
addr_of_edits.push((s, String::new()));
115122
} else {
116123
requires_copy = true;
117124
requires_deref = true;
@@ -158,10 +165,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
158165
}
159166
}
160167

161-
if can_lint
162-
&& (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty))
168+
if (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty))
163169
// This case could be handled, but a fair bit of care would need to be taken.
164170
&& (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env()))
171+
&& let Some(final_expr_span) = final_expr.span.map_range(cx, SourceFileRange::add_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 {

clippy_lints/src/multiple_bound_locations.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ impl EarlyLintPass for MultipleBoundLocations {
5757
&& let Some(Some(bound_span)) = pred
5858
.bounded_ty
5959
.span
60-
.with_source_text(cx, |src| generic_params_with_bounds.get(src))
60+
.get_source_text(cx)
61+
.map(|src| generic_params_with_bounds.get(&*src))
6162
{
6263
emit_lint(cx, *bound_span, pred.bounded_ty.span);
6364
}

0 commit comments

Comments
 (0)