@@ -6,7 +6,7 @@ use hir::{Documentation, HasAttrs};
66use ide_db:: { imports:: insert_use:: ImportScope , ty_filter:: TryEnum , SnippetCap } ;
77use syntax:: {
88 ast:: { self , make, AstNode , AstToken } ,
9- SyntaxKind :: { EXPR_STMT , STMT_LIST } ,
9+ SyntaxKind :: { BLOCK_EXPR , EXPR_STMT , FOR_EXPR , IF_EXPR , LOOP_EXPR , STMT_LIST , WHILE_EXPR } ,
1010 TextRange , TextSize ,
1111} ;
1212use text_edit:: TextEdit ;
@@ -123,6 +123,22 @@ pub(crate) fn complete_postfix(
123123 postfix_snippet ( "ref" , "&expr" , & format ! ( "&{receiver_text}" ) ) . add_to ( acc) ;
124124 postfix_snippet ( "refm" , "&mut expr" , & format ! ( "&mut {receiver_text}" ) ) . add_to ( acc) ;
125125
126+ let mut unsafe_should_be_wrapped = true ;
127+ if dot_receiver. syntax ( ) . kind ( ) == BLOCK_EXPR {
128+ unsafe_should_be_wrapped = false ;
129+ if let Some ( parent) = dot_receiver. syntax ( ) . parent ( ) {
130+ if matches ! ( parent. kind( ) , IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR ) {
131+ unsafe_should_be_wrapped = true ;
132+ }
133+ }
134+ } ;
135+ let unsafe_completion_string = if unsafe_should_be_wrapped {
136+ format ! ( "unsafe {{ {receiver_text} }}" )
137+ } else {
138+ format ! ( "unsafe {receiver_text}" )
139+ } ;
140+ postfix_snippet ( "unsafe" , "unsafe {}" , & unsafe_completion_string) . add_to ( acc) ;
141+
126142 // The rest of the postfix completions create an expression that moves an argument,
127143 // so it's better to consider references now to avoid breaking the compilation
128144
@@ -329,18 +345,19 @@ fn main() {
329345}
330346"# ,
331347 expect ! [ [ r#"
332- sn box Box::new(expr)
333- sn call function(expr)
334- sn dbg dbg!(expr)
335- sn dbgr dbg!(&expr)
336- sn if if expr {}
337- sn let let
338- sn letm let mut
339- sn match match expr {}
340- sn not !expr
341- sn ref &expr
342- sn refm &mut expr
343- sn while while expr {}
348+ sn box Box::new(expr)
349+ sn call function(expr)
350+ sn dbg dbg!(expr)
351+ sn dbgr dbg!(&expr)
352+ sn if if expr {}
353+ sn let let
354+ sn letm let mut
355+ sn match match expr {}
356+ sn not !expr
357+ sn ref &expr
358+ sn refm &mut expr
359+ sn unsafe unsafe {}
360+ sn while while expr {}
344361 "# ] ] ,
345362 ) ;
346363 }
@@ -359,16 +376,17 @@ fn main() {
359376}
360377"# ,
361378 expect ! [ [ r#"
362- sn box Box::new(expr)
363- sn call function(expr)
364- sn dbg dbg!(expr)
365- sn dbgr dbg!(&expr)
366- sn if if expr {}
367- sn match match expr {}
368- sn not !expr
369- sn ref &expr
370- sn refm &mut expr
371- sn while while expr {}
379+ sn box Box::new(expr)
380+ sn call function(expr)
381+ sn dbg dbg!(expr)
382+ sn dbgr dbg!(&expr)
383+ sn if if expr {}
384+ sn match match expr {}
385+ sn not !expr
386+ sn ref &expr
387+ sn refm &mut expr
388+ sn unsafe unsafe {}
389+ sn while while expr {}
372390 "# ] ] ,
373391 ) ;
374392 }
@@ -383,15 +401,16 @@ fn main() {
383401}
384402"# ,
385403 expect ! [ [ r#"
386- sn box Box::new(expr)
387- sn call function(expr)
388- sn dbg dbg!(expr)
389- sn dbgr dbg!(&expr)
390- sn let let
391- sn letm let mut
392- sn match match expr {}
393- sn ref &expr
394- sn refm &mut expr
404+ sn box Box::new(expr)
405+ sn call function(expr)
406+ sn dbg dbg!(expr)
407+ sn dbgr dbg!(&expr)
408+ sn let let
409+ sn letm let mut
410+ sn match match expr {}
411+ sn ref &expr
412+ sn refm &mut expr
413+ sn unsafe unsafe {}
395414 "# ] ] ,
396415 )
397416 }
@@ -406,18 +425,19 @@ fn main() {
406425}
407426"# ,
408427 expect ! [ [ r#"
409- sn box Box::new(expr)
410- sn call function(expr)
411- sn dbg dbg!(expr)
412- sn dbgr dbg!(&expr)
413- sn if if expr {}
414- sn let let
415- sn letm let mut
416- sn match match expr {}
417- sn not !expr
418- sn ref &expr
419- sn refm &mut expr
420- sn while while expr {}
428+ sn box Box::new(expr)
429+ sn call function(expr)
430+ sn dbg dbg!(expr)
431+ sn dbgr dbg!(&expr)
432+ sn if if expr {}
433+ sn let let
434+ sn letm let mut
435+ sn match match expr {}
436+ sn not !expr
437+ sn ref &expr
438+ sn refm &mut expr
439+ sn unsafe unsafe {}
440+ sn while while expr {}
421441 "# ] ] ,
422442 ) ;
423443 }
@@ -517,6 +537,49 @@ fn main() {
517537 )
518538 }
519539
540+ #[ test]
541+ fn postfix_completion_for_unsafe ( ) {
542+ check_edit ( "unsafe" , r#"fn main() { foo.$0 }"# , r#"fn main() { unsafe { foo } }"# ) ;
543+ check_edit ( "unsafe" , r#"fn main() { { foo }.$0 }"# , r#"fn main() { unsafe { foo } }"# ) ;
544+ check_edit (
545+ "unsafe" ,
546+ r#"fn main() { if x { foo }.$0 }"# ,
547+ r#"fn main() { unsafe { if x { foo } } }"# ,
548+ ) ;
549+ check_edit (
550+ "unsafe" ,
551+ r#"fn main() { loop { foo }.$0 }"# ,
552+ r#"fn main() { unsafe { loop { foo } } }"# ,
553+ ) ;
554+ check_edit (
555+ "unsafe" ,
556+ r#"fn main() { if true {}.$0 }"# ,
557+ r#"fn main() { unsafe { if true {} } }"# ,
558+ ) ;
559+ check_edit (
560+ "unsafe" ,
561+ r#"fn main() { while true {}.$0 }"# ,
562+ r#"fn main() { unsafe { while true {} } }"# ,
563+ ) ;
564+ check_edit (
565+ "unsafe" ,
566+ r#"fn main() { for i in 0..10 {}.$0 }"# ,
567+ r#"fn main() { unsafe { for i in 0..10 {} } }"# ,
568+ ) ;
569+ check_edit (
570+ "unsafe" ,
571+ r#"fn main() { let x = if true {1} else {2}.$0 }"# ,
572+ r#"fn main() { let x = unsafe { if true {1} else {2} } }"# ,
573+ ) ;
574+
575+ // completion will not be triggered
576+ check_edit (
577+ "unsafe" ,
578+ r#"fn main() { let x = true else {panic!()}.$0}"# ,
579+ r#"fn main() { let x = true else {panic!()}.unsafe}"# ,
580+ ) ;
581+ }
582+
520583 #[ test]
521584 fn custom_postfix_completion ( ) {
522585 let config = CompletionConfig {
0 commit comments