11use hir:: db:: HirDatabase ;
22use ra_syntax:: {
3- ast, AstNode , SyntaxNode , Direction , TextRange ,
3+ ast:: { self , NameOwner } , AstNode , SyntaxNode , Direction , TextRange ,
44 SyntaxKind :: { PATH , PATH_SEGMENT , COLONCOLON , COMMA }
55} ;
66use crate :: assist_ctx:: { AssistCtx , Assist , AssistBuilder } ;
@@ -345,9 +345,9 @@ fn best_action_for_target<'b, 'a: 'b>(
345345 match best_action {
346346 Some ( action) => return action,
347347 None => {
348- // We have no action we no use item was found in container so we find
348+ // We have no action and no UseItem was found in container so we find
349349 // another item and we use it as anchor.
350- // If there are not items, we choose the target path itself as anchor.
350+ // If there are no items, we choose the target path itself as anchor.
351351 let anchor = container
352352 . children ( )
353353 . find_map ( ast:: ModuleItem :: cast)
@@ -480,6 +480,24 @@ fn make_assist_add_nested_import(
480480 }
481481}
482482
483+ fn apply_auto_import < ' a > (
484+ container : & SyntaxNode ,
485+ path : & ast:: Path ,
486+ target : & [ & ' a ast:: PathSegment ] ,
487+ edit : & mut AssistBuilder ,
488+ ) {
489+ let action = best_action_for_target ( container, path, target) ;
490+ make_assist ( & action, target, edit) ;
491+ if let ( Some ( first) , Some ( last) ) = ( target. first ( ) , target. last ( ) ) {
492+ // Here we are assuming the assist will provide a correct use statement
493+ // so we can delete the path qualifier
494+ edit. delete ( TextRange :: from_to (
495+ first. syntax ( ) . range ( ) . start ( ) ,
496+ last. syntax ( ) . range ( ) . start ( ) ,
497+ ) ) ;
498+ }
499+ }
500+
483501pub ( crate ) fn auto_import ( mut ctx : AssistCtx < impl HirDatabase > ) -> Option < Assist > {
484502 let node = ctx. covering_node ( ) ;
485503 let current_file = node. ancestors ( ) . find_map ( ast:: SourceFile :: cast) ?;
@@ -495,18 +513,20 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
495513 return None ;
496514 }
497515
498- ctx. add_action ( format ! ( "import {} in the current file" , fmt_segments( & segments) ) , |edit| {
499- let action = best_action_for_target ( current_file. syntax ( ) , path, & segments) ;
500- make_assist ( & action, segments. as_slice ( ) , edit) ;
501- if let Some ( last_segment) = path. segment ( ) {
502- // Here we are assuming the assist will provide a correct use statement
503- // so we can delete the path qualifier
504- edit. delete ( TextRange :: from_to (
505- path. syntax ( ) . range ( ) . start ( ) ,
506- last_segment. syntax ( ) . range ( ) . start ( ) ,
507- ) ) ;
516+ if let Some ( module) = path. syntax ( ) . ancestors ( ) . find_map ( ast:: Module :: cast) {
517+ if let ( Some ( item_list) , Some ( name) ) = ( module. item_list ( ) , module. name ( ) ) {
518+ ctx. add_action (
519+ format ! ( "import {} in mod {}" , fmt_segments( & segments) , name. text( ) ) ,
520+ |edit| {
521+ apply_auto_import ( item_list. syntax ( ) , path, & segments, edit) ;
522+ } ,
523+ ) ;
508524 }
509- } ) ;
525+ } else {
526+ ctx. add_action ( format ! ( "import {} in the current file" , fmt_segments( & segments) ) , |edit| {
527+ apply_auto_import ( current_file. syntax ( ) , path, & segments, edit) ;
528+ } ) ;
529+ }
510530
511531 ctx. build ( )
512532}
@@ -531,6 +551,21 @@ Debug<|>
531551 ) ;
532552 }
533553
554+ #[ test]
555+ fn test_auto_import_file_add_use_no_anchor_2seg ( ) {
556+ check_assist (
557+ auto_import,
558+ "
559+ std::fmt<|>::Debug
560+ " ,
561+ "
562+ use std::fmt;
563+
564+ fmt<|>::Debug
565+ " ,
566+ ) ;
567+ }
568+
534569 #[ test]
535570 fn test_auto_import_file_add_use ( ) {
536571 check_assist (
@@ -728,4 +763,37 @@ impl foo<|> for Foo {
728763" ,
729764 ) ;
730765 }
766+
767+ #[ test]
768+ fn test_auto_import_not_applicable_in_use ( ) {
769+ check_assist_not_applicable (
770+ auto_import,
771+ "
772+ use std::fmt<|>;
773+ " ,
774+ ) ;
775+ }
776+
777+ #[ test]
778+ fn test_auto_import_file_add_use_no_anchor_in_mod_mod ( ) {
779+ check_assist (
780+ auto_import,
781+ "
782+ mod foo {
783+ mod bar {
784+ std::fmt::Debug<|>
785+ }
786+ }
787+ " ,
788+ "
789+ mod foo {
790+ mod bar {
791+ use std::fmt::Debug;
792+
793+ Debug<|>
794+ }
795+ }
796+ " ,
797+ ) ;
798+ }
731799}
0 commit comments