use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LintContext};
+use rustc_session::Session;
use rustc_span::hygiene;
use rustc_span::source_map::{original_sp, SourceMap};
use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
span: Span,
default: &'a str,
applicability: &mut Applicability,
+) -> Cow<'a, str> {
+ snippet_with_applicability_sess(cx.sess(), span, default, applicability)
+}
+
+fn snippet_with_applicability_sess<'a>(
+ sess: &Session,
+ span: Span,
+ default: &'a str,
+ applicability: &mut Applicability,
) -> Cow<'a, str> {
if *applicability != Applicability::Unspecified && span.from_expansion() {
*applicability = Applicability::MaybeIncorrect;
}
- snippet_opt(cx, span).map_or_else(
+ snippet_opt_sess(sess, span).map_or_else(
|| {
if *applicability == Applicability::MachineApplicable {
*applicability = Applicability::HasPlaceholders;
}
/// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
- cx.sess().source_map().span_to_snippet(span).ok()
+pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
+ snippet_opt_sess(cx.sess(), span)
+}
+
+fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
+ sess.source_map().span_to_snippet(span).ok()
}
/// Converts a span (from a block) to a code snippet if available, otherwise use default.
/// Same as `snippet_block`, but adapts the applicability level by the rules of
/// `snippet_with_applicability`.
-pub fn snippet_block_with_applicability<'a, T: LintContext>(
- cx: &T,
+pub fn snippet_block_with_applicability<'a>(
+ cx: &impl LintContext,
span: Span,
default: &'a str,
indent_relative_to: Option<Span>,
///
/// This will also return whether or not the snippet is a macro call.
pub fn snippet_with_context<'a>(
- cx: &LateContext<'_>,
+ cx: &impl LintContext,
+ span: Span,
+ outer: SyntaxContext,
+ default: &'a str,
+ applicability: &mut Applicability,
+) -> (Cow<'a, str>, bool) {
+ snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
+}
+
+fn snippet_with_context_sess<'a>(
+ sess: &Session,
span: Span,
outer: SyntaxContext,
default: &'a str,
);
(
- snippet_with_applicability(cx, span, default, applicability),
+ snippet_with_applicability_sess(sess, span, default, applicability),
is_macro_call,
)
}
}
/// Prepare a suggestion from an expression.
- pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
+ pub fn ast(
+ cx: &EarlyContext<'_>,
+ expr: &ast::Expr,
+ default: &'a str,
+ ctxt: SyntaxContext,
+ app: &mut Applicability,
+ ) -> Self {
use rustc_ast::ast::RangeLimits;
- let snippet_without_expansion = |cx, span: Span, default| {
- if span.from_expansion() {
- snippet_with_macro_callsite(cx, span, default)
- } else {
- snippet(cx, span, default)
- }
- };
-
+ #[expect(clippy::match_wildcard_for_single_variants)]
match expr.kind {
+ _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::AddrOf(..)
| ast::ExprKind::Box(..)
| ast::ExprKind::Closure { .. }
| ast::ExprKind::If(..)
| ast::ExprKind::Let(..)
| ast::ExprKind::Unary(..)
- | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)),
+ | ast::ExprKind::Match(..) => match snippet_with_context(cx, expr.span, ctxt, default, app) {
+ (snip, false) => Sugg::MaybeParen(snip),
+ (snip, true) => Sugg::NonParen(snip),
+ },
ast::ExprKind::Async(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::Break(..)
| ast::ExprKind::Array(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Await(..)
- | ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)),
+ | ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
AssocOp::DotDot,
- lhs.as_ref()
- .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
- rhs.as_ref()
- .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
+ lhs.as_ref().map_or("".into(), |lhs| {
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0
+ }),
+ rhs.as_ref().map_or("".into(), |rhs| {
+ snippet_with_context(cx, rhs.span, ctxt, default, app).0
+ }),
),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
AssocOp::DotDotEq,
- lhs.as_ref()
- .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
- rhs.as_ref()
- .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
+ lhs.as_ref().map_or("".into(), |lhs| {
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0
+ }),
+ rhs.as_ref().map_or("".into(), |rhs| {
+ snippet_with_context(cx, rhs.span, ctxt, default, app).0
+ }),
),
ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
AssocOp::Assign,
- snippet_without_expansion(cx, lhs.span, default),
- snippet_without_expansion(cx, rhs.span, default),
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+ snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
astbinop2assignop(op),
- snippet_without_expansion(cx, lhs.span, default),
- snippet_without_expansion(cx, rhs.span, default),
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+ snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
AssocOp::from_ast_binop(op.node),
- snippet_without_expansion(cx, lhs.span, default),
- snippet_without_expansion(cx, rhs.span, default),
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+ snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::As,
- snippet_without_expansion(cx, lhs.span, default),
- snippet_without_expansion(cx, ty.span, default),
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+ snippet_with_context(cx, ty.span, ctxt, default, app).0,
),
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::Colon,
- snippet_without_expansion(cx, lhs.span, default),
- snippet_without_expansion(cx, ty.span, default),
+ snippet_with_context(cx, lhs.span, ctxt, default, app).0,
+ snippet_with_context(cx, ty.span, ctxt, default, app).0,
),
}
}