Skip to content

Commit b9bdde6

Browse files
committed
Adding testcases
1 parent aba72d9 commit b9bdde6

14 files changed

Lines changed: 162 additions & 37 deletions

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

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,10 @@ renameProvider state pluginId (RenameParams _prog (TextDocumentIdentifier uri) p
142142
-- Perform rename
143143
let newName = mkTcOcc $ T.unpack newNameText
144144
filesRefs = collectWith locToUri refs
145+
oldOccNames = HS.fromList $ map nameOccName oldNames
145146
getFileEdit (uri, locations) = do
146147
verTxtDocId <- liftIO $ runAction "rename: getVersionedTextDoc" state $ getVersionedTextDoc (TextDocumentIdentifier uri)
147-
getSrcEdit state verTxtDocId (replaceRefs newName locations)
148+
getSrcEdit state verTxtDocId (replaceRefs newName locations oldOccNames)
148149
fileEdits <- mapM getFileEdit filesRefs
149150
pure $ InL $ fold fileEdits
150151

@@ -214,10 +215,10 @@ getSrcEdit state verTxtDocId updatePs = do
214215
replaceRefs ::
215216
OccName ->
216217
HashSet Location ->
218+
HashSet OccName ->
217219
ParsedSource ->
218220
ParsedSource
219-
replaceRefs newName refs = everywhere $
220-
-- there has to be a better way...
221+
replaceRefs newName refs oldOccNames = everywhere $
221222
mkT (replaceLoc @AnnListItem) `extT`
222223
-- replaceLoc @AnnList `extT` -- not needed
223224
-- replaceLoc @AnnParen `extT` -- not needed
@@ -228,8 +229,11 @@ replaceRefs newName refs = everywhere $
228229
where
229230
replaceLoc :: forall an. LocatedAn an RdrName -> LocatedAn an RdrName
230231
replaceLoc (L srcSpan oldRdrName)
231-
| isRef (locA srcSpan) = L srcSpan $ replace oldRdrName
232+
| isRef (locA srcSpan)
233+
, isTarget oldRdrName
234+
= L srcSpan $ replace oldRdrName
232235
replaceLoc lOldRdrName = lOldRdrName
236+
233237
replace :: RdrName -> RdrName
234238
replace (Qual modName _) = Qual modName newName
235239
replace _ = Unqual newName
@@ -239,6 +243,10 @@ replaceRefs newName refs = everywhere $
239243
Just loc -> loc `HS.member` refs
240244
Nothing -> False
241245

246+
-- Only replace RdrNames whose OccName matches a rename target, preventing
247+
-- co-located field selectors from being incorrectly renamed.
248+
isTarget :: RdrName -> Bool
249+
isTarget rdrName = rdrNameOcc rdrName `HS.member` oldOccNames
242250
---------------------------------------------------------------------------------------------------
243251
-- Reference finding
244252

@@ -250,38 +258,23 @@ refsAtName ::
250258
Name ->
251259
ExceptT PluginError m [Location]
252260
refsAtName state nfp targetName = do
253-
-- Get local references from current file's HieAST
254-
ast <- handleGetHieAst state nfp
255-
let localRefs = nameLocs targetName ast
256-
257-
-- Query HieDb for global matches (by OccName)
258-
ShakeExtras{withHieDb} <- liftIO $ runAction "Rename.HieDb" state getShakeExtras
259-
dbCandidates <- liftIO $ withHieDb $ \hieDb ->
260-
fmap (mapMaybe rowToLoc) $
261-
case nameModule_maybe targetName of
262-
Just mod -> findReferences hieDb True (nameOccName targetName) (Just $ moduleName mod) (Just $ moduleUnit mod) []
263-
Nothing -> findReferences hieDb True (nameOccName targetName) Nothing Nothing []
264-
265-
-- Filter candidates by exact Name identity
266-
filteredDbRefs <- filterM (matchesExactName state targetName) dbCandidates
267-
pure $ localRefs ++ filteredDbRefs
268-
269-
matchesExactName ::
270-
MonadIO m =>
271-
IdeState ->
272-
Name ->
273-
Location ->
274-
ExceptT PluginError m Bool
275-
matchesExactName state targetName loc = do
276-
(file, pos) <- locToFilePos loc
277-
namesAtPos <- getNamesAtPos state file pos
278-
pure $ targetName `elem` namesAtPos
279-
280-
nameLocs :: Name -> HieAstResult -> [Location]
281-
nameLocs name (HAR _ _ rm _ _) =
282-
concatMap (map (realSrcSpanToLocation . fst))
283-
(M.lookup (Right name) rm)
284-
261+
HAR{refMap} <- handleGetHieAst state nfp
262+
263+
let localRefs =
264+
case M.lookup (Right targetName) refMap of
265+
Nothing -> []
266+
Just spans -> [ realSrcSpanToLocation sp | (sp, _) <- spans]
267+
268+
-- Only query HieDb if it's a global name
269+
globalRefs <-
270+
case nameModule_maybe targetName of
271+
Nothing -> pure []
272+
Just mod -> do
273+
ShakeExtras{withHieDb} <- liftIO $ runAction "Rename.HieDb" state getShakeExtras
274+
liftIO $ withHieDb $ \hieDb ->
275+
fmap (mapMaybe rowToLoc) $ findReferences hieDb True (nameOccName targetName) (Just $ moduleName mod) (Just $ moduleUnit mod) []
276+
277+
pure (localRefs ++ globalRefs)
285278
---------------------------------------------------------------------------------------------------
286279
-- Util
287280

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

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,78 @@ tests = testGroup "Rename"
111111

112112
-- Make sure renaming succeeds
113113
rename doc (Position 3 0) "foo'"
114+
, goldenWithCrossModuleRename True "Cross Module (Declaration)" "CrossMaster" "CrossFunctionClient" (Position 2 2) "fooRenamed"
115+
, goldenWithCrossModuleRename True "Cross Module (Referenced)" "CrossFunctionClient" "CrossMaster" (Position 4 11) "crossfooRenamed"
116+
, goldenWithCrossModuleRename True "Cross Module Qualified (Declaration)" "CrossMaster" "CrossQualifiedClient" (Position 2 2) "newFoo"
117+
, goldenWithCrossModuleRename True "Cross Module Qualified (Referenced)" "CrossQualifiedClient" "CrossMaster" (Position 4 22) "crossfooRenamed"
118+
, goldenWithCrossModuleSession True "Cross Error : No export list" "CrossMasterTwo" "CrossFunctionClientTwo" $ \masterDoc _clientDoc -> do
119+
let expectedError = TResponseError
120+
(InR ErrorCodes_InvalidParams)
121+
"rename: Invalid Params: Cannot rename symbol: module has no explicit export list and the symbol is referenced from other modules."
122+
Nothing
123+
124+
renameExpectError expectedError masterDoc (Position 2 0) "ImpossibleRename"
125+
, goldenWithCrossModuleSession False "Cross Error : Cross Moduel disabled" "CrossMaster" "CrossFunctionError" $ \masterDoc _clientDoc -> do
126+
let expectedError = TResponseError
127+
(InR ErrorCodes_InternalError)
128+
"rename: Internal Error: Cross-module rename is disabled."
129+
Nothing
130+
131+
renameExpectError expectedError masterDoc (Position 2 0) "ImpossibleRename"
114132
]
115133

