Skip to content

Commit

Permalink
Auto merge of #12972 - Jarcho:span_ex, r=Manishearth
Browse files Browse the repository at this point in the history
Add new span related utils

The none-generic versions of the functions exist to help with both compile times and codegen.

changelog: None
  • Loading branch information
bors committed Jun 21, 2024
2 parents 3e84ca8 + 4baae5d commit fe2fe7f
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 156 deletions.
22 changes: 8 additions & 14 deletions clippy_lints/src/cognitive_complexity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! calculate cognitive complexity and warn about overly complex functions
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
Expand All @@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, BytePos, Span};
use rustc_span::{sym, Span};

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -50,7 +50,6 @@ impl CognitiveComplexity {
impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);

impl CognitiveComplexity {
#[expect(clippy::cast_possible_truncation)]
fn check<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
Expand Down Expand Up @@ -100,17 +99,12 @@ impl CognitiveComplexity {
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
FnKind::Closure => {
let header_span = body_span.with_hi(decl.output.span().lo());
let pos = snippet_opt(cx, header_span).and_then(|snip| {
let low_offset = snip.find('|')?;
let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?;
let low = header_span.lo() + BytePos(low_offset as u32);
let high = low + BytePos(high_offset as u32 + 1);

Some((low, high))
});

if let Some((low, high)) = pos {
Span::new(low, high, header_span.ctxt(), header_span.parent())
#[expect(clippy::range_plus_one)]
if let Some(range) = header_span.map_range(cx, |src, range| {
let mut idxs = src.get(range.clone())?.match_indices('|');
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
}) {
range.with_ctxt(header_span.ctxt())
} else {
return;
}
Expand Down
16 changes: 8 additions & 8 deletions clippy_lints/src/copies.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt};
use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{
Expand All @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::hygiene::walk_chain;
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, Span, Symbol};
use rustc_span::{Span, Symbol};
use std::borrow::Cow;

declare_clippy_lint! {
Expand Down Expand Up @@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>(

let span = span.with_hi(last_block.span.hi());
// Improve formatting if the inner block has indention (i.e. normal Rust formatting)
let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent());
let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == " ") {
span.with_lo(test_span.lo())
} else {
span
};
let span = span
.map_range(cx, |src, range| {
(range.start > 4 && src.get(range.start - 4..range.start)? == " ")
.then_some(range.start - 4..range.end)
})
.map_or(span, |range| range.with_ctxt(span.ctxt()));
(span, suggestion.to_string())
});

Expand Down
40 changes: 17 additions & 23 deletions clippy_lints/src/implicit_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
use rustc_span::Span;

use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt};
use clippy_utils::ty::is_type_diagnostic_item;

declare_clippy_lint! {
Expand Down Expand Up @@ -59,10 +59,8 @@ declare_clippy_lint! {
declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);

impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
#[expect(clippy::cast_possible_truncation, clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
use rustc_span::BytePos;

fn suggestion(
cx: &LateContext<'_>,
diag: &mut Diag<'_, ()>,
Expand Down Expand Up @@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
}

let generics_suggestion_span = impl_.generics.span.substitute_dummy({
let pos = snippet_opt(cx, item.span.until(target.span()))
.and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
if let Some(pos) = pos {
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
Some(src.get(range.clone())?.find("impl")? + 4..range.end)
});
if let Some(range) = range {
range.with_ctxt(item.span.ctxt())
} else {
return;
}
Expand Down Expand Up @@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
continue;
}
let generics_suggestion_span = generics.span.substitute_dummy({
let pos = snippet_opt(
cx,
Span::new(
item.span.lo(),
body.params[0].pat.span.lo(),
item.span.ctxt(),
item.span.parent(),
),
)
.and_then(|snip| {
let i = snip.find("fn")?;
Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
})
.expect("failed to create span for type parameters");
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
let (pre, post) = src.get(range.clone())?.split_once("fn")?;
let pos = post.find('(')? + pre.len() + 2;
Some(pos..pos)
});
if let Some(range) = range {
range.with_ctxt(item.span.ctxt())
} else {
return;
}
});

let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/matches/single_match.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{expr_block, get_source_text, snippet};
use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
use core::cmp::max;
Expand All @@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
/// match arms.
fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
if let Some(ff) = get_source_text(cx, span)
if let Some(ff) = span.get_source_text(cx)
&& let Some(text) = ff.as_str()
{
text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")
Expand Down
31 changes: 18 additions & 13 deletions clippy_lints/src/methods/manual_inspect.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{get_source_text, with_leading_whitespace, SpanRange};
use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::get_field_by_name;
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode};
Expand All @@ -9,7 +9,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_span::{sym, BytePos, Span, Symbol, DUMMY_SP};
use rustc_span::{sym, Span, Symbol, DUMMY_SP};

use super::MANUAL_INSPECT;

