@@ -49,16 +49,16 @@ use rustc_trait_selection::traits::{self};
49
49
use crate :: errors:: BuiltinEllipsisInclusiveRangePatterns ;
50
50
use crate :: lints:: {
51
51
BuiltinAnonymousParams , BuiltinConstNoMangle , BuiltinDeprecatedAttrLink ,
52
- BuiltinDeprecatedAttrLinkSuggestion , BuiltinDerefNullptr ,
53
- BuiltinEllipsisInclusiveRangePatternsLint , BuiltinExplicitOutlives ,
54
- BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
55
- BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
56
- BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc , BuiltinMutablesTransmutes ,
57
- BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns , BuiltinSpecialModuleNameUsed ,
58
- BuiltinTrivialBounds , BuiltinTypeAliasBounds , BuiltinUngatedAsyncFnTrackCaller ,
59
- BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub ,
60
- BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
61
- BuiltinWhileTrue , InvalidAsmLabel ,
52
+ BuiltinDeprecatedAttrLinkSuggestion , BuiltinDerefNullptr , BuiltinDoubleNegations ,
53
+ BuiltinDoubleNegationsAddParens , BuiltinEllipsisInclusiveRangePatternsLint ,
54
+ BuiltinExplicitOutlives , BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote ,
55
+ BuiltinIncompleteFeatures , BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures ,
56
+ BuiltinKeywordIdents , BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc ,
57
+ BuiltinMutablesTransmutes , BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns ,
58
+ BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds , BuiltinTypeAliasBounds ,
59
+ BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit , BuiltinUnpermittedTypeInitSub ,
60
+ BuiltinUnreachablePub , BuiltinUnsafe , BuiltinUnstableFeatures , BuiltinUnusedDocComment ,
61
+ BuiltinUnusedDocCommentSub , BuiltinWhileTrue , InvalidAsmLabel ,
62
62
} ;
63
63
use crate :: nonstandard_style:: { MethodLateContext , method_context} ;
64
64
use crate :: {
@@ -90,19 +90,11 @@ declare_lint! {
90
90
91
91
declare_lint_pass ! ( WhileTrue => [ WHILE_TRUE ] ) ;
92
92
93
- /// Traverse through any amount of parenthesis and return the first non-parens expression.
94
- fn pierce_parens ( mut expr : & ast:: Expr ) -> & ast:: Expr {
95
- while let ast:: ExprKind :: Paren ( sub) = & expr. kind {
96
- expr = sub;
97
- }
98
- expr
99
- }
100
-
101
93
impl EarlyLintPass for WhileTrue {
102
94
#[ inline]
103
95
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
104
96
if let ast:: ExprKind :: While ( cond, _, label) = & e. kind
105
- && let ast:: ExprKind :: Lit ( token_lit) = pierce_parens ( cond) . kind
97
+ && let ast:: ExprKind :: Lit ( token_lit) = cond. peel_parens ( ) . kind
106
98
&& let token:: Lit { kind : token:: Bool , symbol : kw:: True , .. } = token_lit
107
99
&& !cond. span . from_expansion ( )
108
100
{
@@ -1576,6 +1568,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
1576
1568
}
1577
1569
}
1578
1570
1571
+ declare_lint ! {
1572
+ /// The `double_negations` lint detects expressions of the form `--x`.
1573
+ ///
1574
+ /// ### Example
1575
+ ///
1576
+ /// ```rust
1577
+ /// fn main() {
1578
+ /// let x = 1;
1579
+ /// let _b = --x;
1580
+ /// }
1581
+ /// ```
1582
+ ///
1583
+ /// {{produces}}
1584
+ ///
1585
+ /// ### Explanation
1586
+ ///
1587
+ /// Negating something twice is usually the same as not negating it at all.
1588
+ /// However, a double negation in Rust can easily be confused with the
1589
+ /// prefix decrement operator that exists in many languages derived from C.
1590
+ /// Use `-(-x)` if you really wanted to negate the value twice.
1591
+ ///
1592
+ /// To decrement a value, use `x -= 1` instead.
1593
+ pub DOUBLE_NEGATIONS ,
1594
+ Warn ,
1595
+ "detects expressions of the form `--x`"
1596
+ }
1597
+
1598
+ declare_lint_pass ! (
1599
+ /// Lint for expressions of the form `--x` that can be confused with C's
1600
+ /// prefix decrement operator.
1601
+ DoubleNegations => [ DOUBLE_NEGATIONS ]
1602
+ ) ;
1603
+
1604
+ impl EarlyLintPass for DoubleNegations {
1605
+ #[ inline]
1606
+ fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
1607
+ // only lint on the innermost `--` in a chain of `-` operators,
1608
+ // even if there are 3 or more negations
1609
+ if let ExprKind :: Unary ( UnOp :: Neg , ref inner) = expr. kind
1610
+ && let ExprKind :: Unary ( UnOp :: Neg , ref inner2) = inner. kind
1611
+ && !matches ! ( inner2. kind, ExprKind :: Unary ( UnOp :: Neg , _) )
1612
+ {
1613
+ cx. emit_span_lint ( DOUBLE_NEGATIONS , expr. span , BuiltinDoubleNegations {
1614
+ add_parens : BuiltinDoubleNegationsAddParens {
1615
+ start_span : inner. span . shrink_to_lo ( ) ,
1616
+ end_span : inner. span . shrink_to_hi ( ) ,
1617
+ } ,
1618
+ } ) ;
1619
+ }
1620
+ }
1621
+ }
1622
+
1579
1623
declare_lint_pass ! (
1580
1624
/// Does nothing as a lint pass, but registers some `Lint`s
1581
1625
/// which are used by other parts of the compiler.
@@ -1594,7 +1638,8 @@ declare_lint_pass!(
1594
1638
UNSTABLE_FEATURES ,
1595
1639
UNREACHABLE_PUB ,
1596
1640
TYPE_ALIAS_BOUNDS ,
1597
- TRIVIAL_BOUNDS
1641
+ TRIVIAL_BOUNDS ,
1642
+ DOUBLE_NEGATIONS
1598
1643
]
1599
1644
) ;
1600
1645
@@ -2651,7 +2696,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
2651
2696
}
2652
2697
2653
2698
declare_lint ! {
2654
- /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
2699
+ /// The `deref_nullptr` lint detects when a null pointer is dereferenced,
2655
2700
/// which causes [undefined behavior].
2656
2701
///
2657
2702
/// ### Example
0 commit comments