116134
goldenWithRename :: TestName-> FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree
117135
goldenWithRename title path act =
118136
goldenWithHaskellDoc (def { plugins = M.fromList [("rename", def { plcConfig = "crossModule" .= True })] })
119-
renamePlugin title testDataDir path "expected" "hs" act
137+
renamePlugin title testDataDir path "expected" "hs"
138+
$ \_ -> do
139+
doc <- openDoc (path <.> "hs") "haskell"
140+
_ <- getDocumentSymbols doc
141+
_ <- waitForBuildQueue
142+
act doc
143+
144+
goldenWithCrossModuleRename :: Bool -> TestName -> FilePath -> FilePath -> Position -> String -> TestTree
145+
goldenWithCrossModuleRename crossModuleEnabled title primaryFile secondaryFile pos newName =
146+
goldenWithHaskellDoc
147+
(def { plugins = M.fromList [("rename", def { plcConfig = "crossModule" .= crossModuleEnabled })] })
148+
renamePlugin
149+
title
150+
testDataDir
151+
secondaryFile
152+
"expected"
153+
"hs"
154+
$ \_ -> do
155+
156+
primaryDoc <- openDoc (primaryFile <.> "hs") "haskell"
157+
secondaryDoc <- openDoc (secondaryFile <.> "hs") "haskell"
158+
159+
_ <- getDocumentSymbols primaryDoc
160+
_ <- getDocumentSymbols secondaryDoc
161+
_ <- waitForBuildQueue
162+
163+
164+
rename primaryDoc pos newName
165+
166+
goldenWithCrossModuleSession :: Bool -> TestName -> FilePath -> FilePath -> (TextDocumentIdentifier -> TextDocumentIdentifier -> Session ()) -> TestTree
167+
goldenWithCrossModuleSession crossModuleEnabled title primaryFile secondaryFile action =
168+
goldenWithHaskellDoc
169+
(def { plugins = M.fromList [("rename", def { plcConfig = "crossModule" .= crossModuleEnabled })] })
170+
renamePlugin
171+
title
172+
testDataDir
173+
secondaryFile
174+
"expected"
175+
"hs"
176+
$ \_ -> do
177+
178+
primaryDoc <- openDoc (primaryFile <.> "hs") "haskell"
179+
secondaryDoc <- openDoc (secondaryFile <.> "hs") "haskell"
180+
181+
_ <- getDocumentSymbols primaryDoc
182+
_ <- getDocumentSymbols secondaryDoc
183+
_ <- waitForBuildQueue
184+
185+
action primaryDoc secondaryDoc
120186

121187
renameExpectError :: TResponseError Method_TextDocumentRename -> TextDocumentIdentifier -> Position -> Text -> Session ()
122188
renameExpectError expectedError doc pos newName = do
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionClient where
2+
3+
import CrossMaster
4+
5+
bar = fooRenamed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionClient where
2+
3+
import CrossMaster
4+
5+
bar = crossfoo
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionClientTwo where
2+
3+
import CrossMasterTwo
4+
5+
bar = crossfooTwo
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionClientTwo where
2+
3+
import CrossMasterTwo
4+
5+
bar = crossfooTwo
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionError where
2+
3+
import CrossMaster
4+
5+
bar = crossfoo
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module CrossFunctionError where
2+
3+
import CrossMaster
4+
5+
bar = crossfoo
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module CrossMaster (crossfooRenamed) where
2+
3+
crossfooRenamed :: Int
4+
crossfooRenamed = 42
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module CrossMaster (crossfoo) where
2+
3+
crossfoo :: Int
4+
crossfoo = 42

0 commit comments

Comments
 (0)