Skip to content

Commit 0eb79a4

Browse files
author
Zdeno Osina
authored
Fix action removes ticks from TemplateHaskellQuotes (#628) (#3260)
1 parent 4898f5b commit 0eb79a4

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

plugins/hls-refactor-plugin/src/Development/IDE/Plugin/CodeAction.hs

+35-7
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,13 @@ suggestAddTypeAnnotationToSatisfyContraints sourceOpt Diagnostic{_range=_range,.
839839
in [( title, edits )]
840840

841841

842-
suggestReplaceIdentifier :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
843-
suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
842+
-- | GHC strips out backticks in case of infix functions as well as single quote
843+
-- in case of quoted name when using TemplateHaskellQuotes. Which is not desired.
844+
--
845+
-- For example:
846+
-- 1.
847+
--
848+
-- @
844849
-- File.hs:52:41: error:
845850
-- * Variable not in scope:
846851
-- suggestAcion :: Maybe T.Text -> Range -> Range
@@ -852,6 +857,27 @@ suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
852857
-- ‘T.isInfixOf’ (imported from Data.Text),
853858
-- ‘T.isSuffixOf’ (imported from Data.Text)
854859
-- Module ‘Data.Text’ does not export ‘isPrfixOf’.
860+
-- @
861+
--
862+
-- * action: \`suggestAcion\` will be renamed to \`suggestAction\` keeping back ticks around the function
863+
--
864+
-- 2.
865+
--
866+
-- @
867+
-- import Language.Haskell.TH (Name)
868+
-- foo :: Name
869+
-- foo = 'bread
870+
--
871+
-- File.hs:8:7: error:
872+
-- Not in scope: ‘bread’
873+
-- * Perhaps you meant one of these:
874+
-- ‘break’ (imported from Prelude), ‘read’ (imported from Prelude)
875+
-- * In the Template Haskell quotation 'bread
876+
-- @
877+
--
878+
-- * action: 'bread will be renamed to 'break keeping single quote on beginning of name
879+
suggestReplaceIdentifier :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
880+
suggestReplaceIdentifier contents Diagnostic{_range=_range,..}
855881
| renameSuggestions@(_:_) <- extractRenamableTerms _message
856882
= [ ("Replace with ‘" <> name <> "", [mkRenameEdit contents _range name]) | name <- renameSuggestions ]
857883
| otherwise = []
@@ -1771,15 +1797,17 @@ extractDoesNotExportModuleName x
17711797

17721798

17731799
mkRenameEdit :: Maybe T.Text -> Range -> T.Text -> TextEdit
1774-
mkRenameEdit contents range name =
1775-
if maybeIsInfixFunction == Just True
1776-
then TextEdit range ("`" <> name <> "`")
1777-
else TextEdit range name
1800+
mkRenameEdit contents range name
1801+
| maybeIsInfixFunction == Just True = TextEdit range ("`" <> name <> "`")
1802+
| maybeIsTemplateFunction == Just True = TextEdit range ("'" <> name)
1803+
| otherwise = TextEdit range name
17781804
where
17791805
maybeIsInfixFunction = do
17801806
curr <- textInRange range <$> contents
17811807
pure $ "`" `T.isPrefixOf` curr && "`" `T.isSuffixOf` curr
1782-
1808+
maybeIsTemplateFunction = do
1809+
curr <- textInRange range <$> contents
1810+
pure $ "'" `T.isPrefixOf` curr
17831811

17841812
-- | Extract the type and surround it in parentheses except in obviously safe cases.
17851813
--

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

+22
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,28 @@ renameActionTests = testGroup "rename actions"
609609
, "foo x y = x `monus` y"
610610
]
611611
liftIO $ expectedContentAfterAction @=? contentAfterAction
612+
, testSession "change template function" $ do
613+
let content = T.unlines
614+
[ "{-# LANGUAGE TemplateHaskellQuotes #-}"
615+
, "module Testing where"
616+
, "import Language.Haskell.TH (Name)"
617+
, "foo :: Name"
618+
, "foo = 'bread"
619+
]
620+
doc <- createDoc "Testing.hs" "haskell" content
621+
diags <- waitForDiagnostics
622+
actionsOrCommands <- getCodeActions doc (Range (Position 4 6) (Position 4 12))
623+
[fixTypo] <- pure [action | InR action@CodeAction{ _title = actionTitle } <- actionsOrCommands, "break" `T.isInfixOf` actionTitle ]
624+
executeCodeAction fixTypo
625+
contentAfterAction <- documentContents doc
626+
let expectedContentAfterAction = T.unlines
627+
[ "{-# LANGUAGE TemplateHaskellQuotes #-}"
628+
, "module Testing where"
629+
, "import Language.Haskell.TH (Name)"
630+
, "foo :: Name"
631+
, "foo = 'break"
632+
]
633+
liftIO $ expectedContentAfterAction @=? contentAfterAction
612634
]
613635

614636
typeWildCardActionTests :: TestTree

0 commit comments

Comments
 (0)