Skip to main content

rustc_lint/
precedence.rs

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
11#[doc = r" The `ambiguous_negative_literals` lint checks for cases that are"]
#[doc =
r" confusing between a negative literal and a negation that's not part"]
#[doc = r" of the literal."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" # #![deny(ambiguous_negative_literals)]"]
#[doc = r" # #![allow(unused)]"]
#[doc = r" -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" Method calls take precedence over unary precedence. Setting the"]
#[doc =
r" precedence explicitly makes the code clearer and avoid potential bugs."]
pub static AMBIGUOUS_NEGATIVE_LITERALS: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "AMBIGUOUS_NEGATIVE_LITERALS",
            default_level: ::rustc_lint_defs::Allow,
            desc: "ambiguous negative literals operations",
            is_externally_loaded: false,
            report_in_external_macro: true,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
12    /// The `ambiguous_negative_literals` lint checks for cases that are
13    /// confusing between a negative literal and a negation that's not part
14    /// of the literal.
15    ///
16    /// ### Example
17    ///
18    /// ```rust,compile_fail
19    /// # #![deny(ambiguous_negative_literals)]
20    /// # #![allow(unused)]
21    /// -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1
22    /// ```
23    ///
24    /// {{produces}}
25    ///
26    /// ### Explanation
27    ///
28    /// Method calls take precedence over unary precedence. Setting the
29    /// precedence explicitly makes the code clearer and avoid potential bugs.
30    pub AMBIGUOUS_NEGATIVE_LITERALS,
31    Allow,
32    "ambiguous negative literals operations",
33    report_in_external_macro
34}
35
36pub struct Precedence;
#[automatically_derived]
impl ::core::marker::Copy for Precedence { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Precedence { }
#[automatically_derived]
impl ::core::clone::Clone for Precedence {
    #[inline]
    fn clone(&self) -> Precedence { *self }
}
impl ::rustc_lint_defs::LintPass for Precedence {
    fn name(&self) -> &'static str { "Precedence" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        <[_]>::into_vec(::alloc::boxed::box_new([AMBIGUOUS_NEGATIVE_LITERALS]))
    }
}
impl Precedence {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        <[_]>::into_vec(::alloc::boxed::box_new([AMBIGUOUS_NEGATIVE_LITERALS]))
    }
}declare_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}