Skip to content

Commit 9df3d3b

Browse files
author
izuzu
committed
Rename alias in re-exported names
This commit implements renaming an alias in qualified names in the module export list, such as from `module Main (M.isJust) where` to `module Main (Maybe.isJust) where`.
1 parent 42ad67c commit 9df3d3b

6 files changed

Lines changed: 42 additions & 18 deletions

File tree

plugins/hls-rename-plugin/src/Ide/Plugin/Rename.hs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ prepareRenameProvider state _pluginId (PrepareRenameParams (TextDocumentIdentifi
9999
"The module hasn’t yet been parsed. Please wait for indexing to complete and try again."
100100
Just parsed -> do
101101
let hsModule = unLoc $ pm_parsed_source parsed
102+
exports = hsmodExports hsModule
102103
imports = hsmodImports hsModule
103104
hsDecls = hsmodDecls hsModule
104105
maybeAlias <- ImportAlias.resolveAliasAtPos
105-
getNamesAtPos state nfp lspPos codePointPos imports hsDecls
106+
getNamesAtPos state nfp lspPos codePointPos exports imports hsDecls
106107
case maybeAlias of
107108
Just (lspRange, _importAlias) ->
108109
pure $ InL $ PrepareRenameResult $ InL $ lspRange
@@ -134,13 +135,14 @@ renameProvider state pluginId (RenameParams _prog (TextDocumentIdentifier uri) l
134135
"The module hasn’t yet been parsed. Please wait for indexing to complete and try again."
135136
Just parsed -> do
136137
let hsModule = unLoc $ pm_parsed_source parsed
138+
exports = hsmodExports hsModule
137139
imports = hsmodImports hsModule
138140
hsDecls = hsmodDecls hsModule
139141
maybeAlias <- ImportAlias.resolveAliasAtPos
140-
getNamesAtPos state nfp lspPos codePointPos imports hsDecls
142+
getNamesAtPos state nfp lspPos codePointPos exports imports hsDecls
141143
case maybeAlias of
142144
Just (_lspRange, importAlias) -> ImportAlias.aliasBasedRename
143-
state nfp uri importAlias hsDecls newNameText
145+
state nfp uri importAlias exports hsDecls newNameText
144146
Nothing ->
145147
nameBasedRename state pluginId nfp lspPos newNameText
146148

plugins/hls-rename-plugin/src/Ide/Plugin/Rename/ImportAlias.hs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,11 @@ resolveAliasAtPos ::
101101
NormalizedFilePath ->
102102
LSP.Position ->
103103
VFS.CodePointPosition ->
104+
Maybe (XRec GhcPs [LIE GhcPs]) ->
104105
[LImportDecl GhcPs] ->
105106
[LHsDecl GhcPs] ->
106107
ExceptT PluginError m (Maybe (LSP.Range, ImportAlias))
107-
resolveAliasAtPos getNamesAtPosFn state nfp lspPos pos imports hsDecls = do
108+
resolveAliasAtPos getNamesAtPosFn state nfp lspPos pos exports imports hsDecls = do
108109
virtualFile <- runActionE "rename.getVirtualFile" state
109110
$ handleMaybeM (PluginInternalError
110111
("Virtual file not found: " <> T.pack (show nfp)))
@@ -114,7 +115,7 @@ resolveAliasAtPos getNamesAtPosFn state nfp lspPos pos imports hsDecls = do
114115
Just lspRange -> Just (lspRange, alias)
115116
case findAliasDeclAtPos pos imports of
116117
Just alias -> pure $ toLSPRange (aliasDeclRange alias, alias)
117-
Nothing -> case findAliasUseAtPos pos imports hsDecls of
118+
Nothing -> case findAliasUseAtPos pos exports imports hsDecls of
118119
Nothing -> pure Nothing
119120
Just (_, []) -> pure Nothing
120121
Just (range, [alias]) -> pure $ toLSPRange (range, alias)
@@ -134,10 +135,11 @@ aliasBasedRename ::
134135
NormalizedFilePath ->
135136
Uri ->
136137
ImportAlias ->
138+
Maybe (XRec GhcPs [LIE GhcPs]) ->
137139
[LHsDecl GhcPs] ->
138140
T.Text ->
139141
ExceptT PluginError m (MessageResult Method_TextDocumentRename)
140-
aliasBasedRename state nfp uri importAlias hsDecls newNameText = do
142+
aliasBasedRename state nfp uri importAlias exports hsDecls newNameText = do
141143
let ImportAlias{aliasDeclRange, aliasIsShared} = importAlias
142144
virtualFile <- runActionE "rename.getVirtualFile" state
143145
$ handleMaybeM (PluginInternalError
@@ -147,9 +149,9 @@ aliasBasedRename state nfp uri importAlias hsDecls newNameText = do
147149
if aliasIsShared
148150
then do
149151
tcModule <- runActionE "rename.sharedAliasRanges" state $ useE TypeCheck nfp
150-
pure $ aliasUseSiteRangesDisambiguated tcModule importAlias hsDecls
152+
pure $ aliasUseSiteRangesDisambiguated tcModule importAlias exports hsDecls
151153
else
152-
pure $ aliasUseSiteRanges importAlias hsDecls
154+
pure $ aliasUseSiteRanges importAlias exports hsDecls
153155
declEdit <- handleMaybe (PluginInternalError "Alias declaration span is out of range")
154156
$ rangeToTextEdit virtualFile newNameText aliasDeclRange
155157
useEdits <- handleMaybe (PluginInternalError "A use site span is out of range")
@@ -185,12 +187,14 @@ findAliasDeclAtPos pos imports = listToMaybe $ do
185187
-- Returns multiple aliases if multiple modules share the same alias.
186188
findAliasUseAtPos ::
187189
VFS.CodePointPosition ->
190+
Maybe (XRec GhcPs [LIE GhcPs]) ->
188191
[LImportDecl GhcPs] ->
189192
[LHsDecl GhcPs] ->
190193
Maybe (VFS.CodePointRange, [ImportAlias])
191-
findAliasUseAtPos pos imports hsDecls =
194+
findAliasUseAtPos pos exports imports hsDecls =
192195
let qualifiersAtPos = do
193-
locatedRdrName :: XRec GhcPs RdrName <- listify (const True) hsDecls
196+
locatedRdrName :: XRec GhcPs RdrName <-
197+
listify (const True) exports ++ listify (const True) hsDecls
194198
Qual qualifier _ <- [unLoc locatedRdrName]
195199
RealSrcSpan qualifiedNameSpan _ <- [getLoc locatedRdrName]
196200
let qualifiedNameRange = realSrcSpanToCodePointRange qualifiedNameSpan
@@ -217,11 +221,16 @@ findAliasUseAtPos pos imports hsDecls =
217221

218222
-- | Collect the 'CodePointRange' of every qualified use of @importAlias@, such
219223
-- as @L@ in @L.take@, @L.drop@, and so on.
220-
aliasUseSiteRanges :: ImportAlias -> [LHsDecl GhcPs] -> [VFS.CodePointRange]
221-
aliasUseSiteRanges importAlias hsDecls = nubOrd $ do
224+
aliasUseSiteRanges ::
225+
ImportAlias ->
226+
Maybe (XRec GhcPs [LIE GhcPs]) ->
227+
[LHsDecl GhcPs] ->
228+
[VFS.CodePointRange]
229+
aliasUseSiteRanges importAlias exports hsDecls = nubOrd $ do
222230
let ImportAlias{aliasName} = importAlias
223231
aliasLength = fromIntegral (moduleNameLength aliasName)
224-
locatedRdrName :: XRec GhcPs RdrName <- listify (const True) hsDecls
232+
locatedRdrName :: XRec GhcPs RdrName <-
233+
listify (const True) exports ++ listify (const True) hsDecls
225234
Qual qualifier _ <- [unLoc locatedRdrName]
226235
guard (qualifier == aliasName)
227236
RealSrcSpan qualifiedNameSpan _ <- [getLoc locatedRdrName]
@@ -259,13 +268,15 @@ disambiguateAliasUse tcModule namesAtPos candidates = nubOrd $ do
259268
aliasUseSiteRangesDisambiguated ::
260269
TcModuleResult ->
261270
ImportAlias ->
271+
Maybe (XRec GhcPs [LIE GhcPs]) ->
262272
[LHsDecl GhcPs] ->
263273
[VFS.CodePointRange]
264-
aliasUseSiteRangesDisambiguated tcModule importAlias hsDecls = nubOrd $ do
274+
aliasUseSiteRangesDisambiguated tcModule importAlias exports hsDecls = nubOrd $ do
265275
let rdrEnv = tcg_rdr_env (tmrTypechecked tcModule)
266276
ImportAlias{aliasModuleName, aliasName} = importAlias
267277
aliasLength = fromIntegral (moduleNameLength aliasName)
268-
locatedRdrName :: XRec GhcPs RdrName <- listify (const True) hsDecls
278+
locatedRdrName :: XRec GhcPs RdrName <-
279+
listify (const True) exports ++ listify (const True) hsDecls
269280
rdrName@(Qual qualifier name) <- [unLoc locatedRdrName]
270281
guard (qualifier == aliasName)
271282
nameGREElement <- pickGREs rdrName $ lookupGlobalRdrEnv rdrEnv name

plugins/hls-rename-plugin/test/Main.hs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ prepareRenameTests = testGroup "PrepareRename"
5959
resultOutside <- prepareRename doc (Position 10 16)
6060
liftIO $ resultOutside /= expected @? "Cursor is outside qualifier"
6161

62+
, testCase "Import alias in re-export" $ runRenameSession "" $ do
63+
doc <- openDoc "PrepareRename.hs" "haskell"
64+
void waitForBuildQueue
65+
result <- prepareRename doc (Position 0 27)
66+
liftIO $ result @?=
67+
InL (PrepareRenameResult (InL (Range (Position 0 27) (Position 0 28))))
68+
6269
, testCase "Function name" $ runRenameSession "" $ do
6370
doc <- openDoc "PrepareRename.hs" "haskell"
6471
void waitForBuildQueue
@@ -120,9 +127,9 @@ renameTests = testGroup "Identifier"
120127
, goldenWithRename "Import alias at use site" "ImportAlias" $ \doc ->
121128
rename doc (Position 5 10) "G"
122129
, goldenWithRename "Import alias declaration (shared by unrelated imports)" "ImportAliasShared" $ \doc ->
123-
rename doc (Position 1 31) "Maybe"
130+
rename doc (Position 3 31) "Maybe"
124131
, goldenWithRename "Import alias at use site (shared by unrelated imports)" "ImportAliasShared" $ \doc ->
125-
rename doc (Position 4 6) "Maybe"
132+
rename doc (Position 6 6) "Maybe"
126133
, goldenWithRename "Import alias declaration (with re-exports)" "ImportAliasReexport" $ \doc -> do
127134
rename doc (Position 1 18) "Reexport"
128135
, testCase "Import alias at use site (ambiguous due to re-exports)" $ runRenameSession "" $ do

plugins/hls-rename-plugin/test/testdata/ImportAliasShared.expected.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
module ImportAliasShared (Maybe.fromMaybe, M.mapM) where
2+
13
import qualified Control.Monad as M
24
import qualified Data.Maybe as Maybe
35

plugins/hls-rename-plugin/test/testdata/ImportAliasShared.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
module ImportAliasShared (M.fromMaybe, M.mapM) where
2+
13
import qualified Control.Monad as M
24
import qualified Data.Maybe as M
35

plugins/hls-rename-plugin/test/testdata/PrepareRename.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module PrepareRename where
1+
module PrepareRename (bar, F.foo) where
22

33
import qualified Foo as F
44

0 commit comments

Comments
 (0)