Skip to content

Commit 04041b3

Browse files
author
kokobd
committed
fix auto import for ghc version < 9.2
1 parent 8999342 commit 04041b3

File tree

2 files changed

+86
-61
lines changed

2 files changed

+86
-61
lines changed

ghcide/src/Development/IDE/Plugin/CodeAction.hs

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import Control.Arrow (second,
2222
(&&&),
2323
(>>>))
2424
import Control.Concurrent.STM.Stats (atomically)
25-
import Control.Monad (guard, join,
26-
msum)
25+
import Control.Monad (guard, join)
2726
import Control.Monad.IO.Class
2827
import Data.Char
2928
import qualified Data.DList as DL
@@ -34,21 +33,19 @@ import qualified Data.HashSet as Set
3433
import Data.List.Extra
3534
import Data.List.NonEmpty (NonEmpty ((:|)))
3635
import qualified Data.List.NonEmpty as NE
37-
import qualified Data.Map as M
36+
import qualified Data.Map.Strict as M
3837
import Data.Maybe
3938
import Data.Ord (comparing)
4039
import qualified Data.Rope.UTF16 as Rope
4140
import qualified Data.Set as S
4241
import qualified Data.Text as T
4342
import Data.Tuple.Extra (fst3)
44-
import Debug.Trace
4543
import Development.IDE.Core.Rules
4644
import Development.IDE.Core.RuleTypes
4745
import Development.IDE.Core.Service
4846
import Development.IDE.GHC.Compat
4947
import Development.IDE.GHC.Compat.Util
5048
import Development.IDE.GHC.Error
51-
import Development.IDE.GHC.ExactPrint
5249
import Development.IDE.GHC.Util (printOutputable,
5350
printRdrName,
5451
traceAst)
@@ -59,12 +56,6 @@ import Development.IDE.Plugin.TypeLenses (suggestSigna
5956
import Development.IDE.Types.Exports
6057
import Development.IDE.Types.Location
6158
import Development.IDE.Types.Options
62-
import GHC (AddEpAnn (AddEpAnn),
63-
Anchor (anchor),
64-
AnnsModule (am_main),
65-
DeltaPos (..),
66-
EpAnn (..),
67-
EpaLocation (..))
6859
import qualified GHC.LanguageExtensions as Lang
6960
import Ide.PluginUtils (subRange)
7061
import Ide.Types
@@ -87,6 +78,22 @@ import Language.LSP.Types (CodeAction (
8778
import Language.LSP.VFS
8879
import Text.Regex.TDFA (mrAfter,
8980
(=~), (=~~))
81+
#if MIN_VERSION_ghc(9,2,0)
82+
import GHC (AddEpAnn (AddEpAnn),
83+
AnnsModule (am_main),
84+
DeltaPos (..),
85+
EpAnn (..),
86+
EpaLocation (..),
87+
LocatedA)
88+
89+
import Control.Monad (msum)
90+
#else
91+
import Language.Haskell.GHC.ExactPrint.Types (Annotation (annsDP),
92+
DeltaPos,
93+
KeywordId (G),
94+
deltaRow,
95+
mkAnnKey)
96+
#endif
9097

9198
-------------------------------------------------------------------------------------------------
9299

@@ -234,10 +241,8 @@ findInstanceHead df instanceHead decls =
234241

235242
#if MIN_VERSION_ghc(9,2,0)
236243
findDeclContainingLoc :: Foldable t => Position -> t (GenLocated (SrcSpanAnn' a) e) -> Maybe (GenLocated (SrcSpanAnn' a) e)
237-
#elif MIN_VERSION_ghc(8,10,0)
238-
findDeclContainingLoc :: Foldable t => Position -> t (GenLocated SrcSpan e) -> Maybe (GenLocated SrcSpan e)
239244
#else
240-
-- TODO populate this type signature for GHC versions <8.10
245+
findDeclContainingLoc :: Foldable t => Position -> t (GenLocated SrcSpan e) -> Maybe (GenLocated SrcSpan e)
241246
#endif
242247
findDeclContainingLoc loc = find (\(L l _) -> loc `isInsideSrcSpan` locA l)
243248

@@ -250,8 +255,8 @@ findDeclContainingLoc loc = find (\(L l _) -> loc `isInsideSrcSpan` locA l)
250255
-- imported from ‘Data.ByteString’ at B.hs:6:1-22
251256
-- imported from ‘Data.ByteString.Lazy’ at B.hs:8:1-27
252257
-- imported from ‘Data.Text’ at B.hs:7:1-16
253-
suggestHideShadow :: ParsedSource -> T.Text -> Maybe TcModuleResult -> Maybe HieAstResult -> Diagnostic -> [(T.Text, [Either TextEdit Rewrite])]
254-
suggestHideShadow ps@(L _ HsModule {hsmodImports}) fileContents mTcM mHar Diagnostic {_message, _range}
258+
suggestHideShadow :: Annotated ParsedSource -> T.Text -> Maybe TcModuleResult -> Maybe HieAstResult -> Diagnostic -> [(T.Text, [Either TextEdit Rewrite])]
259+
suggestHideShadow ps fileContents mTcM mHar Diagnostic {_message, _range}
255260
| Just [identifier, modName, s] <-
256261
matchRegexUnifySpaces
257262
_message
@@ -268,6 +273,8 @@ suggestHideShadow ps@(L _ HsModule {hsmodImports}) fileContents mTcM mHar Diagno
268273
result <> [hideAll]
269274
| otherwise = []
270275
where
276+
L _ HsModule {hsmodImports} = astA ps
277+
271278
suggests identifier modName s
272279
| Just tcM <- mTcM,
273280
Just har <- mHar,
@@ -947,11 +954,11 @@ isPreludeImplicit = xopt Lang.ImplicitPrelude
947954
suggestImportDisambiguation ::
948955
DynFlags ->
949956
Maybe T.Text ->
950-
ParsedSource ->
957+
Annotated ParsedSource ->
951958
T.Text ->
952959
Diagnostic ->
953960
[(T.Text, [Either TextEdit Rewrite])]
954-
suggestImportDisambiguation df (Just txt) ps@(L _ HsModule {hsmodImports}) fileContents diag@Diagnostic {..}
961+
suggestImportDisambiguation df (Just txt) ps fileContents diag@Diagnostic {..}
955962
| Just [ambiguous] <-
956963
matchRegexUnifySpaces
957964
_message
@@ -963,6 +970,8 @@ suggestImportDisambiguation df (Just txt) ps@(L _ HsModule {hsmodImports}) fileC
963970
suggestions ambiguous modules (isJust local)
964971
| otherwise = []
965972
where
973+
L _ HsModule {hsmodImports} = astA ps
974+
966975
locDic =
967976
fmap (NE.fromList . DL.toList) $
968977
Map.fromListWith (<>) $
@@ -1055,21 +1064,21 @@ targetModuleName (ExistingImp _) =
10551064
error "Cannot happen!"
10561065

10571066
disambiguateSymbol ::
1058-
ParsedSource ->
1067+
Annotated ParsedSource ->
10591068
T.Text ->
10601069
Diagnostic ->
10611070
T.Text ->
10621071
HidingMode ->
10631072
[Either TextEdit Rewrite]
1064-
disambiguateSymbol pm fileContents Diagnostic {..} (T.unpack -> symbol) = \case
1073+
disambiguateSymbol ps fileContents Diagnostic {..} (T.unpack -> symbol) = \case
10651074
(HideOthers hiddens0) ->
10661075
[ Right $ hideSymbol symbol idecl
10671076
| ExistingImp idecls <- hiddens0
10681077
, idecl <- NE.toList idecls
10691078
]
10701079
++ mconcat
10711080
[ if null imps
1072-
then maybeToList $ Left . snd <$> newImportToEdit (hideImplicitPreludeSymbol $ T.pack symbol) pm fileContents
1081+
then maybeToList $ Left . snd <$> newImportToEdit (hideImplicitPreludeSymbol $ T.pack symbol) ps fileContents
10731082
else Right . hideSymbol symbol <$> imps
10741083
| ImplicitPrelude imps <- hiddens0
10751084
]
@@ -1299,7 +1308,7 @@ removeRedundantConstraints df (L _ HsModule {hsmodDecls}) Diagnostic{..}
12991308

13001309
-------------------------------------------------------------------------------------------------
13011310

1302-
suggestNewOrExtendImportForClassMethod :: ExportsMap -> ParsedSource -> T.Text -> Diagnostic -> [(T.Text, CodeActionKind, [Either TextEdit Rewrite])]
1311+
suggestNewOrExtendImportForClassMethod :: ExportsMap -> Annotated ParsedSource -> T.Text -> Diagnostic -> [(T.Text, CodeActionKind, [Either TextEdit Rewrite])]
13031312
suggestNewOrExtendImportForClassMethod packageExportsMap ps fileContents Diagnostic {_message}
13041313
| Just [methodName, className] <-
13051314
matchRegexUnifySpaces
@@ -1313,7 +1322,7 @@ suggestNewOrExtendImportForClassMethod packageExportsMap ps fileContents Diagnos
13131322
where
13141323
suggest identInfo@IdentInfo {moduleNameText}
13151324
| importStyle <- NE.toList $ importStyles identInfo,
1316-
mImportDecl <- findImportDeclByModuleName (hsmodImports $ unLoc ps) (T.unpack moduleNameText) =
1325+
mImportDecl <- findImportDeclByModuleName (hsmodImports . unLoc . astA $ ps) (T.unpack moduleNameText) =
13171326
case mImportDecl of
13181327
-- extend
13191328
Just decl ->
@@ -1335,8 +1344,8 @@ suggestNewOrExtendImportForClassMethod packageExportsMap ps fileContents Diagnos
13351344
<> [(quickFixImportKind "new.all", newImportAll moduleNameText)]
13361345
| otherwise -> []
13371346

1338-
suggestNewImport :: ExportsMap -> ParsedSource -> T.Text -> Diagnostic -> [(T.Text, CodeActionKind, TextEdit)]
1339-
suggestNewImport packageExportsMap ps@(L _ HsModule {..}) fileContents Diagnostic{_message}
1347+
suggestNewImport :: ExportsMap -> Annotated ParsedSource -> T.Text -> Diagnostic -> [(T.Text, CodeActionKind, TextEdit)]
1348+
suggestNewImport packageExportsMap ps fileContents Diagnostic{_message}
13401349
| msg <- unifySpaces _message
13411350
, Just thingMissing <- extractNotInScopeName msg
13421351
, qual <- extractQualifiedModuleName msg
@@ -1351,6 +1360,8 @@ suggestNewImport packageExportsMap ps@(L _ HsModule {..}) fileContents Diagnosti
13511360
= sortOn fst3 [(imp, kind, TextEdit range (imp <> "\n" <> T.replicate indent " "))
13521361
| (kind, unNewImport -> imp) <- constructNewImportSuggestions packageExportsMap (qual <|> qual', thingMissing) extendImportSuggestions
13531362
]
1363+
where
1364+
L _ HsModule {..} = astA ps
13541365
suggestNewImport _ _ _ _ = []
13551366

13561367
constructNewImportSuggestions
@@ -1378,7 +1389,7 @@ constructNewImportSuggestions exportsMap (qual, thingMissing) notTheseModules =
13781389
newtype NewImport = NewImport {unNewImport :: T.Text}
13791390
deriving (Show, Eq, Ord)
13801391

1381-
newImportToEdit :: NewImport -> ParsedSource -> T.Text -> Maybe (T.Text, TextEdit)
1392+
newImportToEdit :: NewImport -> Annotated ParsedSource -> T.Text -> Maybe (T.Text, TextEdit)
13821393
newImportToEdit (unNewImport -> imp) ps fileContents
13831394
| Just (range, indent) <- newImportInsertRange ps fileContents
13841395
= Just (imp, TextEdit range (imp <> "\n" <> T.replicate indent " "))
@@ -1392,54 +1403,71 @@ newImportToEdit (unNewImport -> imp) ps fileContents
13921403
-- * If the file has neither existing imports nor a module declaration,
13931404
-- the import will be inserted at line zero if there are no pragmas,
13941405
-- * otherwise inserted one line after the last file-header pragma
1406+
#if MIN_VERSION_ghc(9,2,0)
13951407
newImportInsertRange :: ParsedSource -> T.Text -> Maybe (Range, Int)
13961408
newImportInsertRange ps@(L _ HsModule {..}) fileContents
1409+
#else
1410+
newImportInsertRange :: Annotated ParsedSource -> T.Text -> Maybe (Range, Int)
1411+
newImportInsertRange ps fileContents
1412+
#endif
13971413
| Just ((l, c), col) <- case hsmodImports of
13981414
[] -> (\line -> ((line, 0), 0)) <$> findPositionNoImports ps fileContents
13991415
_ -> findPositionFromImportsOrModuleDecl (map reLoc hsmodImports) last
14001416
, let insertPos = Position (fromIntegral l) (fromIntegral c)
14011417
= Just (Range insertPos insertPos, col)
14021418
| otherwise = Nothing
1419+
where
1420+
L _ HsModule {..} = astA ps
14031421

14041422
-- | Insert the import under the Module declaration exports if they exist, otherwise just under the module declaration.
14051423
-- If no module declaration exists, then no exports will exist either, in that case
14061424
-- insert the import after any file-header pragmas or at position zero if there are no pragmas
1407-
findPositionNoImports :: ParsedSource -> T.Text -> Maybe Int
1408-
findPositionNoImports (L _ HsModule {..}) fileContents =
1409-
case hsmodName of
1410-
Nothing -> Just $ findNextPragmaPosition fileContents
1411-
Just hsmodName' -> case hsmodAnn of
1412-
EpAnn _ annsModule _ ->
1413-
let prevSrcSpan = maybe (getLoc hsmodName') getLoc hsmodExports
1414-
in do
1415-
whereLocation <- fmap NE.head . NE.nonEmpty . mapMaybe filterWhere . am_main $ annsModule
1416-
epaLocationToLine prevSrcSpan whereLocation
1417-
EpAnnNotUsed -> Nothing
1425+
findPositionNoImports :: Annotated ParsedSource -> T.Text -> Maybe Int
1426+
findPositionNoImports ps fileContents =
1427+
maybe (Just (findNextPragmaPosition fileContents)) (findPositionAfterModuleName ps) hsmodName
14181428
where
1419-
filterWhere (AddEpAnn AnnWhere loc) = Just loc
1420-
filterWhere _ = Nothing
1429+
L _ HsModule {..} = astA ps
14211430

1422-
epaLocationToLine :: SrcSpan -> EpaLocation -> Maybe Int
1423-
epaLocationToLine _ (EpaSpan sp) =
1424-
let loc = realSrcSpanEnd sp
1425-
in Just $ srcLocLine loc
1426-
epaLocationToLine (UnhelpfulSpan _) _ = Nothing
1427-
epaLocationToLine (RealSrcSpan prevSrcSpan _) (EpaDelta deltaPos _) =
1428-
case deltaPos of
1429-
SameLine _ -> Just prevEndLine
1430-
DifferentLine line _ -> Just $ prevEndLine + line
1431-
where
1432-
prevEndLine = srcLocLine (realSrcSpanEnd prevSrcSpan)
1431+
#if MIN_VERSION_ghc(9,2,0)
1432+
findPositionAfterModuleName :: ParsedSource -> LocatedA ModuleName -> Maybe Int
1433+
#else
1434+
findPositionAfterModuleName :: Annotated ParsedSource -> Located ModuleName -> Maybe Int
1435+
#endif
1436+
findPositionAfterModuleName ps hsmodName' = do
1437+
lineOffset <- whereKeywordLineOffset
1438+
case prevSrcSpan of
1439+
UnhelpfulSpan _ -> Nothing
1440+
(RealSrcSpan prevSrcSpan' _) ->
1441+
Just $ srcLocLine (realSrcSpanEnd prevSrcSpan') + lineOffset
1442+
where
1443+
L _ HsModule {..} = astA ps
14331444

1434-
showAddEpAnns :: [AddEpAnn] -> String
1435-
showAddEpAnns = unlines . fmap showAddEpAnn
1445+
prevSrcSpan = maybe (getLoc hsmodName') getLoc hsmodExports
14361446

1437-
showAddEpAnn :: AddEpAnn -> String
1438-
showAddEpAnn (AddEpAnn keywordId loc) = show keywordId ++ "," ++ showEpaLocation loc
1447+
whereKeywordLineOffset :: Maybe Int
1448+
#if MIN_VERSION_ghc(9,2,0)
1449+
whereKeywordLineOffset = case hsmodAnn of
1450+
EpAnn _ annsModule _ -> do
1451+
whereLocation <- fmap NE.head . NE.nonEmpty . mapMaybe filterWhere . am_main $ annsModule
1452+
epaLocationToLine whereLocation
1453+
EpAnnNotUsed -> Nothing
1454+
filterWhere (AddEpAnn AnnWhere loc) = Just loc
1455+
filterWhere _ = Nothing
14391456

1440-
showEpaLocation :: EpaLocation -> String
1441-
showEpaLocation (EpaDelta pos _) = show pos
1442-
showEpaLocation _ = error "should not be EpaSpan"
1457+
epaLocationToLine :: EpaLocation -> Maybe Int
1458+
epaLocationToLine (EpaSpan sp) = Just . srcLocLine . realSrcSpanEnd $ sp
1459+
epaLocationToLine (EpaDelta (SameLine _) _) = Just 0
1460+
epaLocationToLine (EpaDelta (DifferentLine line _) _) = Just line
1461+
#else
1462+
whereKeywordLineOffset = do
1463+
ann <- annsA ps M.!? mkAnnKey (astA ps)
1464+
deltaPos <- fmap NE.head . NE.nonEmpty .mapMaybe filterWhere $ annsDP ann
1465+
pure $ deltaRow deltaPos
1466+
1467+
filterWhere :: (KeywordId, DeltaPos) -> Maybe DeltaPos
1468+
filterWhere (keywordId, deltaPos) =
1469+
if keywordId == G AnnWhere then Just deltaPos else Nothing
1470+
#endif
14431471

14441472
findPositionFromImportsOrModuleDecl :: HasSrcSpan a => t -> (t -> a) -> Maybe ((Int, Int), Int)
14451473
findPositionFromImportsOrModuleDecl hsField f = case getLoc (f hsField) of

ghcide/src/Development/IDE/Plugin/Completions.hs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,7 @@ extendImportHandler' ideState ExtendImport {..}
250250
it = case thingParent of
251251
Nothing -> newThing
252252
Just p -> p <> "(" <> newThing <> ")"
253-
t <- liftMaybe $ snd <$> newImportToEdit
254-
n
255-
(astA ps)
256-
(fromMaybe "" contents)
253+
t <- liftMaybe $ snd <$> newImportToEdit n ps (fromMaybe "" contents)
257254
return (nfp, WorkspaceEdit {_changes=Just (fromList [(doc,List [t])]), _documentChanges=Nothing, _changeAnnotations=Nothing})
258255
| otherwise =
259256
mzero

0 commit comments

Comments
 (0)