@@ -260,6 +260,7 @@ var codeActionProducers = [...]codeActionProducer{
260
260
{kind : settings .RefactorRewriteMoveParamLeft , fn : refactorRewriteMoveParamLeft , needPkg : true },
261
261
{kind : settings .RefactorRewriteMoveParamRight , fn : refactorRewriteMoveParamRight , needPkg : true },
262
262
{kind : settings .RefactorRewriteSplitLines , fn : refactorRewriteSplitLines , needPkg : true },
263
+ {kind : settings .RefactorRewriteEliminateDotImport , fn : refactorRewriteEliminateDotImport , needPkg : true },
263
264
264
265
// Note: don't forget to update the allow-list in Server.CodeAction
265
266
// when adding new query operations like GoTest and GoDoc that
@@ -678,6 +679,105 @@ func refactorRewriteSplitLines(ctx context.Context, req *codeActionsRequest) err
678
679
return nil
679
680
}
680
681
682
+ func refactorRewriteEliminateDotImport (ctx context.Context , req * codeActionsRequest ) error {
683
+ // Figure out if the request is placed over a dot import.
684
+ var importSpec * ast.ImportSpec
685
+ for _ , imp := range req .pgf .File .Imports {
686
+ if posRangeContains (imp .Pos (), imp .End (), req .start , req .end ) {
687
+ importSpec = imp
688
+ break
689
+ }
690
+ }
691
+ if importSpec == nil {
692
+ return nil
693
+ }
694
+ if importSpec .Name == nil || importSpec .Name .Name != "." {
695
+ return nil
696
+ }
697
+
698
+ // dotImported package path and its imported name after removing the dot.
699
+ imported := req .pkg .TypesInfo ().PkgNameOf (importSpec ).Imported ()
700
+ newName := imported .Name ()
701
+
702
+ rng , err := req .pgf .PosRange (importSpec .Name .Pos (), importSpec .Path .Pos ())
703
+ if err != nil {
704
+ return err
705
+ }
706
+ // Delete the '.' part of the import.
707
+ edits := []protocol.TextEdit {{
708
+ Range : rng ,
709
+ }}
710
+
711
+ fileScope , ok := req .pkg .TypesInfo ().Scopes [req .pgf .File ]
712
+ if ! ok {
713
+ return nil
714
+ }
715
+
716
+ // Go through each use of the dot imported package, checking its scope for
717
+ // shadowing and calculating an edit to qualify the identifier.
718
+ var stack []ast.Node
719
+ ast .Inspect (req .pgf .File , func (n ast.Node ) bool {
720
+ if n == nil {
721
+ stack = stack [:len (stack )- 1 ] // pop
722
+ return false
723
+ }
724
+ stack = append (stack , n ) // push
725
+
726
+ ident , ok := n .(* ast.Ident )
727
+ if ! ok {
728
+ return true
729
+ }
730
+ // Only keep identifiers that use a symbol from the
731
+ // dot imported package.
732
+ use := req .pkg .TypesInfo ().Uses [ident ]
733
+ if use == nil || use .Pkg () == nil {
734
+ return true
735
+ }
736
+ if use .Pkg () != imported {
737
+ return true
738
+ }
739
+
740
+ // Only qualify unqualified identifiers (due to dot imports).
741
+ // All other references to a symbol imported from another package
742
+ // are nested within a select expression (pkg.Foo, v.Method, v.Field).
743
+ if is [* ast.SelectorExpr ](stack [len (stack )- 2 ]) {
744
+ return true
745
+ }
746
+
747
+ // Make sure that the package name will not be shadowed by something else in scope.
748
+ // If it is then we cannot offer this particular code action.
749
+ //
750
+ // TODO: If the object found in scope is the package imported without a
751
+ // dot, or some builtin not used in the file, the code action could be
752
+ // allowed to go through.
753
+ sc := fileScope .Innermost (ident .Pos ())
754
+ if sc == nil {
755
+ return true
756
+ }
757
+ _ , obj := sc .LookupParent (newName , ident .Pos ())
758
+ if obj != nil {
759
+ return true
760
+ }
761
+
762
+ rng , err := req .pgf .PosRange (ident .Pos (), ident .Pos ()) // sic, zero-width range before ident
763
+ if err != nil {
764
+ return true
765
+ }
766
+ edits = append (edits , protocol.TextEdit {
767
+ Range : rng ,
768
+ NewText : newName + "." ,
769
+ })
770
+
771
+ return true
772
+ })
773
+
774
+ req .addEditAction ("Eliminate dot import" , nil , protocol .DocumentChangeEdit (
775
+ req .fh ,
776
+ edits ,
777
+ ))
778
+ return nil
779
+ }
780
+
681
781
// refactorRewriteJoinLines produces "Join ITEMS into one line" code actions.
682
782
// See [joinLines] for command implementation.
683
783
func refactorRewriteJoinLines (ctx context.Context , req * codeActionsRequest ) error {
0 commit comments