1
+ use std:: cmp;
2
+
1
3
use anyhow:: Result ;
2
4
use libcst_native:: CompOp ;
3
5
@@ -14,6 +16,7 @@ use crate::cst::helpers::or_space;
14
16
use crate :: cst:: matchers:: { match_comparison, transform_expression} ;
15
17
use crate :: fix:: edits:: pad;
16
18
use crate :: fix:: snippet:: SourceCodeSnippet ;
19
+ use crate :: settings:: types:: PreviewMode ;
17
20
18
21
/// ## What it does
19
22
/// Checks for conditions that position a constant on the left-hand side of the
@@ -78,18 +81,65 @@ impl Violation for YodaConditions {
78
81
}
79
82
}
80
83
81
- /// Return `true` if an [`Expr`] is a constant or a constant-like name.
82
- fn is_constant_like ( expr : & Expr ) -> bool {
83
- match expr {
84
- Expr :: Attribute ( ast:: ExprAttribute { attr, .. } ) => str:: is_cased_uppercase ( attr) ,
85
- Expr :: Tuple ( ast:: ExprTuple { elts, .. } ) => elts. iter ( ) . all ( is_constant_like) ,
86
- Expr :: Name ( ast:: ExprName { id, .. } ) => str:: is_cased_uppercase ( id) ,
87
- Expr :: UnaryOp ( ast:: ExprUnaryOp {
88
- op : UnaryOp :: UAdd | UnaryOp :: USub | UnaryOp :: Invert ,
89
- operand,
90
- range : _,
91
- } ) => operand. is_literal_expr ( ) ,
92
- _ => expr. is_literal_expr ( ) ,
84
+ /// Comparisons left-hand side must not be more [`ConstantLikelihood`] than the right-hand side.
85
+ #[ derive( PartialEq , Eq , PartialOrd , Ord , Debug ) ]
86
+ enum ConstantLikelihood {
87
+ /// The expression is unlikely to be a constant (e.g., `foo` or `foo(bar)`).
88
+ Unlikely = 0 ,
89
+
90
+ /// The expression is likely to be a constant (e.g., `FOO`).
91
+ Probably = 1 ,
92
+
93
+ /// The expression is definitely a constant (e.g., `42` or `"foo"`).
94
+ Definitely = 2 ,
95
+ }
96
+
97
+ impl ConstantLikelihood {
98
+ /// Determine the [`ConstantLikelihood`] of an expression.
99
+ fn from_expression ( expr : & Expr , preview : PreviewMode ) -> Self {
100
+ match expr {
101
+ _ if expr. is_literal_expr ( ) => ConstantLikelihood :: Definitely ,
102
+ Expr :: Attribute ( ast:: ExprAttribute { attr, .. } ) => {
103
+ ConstantLikelihood :: from_identifier ( attr)
104
+ }
105
+ Expr :: Name ( ast:: ExprName { id, .. } ) => ConstantLikelihood :: from_identifier ( id) ,
106
+ Expr :: Tuple ( ast:: ExprTuple { elts, .. } ) => elts
107
+ . iter ( )
108
+ . map ( |expr| ConstantLikelihood :: from_expression ( expr, preview) )
109
+ . min ( )
110
+ . unwrap_or ( ConstantLikelihood :: Definitely ) ,
111
+ Expr :: List ( ast:: ExprList { elts, .. } ) if preview. is_enabled ( ) => elts
112
+ . iter ( )
113
+ . map ( |expr| ConstantLikelihood :: from_expression ( expr, preview) )
114
+ . min ( )
115
+ . unwrap_or ( ConstantLikelihood :: Definitely ) ,
116
+ Expr :: Dict ( ast:: ExprDict { values : vs, .. } ) if preview. is_enabled ( ) => {
117
+ if vs. is_empty ( ) {
118
+ ConstantLikelihood :: Definitely
119
+ } else {
120
+ ConstantLikelihood :: Probably
121
+ }
122
+ }
123
+ Expr :: BinOp ( ast:: ExprBinOp { left, right, .. } ) => cmp:: min (
124
+ ConstantLikelihood :: from_expression ( left, preview) ,
125
+ ConstantLikelihood :: from_expression ( right, preview) ,
126
+ ) ,
127
+ Expr :: UnaryOp ( ast:: ExprUnaryOp {
128
+ op : UnaryOp :: UAdd | UnaryOp :: USub | UnaryOp :: Invert ,
129
+ operand,
130
+ range : _,
131
+ } ) => ConstantLikelihood :: from_expression ( operand, preview) ,
132
+ _ => ConstantLikelihood :: Unlikely ,
133
+ }
134
+ }
135
+
136
+ /// Determine the [`ConstantLikelihood`] of an identifier.
137
+ fn from_identifier ( identifier : & str ) -> Self {
138
+ if str:: is_cased_uppercase ( identifier) {
139
+ ConstantLikelihood :: Probably
140
+ } else {
141
+ ConstantLikelihood :: Unlikely
142
+ }
93
143
}
94
144
}
95
145
@@ -180,7 +230,9 @@ pub(crate) fn yoda_conditions(
180
230
return ;
181
231
}
182
232
183
- if !is_constant_like ( left) || is_constant_like ( right) {
233
+ if ConstantLikelihood :: from_expression ( left, checker. settings . preview )
234
+ <= ConstantLikelihood :: from_expression ( right, checker. settings . preview )
235
+ {
184
236
return ;
185
237
}
186
238
0 commit comments