Expand Down Expand Up @@ -98,17 +98,19 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
let mut addr_of_edits = Vec::with_capacity(delayed.len());
for x in delayed {
match x {
UseKind::Return(s) => edits.push((with_leading_whitespace(cx, s).set_span_pos(s), String::new())),
UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
UseKind::Borrowed(s) => {
if let Some(src) = get_source_text(cx, s)
&& let Some(src) = src.as_str()
&& let trim_src = src.trim_start_matches([' ', '\t', '\n', '\r', '('])
&& trim_src.starts_with('&')
{
let range = s.into_range();
#[expect(clippy::cast_possible_truncation)]
let start = BytePos(range.start.0 + (src.len() - trim_src.len()) as u32);
addr_of_edits.push(((start..BytePos(start.0 + 1)).set_span_pos(s), String::new()));
#[expect(clippy::range_plus_one)]
let range = s.map_range(cx, |src, range| {
let src = src.get(range.clone())?;
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
trimmed.starts_with('&').then(|| {
let pos = range.start + src.len() - trimmed.len();
pos..pos + 1
})
});
if let Some(range) = range {
addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
} else {
requires_copy = true;
requires_deref = true;
Expand Down Expand Up @@ -174,7 +176,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
}),
));
edits.push((
with_leading_whitespace(cx, final_expr.span).set_span_pos(final_expr.span),
final_expr
.span
.with_leading_whitespace(cx)
.with_ctxt(final_expr.span.ctxt()),
String::new(),
));
let app = if edits.iter().any(|(s, _)| s.from_expansion()) {
Expand Down
7 changes: 2 additions & 5 deletions clippy_lints/src/missing_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_from_proc_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
Expand Down Expand Up @@ -266,8 +266,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}

fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool {
let Some(snippet) = snippet_opt(cx, search_span) else {
return false;
};
snippet.lines().rev().any(|line| line.trim().starts_with("///"))
search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///")))
}
8 changes: 5 additions & 3 deletions clippy_lints/src/multiple_bound_locations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass;
use rustc_span::Span;

use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -54,8 +54,10 @@ impl EarlyLintPass for MultipleBoundLocations {
match clause {
WherePredicate::BoundPredicate(pred) => {
if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty())
&& let Some(name) = snippet_opt(cx, pred.bounded_ty.span)
&& let Some(bound_span) = generic_params_with_bounds.get(name.as_str())
&& let Some(Some(bound_span)) = pred
.bounded_ty
.span
.with_source_text(cx, |src| generic_params_with_bounds.get(src))
{
emit_lint(cx, *bound_span, pred.bounded_ty.span);
}
Expand Down
16 changes: 8 additions & 8 deletions clippy_lints/src/needless_else.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, trim_span};
use clippy_utils::source::{IntoSpan, SpanRangeExt};
use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
Expand Down Expand Up @@ -41,16 +41,16 @@ impl EarlyLintPass for NeedlessElse {
&& !expr.span.from_expansion()
&& !else_clause.span.from_expansion()
&& block.stmts.is_empty()
&& let Some(trimmed) = expr.span.trim_start(then_block.span)
&& let span = trim_span(cx.sess().source_map(), trimmed)
&& let Some(else_snippet) = snippet_opt(cx, span)
// Ignore else blocks that contain comments or #[cfg]s
&& !else_snippet.contains(['/', '#'])
&& let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx)
&& range.clone().check_source_text(cx, |src| {
// Ignore else blocks that contain comments or #[cfg]s
!src.contains(['/', '#'])
})
{
span_lint_and_sugg(
cx,
NEEDLESS_ELSE,
span,
range.with_ctxt(expr.span.ctxt()),
"this `else` branch is empty",
"you can remove it",
String::new(),
Expand Down
24 changes: 15 additions & 9 deletions clippy_lints/src/needless_if.rs
Original file line number Diff line number Diff line change
@@ -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;
use clippy_utils::source::{snippet_opt, SpanRangeExt};
use rustc_errors::Applicability;
use rustc_hir::{ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
Expand Down Expand Up @@ -39,18 +39,24 @@ declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]);
impl LateLintPass<'_> for NeedlessIf {
fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) {
if let StmtKind::Expr(expr) = stmt.kind
&& let Some(If {cond, then, r#else: None }) = If::hir(expr)
&& let Some(If {
cond,
then,
r#else: None,
}) = If::hir(expr)
&& let ExprKind::Block(block, ..) = then.kind
&& block.stmts.is_empty()
&& block.expr.is_none()
&& !in_external_macro(cx.sess(), expr.span)
&& let Some(then_snippet) = snippet_opt(cx, then.span)
// Ignore
// - empty macro expansions
// - empty reptitions in macro expansions
// - comments
// - #[cfg]'d out code
&& then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace())
&& then.span.check_source_text(cx, |src| {
// Ignore
// - empty macro expansions
// - empty reptitions in macro expansions
// - comments
// - #[cfg]'d out code
src.bytes()
.all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace())
})
&& let Some(cond_snippet) = snippet_opt(cx, cond.span)
&& !is_from_proc_macro(cx, expr)
{
Expand Down
12 changes: 7 additions & 5 deletions clippy_lints/src/non_octal_unix_permissions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::source::{snippet_with_applicability, SpanRangeExt};
use clippy_utils::{match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
Expand Down Expand Up @@ -53,8 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
&& cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
&& let ExprKind::Lit(_) = param.kind
&& param.span.eq_ctxt(expr.span)
&& let Some(snip) = snippet_opt(cx, param.span)
&& !(snip.starts_with("0o") || snip.starts_with("0b"))
&& param
.span
.check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..]))
{
show_error(cx, param);
}
Expand All @@ -65,8 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
&& match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE)
&& let ExprKind::Lit(_) = param.kind
&& param.span.eq_ctxt(expr.span)
&& let Some(snip) = snippet_opt(cx, param.span)
&& !(snip.starts_with("0o") || snip.starts_with("0b"))
&& param
.span
.check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..]))
{
show_error(cx, param);
}
Expand Down
Loading

0 comments on commit fe2fe7f

Please sign in to comment.