Skip to content

Commit fd01d20

Browse files
authored
Fix add suggested import for operators (#428)
1 parent 71ecd10 commit fd01d20

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

src/Development/IDE/GHC/Util.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Development.IDE.GHC.Util(
99
runGhcEnv,
1010
-- * GHC wrappers
1111
prettyPrint,
12+
ParseResult(..), runParser,
1213
lookupPackageConfig,
1314
moduleImportPath,
1415
cgGutsToCoreModule,
@@ -47,6 +48,7 @@ import qualified Data.Text as T
4748
import qualified Data.Text.Encoding as T
4849
import qualified Data.Text.Encoding.Error as T
4950
import qualified Data.ByteString as BS
51+
import Lexer
5052
import StringBuffer
5153
import System.FilePath
5254

@@ -82,6 +84,13 @@ lookupPackageConfig unitId env =
8284
textToStringBuffer :: T.Text -> StringBuffer
8385
textToStringBuffer = stringToStringBuffer . T.unpack
8486

87+
runParser :: DynFlags -> String -> P a -> ParseResult a
88+
runParser flags str parser = unP parser parseState
89+
where
90+
filename = "<interactive>"
91+
location = mkRealSrcLoc (mkFastString filename) 1 1
92+
buffer = stringToStringBuffer str
93+
parseState = mkPState flags buffer location
8594

8695
-- | Pretty print a GHC value using 'unsafeGlobalDynFlags '.
8796
prettyPrint :: Outputable a => a -> String

src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Development.IDE.Core.RuleTypes
1717
import Development.IDE.Core.Service
1818
import Development.IDE.Core.Shake
1919
import Development.IDE.GHC.Error
20+
import Development.IDE.GHC.Util
2021
import Development.IDE.LSP.Server
2122
import Development.IDE.Types.Location
2223
import Development.IDE.Types.Options
@@ -32,9 +33,13 @@ import Data.Maybe
3233
import Data.List.Extra
3334
import qualified Data.Text as T
3435
import Data.Tuple.Extra ((&&&))
36+
import HscTypes
37+
import OccName
38+
import Parser
39+
import RdrName
3540
import Text.Regex.TDFA ((=~), (=~~))
3641
import Text.Regex.TDFA.Text()
37-
import Outputable (ppr, showSDocUnsafe)
42+
import Outputable (showSDoc, ppr, showSDocUnsafe)
3843
import DynFlags (xFlags, FlagSpec(..))
3944
import GHC.LanguageExtensions.Type (Extension)
4045

@@ -54,12 +59,15 @@ codeAction lsp state (TextDocumentIdentifier uri) _range CodeActionContext{_diag
5459
-- logInfo (ideLogger ide) $ T.pack $ "Code action req: " ++ show arg
5560
contents <- LSP.getVirtualFileFunc lsp $ toNormalizedUri uri
5661
let text = Rope.toText . (_text :: VirtualFile -> Rope.Rope) <$> contents
57-
(ideOptions, parsedModule) <- runAction state $
58-
(,) <$> getIdeOptions
59-
<*> (getParsedModule . toNormalizedFilePath) `traverse` uriToFilePath uri
62+
mbFile = toNormalizedFilePath <$> uriToFilePath uri
63+
(ideOptions, parsedModule, env) <- runAction state $
64+
(,,) <$> getIdeOptions
65+
<*> getParsedModule `traverse` mbFile
66+
<*> use_ GhcSession `traverse` mbFile
67+
let dflags = hsc_dflags . hscEnv <$> env
6068
pure $ Right
6169
[ CACodeAction $ CodeAction title (Just CodeActionQuickFix) (Just $ List [x]) (Just edit) Nothing
62-
| x <- xs, (title, tedit) <- suggestAction ideOptions ( join parsedModule ) text x
70+
| x <- xs, (title, tedit) <- suggestAction dflags ideOptions ( join parsedModule ) text x
6371
, let edit = WorkspaceEdit (Just $ Map.singleton uri $ List tedit) Nothing
6472
]
6573

@@ -98,10 +106,10 @@ executeAddSignatureCommand _lsp _ideState ExecuteCommandParams{..}
98106
| otherwise
99107
= return (Null, Nothing)
100108

101-
suggestAction :: IdeOptions -> Maybe ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
102-
suggestAction ideOptions parsedModule text diag = concat
109+
suggestAction :: Maybe DynFlags -> IdeOptions -> Maybe ParsedModule -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
110+
suggestAction dflags ideOptions parsedModule text diag = concat
103111
[ suggestAddExtension diag
104-
, suggestExtendImport text diag
112+
, suggestExtendImport dflags text diag
105113
, suggestFillHole diag
106114
, suggestFillTypeWildcard diag
107115
, suggestFixConstructorImport text diag
@@ -268,20 +276,23 @@ suggestFillHole Diagnostic{_range=_range,..}
268276

269277
| otherwise = []
270278

271-
suggestExtendImport :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
272-
suggestExtendImport contents Diagnostic{_range=_range,..}
279+
suggestExtendImport :: Maybe DynFlags -> Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
280+
suggestExtendImport (Just dflags) contents Diagnostic{_range=_range,..}
273281
| Just [binding, mod, srcspan] <-
274282
matchRegex _message
275283
"Perhaps you want to add ‘([^’]*)’ to the import list in the import of ‘([^’]*)’ *\\((.*)\\).$"
276284
, Just c <- contents
285+
, POk _ (L _ name) <- runParser dflags (T.unpack binding) parseIdentifier
277286
= let range = case [ x | (x,"") <- readSrcSpan (T.unpack srcspan)] of
278287
[s] -> let x = srcSpanToRange s
279288
in x{_end = (_end x){_character = succ (_character (_end x))}}
280289
_ -> error "bug in srcspan parser"
281290
importLine = textInRange range c
291+
printedName = let rn = rdrNameOcc name in showSDoc dflags $ parenSymOcc rn (ppr rn)
282292
in [("Add " <> binding <> " to the import list of " <> mod
283-
, [TextEdit range (addBindingToImportList binding importLine)])]
293+
, [TextEdit range (addBindingToImportList (T.pack printedName) importLine)])]
284294
| otherwise = []
295+
suggestExtendImport Nothing _ _ = []
285296

286297
suggestFixConstructorImport :: Maybe T.Text -> Diagnostic -> [(T.Text, [TextEdit])]
287298
suggestFixConstructorImport _ Diagnostic{_range=_range,..}

test/exe/Main.hs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,26 @@ extendImportTests = testGroup "extend import actions"
752752
, "import ModuleA as A (stuffA, stuffB)"
753753
, "main = print (stuffA, stuffB)"
754754
])
755+
, testSession "extend single line import with operator" $ template
756+
(T.unlines
757+
[ "module ModuleA where"
758+
, "(.*) :: Integer -> Integer -> Integer"
759+
, "x .* y = x * y"
760+
, "stuffB :: Integer"
761+
, "stuffB = 123"
762+
])
763+
(T.unlines
764+
[ "module ModuleB where"
765+
, "import ModuleA as A (stuffB)"
766+
, "main = print (stuffB .* stuffB)"
767+
])
768+
(Range (Position 3 17) (Position 3 18))
769+
"Add .* to the import list of ModuleA"
770+
(T.unlines
771+
[ "module ModuleB where"
772+
, "import ModuleA as A ((.*), stuffB)"
773+
, "main = print (stuffB .* stuffB)"
774+
])
755775
, testSession "extend single line import with type" $ template
756776
(T.unlines
757777
[ "module ModuleA where"

0 commit comments

Comments
 (0)