Skip to content

Commit b89b849

Browse files
committed
Rework clippy_utils::source.
1 parent 1d8598c commit b89b849

18 files changed

+805
-349
lines changed

clippy_lints/src/cognitive_complexity.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::span_lint_and_help;
3-
use clippy_utils::source::{IntoSpan, SpanExt};
3+
use clippy_utils::source::SpanExt;
44
use clippy_utils::ty::is_type_diagnostic_item;
55
use clippy_utils::visitors::for_each_expr_without_closures;
66
use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym};
@@ -110,14 +110,15 @@ impl CognitiveComplexity {
110110
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
111111
FnKind::Closure => {
112112
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 {
113+
let Some(s) = header_span.map_range(cx, |range| {
114+
range.edit_range(|src, range| {
115+
let mut idxs = src.get(range.clone())?.match_indices('|');
116+
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
117+
})
118+
}) else {
119119
return;
120-
}
120+
};
121+
s
121122
},
122123
};
123124

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_and_then;
33
use clippy_utils::msrvs::{self, 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::{span_contains_non_whitespace, tokenize_with_text};
66
use rustc_ast::BinOpKind;
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()),
@@ -171,20 +171,19 @@ impl CollapsibleIf {
171171
&& self.eligible_condition(cx, check_inner)
172172
&& expr.span.eq_ctxt(inner.span)
173173
&& !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code)
174+
&& let Some(then_open_bracket) = then
175+
.span
176+
.map_range(cx, |range| range.set_to_prefix('{')?.add_leading_whitespace())
177+
&& let Some(then_closing_bracket) = then
178+
.span
179+
.map_range(cx, |range| range.set_to_suffix('}')?.add_leading_whitespace())
174180
{
175181
span_lint_and_then(
176182
cx,
177183
COLLAPSIBLE_IF,
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/copies.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, span_lint_and_note, span_lint_and_then};
33
use clippy_utils::higher::has_let_expr;
4-
use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet};
4+
use clippy_utils::source::{SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet};
55
use clippy_utils::ty::{InteriorMut, needs_ordered_drop};
66
use clippy_utils::visitors::for_each_expr_without_closures;
77
use clippy_utils::{
@@ -239,21 +239,23 @@ fn lint_branches_sharing_code<'tcx>(
239239
let suggestion = reindent_multiline(&suggestion, true, cond_indent);
240240
(replace_span, suggestion)
241241
});
242-
let end_suggestion = res.end_span(last_block, sm).map(|span| {
242+
let end_suggestion = res.end_span(last_block, sm).and_then(|span| {
243243
let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None);
244244
let indent = indent_of(cx, expr.span.shrink_to_hi());
245245
let suggestion = "}\n".to_string() + &moved_snipped;
246246
let suggestion = reindent_multiline(&suggestion, true, indent);
247247

248-
let span = span.with_hi(last_block.span.hi());
249248
// Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
250-
let span = span
251-
.map_range(cx, |_, src, range| {
252-
(range.start > 4 && src.get(range.start - 4..range.start)? == " ")
253-
.then_some(range.start - 4..range.end)
249+
let span = span.map_range(cx, |range| {
250+
range.set_end_if_after(last_block.span.hi())?.edit_range(|src, range| {
251+
if src.get(..range.start)?.ends_with(" ") {
252+
Some(range.start - 4..range.end)
253+
} else {
254+
Some(range)
255+
}
254256
})
255-
.map_or(span, |range| range.with_ctxt(span.ctxt()));
256-
(span, suggestion.clone())
257+
})?;
258+
Some((span, suggestion))
257259
});
258260

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

clippy_lints/src/default_constructed_unit_structs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
7575
&& !base.is_suggestable_infer_ty()
7676
{
7777
let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())];
78-
if expr.span.with_source_text(cx, |s| s.starts_with('<')) == Some(true) {
78+
if expr.span.check_source_text(cx, |s| s.starts_with('<')) {
7979
// Remove `<`, '>` has already been removed by the existing removal expression.
8080
removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new()));
8181
}

clippy_lints/src/implicit_hasher.rs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_session::declare_lint_pass;
1212
use rustc_span::Span;
1313

1414
use clippy_utils::diagnostics::span_lint_and_then;
15-
use clippy_utils::source::{IntoSpan, SpanExt, snippet};
15+
use clippy_utils::source::{SpanExt, snippet};
1616
use clippy_utils::sym;
1717
use clippy_utils::ty::is_type_diagnostic_item;
1818

@@ -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
@@ -64,15 +64,15 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
6464
match name.ident.name {
6565
sym::append => append = true,
6666
sym::write
67-
if let Some(range) = call_span.map_range(cx, |_, text, range| {
68-
if text.get(..range.start)?.ends_with('.') {
69-
Some(range.start - 1..range.end)
70-
} else {
71-
None
72-
}
67+
if let Some(call_span) = call_span.map_range(cx, |range| {
68+
range.add_leading_whitespace()?.edit_range(|text, range| {
69+
text.get(..range.start)?
70+
.ends_with('.')
71+
.then_some(range.start.wrapping_sub(1)..range.end)
72+
})
7373
}) =>
7474
{
75-
write = Some(call_span.with_lo(range.start));
75+
write = Some(call_span);
7676
},
7777
_ => {},
7878
}

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/matches/single_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
2323
/// match arms.
2424
fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
2525
if let Some(ff) = span.get_source_range(cx)
26-
&& let Some(text) = ff.as_str()
26+
&& let Some(text) = ff.current_text()
2727
{
2828
text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")
2929
} else {

clippy_lints/src/methods/manual_inspect.rs

Lines changed: 22 additions & 21 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::msrvs::{self, Msrv};
3-
use clippy_utils::source::{IntoSpan, SpanExt};
3+
use clippy_utils::source::{SourceFileRange, SpanExt};
44
use clippy_utils::ty::get_field_by_name;
55
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
66
use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym};
@@ -89,7 +89,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
8989
})
9090
.is_none();
9191

92-
if ret_count != 0 {
92+
if !can_lint || ret_count != 0 {
9393
// A return expression that didn't return the original value was found.
9494
return;
9595
}
@@ -98,18 +98,25 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
9898
let mut addr_of_edits = Vec::with_capacity(delayed.len());
9999
for x in delayed {
100100
match x {
101-
UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
101+
UseKind::Return(s) => {
102+
if let Some(s) = s.map_range(cx, SourceFileRange::add_leading_whitespace) {
103+
edits.push((s, String::new()));
104+
} else {
105+
return;
106+
}
107+
},
102108
UseKind::Borrowed(s) => {
103-
let range = s.map_range(cx, |_, src, range| {
104-
let src = src.get(range.clone())?;
105-
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
106-
trimmed.starts_with('&').then(|| {
107-
let pos = range.start + src.len() - trimmed.len();
108-
pos..pos + 1
109+
if let Some(s) = s.map_range(cx, |range| {
110+
range.edit_range(|src, range| {
111+
let src = src.get(range.clone())?;
112+
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
113+
trimmed.starts_with('&').then(|| {
114+
let pos = range.start + src.len() - trimmed.len();
115+
pos..pos + 1
116+
})
109117
})
110-
});
111-
if let Some(range) = range {
112-
addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
118+
}) {
119+
addr_of_edits.push((s, String::new()));
113120
} else {
114121
requires_copy = true;
115122
requires_deref = true;
@@ -156,10 +163,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
156163
}
157164
}
158165

159-
if can_lint
160-
&& (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty))
166+
if (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty))
161167
// This case could be handled, but a fair bit of care would need to be taken.
162168
&& (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env()))
169+
&& let Some(final_expr_span) = final_expr.span.map_range(cx, SourceFileRange::add_leading_whitespace)
163170
{
164171
if requires_deref {
165172
edits.push((param.span.shrink_to_lo(), "&".into()));
@@ -172,13 +179,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
172179
_ => return,
173180
};
174181
edits.push((name_span, edit.to_string()));
175-
edits.push((
176-
final_expr
177-
.span
178-
.with_leading_whitespace(cx)
179-
.with_ctxt(final_expr.span.ctxt()),
180-
String::new(),
181-
));
182+
edits.push((final_expr_span, String::new()));
182183
let app = if edits.iter().any(|(s, _)| s.from_expansion()) {
183184
Applicability::MaybeIncorrect
184185
} 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)