| use rustc_ast::token::LitKind; |
| use rustc_ast::{Expr, ExprKind, MethodCall, UnOp}; |
| use rustc_session::{declare_lint, declare_lint_pass}; |
| |
| use crate::lints::{ |
| AmbiguousNegativeLiteralsCurrentBehaviorSuggestion, AmbiguousNegativeLiteralsDiag, |
| AmbiguousNegativeLiteralsNegativeLiteralSuggestion, |
| }; |
| use crate::{EarlyContext, EarlyLintPass, LintContext}; |
| |
| declare_lint! { |
| /// The `ambiguous_negative_literals` lint checks for cases that are |
| /// confusing between a negative literal and a negation that's not part |
| /// of the literal. |
| /// |
| /// ### Example |
| /// |
| /// ```rust,compile_fail |
| /// # #![deny(ambiguous_negative_literals)] |
| /// # #![allow(unused)] |
| /// -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1 |
| /// ``` |
| /// |
| /// {{produces}} |
| /// |
| /// ### Explanation |
| /// |
| /// Method calls take precedence over unary precedence. Setting the |
| /// precedence explicitly makes the code clearer and avoid potential bugs. |
| pub AMBIGUOUS_NEGATIVE_LITERALS, |
| Allow, |
| "ambiguous negative literals operations", |
| report_in_external_macro |
| } |
| |
| declare_lint_pass!(Precedence => [AMBIGUOUS_NEGATIVE_LITERALS]); |
| |
| impl EarlyLintPass for Precedence { |
| fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind else { |
| return; |
| }; |
| |
| let mut arg = operand; |
| let mut at_least_one = false; |
| while let ExprKind::MethodCall(box MethodCall { receiver, .. }) = &arg.kind { |
| at_least_one = true; |
| arg = receiver; |
| } |
| |
| if at_least_one |
| && let ExprKind::Lit(lit) = &arg.kind |
| && let LitKind::Integer | LitKind::Float = &lit.kind |
| { |
| cx.emit_span_lint( |
| AMBIGUOUS_NEGATIVE_LITERALS, |
| expr.span, |
| AmbiguousNegativeLiteralsDiag { |
| negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion { |
| start_span: expr.span.shrink_to_lo(), |
| end_span: arg.span.shrink_to_hi(), |
| }, |
| current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion { |
| start_span: operand.span.shrink_to_lo(), |
| end_span: operand.span.shrink_to_hi(), |
| }, |
| }, |
| ); |
| } |
| } |
| } |