@@ -41,30 +41,31 @@ use crate::fix::snippet::SourceCodeSnippet;
41
41
/// [preview]: https://docs.astral.sh/ruff/preview/
42
42
#[ violation]
43
43
pub struct NeedlessBool {
44
- condition : SourceCodeSnippet ,
45
- replacement : Option < SourceCodeSnippet > ,
44
+ condition : Option < SourceCodeSnippet > ,
45
+ negate : bool ,
46
46
}
47
47
48
48
impl Violation for NeedlessBool {
49
49
const FIX_AVAILABILITY : FixAvailability = FixAvailability :: Sometimes ;
50
50
51
51
#[ derive_message_formats]
52
52
fn message ( & self ) -> String {
53
- let NeedlessBool { condition, .. } = self ;
54
- if let Some ( condition) = condition. full_display ( ) {
53
+ let NeedlessBool { condition, negate } = self ;
54
+
55
+ if let Some ( condition) = condition. as_ref ( ) . and_then ( SourceCodeSnippet :: full_display) {
55
56
format ! ( "Return the condition `{condition}` directly" )
57
+ } else if * negate {
58
+ format ! ( "Return the negated condition directly" )
56
59
} else {
57
60
format ! ( "Return the condition directly" )
58
61
}
59
62
}
60
63
61
64
fn fix_title ( & self ) -> Option < String > {
62
- let NeedlessBool { replacement, .. } = self ;
63
- if let Some ( replacement) = replacement
64
- . as_ref ( )
65
- . and_then ( SourceCodeSnippet :: full_display)
66
- {
67
- Some ( format ! ( "Replace with `{replacement}`" ) )
65
+ let NeedlessBool { condition, .. } = self ;
66
+
67
+ if let Some ( condition) = condition. as_ref ( ) . and_then ( SourceCodeSnippet :: full_display) {
68
+ Some ( format ! ( "Replace with `return {condition}`" ) )
68
69
} else {
69
70
Some ( format ! ( "Inline condition" ) )
70
71
}
@@ -191,37 +192,29 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
191
192
return ;
192
193
}
193
194
194
- let condition = checker . locator ( ) . slice ( if_test ) ;
195
- let replacement = if checker. indexer ( ) . has_comments ( & range, checker. locator ( ) ) {
195
+ // Generate the replacement condition.
196
+ let condition = if checker. indexer ( ) . has_comments ( & range, checker. locator ( ) ) {
196
197
None
197
198
} else {
198
199
// If the return values are inverted, wrap the condition in a `not`.
199
200
if inverted {
200
- let node = ast:: StmtReturn {
201
- value : Some ( Box :: new ( Expr :: UnaryOp ( ast:: ExprUnaryOp {
202
- op : ast:: UnaryOp :: Not ,
203
- operand : Box :: new ( if_test. clone ( ) ) ,
204
- range : TextRange :: default ( ) ,
205
- } ) ) ) ,
201
+ Some ( Expr :: UnaryOp ( ast:: ExprUnaryOp {
202
+ op : ast:: UnaryOp :: Not ,
203
+ operand : Box :: new ( if_test. clone ( ) ) ,
206
204
range : TextRange :: default ( ) ,
207
- } ;
208
- Some ( checker. generator ( ) . stmt ( & node. into ( ) ) )
205
+ } ) )
209
206
} else if if_test. is_compare_expr ( ) {
210
207
// If the condition is a comparison, we can replace it with the condition, since we
211
208
// know it's a boolean.
212
- let node = ast:: StmtReturn {
213
- value : Some ( Box :: new ( if_test. clone ( ) ) ) ,
214
- range : TextRange :: default ( ) ,
215
- } ;
216
- Some ( checker. generator ( ) . stmt ( & node. into ( ) ) )
209
+ Some ( if_test. clone ( ) )
217
210
} else if checker. semantic ( ) . is_builtin ( "bool" ) {
218
211
// Otherwise, we need to wrap the condition in a call to `bool`.
219
212
let func_node = ast:: ExprName {
220
213
id : "bool" . into ( ) ,
221
214
ctx : ExprContext :: Load ,
222
215
range : TextRange :: default ( ) ,
223
216
} ;
224
- let value_node = ast:: ExprCall {
217
+ let call_node = ast:: ExprCall {
225
218
func : Box :: new ( func_node. into ( ) ) ,
226
219
arguments : Arguments {
227
220
args : Box :: from ( [ if_test. clone ( ) ] ) ,
@@ -230,20 +223,32 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
230
223
} ,
231
224
range : TextRange :: default ( ) ,
232
225
} ;
233
- let return_node = ast:: StmtReturn {
234
- value : Some ( Box :: new ( value_node. into ( ) ) ) ,
235
- range : TextRange :: default ( ) ,
236
- } ;
237
- Some ( checker. generator ( ) . stmt ( & return_node. into ( ) ) )
226
+ Some ( Expr :: Call ( call_node) )
238
227
} else {
239
228
None
240
229
}
241
230
} ;
242
231
232
+ // Generate the replacement `return` statement.
233
+ let replacement = condition. as_ref ( ) . map ( |expr| {
234
+ Stmt :: Return ( ast:: StmtReturn {
235
+ value : Some ( Box :: new ( expr. clone ( ) ) ) ,
236
+ range : TextRange :: default ( ) ,
237
+ } )
238
+ } ) ;
239
+
240
+ // Generate source code.
241
+ let replacement = replacement
242
+ . as_ref ( )
243
+ . map ( |stmt| checker. generator ( ) . stmt ( stmt) ) ;
244
+ let condition = condition
245
+ . as_ref ( )
246
+ . map ( |expr| checker. generator ( ) . expr ( expr) ) ;
247
+
243
248
let mut diagnostic = Diagnostic :: new (
244
249
NeedlessBool {
245
- condition : SourceCodeSnippet :: from_str ( condition ) ,
246
- replacement : replacement . clone ( ) . map ( SourceCodeSnippet :: new ) ,
250
+ condition : condition . map ( SourceCodeSnippet :: new ) ,
251
+ negate : inverted ,
247
252
} ,
248
253
range,
249
254
) ;
0 commit comments