Skip to content

Commit f14e5a6

Browse files
authored
Change refine imports behaviour for qualified imports (#3806)
1 parent 6388882 commit f14e5a6

File tree

7 files changed

+81
-33
lines changed

7 files changed

+81
-33
lines changed

Diff for: plugins/hls-explicit-imports-plugin/src/Ide/Plugin/ExplicitImports.hs

+35-32
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import qualified Data.IntMap as IM (IntMap, elems,
2929
fromList, (!?))
3030
import Data.IORef (readIORef)
3131
import qualified Data.Map.Strict as Map
32-
import Data.Maybe (mapMaybe)
32+
import Data.Maybe (isNothing, mapMaybe)
3333
import qualified Data.Set as S
3434
import Data.String (fromString)
3535
import qualified Data.Text as T
@@ -316,42 +316,32 @@ minimalImportsRule recorder modFilter = defineNoDiagnostics (cmapWithPrio LogSha
316316
return $ mi_exports $ hirModIface imp_hir
317317

318318
-- Use the GHC api to extract the "minimal" imports
319-
(imports, mbMinImports) <- MaybeT $ liftIO $ extractMinimalImports hsc tmr
319+
locationImportWithMinimal <- MaybeT $ liftIO $ extractMinimalImports hsc tmr
320320

321-
let importsMap =
322-
Map.fromList
323-
[ (realSrcSpanStart l, printOutputable i)
324-
| L (locA -> RealSrcSpan l _) i <- mbMinImports
325-
]
326-
minimalImportsResult =
327-
[ (range, (minImport, ExplicitImport))
328-
| imp@(L _ impDecl) <- imports
321+
let minimalImportsResult =
322+
[ (range, (printOutputable minImport, ExplicitImport))
323+
| (location, impDecl, minImport) <- locationImportWithMinimal
329324
, not (isQualifiedImport impDecl)
330325
, not (isExplicitImport impDecl)
331326
, let L _ moduleName = ideclName impDecl
332327
, modFilter moduleName
333-
, RealSrcSpan location _ <- [getLoc imp]
334-
, let range = realSrcSpanToRange location
335-
, Just minImport <- [Map.lookup (realSrcSpanStart location) importsMap]
336-
]
328+
, let range = realSrcSpanToRange location]
329+
337330
refineImportsResult =
338331
[ (range, (T.intercalate "\n"
339-
. map (printOutputable . constructImport i)
332+
. map (printOutputable . constructImport origImport minImport)
340333
. Map.toList
341334
$ filteredInnerImports, RefineImport))
342335
-- for every minimal imports
343-
| minImports <- [mbMinImports]
344-
, i@(L _ ImportDecl{ideclName = L _ mn}) <- minImports
336+
| (location, origImport, minImport@(ImportDecl{ideclName = L _ mn})) <- locationImportWithMinimal
345337
-- (almost) no one wants to see an refine import list for Prelude
346338
, mn /= moduleName pRELUDE
347339
-- we check for the inner imports
348340
, Just innerImports <- [Map.lookup mn import2Map]
349341
-- and only get those symbols used
350-
, Just filteredInnerImports <- [filterByImport i innerImports]
342+
, Just filteredInnerImports <- [filterByImport minImport innerImports]
351343
-- if no symbols from this modules then don't need to generate new import
352344
, not $ null filteredInnerImports
353-
-- get the location
354-
, RealSrcSpan location _ <- [getLoc i]
355345
-- and then convert that to a Range
356346
, let range = realSrcSpanToRange location
357347
]
@@ -370,7 +360,7 @@ minimalImportsRule recorder modFilter = defineNoDiagnostics (cmapWithPrio LogSha
370360
extractMinimalImports ::
371361
HscEnvEq ->
372362
TcModuleResult ->
373-
IO (Maybe ([LImportDecl GhcRn], [LImportDecl GhcRn]))
363+
IO (Maybe [(RealSrcSpan, ImportDecl GhcRn, ImportDecl GhcRn)])
374364
extractMinimalImports hsc TcModuleResult {..} = runMaybeT $ do
375365
-- extract the original imports and the typechecking environment
376366
let tcEnv = tmrTypechecked
@@ -391,8 +381,17 @@ extractMinimalImports hsc TcModuleResult {..} = runMaybeT $ do
391381
(_, Just minimalImports) <- liftIO $
392382
initTcWithGbl (hscEnv hsc) tcEnv srcSpan $ getMinimalImports usage
393383

384+
let minimalImportsMap =
385+
Map.fromList
386+
[ (realSrcSpanStart l, impDecl)
387+
| L (locA -> RealSrcSpan l _) impDecl <- minimalImports
388+
]
389+
results =
390+
[ (location, imp, minImport)
391+
| L (locA -> RealSrcSpan location _) imp <- imports
392+
, Just minImport <- [Map.lookup (realSrcSpanStart location) minimalImportsMap]]
394393
-- return both the original imports and the computed minimal ones
395-
return (imports, minimalImports)
394+
return results
396395
where
397396
notExported :: [String] -> LImportDecl GhcRn -> Bool
398397
notExported [] _ = True
@@ -451,11 +450,11 @@ abbreviateImportTitle input =
451450
--------------------------------------------------------------------------------
452451

453452

454-
filterByImport :: LImportDecl GhcRn -> Map.Map ModuleName [AvailInfo] -> Maybe (Map.Map ModuleName [AvailInfo])
453+
filterByImport :: ImportDecl GhcRn -> Map.Map ModuleName [AvailInfo] -> Maybe (Map.Map ModuleName [AvailInfo])
455454
#if MIN_VERSION_ghc(9,5,0)
456-
filterByImport (L _ ImportDecl{ideclImportList = Just (_, L _ names)})
455+
filterByImport (ImportDecl{ideclImportList = Just (_, L _ names)})
457456
#else
458-
filterByImport (L _ ImportDecl{ideclHiding = Just (_, L _ names)})
457+
filterByImport (ImportDecl{ideclHiding = Just (_, L _ names)})
459458
#endif
460459
avails =
461460
-- if there is a function defined in the current module and is used
@@ -474,18 +473,22 @@ filterByImport (L _ ImportDecl{ideclHiding = Just (_, L _ names)})
474473
$ Map.elems res
475474
filterByImport _ _ = Nothing
476475

477-
constructImport :: LImportDecl GhcRn -> (ModuleName, [AvailInfo]) -> LImportDecl GhcRn
476+
constructImport :: ImportDecl GhcRn -> ImportDecl GhcRn -> (ModuleName, [AvailInfo]) -> ImportDecl GhcRn
478477
#if MIN_VERSION_ghc(9,5,0)
479-
constructImport (L lim imd@ImportDecl {ideclName = L _ _, ideclImportList = Just (hiding, L _ names)})
478+
constructImport ImportDecl{ideclQualified = qualified, ideclImportList = origHiding} imd@ImportDecl{ideclImportList = Just (hiding, L _ names)}
480479
#else
481-
constructImport (L lim imd@ImportDecl{ideclName = L _ _, ideclHiding = Just (hiding, L _ names)})
480+
constructImport ImportDecl{ideclQualified = qualified, ideclHiding = origHiding} imd@ImportDecl{ideclHiding = Just (hiding, L _ names)}
482481
#endif
483-
(newModuleName, avails) = L lim imd
482+
(newModuleName, avails) = imd
484483
{ ideclName = noLocA newModuleName
485484
#if MIN_VERSION_ghc(9,5,0)
486-
, ideclImportList = Just (hiding, noLocA newNames)
485+
, ideclImportList = if isNothing origHiding && qualified /= NotQualified
486+
then Nothing
487+
else Just (hiding, noLocA newNames)
487488
#else
488-
, ideclHiding = Just (hiding, noLocA newNames)
489+
, ideclHiding = if isNothing origHiding && qualified /= NotQualified
490+
then Nothing
491+
else Just (hiding, noLocA newNames)
489492
#endif
490493
}
491494
where newNames = filter (\n -> any (n `containsAvail`) avails) names
@@ -495,4 +498,4 @@ constructImport (L lim imd@ImportDecl{ideclName = L _ _, ideclHiding = Just (hid
495498
any (\an -> printOutputable an == (printOutputable . ieName . unLoc $ name))
496499
$ availNamesWithSelectors avail
497500

498-
constructImport lim _ = lim
501+
constructImport _ lim _ = lim

Diff for: plugins/hls-explicit-imports-plugin/test/Main.hs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ main = defaultTestRunner $ testGroup "import-actions"
3131
"Refine Imports"
3232
[ codeActionGoldenTest "RefineWithOverride" 3 1
3333
, codeLensGoldenTest isRefineImports "RefineUsualCase" 1
34+
, codeLensGoldenTest isRefineImports "RefineQualified" 0
35+
, codeLensGoldenTest isRefineImports "RefineQualifiedExplicit" 0
3436
],
3537
testGroup
3638
"Make imports explicit"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Main where
2+
3+
import qualified RefineB as RA
4+
import qualified RefineC as RA
5+
import RefineD
6+
import Data.List (intercalate)
7+
8+
main :: IO ()
9+
main = putStrLn
10+
$ "hello "
11+
<> intercalate ", " [RA.b1, RA.c1, e2]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module Main where
2+
3+
import qualified RefineA as RA
4+
import RefineD
5+
import Data.List (intercalate)
6+
7+
main :: IO ()
8+
main = putStrLn
9+
$ "hello "
10+
<> intercalate ", " [RA.b1, RA.c1, e2]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Main where
2+
3+
import qualified RefineB as RA ( b1 )
4+
import qualified RefineC as RA ( c1 )
5+
import RefineD
6+
import Data.List (intercalate)
7+
8+
main :: IO ()
9+
main = putStrLn
10+
$ "hello "
11+
<> intercalate ", " [RA.b1, RA.c1, e2]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module Main where
2+
3+
import qualified RefineA as RA (b1, c1)
4+
import RefineD
5+
import Data.List (intercalate)
6+
7+
main :: IO ()
8+
main = putStrLn
9+
$ "hello "
10+
<> intercalate ", " [RA.b1, RA.c1, e2]

Diff for: plugins/hls-explicit-imports-plugin/test/testdata/hie.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
cradle:
32
direct:
43
arguments:
@@ -9,6 +8,8 @@ cradle:
98
- ExplicitA.hs
109
- ExplicitB.hs
1110
- RefineUsualCase.hs
11+
- RefineQualified.hs
12+
- RefineQualifiedExplicit.hs
1213
- RefineWithOverride.hs
1314
- RefineA.hs
1415
- RefineB.hs

0 commit comments

Comments
 (0)