Skip to main content

ide_assists/handlers/
inline_local_variable.rs

1use either::{Either, for_both};
2use hir::{PathResolution, Semantics};
3use ide_db::{
4    EditionedFileId, RootDatabase,
5    defs::Definition,
6    search::{FileReference, FileReferenceNode, UsageSearchResult},
7};
8use syntax::{
9    Direction, TextRange,
10    ast::{self, AstNode, AstToken, HasName},
11    syntax_editor::{Element, SyntaxEditor},
12};
13
14use crate::{
15    AssistId,
16    assist_context::{AssistContext, Assists},
17};
18
19// Assist: inline_local_variable
20//
21// Inlines a local variable.
22//
23// ```
24// fn main() {
25//     let x$0 = 1 + 2;
26//     x * 4;
27// }
28// ```
29// ->
30// ```
31// fn main() {
32//     (1 + 2) * 4;
33// }
34// ```
35pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
36    let file_id = ctx.file_id();
37    let range = ctx.selection_trimmed();
38    let InlineData { let_stmt, delete_let, references, target } =
39        if let Some(path_expr) = ctx.find_node_at_offset::<ast::PathExpr>() {
40            inline_usage(&ctx.sema, path_expr, range, file_id)
41        } else if let Some(let_stmt) = ctx.find_node_at_offset() {
42            inline_let(&ctx.sema, let_stmt, range, file_id)
43        } else {
44            None
45        }?;
46    let initializer_expr = match &let_stmt {
47        either::Either::Left(it) => it.initializer()?,
48        either::Either::Right(it) => it.expr()?,
49    };
50
51    let wrap_in_parens = references
52        .into_iter()
53        .filter_map(|FileReference { range, name, .. }| match name {
54            FileReferenceNode::NameRef(name) => Some((range, name)),
55            _ => None,
56        })
57        .map(|(range, name_ref)| {
58            if range != name_ref.syntax().text_range() {
59                // Do not rename inside macros
60                // FIXME: This feels like a bad heuristic for macros
61                return None;
62            }
63            let usage_node =
64                name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind()));
65            let usage_parent_option = usage_node.as_ref().and_then(|it| it.parent());
66            let usage_parent = match usage_parent_option {
67                Some(u) => u,
68                None => return Some((name_ref, false)),
69            };
70            let should_wrap = initializer_expr
71                .needs_parens_in_place_of(&usage_parent, usage_node.as_ref().unwrap());
72            Some((name_ref, should_wrap))
73        })
74        .collect::<Option<Vec<_>>>()?;
75
76    let target = match target {
77        ast::NameOrNameRef::Name(it) => it.syntax().clone(),
78        ast::NameOrNameRef::NameRef(it) => it.syntax().clone(),
79    };
80
81    acc.add(
82        AssistId::refactor_inline("inline_local_variable"),
83        "Inline variable",
84        target.text_range(),
85        move |builder| {
86            let editor = builder.make_editor(&target);
87            let make = editor.make();
88            if delete_let {
89                editor.delete(let_stmt.syntax());
90
91                if let Some(bin_expr) = let_stmt.syntax().parent().and_then(ast::BinExpr::cast)
92                    && let Some(op_token) = bin_expr.op_token()
93                {
94                    editor.delete(&op_token);
95                    remove_whitespace(op_token, Direction::Prev, &editor);
96                    remove_whitespace(let_stmt.syntax(), Direction::Prev, &editor);
97                } else {
98                    remove_whitespace(let_stmt.syntax(), Direction::Next, &editor);
99                }
100            }
101
102            for (name, should_wrap) in wrap_in_parens {
103                let replacement = if should_wrap {
104                    make.expr_paren(initializer_expr.clone()).into()
105                } else {
106                    initializer_expr.clone()
107                };
108
109                if let Some(record_field) = ast::RecordExprField::for_field_name(&name) {
110                    cov_mark::hit!(inline_field_shorthand);
111                    let replacement = make.record_expr_field(name, Some(replacement));
112                    editor.replace(record_field.syntax(), replacement.syntax());
113                } else {
114                    editor.replace(name.syntax(), replacement.syntax());
115                }
116            }
117            builder.add_file_edits(ctx.vfs_file_id(), editor);
118        },
119    )
120}
121
122struct InlineData {
123    let_stmt: Either<ast::LetStmt, ast::LetExpr>,
124    delete_let: bool,
125    target: ast::NameOrNameRef,
126    references: Vec<FileReference>,
127}
128
129fn inline_let(
130    sema: &Semantics<'_, RootDatabase>,
131    let_stmt: Either<ast::LetStmt, ast::LetExpr>,
132    range: TextRange,
133    file_id: EditionedFileId,
134) -> Option<InlineData> {
135    let bind_pat = match for_both!(&let_stmt, it => it.pat())? {
136        ast::Pat::IdentPat(pat) => pat,
137        _ => return None,
138    };
139    if bind_pat.mut_token().is_some() {
140        cov_mark::hit!(test_not_inline_mut_variable);
141        return None;
142    }
143    if !bind_pat.syntax().text_range().contains_range(range) {
144        cov_mark::hit!(not_applicable_outside_of_bind_pat);
145        return None;
146    }
147
148    let local = sema.to_def(&bind_pat)?;
149    let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
150    match references.remove(&file_id) {
151        Some(references) => Some(InlineData {
152            let_stmt,
153            delete_let: true,
154            target: ast::NameOrNameRef::Name(bind_pat.name()?),
155            references,
156        }),
157        None => {
158            cov_mark::hit!(test_not_applicable_if_variable_unused);
159            None
160        }
161    }
162}
163
164fn inline_usage(
165    sema: &Semantics<'_, RootDatabase>,
166    path_expr: ast::PathExpr,
167    range: TextRange,
168    file_id: EditionedFileId,
169) -> Option<InlineData> {
170    let path = path_expr.path()?;
171    let name = path.as_single_name_ref()?;
172    if !name.syntax().text_range().contains_range(range) {
173        cov_mark::hit!(test_not_inline_selection_too_broad);
174        return None;
175    }
176
177    let local = match sema.resolve_path(&path)? {
178        PathResolution::Local(local) => local,
179        _ => return None,
180    };
181    if local.is_mut(sema.db) {
182        cov_mark::hit!(test_not_inline_mut_variable_use);
183        return None;
184    }
185
186    let sources = local.sources(sema.db);
187    let [source] = sources.as_slice() else {
188        // Not applicable with locals with multiple definitions (i.e. or patterns)
189        return None;
190    };
191
192    let bind_pat = source.as_ident_pat()?;
193
194    let let_stmt = AstNode::cast(bind_pat.syntax().parent()?)?;
195
196    let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
197    let mut references = references.remove(&file_id)?;
198    let delete_let = references.len() == 1;
199    references.retain(|fref| fref.name.as_name_ref() == Some(&name));
200
201    Some(InlineData { let_stmt, delete_let, target: ast::NameOrNameRef::NameRef(name), references })
202}
203
204fn remove_whitespace(elem: impl Element, dir: Direction, editor: &SyntaxEditor) {
205    let token = match elem.syntax_element() {
206        syntax::NodeOrToken::Node(node) => match dir {
207            Direction::Next => node.last_token(),
208            Direction::Prev => node.first_token(),
209        },
210        syntax::NodeOrToken::Token(t) => Some(t),
211    };
212    let next_token = match dir {
213        Direction::Next => token.and_then(|it| it.next_token()),
214        Direction::Prev => token.and_then(|it| it.prev_token()),
215    };
216    if let Some(whitespace) = next_token.and_then(ast::Whitespace::cast) {
217        editor.delete(whitespace.syntax());
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use crate::tests::{check_assist, check_assist_not_applicable};
224
225    use super::*;
226
227    #[test]
228    fn test_inline_let_bind_literal_expr() {
229        check_assist(
230            inline_local_variable,
231            r"
232fn bar(a: usize) {}
233fn foo() {
234    let a$0 = 1;
235    a + 1;
236    if a > 10 {
237    }
238
239    while a > 10 {
240
241    }
242    let b = a * 10;
243    bar(a);
244}",
245            r"
246fn bar(a: usize) {}
247fn foo() {
248    1 + 1;
249    if 1 > 10 {
250    }
251
252    while 1 > 10 {
253
254    }
255    let b = 1 * 10;
256    bar(1);
257}",
258        );
259    }
260
261    #[test]
262    fn test_inline_let_bind_bin_expr() {
263        check_assist(
264            inline_local_variable,
265            r"
266fn bar(a: usize) {}
267fn foo() {
268    let a$0 = 1 + 1;
269    a + 1;
270    if a > 10 {
271    }
272
273    while a > 10 {
274
275    }
276    let b = a * 10;
277    bar(a);
278}",
279            r"
280fn bar(a: usize) {}
281fn foo() {
282    1 + 1 + 1;
283    if 1 + 1 > 10 {
284    }
285
286    while 1 + 1 > 10 {
287
288    }
289    let b = (1 + 1) * 10;
290    bar(1 + 1);
291}",
292        );
293    }
294
295    #[test]
296    fn test_inline_let_bind_function_call_expr() {
297        check_assist(
298            inline_local_variable,
299            r"
300fn bar(a: usize) {}
301fn foo() {
302    let a$0 = bar(1);
303    a + 1;
304    if a > 10 {
305    }
306
307    while a > 10 {
308
309    }
310    let b = a * 10;
311    bar(a);
312}",
313            r"
314fn bar(a: usize) {}
315fn foo() {
316    bar(1) + 1;
317    if bar(1) > 10 {
318    }
319
320    while bar(1) > 10 {
321
322    }
323    let b = bar(1) * 10;
324    bar(bar(1));
325}",
326        );
327    }
328
329    #[test]
330    fn test_inline_let_bind_cast_expr() {
331        check_assist(
332            inline_local_variable,
333            r"
334//- minicore: sized
335fn bar(a: usize) -> usize { a }
336fn foo() {
337    let a$0 = bar(1) as u64;
338    a + 1;
339    if a > 10 {
340    }
341
342    while a > 10 {
343
344    }
345    let b = a * 10;
346    bar(a);
347}",
348            r"
349fn bar(a: usize) -> usize { a }
350fn foo() {
351    bar(1) as u64 + 1;
352    if bar(1) as u64 > 10 {
353    }
354
355    while bar(1) as u64 > 10 {
356
357    }
358    let b = bar(1) as u64 * 10;
359    bar(bar(1) as u64);
360}",
361        );
362    }
363
364    #[test]
365    fn test_inline_let_bind_block_expr() {
366        check_assist(
367            inline_local_variable,
368            r"
369fn foo() {
370    let a$0 = { 10 + 1 };
371    a + 1;
372    if a > 10 {
373    }
374
375    while a > 10 {
376
377    }
378    let b = a * 10;
379    bar(a);
380}",
381            r"
382fn foo() {
383    { 10 + 1 } + 1;
384    if { 10 + 1 } > 10 {
385    }
386
387    while { 10 + 1 } > 10 {
388
389    }
390    let b = { 10 + 1 } * 10;
391    bar({ 10 + 1 });
392}",
393        );
394    }
395
396    #[test]
397    fn test_inline_let_bind_paren_expr() {
398        check_assist(
399            inline_local_variable,
400            r"
401fn foo() {
402    let a$0 = ( 10 + 1 );
403    a + 1;
404    if a > 10 {
405    }
406
407    while a > 10 {
408
409    }
410    let b = a * 10;
411    bar(a);
412}",
413            r"
414fn foo() {
415    ( 10 + 1 ) + 1;
416    if ( 10 + 1 ) > 10 {
417    }
418
419    while ( 10 + 1 ) > 10 {
420
421    }
422    let b = ( 10 + 1 ) * 10;
423    bar(( 10 + 1 ));
424}",
425        );
426    }
427
428    #[test]
429    fn test_inline_let_expr() {
430        check_assist(
431            inline_local_variable,
432            r"
433fn bar(a: usize) {}
434fn foo() {
435    if let a$0 = 1
436        && true
437    {
438        a + 1;
439        if a > 10 {}
440        while a > 10 {}
441        let b = a * 10;
442        bar(a);
443    }
444}",
445            r"
446fn bar(a: usize) {}
447fn foo() {
448    if true
449    {
450        1 + 1;
451        if 1 > 10 {}
452        while 1 > 10 {}
453        let b = 1 * 10;
454        bar(1);
455    }
456}",
457        );
458    }
459
460    #[test]
461    fn test_not_inline_mut_variable() {
462        cov_mark::check!(test_not_inline_mut_variable);
463        check_assist_not_applicable(
464            inline_local_variable,
465            r"
466fn foo() {
467    let mut a$0 = 1 + 1;
468    a + 1;
469}",
470        );
471    }
472
473    #[test]
474    fn test_not_inline_mut_variable_use() {
475        cov_mark::check!(test_not_inline_mut_variable_use);
476        check_assist_not_applicable(
477            inline_local_variable,
478            r"
479fn foo() {
480    let mut a = 1 + 1;
481    a$0 + 1;
482}",
483        );
484    }
485
486    #[test]
487    fn test_call_expr() {
488        check_assist(
489            inline_local_variable,
490            r"
491fn foo() {
492    let a$0 = bar(10 + 1);
493    let b = a * 10;
494    let c = a as usize;
495}",
496            r"
497fn foo() {
498    let b = bar(10 + 1) * 10;
499    let c = bar(10 + 1) as usize;
500}",
501        );
502    }
503
504    #[test]
505    fn test_index_expr() {
506        check_assist(
507            inline_local_variable,
508            r"
509fn foo() {
510    let x = vec![1, 2, 3];
511    let a$0 = x[0];
512    let b = a * 10;
513    let c = a as usize;
514}",
515            r"
516fn foo() {
517    let x = vec![1, 2, 3];
518    let b = x[0] * 10;
519    let c = x[0] as usize;
520}",
521        );
522    }
523
524    #[test]
525    fn test_method_call_expr() {
526        check_assist(
527            inline_local_variable,
528            r"
529fn foo() {
530    let bar = vec![1];
531    let a$0 = bar.len();
532    let b = a * 10;
533    let c = a as usize;
534}",
535            r"
536fn foo() {
537    let bar = vec![1];
538    let b = bar.len() * 10;
539    let c = bar.len() as usize;
540}",
541        );
542    }
543
544    #[test]
545    fn test_field_expr() {
546        check_assist(
547            inline_local_variable,
548            r"
549struct Bar {
550    foo: usize
551}
552
553fn foo() {
554    let bar = Bar { foo: 1 };
555    let a$0 = bar.foo;
556    let b = a * 10;
557    let c = a as usize;
558}",
559            r"
560struct Bar {
561    foo: usize
562}
563
564fn foo() {
565    let bar = Bar { foo: 1 };
566    let b = bar.foo * 10;
567    let c = bar.foo as usize;
568}",
569        );
570    }
571
572    #[test]
573    fn test_try_expr() {
574        check_assist(
575            inline_local_variable,
576            r"
577fn foo() -> Option<usize> {
578    let bar = Some(1);
579    let a$0 = bar?;
580    let b = a * 10;
581    let c = a as usize;
582    None
583}",
584            r"
585fn foo() -> Option<usize> {
586    let bar = Some(1);
587    let b = bar? * 10;
588    let c = bar? as usize;
589    None
590}",
591        );
592    }
593
594    #[test]
595    fn test_ref_expr() {
596        check_assist(
597            inline_local_variable,
598            r"
599fn foo() {
600    let bar = 10;
601    let a$0 = &bar;
602    let b = a * 10;
603}",
604            r"
605fn foo() {
606    let bar = 10;
607    let b = &bar * 10;
608}",
609        );
610    }
611
612    #[test]
613    fn test_tuple_expr() {
614        check_assist(
615            inline_local_variable,
616            r"
617fn foo() {
618    let a$0 = (10, 20);
619    let b = a[0];
620}",
621            r"
622fn foo() {
623    let b = (10, 20)[0];
624}",
625        );
626    }
627
628    #[test]
629    fn test_array_expr() {
630        check_assist(
631            inline_local_variable,
632            r"
633fn foo() {
634    let a$0 = [1, 2, 3];
635    let b = a.len();
636}",
637            r"
638fn foo() {
639    let b = [1, 2, 3].len();
640}",
641        );
642    }
643
644    #[test]
645    fn test_paren() {
646        check_assist(
647            inline_local_variable,
648            r"
649fn foo() {
650    let a$0 = (10 + 20);
651    let b = a * 10;
652    let c = a as usize;
653}",
654            r"
655fn foo() {
656    let b = (10 + 20) * 10;
657    let c = (10 + 20) as usize;
658}",
659        );
660    }
661
662    #[test]
663    fn test_path_expr() {
664        check_assist(
665            inline_local_variable,
666            r"
667fn foo() {
668    let d = 10;
669    let a$0 = d;
670    let b = a * 10;
671    let c = a as usize;
672}",
673            r"
674fn foo() {
675    let d = 10;
676    let b = d * 10;
677    let c = d as usize;
678}",
679        );
680    }
681
682    #[test]
683    fn test_block_expr() {
684        check_assist(
685            inline_local_variable,
686            r"
687fn foo() {
688    let a$0 = { 10 };
689    let b = a * 10;
690    let c = a as usize;
691}",
692            r"
693fn foo() {
694    let b = { 10 } * 10;
695    let c = { 10 } as usize;
696}",
697        );
698    }
699
700    #[test]
701    fn test_used_in_different_expr1() {
702        check_assist(
703            inline_local_variable,
704            r"
705fn foo() {
706    let a$0 = 10 + 20;
707    let b = a * 10;
708    let c = (a, 20);
709    let d = [a, 10];
710    let e = (a);
711}",
712            r"
713fn foo() {
714    let b = (10 + 20) * 10;
715    let c = (10 + 20, 20);
716    let d = [10 + 20, 10];
717    let e = (10 + 20);
718}",
719        );
720    }
721
722    #[test]
723    fn test_used_in_for_expr() {
724        check_assist(
725            inline_local_variable,
726            r"
727//- minicore: iterator
728fn foo() {
729    let a$0 = vec![10, 20];
730    for i in a {}
731}",
732            r"
733fn foo() {
734    for i in vec![10, 20] {}
735}",
736        );
737    }
738
739    #[test]
740    fn test_used_in_while_expr() {
741        check_assist(
742            inline_local_variable,
743            r"
744fn foo() {
745    let a$0 = 1 > 0;
746    while a {}
747}",
748            r"
749fn foo() {
750    while 1 > 0 {}
751}",
752        );
753    }
754
755    #[test]
756    fn test_used_in_break_expr() {
757        check_assist(
758            inline_local_variable,
759            r"
760fn foo() {
761    let a$0 = 1 + 1;
762    loop {
763        break a;
764    }
765}",
766            r"
767fn foo() {
768    loop {
769        break 1 + 1;
770    }
771}",
772        );
773    }
774
775    #[test]
776    fn test_used_in_return_expr() {
777        check_assist(
778            inline_local_variable,
779            r"
780fn foo() {
781    let a$0 = 1 > 0;
782    return a;
783}",
784            r"
785fn foo() {
786    return 1 > 0;
787}",
788        );
789    }
790
791    #[test]
792    fn test_used_in_match_expr() {
793        check_assist(
794            inline_local_variable,
795            r"
796fn foo() {
797    let a$0 = 1 > 0;
798    match a {}
799}",
800            r"
801fn foo() {
802    match 1 > 0 {}
803}",
804        );
805    }
806
807    #[test]
808    fn inline_field_shorthand() {
809        cov_mark::check!(inline_field_shorthand);
810        check_assist(
811            inline_local_variable,
812            r"
813struct S { foo: i32}
814fn main() {
815    let $0foo = 92;
816    S { foo }
817}
818",
819            r"
820struct S { foo: i32}
821fn main() {
822    S { foo: 92 }
823}
824",
825        );
826    }
827
828    #[test]
829    fn test_not_applicable_if_variable_unused() {
830        cov_mark::check!(test_not_applicable_if_variable_unused);
831        check_assist_not_applicable(
832            inline_local_variable,
833            r"
834fn foo() {
835    let $0a = 0;
836}
837            ",
838        )
839    }
840
841    #[test]
842    fn not_applicable_outside_of_bind_pat() {
843        cov_mark::check!(not_applicable_outside_of_bind_pat);
844        check_assist_not_applicable(
845            inline_local_variable,
846            r"
847fn main() {
848    let x = $01 + 2;
849    x * 4;
850}
851",
852        )
853    }
854
855    #[test]
856    fn works_on_local_usage() {
857        check_assist(
858            inline_local_variable,
859            r#"
860fn f() {
861    let xyz = 0;
862    xyz$0;
863}
864"#,
865            r#"
866fn f() {
867    0;
868}
869"#,
870        );
871    }
872
873    #[test]
874    fn let_expr_works_on_local_usage() {
875        check_assist(
876            inline_local_variable,
877            r#"
878fn f() {
879    if let xyz = 0
880        && true
881    {
882        xyz$0;
883    }
884}
885"#,
886            r#"
887fn f() {
888    if true
889    {
890        0;
891    }
892}
893"#,
894        );
895
896        check_assist(
897            inline_local_variable,
898            r#"
899fn f() {
900    if let xyz = true
901        && xyz$0
902    {
903    }
904}
905"#,
906            r#"
907fn f() {
908    if true
909    {
910    }
911}
912"#,
913        );
914
915        check_assist(
916            inline_local_variable,
917            r#"
918fn f() {
919    if true
920        && let xyz = 0
921    {
922        xyz$0;
923    }
924}
925"#,
926            r#"
927fn f() {
928    if true
929    {
930        0;
931    }
932}
933"#,
934        );
935    }
936
937    #[test]
938    fn does_not_remove_let_when_multiple_usages() {
939        check_assist(
940            inline_local_variable,
941            r#"
942fn f() {
943    let xyz = 0;
944    xyz$0;
945    xyz;
946}
947"#,
948            r#"
949fn f() {
950    let xyz = 0;
951    0;
952    xyz;
953}
954"#,
955        );
956    }
957
958    #[test]
959    fn not_applicable_with_non_ident_pattern() {
960        check_assist_not_applicable(
961            inline_local_variable,
962            r#"
963fn main() {
964    let (x, y) = (0, 1);
965    x$0;
966}
967"#,
968        );
969    }
970
971    #[test]
972    fn not_applicable_on_local_usage_in_macro() {
973        check_assist_not_applicable(
974            inline_local_variable,
975            r#"
976macro_rules! m {
977    ($i:ident) => { $i }
978}
979fn f() {
980    let xyz = 0;
981    m!(xyz$0); // replacing it would break the macro
982}
983"#,
984        );
985        check_assist_not_applicable(
986            inline_local_variable,
987            r#"
988macro_rules! m {
989    ($i:ident) => { $i }
990}
991fn f() {
992    let xyz$0 = 0;
993    m!(xyz); // replacing it would break the macro
994}
995"#,
996        );
997    }
998
999    #[test]
1000    fn test_not_inline_selection_too_broad() {
1001        cov_mark::check!(test_not_inline_selection_too_broad);
1002        check_assist_not_applicable(
1003            inline_local_variable,
1004            r#"
1005fn f() {
1006    let foo = 0;
1007    let bar = 0;
1008    $0foo + bar$0;
1009}
1010"#,
1011        );
1012    }
1013
1014    #[test]
1015    fn test_inline_ref_in_let() {
1016        check_assist(
1017            inline_local_variable,
1018            r#"
1019fn f() {
1020    let x = {
1021        let y = 0;
1022        y$0
1023    };
1024}
1025"#,
1026            r#"
1027fn f() {
1028    let x = {
1029        0
1030    };
1031}
1032"#,
1033        );
1034    }
1035
1036    #[test]
1037    fn test_inline_let_unit_struct() {
1038        check_assist_not_applicable(
1039            inline_local_variable,
1040            r#"
1041struct S;
1042fn f() {
1043    let S$0 = S;
1044    S;
1045}
1046"#,
1047        );
1048    }
1049
1050    #[test]
1051    fn test_inline_closure() {
1052        check_assist(
1053            inline_local_variable,
1054            r#"
1055//- minicore: fn
1056fn main() {
1057    let $0f = || 2;
1058    let _ = f();
1059}
1060"#,
1061            r#"
1062fn main() {
1063    let _ = (|| 2)();
1064}
1065"#,
1066        );
1067    }
1068
1069    #[test]
1070    fn test_wrap_in_parens() {
1071        check_assist(
1072            inline_local_variable,
1073            r#"
1074fn main() {
1075    let $0a = 123 < 456;
1076    let b = !a;
1077}
1078"#,
1079            r#"
1080fn main() {
1081    let b = !(123 < 456);
1082}
1083"#,
1084        );
1085        check_assist(
1086            inline_local_variable,
1087            r#"
1088trait Foo {
1089    fn foo(&self);
1090}
1091
1092impl Foo for bool {
1093    fn foo(&self) {}
1094}
1095
1096fn main() {
1097    let $0a = 123 < 456;
1098    let b = a.foo();
1099}
1100"#,
1101            r#"
1102trait Foo {
1103    fn foo(&self);
1104}
1105
1106impl Foo for bool {
1107    fn foo(&self) {}
1108}
1109
1110fn main() {
1111    let b = (123 < 456).foo();
1112}
1113"#,
1114        );
1115    }
1116}