1use rustc_ast::token::LitKind;
2use rustc_ast::{Expr, ExprKind, MethodCall, UnOp};
3use rustc_session::{declare_lint, declare_lint_pass};
4
5use crate::lints::{
6 AmbiguousNegativeLiteralsCurrentBehaviorSuggestion, AmbiguousNegativeLiteralsDiag,
7 AmbiguousNegativeLiteralsNegativeLiteralSuggestion,
8};
9use crate::{EarlyContext, EarlyLintPass, LintContext};
10
11declare_lint! {
12 pub AMBIGUOUS_NEGATIVE_LITERALS,
31 Allow,
32 "ambiguous negative literals operations",
33 report_in_external_macro
34}
35
36declare_lint_pass!(Precedence => [AMBIGUOUS_NEGATIVE_LITERALS]);
37
38impl EarlyLintPass for Precedence {
39 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
40 let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind else {
41 return;
42 };
43
44 let mut arg = operand;
45 let mut at_least_one = false;
46 while let ExprKind::MethodCall(box MethodCall { receiver, .. }) = &arg.kind {
47 at_least_one = true;
48 arg = receiver;
49 }
50
51 if at_least_one
52 && let ExprKind::Lit(lit) = &arg.kind
53 && let LitKind::Integer | LitKind::Float = &lit.kind
54 {
55 cx.emit_span_lint(
56 AMBIGUOUS_NEGATIVE_LITERALS,
57 expr.span,
58 AmbiguousNegativeLiteralsDiag {
59 negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion {
60 start_span: expr.span.shrink_to_lo(),
61 end_span: arg.span.shrink_to_hi(),
62 },
63 current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion {
64 start_span: operand.span.shrink_to_lo(),
65 end_span: operand.span.shrink_to_hi(),
66 },
67 },
68 );
69 }
70 }
71}