| use rustc_ast::token::LitKind; | |
| use rustc_ast::{Expr, ExprKind, MethodCall, UnOp}; | |
| use rustc_session::{declare_lint, declare_lint_pass}; | |
| use crate::diagnostics::{ | |
| 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(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(), | |
| }, | |
| }, | |
| ); | |
| } | |
| } | |
| } |