diff --git a/hls-explicit-imports-plugin.cabal b/hls-explicit-imports-plugin.cabal
--- a/hls-explicit-imports-plugin.cabal
+++ b/hls-explicit-imports-plugin.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               hls-explicit-imports-plugin
-version:            2.0.0.1
+version:            2.6.0.0
 synopsis:           Explicit imports plugin for Haskell Language Server
 description:
   Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>
@@ -19,8 +19,16 @@
     type:     git
     location: https://github.com/haskell/haskell-language-server.git
 
+flag pedantic
+  description: Enable -Werror
+  default:     False
+  manual:      True
+
+common warnings
+    ghc-options: -Wall
+
 library
-  buildable: True
+  import:           warnings
   exposed-modules:    Ide.Plugin.ExplicitImports
   hs-source-dirs:     src
   build-depends:
@@ -29,11 +37,14 @@
     , containers
     , deepseq
     , ghc
-    , ghcide                == 2.0.0.1
+    , ghcide                == 2.6.0.0
     , hls-graph
-    , hls-plugin-api        == 2.0.0.1
+    , hls-plugin-api        == 2.6.0.0
+    , lens
     , lsp
+    , mtl
     , text
+    , transformers
     , unordered-containers
 
   default-language:   Haskell2010
@@ -41,8 +52,11 @@
     DataKinds
     TypeOperators
 
+  if flag(pedantic)
+    ghc-options: -Werror
+
 test-suite tests
-  buildable: True
+  import:           warnings
   type:             exitcode-stdio-1.0
   default-language: Haskell2010
   hs-source-dirs:   test
@@ -50,7 +64,11 @@
   ghc-options:      -threaded -rtsopts -with-rtsopts=-N
   build-depends:
     , base
+    , extra
     , filepath
     , hls-explicit-imports-plugin
     , hls-test-utils
+    , lens
+    , lsp-types
+    , row-types
     , text
diff --git a/src/Ide/Plugin/ExplicitImports.hs b/src/Ide/Plugin/ExplicitImports.hs
--- a/src/Ide/Plugin/ExplicitImports.hs
+++ b/src/Ide/Plugin/ExplicitImports.hs
@@ -1,58 +1,80 @@
-{-# LANGUAGE CPP                #-}
-{-# LANGUAGE DeriveAnyClass     #-}
-{-# LANGUAGE DeriveGeneric      #-}
-{-# LANGUAGE DerivingStrategies #-}
-{-# LANGUAGE LambdaCase         #-}
-{-# LANGUAGE NamedFieldPuns     #-}
-{-# LANGUAGE OverloadedStrings  #-}
-{-# LANGUAGE RecordWildCards    #-}
-{-# LANGUAGE TypeFamilies       #-}
-{-# LANGUAGE ViewPatterns       #-}
-
+{-# LANGUAGE CPP                       #-}
+{-# LANGUAGE DeriveAnyClass            #-}
+{-# LANGUAGE DeriveGeneric             #-}
+{-# LANGUAGE DerivingStrategies        #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE LambdaCase                #-}
+{-# LANGUAGE NamedFieldPuns            #-}
+{-# LANGUAGE OverloadedStrings         #-}
+{-# LANGUAGE RecordWildCards           #-}
+{-# LANGUAGE TypeFamilies              #-}
+{-# LANGUAGE ViewPatterns              #-}
 module Ide.Plugin.ExplicitImports
   ( descriptor
   , descriptorForModules
-  , extractMinimalImports
-  , within
   , abbreviateImportTitle
   , Log(..)
   ) where
 
 import           Control.DeepSeq
+import           Control.Lens                         ((&), (?~))
+import           Control.Monad.Error.Class            (MonadError (throwError))
 import           Control.Monad.IO.Class
-import           Data.Aeson                           (ToJSON (toJSON),
-                                                       Value (Null))
+import           Control.Monad.Trans.Class            (lift)
+import           Control.Monad.Trans.Except           (ExceptT)
+import           Control.Monad.Trans.Maybe
+import qualified Data.Aeson                           as A (ToJSON (toJSON))
 import           Data.Aeson.Types                     (FromJSON)
-import qualified Data.HashMap.Strict                  as HashMap
+import qualified Data.IntMap                          as IM (IntMap, elems,
+                                                             fromList, (!?))
 import           Data.IORef                           (readIORef)
 import qualified Data.Map.Strict                      as Map
-import           Data.Maybe                           (catMaybes, fromMaybe,
-                                                       isJust)
+import           Data.Maybe                           (isNothing, mapMaybe)
+import qualified Data.Set                             as S
 import           Data.String                          (fromString)
 import qualified Data.Text                            as T
+import           Data.Traversable                     (for)
+import qualified Data.Unique                          as U (hashUnique,
+                                                            newUnique)
 import           Development.IDE                      hiding (pluginHandlers,
                                                        pluginRules)
+import           Development.IDE.Core.PluginUtils
 import           Development.IDE.Core.PositionMapping
 import qualified Development.IDE.Core.Shake           as Shake
-import           Development.IDE.GHC.Compat
+import           Development.IDE.GHC.Compat           hiding ((<+>))
 import           Development.IDE.Graph.Classes
-import           Development.IDE.Types.Logger         as Logger (Pretty (pretty))
 import           GHC.Generics                         (Generic)
-import           Ide.PluginUtils                      (mkLspCommand)
+import           Ide.Plugin.Error                     (PluginError (..),
+                                                       getNormalizedFilePathE,
+                                                       handleMaybe)
+import           Ide.Plugin.RangeMap                  (filterByRange)
+import qualified Ide.Plugin.RangeMap                  as RM (RangeMap, fromList)
+import           Ide.Plugin.Resolve
+import           Ide.PluginUtils
 import           Ide.Types
+import qualified Language.LSP.Protocol.Lens           as L
+import           Language.LSP.Protocol.Message
+import           Language.LSP.Protocol.Types
 import           Language.LSP.Server
-import           Language.LSP.Types
 
+-- This plugin is named explicit-imports for historical reasons. Besides
+-- providing code actions and lenses to make imports explicit it also provides
+-- code actions and lens to refine imports.
+
 importCommandId :: CommandId
 importCommandId = "ImportLensCommand"
 
-newtype Log
+data Log
   = LogShake Shake.Log
-  deriving Show
+  | LogWAEResponseError ResponseError
+  | forall a. (Pretty a) => LogResolve a
 
+
 instance Pretty Log where
   pretty = \case
-    LogShake log -> pretty log
+    LogShake logMsg -> pretty logMsg
+    LogWAEResponseError rspErr -> "RequestWorkspaceApplyEdit Failed with " <+> pretty rspErr
+    LogResolve msg -> pretty msg
 
 -- | The "main" function of a plugin
 descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
@@ -66,133 +88,208 @@
       -- ^ Predicate to select modules that will be annotated
     -> PluginId
     -> PluginDescriptor IdeState
-descriptorForModules recorder pred plId =
-  (defaultPluginDescriptor plId)
+descriptorForModules recorder modFilter plId =
+  let resolveRecorder = cmapWithPrio LogResolve recorder
+      codeActionHandlers = mkCodeActionHandlerWithResolve resolveRecorder (codeActionProvider recorder) (codeActionResolveProvider recorder)
+  in (defaultPluginDescriptor plId "Provides a code action to make imports explicit")
     {
       -- This plugin provides a command handler
-      pluginCommands = [importLensCommand],
+      pluginCommands = [PluginCommand importCommandId "Explicit import command" (runImportCommand recorder)],
       -- This plugin defines a new rule
-      pluginRules = minimalImportsRule recorder,
-      pluginHandlers = mconcat
-        [ -- This plugin provides code lenses
-          mkPluginHandler STextDocumentCodeLens $ lensProvider pred
+      pluginRules = minimalImportsRule recorder modFilter,
+      pluginHandlers =
+         -- This plugin provides code lenses
+           mkPluginHandler SMethod_TextDocumentCodeLens (lensProvider recorder)
+        <> mkResolveHandler SMethod_CodeLensResolve (lensResolveProvider recorder)
           -- This plugin provides code actions
-        , mkPluginHandler STextDocumentCodeAction $ codeActionProvider pred
-        ]
-    }
-
--- | The command descriptor
-importLensCommand :: PluginCommand IdeState
-importLensCommand =
-  PluginCommand importCommandId "Explicit import command" runImportCommand
+        <> codeActionHandlers
 
--- | The type of the parameters accepted by our command
-newtype ImportCommandParams = ImportCommandParams WorkspaceEdit
-  deriving (Generic)
-  deriving anyclass (FromJSON, ToJSON)
+    }
 
 -- | The actual command handler
-runImportCommand :: CommandFunction IdeState ImportCommandParams
-runImportCommand _state (ImportCommandParams edit) = do
-  -- This command simply triggers a workspace edit!
-  _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing edit) (\_ -> pure ())
-  return (Right Null)
+runImportCommand :: Recorder (WithPriority Log) -> CommandFunction IdeState IAResolveData
+runImportCommand recorder ideState eird@(ResolveOne _ _) = do
+  wedit <- resolveWTextEdit ideState eird
+  _ <- lift $ sendRequest SMethod_WorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing wedit) logErrors
+  return $ InR  Null
+  where logErrors (Left re@(ResponseError{})) = do
+          logWith recorder Error (LogWAEResponseError re)
+          pure ()
+        logErrors (Right _) = pure ()
+runImportCommand _ _ rd = do
+  throwError $ PluginInvalidParams (T.pack $ "Unexpected argument for command handler:" <> show rd)
 
--- | For every implicit import statement, return a code lens of the corresponding explicit import
--- Example - for the module below:
---
+
+-- | We provide two code lenses for imports. The first lens makes imports
+-- explicit. For example, for the module below:
 -- > import Data.List
--- >
 -- > f = intercalate " " . sortBy length
---
 -- the provider should produce one code lens associated to the import statement:
---
 -- > import Data.List (intercalate, sortBy)
-lensProvider :: (ModuleName -> Bool) -> PluginMethodHandler IdeState TextDocumentCodeLens
-lensProvider
-  pred
-  state -- ghcide state, used to retrieve typechecking artifacts
-  pId -- plugin Id
-  CodeLensParams {_textDocument = TextDocumentIdentifier {_uri}}
-    -- VSCode uses URIs instead of file paths
-    -- haskell-lsp provides conversion functions
-    | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri _uri = liftIO $
-      do
-        mbMinImports <- runAction "MinimalImports" state $ useWithStale MinimalImports nfp
-        case mbMinImports of
-          -- Implement the provider logic:
-          -- for every import, if it's lacking a explicit list, generate a code lens
-          Just (MinimalImportsResult minImports, posMapping) -> do
-            commands <-
-              sequence
-                [ generateLens pId _uri edit
-                  | (imp, Just minImport) <- minImports,
-                    Just edit <- [mkExplicitEdit pred posMapping imp minImport]
-                ]
-            return $ Right (List $ catMaybes commands)
-          _ ->
-            return $ Right (List [])
-    | otherwise =
-      return $ Right (List [])
+--
+-- The second one allows us to import functions directly from the original
+-- module. For example, for the following import
+-- > import Random.ReExporting.Module (liftIO)
+-- the provider should produce one code lens associated to the import statement:
+-- > Refine imports to import Control.Monad.IO.Class (liftIO)
+lensProvider :: Recorder (WithPriority Log) -> PluginMethodHandler IdeState 'Method_TextDocumentCodeLens
+lensProvider _  state _ CodeLensParams {_textDocument = TextDocumentIdentifier {_uri}} = do
+    nfp <- getNormalizedFilePathE _uri
+    (ImportActionsResult{forLens}, pm) <- runActionE "ImportActions" state $ useWithStaleE ImportActions nfp
+    let lens = [ generateLens _uri newRange int
+                | (range, int) <- forLens
+                , Just newRange <- [toCurrentRange pm range]]
+    pure $ InL lens
+  where -- because these are non resolved lenses we only need the range and a
+        -- unique id to later resolve them with. These are for both refine
+        -- import lenses and for explicit import lenses.
+        generateLens :: Uri  -> Range -> Int -> CodeLens
+        generateLens uri range int =
+          CodeLens { _data_ = Just $ A.toJSON $ ResolveOne uri int
+                   , _range = range
+                   , _command = Nothing }
 
--- | If there are any implicit imports, provide one code action to turn them all
---   into explicit imports.
-codeActionProvider :: (ModuleName -> Bool) -> PluginMethodHandler IdeState TextDocumentCodeAction
-codeActionProvider pred ideState _pId (CodeActionParams _ _ docId range _context)
-  | TextDocumentIdentifier {_uri} <- docId,
-    Just nfp <- uriToNormalizedFilePath $ toNormalizedUri _uri = liftIO $
-    do
-      pm <- runIde ideState $ use GetParsedModule nfp
-      let insideImport = case pm of
-            Just ParsedModule {pm_parsed_source}
-              | locImports <- hsmodImports (unLoc pm_parsed_source),
-                rangesImports <- map getLoc locImports ->
-                any (within range) rangesImports
-            _ -> False
-      if not insideImport
-        then return (Right (List []))
-        else do
-          minImports <- runAction "MinimalImports" ideState $ use MinimalImports nfp
-          let edits =
-                [ e
-                  | (imp, Just explicit) <-
-                      maybe [] getMinimalImportsResult minImports,
-                    Just e <- [mkExplicitEdit pred zeroMapping imp explicit]
-                ]
-              caExplicitImports = InR CodeAction {..}
-              _title = "Make all imports explicit"
-              _kind = Just CodeActionQuickFix
-              _command = Nothing
-              _edit = Just WorkspaceEdit {_changes, _documentChanges, _changeAnnotations}
-              _changes = Just $ HashMap.singleton _uri $ List edits
-              _documentChanges = Nothing
-              _diagnostics = Nothing
-              _isPreferred = Nothing
-              _disabled = Nothing
-              _xdata = Nothing
-              _changeAnnotations = Nothing
-          return $ Right $ List [caExplicitImports | not (null edits)]
-  | otherwise =
-    return $ Right $ List []
+lensResolveProvider :: Recorder (WithPriority Log) -> ResolveFunction IdeState IAResolveData 'Method_CodeLensResolve
+lensResolveProvider _ ideState plId cl uri rd@(ResolveOne _ uid) = do
+    nfp <- getNormalizedFilePathE uri
+    (ImportActionsResult{forResolve}, _) <- runActionE "ImportActions" ideState $ useWithStaleE ImportActions nfp
+    target <- handleMaybe PluginStaleResolve $ forResolve IM.!? uid
+    let updatedCodeLens = cl & L.command ?~  mkCommand plId target
+    pure updatedCodeLens
+  where mkCommand ::  PluginId -> ImportEdit -> Command
+        mkCommand pId (ImportEdit{ieResType, ieText}) =
+          let -- The only new thing we need to provide to resolve a lens is the
+              -- title, as the unique Id is the same to resolve the lens title
+              -- as it is to apply the lens through a command.
+              -- The title is written differently depending on what type of lens
+              -- it is.
+              title ExplicitImport = abbreviateImportTitle ieText
+              title RefineImport = "Refine imports to " <> T.intercalate ", " (T.lines ieText)
+          in mkLspCommand pId importCommandId (title ieResType) (Just [A.toJSON rd])
+lensResolveProvider _ _ _ _ _ rd = do
+   throwError $ PluginInvalidParams (T.pack $ "Unexpected argument for lens resolve handler: " <> show rd)
 
+-- |For explicit imports: If there are any implicit imports, provide both one
+-- code action per import to make that specific import explicit, and one code
+-- action to turn them all into explicit imports. For refine imports: If there
+-- are any reexported imports, provide both one code action per import to refine
+-- that specific import, and one code action to refine all imports.
+codeActionProvider :: Recorder (WithPriority Log) -> PluginMethodHandler IdeState 'Method_TextDocumentCodeAction
+codeActionProvider _ ideState _pId (CodeActionParams _ _ TextDocumentIdentifier {_uri} range _context) = do
+    nfp <- getNormalizedFilePathE _uri
+    (ImportActionsResult{forCodeActions}, pm) <- runActionE "ImportActions" ideState $ useWithStaleE ImportActions nfp
+    newRange <- toCurrentRangeE pm range
+    let relevantCodeActions = filterByRange newRange forCodeActions
+        allExplicit =
+          [InR $ mkCodeAction "Make all imports explicit" (Just $ A.toJSON $ ExplicitAll _uri)
+          -- We should only provide this code action if there are any code
+          -- of this type
+          | any (\x -> iaResType x == ExplicitImport) relevantCodeActions]
+        allRefine =
+          [InR $ mkCodeAction "Refine all imports" (Just $ A.toJSON $ RefineAll _uri)
+          -- We should only provide this code action if there are any code
+          -- of this type
+          | any (\x -> iaResType x == RefineImport) relevantCodeActions]
+        -- The only thing different in making the two types of code actions, is
+        -- the title. The actual resolve data type, ResolveOne is used by both
+        -- of them
+        toCodeAction uri (ImportAction _ int ExplicitImport) =
+          mkCodeAction "Make this import explicit" (Just $ A.toJSON $ ResolveOne uri int)
+        toCodeAction uri (ImportAction _  int RefineImport) =
+          mkCodeAction "Refine this import" (Just $ A.toJSON $ ResolveOne uri int)
+    pure $ InL ((InR . toCodeAction _uri <$> relevantCodeActions) <> allExplicit <> allRefine)
+    where mkCodeAction title data_  =
+            CodeAction
+            { _title = title
+            , _kind = Just CodeActionKind_QuickFix
+            , _command = Nothing
+            , _edit = Nothing
+            , _diagnostics = Nothing
+            , _isPreferred = Nothing
+            , _disabled = Nothing
+            , _data_ = data_}
+
+codeActionResolveProvider :: Recorder (WithPriority Log) -> ResolveFunction IdeState IAResolveData 'Method_CodeActionResolve
+codeActionResolveProvider _ ideState _ ca _ rd = do
+    wedit <- resolveWTextEdit ideState rd
+    pure $ ca & L.edit ?~ wedit
 --------------------------------------------------------------------------------
 
-data MinimalImports = MinimalImports
+resolveWTextEdit :: IdeState -> IAResolveData -> ExceptT PluginError (LspT Config IO) WorkspaceEdit
+-- Providing the edit for the command, or the resolve for the code action is
+-- completely generic, as all we need is the unique id and the text edit.
+resolveWTextEdit ideState (ResolveOne uri int) = do
+  nfp <- getNormalizedFilePathE uri
+  (ImportActionsResult{forResolve}, pm) <- runActionE "ImportActions" ideState $ useWithStaleE ImportActions nfp
+  iEdit <- handleMaybe PluginStaleResolve $ forResolve IM.!? int
+  pure $ mkWorkspaceEdit uri [iEdit] pm
+resolveWTextEdit ideState (ExplicitAll uri) = do
+  nfp <- getNormalizedFilePathE uri
+  (ImportActionsResult{forResolve}, pm) <- runActionE "ImportActions" ideState $ useWithStaleE ImportActions nfp
+  let edits = [ ie | ie@ImportEdit{ieResType = ExplicitImport} <- IM.elems forResolve]
+  pure $ mkWorkspaceEdit uri edits pm
+resolveWTextEdit ideState (RefineAll uri) = do
+  nfp <- getNormalizedFilePathE uri
+  (ImportActionsResult{forResolve}, pm) <- runActionE "ImportActions" ideState $ useWithStaleE ImportActions nfp
+  let edits = [ re | re@ImportEdit{ieResType = RefineImport} <- IM.elems forResolve]
+  pure $ mkWorkspaceEdit uri edits pm
+mkWorkspaceEdit :: Uri -> [ImportEdit] -> PositionMapping -> WorkspaceEdit
+mkWorkspaceEdit uri edits pm =
+      WorkspaceEdit {_changes = Just $ Map.fromList [(uri, mapMaybe toWEdit edits)]
+                    , _documentChanges = Nothing
+                    , _changeAnnotations = Nothing}
+  where toWEdit ImportEdit{ieRange, ieText} =
+          let newRange = toCurrentRange pm ieRange
+          in (\r -> TextEdit r ieText) <$> newRange
+
+data ImportActions = ImportActions
   deriving (Show, Generic, Eq, Ord)
 
-instance Hashable MinimalImports
+instance Hashable ImportActions
 
-instance NFData MinimalImports
+instance NFData ImportActions
 
-type instance RuleResult MinimalImports = MinimalImportsResult
+type instance RuleResult ImportActions = ImportActionsResult
 
-newtype MinimalImportsResult = MinimalImportsResult
-  {getMinimalImportsResult :: [(LImportDecl GhcRn, Maybe T.Text)]}
+data ResultType = ExplicitImport | RefineImport
+  deriving Eq
 
-instance Show MinimalImportsResult where show _ = "<minimalImportsResult>"
+data ImportActionsResult = ImportActionsResult
+  { -- |For providing the code lenses we need to have a range, and a unique id
+    -- that is later resolved to the new text for each import. It is stored in
+    -- a list, because we always need to provide all the code lens in a file.
+    forLens        :: [(Range, Int)]
+    -- |For the code actions we have the same data as for the code lenses, but
+    -- we store it in a RangeMap, because that allows us to filter on a specific
+    -- range with better performance, and code actions are almost always only
+    -- requested for a specific range
+  , forCodeActions :: RM.RangeMap ImportAction
+    -- |For resolve we have an intMap where for every previously provided unique id
+    -- we provide a textEdit to allow our code actions or code lens to be resolved
+  , forResolve     :: IM.IntMap ImportEdit }
 
-instance NFData MinimalImportsResult where rnf = rwhnf
+-- |For resolving code lenses and code actions we need standard text edit stuff,
+-- such as range and text, and then we need the result type, because we use this
+-- for code lenses which need to create a appropriate title
+data ImportEdit = ImportEdit { ieRange :: Range, ieText :: T.Text, ieResType :: ResultType}
 
+-- |The necessary data for providing code actions: the range, a unique ID for
+-- later resolving the action, and the type of action for giving a proper name.
+data ImportAction = ImportAction { iaRange :: Range, iaUniqueId :: Int, iaResType :: ResultType}
+
+instance Show ImportActionsResult where show _ = "<ImportActionsResult>"
+
+instance NFData ImportActionsResult where rnf = rwhnf
+
+data IAResolveData = ResolveOne
+                      { uri      :: Uri
+                      , importId :: Int }
+                    | ExplicitAll
+                      { uri :: Uri }
+                    | RefineAll
+                      { uri :: Uri }
+                    deriving (Generic, Show, A.ToJSON, FromJSON)
+
 exportedModuleStrings :: ParsedModule -> [String]
 exportedModuleStrings ParsedModule{pm_parsed_source = L _ HsModule{..}}
   | Just export <- hsmodExports,
@@ -200,89 +297,114 @@
     = map (T.unpack . printOutputable) exports
 exportedModuleStrings _ = []
 
-minimalImportsRule :: Recorder (WithPriority Log) -> Rules ()
-minimalImportsRule recorder = define (cmapWithPrio LogShake recorder) $ \MinimalImports nfp -> do
+minimalImportsRule :: Recorder (WithPriority Log) -> (ModuleName -> Bool) -> Rules ()
+minimalImportsRule recorder modFilter = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \ImportActions nfp -> runMaybeT $ do
   -- Get the typechecking artifacts from the module
-  tmr <- use TypeCheck nfp
+  tmr <- MaybeT $ use TypeCheck nfp
   -- We also need a GHC session with all the dependencies
-  hsc <- use GhcSessionDeps nfp
+  hsc <- MaybeT $ use GhcSessionDeps nfp
+
+  -- refine imports: 2 layer map ModuleName -> ModuleName -> [Avails] (exports)
+  import2Map <- do
+    -- first layer is from current(editing) module to its imports
+    ImportMap currIm <- MaybeT $ use GetImportMap nfp
+    for currIm $ \path -> do
+      -- second layer is from the imports of first layer to their imports
+      ImportMap importIm <- MaybeT $ use GetImportMap path
+      for importIm $ \imp_path -> do
+        imp_hir <- MaybeT $ use GetModIface imp_path
+        return $ mi_exports $ hirModIface imp_hir
+
   -- Use the GHC api to extract the "minimal" imports
-  (imports, mbMinImports) <- liftIO $ extractMinimalImports hsc tmr
-  let importsMap =
-        Map.fromList
-          [ (realSrcSpanStart l, printOutputable i)
-            | L (locA -> RealSrcSpan l _) i <- fromMaybe [] mbMinImports
-            , not (isImplicitPrelude i)
-          ]
-      res =
-        [ (i, Map.lookup (realSrcSpanStart l) importsMap)
-          | i <- imports
-          , RealSrcSpan l _ <- [getLoc i]
-        ]
-  return ([], MinimalImportsResult res <$ mbMinImports)
-  where
-    isImplicitPrelude :: (Outputable a) => a -> Bool
-    isImplicitPrelude importDecl =
-      T.isPrefixOf implicitPreludeImportPrefix (printOutputable importDecl)
+  locationImportWithMinimal <- MaybeT $ liftIO $ extractMinimalImports hsc tmr
 
--- | This is the prefix of an implicit prelude import which should be ignored,
--- when considering the minimal imports rule
-implicitPreludeImportPrefix :: T.Text
-implicitPreludeImportPrefix = "import (implicit) Prelude"
+  let minimalImportsResult =
+        [ (range, (printOutputable minImport, ExplicitImport))
+          | (location, impDecl, minImport) <- locationImportWithMinimal
+          , not (isQualifiedImport impDecl)
+          , not (isExplicitImport impDecl)
+          , let L _ moduleName = ideclName impDecl
+          , modFilter moduleName
+          , let range = realSrcSpanToRange location]
 
+      refineImportsResult =
+        [ (range, (T.intercalate "\n"
+                . map (printOutputable . constructImport origImport minImport)
+                . Map.toList
+                $ filteredInnerImports, RefineImport))
+        -- for every minimal imports
+        | (location, origImport, minImport@(ImportDecl{ideclName = L _ mn})) <- locationImportWithMinimal
+        -- (almost) no one wants to see an refine import list for Prelude
+        , mn /= moduleName pRELUDE
+        -- we check for the inner imports
+        , Just innerImports <- [Map.lookup mn import2Map]
+        -- and only get those symbols used
+        , Just filteredInnerImports <- [filterByImport minImport innerImports]
+        -- if no symbols from this modules then don't need to generate new import
+        , not $ null filteredInnerImports
+        -- and then convert that to a Range
+        , let range = realSrcSpanToRange location
+        ]
+  uniqueAndRangeAndText <- liftIO $ for (minimalImportsResult ++ refineImportsResult) $ \rt -> do
+                                u <- U.hashUnique <$> U.newUnique
+                                pure (u,  rt)
+  let rangeAndUnique =  [ ImportAction r u rt | (u, (r, (_, rt))) <- uniqueAndRangeAndText ]
+  pure ImportActionsResult
+                      { forLens = (\ImportAction{..} -> (iaRange, iaUniqueId)) <$> rangeAndUnique
+                      , forCodeActions = RM.fromList iaRange rangeAndUnique
+                      , forResolve =  IM.fromList ((\(u, (r, (te, ty))) -> (u, ImportEdit r te ty)) <$> uniqueAndRangeAndText) }
+
 --------------------------------------------------------------------------------
 
 -- | Use the ghc api to extract a minimal, explicit set of imports for this module
 extractMinimalImports ::
-  Maybe HscEnvEq ->
-  Maybe TcModuleResult ->
-  IO ([LImportDecl GhcRn], Maybe [LImportDecl GhcRn])
-extractMinimalImports (Just hsc) (Just TcModuleResult {..}) = do
+  HscEnvEq ->
+  TcModuleResult ->
+  IO (Maybe [(RealSrcSpan, ImportDecl GhcRn, ImportDecl GhcRn)])
+extractMinimalImports hsc TcModuleResult {..} = runMaybeT $ do
   -- extract the original imports and the typechecking environment
   let tcEnv = tmrTypechecked
       (_, imports, _, _) = tmrRenamed
       ParsedModule {pm_parsed_source = L loc _} = tmrParsed
       emss = exportedModuleStrings tmrParsed
-      span = fromMaybe (error "expected real") $ realSpan loc
+  Just srcSpan <- pure $ realSpan loc
   -- Don't make suggestions for modules which are also exported, the user probably doesn't want this!
   -- See https://github.com/haskell/haskell-language-server/issues/2079
   let notExportedImports = filter (notExported emss) imports
 
   -- GHC is secretly full of mutable state
-  gblElts <- readIORef (tcg_used_gres tcEnv)
+  gblElts <- liftIO $ readIORef (tcg_used_gres tcEnv)
 
   -- call findImportUsage does exactly what we need
   -- GHC is full of treats like this
   let usage = findImportUsage notExportedImports gblElts
-  (_, minimalImports) <-
-    initTcWithGbl (hscEnv hsc) tcEnv span $ getMinimalImports usage
+  (_, Just minimalImports) <- liftIO $
+    initTcWithGbl (hscEnv hsc) tcEnv srcSpan $ getMinimalImports usage
 
+  let minimalImportsMap =
+        Map.fromList
+          [ (realSrcSpanStart l, impDecl)
+            | L (locA -> RealSrcSpan l _) impDecl <- minimalImports
+          ]
+      results =
+          [ (location, imp, minImport)
+          | L (locA -> RealSrcSpan location _) imp <- imports
+          , Just minImport <- [Map.lookup (realSrcSpanStart location) minimalImportsMap]]
   -- return both the original imports and the computed minimal ones
-  return (imports, minimalImports)
+  return results
   where
       notExported :: [String] -> LImportDecl GhcRn -> Bool
       notExported []  _ = True
       notExported exports (L _ ImportDecl{ideclName = L _ name}) =
           not $ any (\e -> ("module " ++ moduleNameString name) == e) exports
-extractMinimalImports _ _ = return ([], Nothing)
 
-mkExplicitEdit :: (ModuleName -> Bool) -> PositionMapping -> LImportDecl GhcRn -> T.Text -> Maybe TextEdit
-mkExplicitEdit pred posMapping (L (locA -> src) imp) explicit
-  -- Explicit import list case
-#if MIN_VERSION_ghc (9,5,0)
-  | ImportDecl {ideclImportList = Just (Exactly, _)} <- imp =
+isExplicitImport :: ImportDecl GhcRn -> Bool
+#if MIN_VERSION_ghc(9,5,0)
+isExplicitImport ImportDecl {ideclImportList = Just (Exactly, _)} = True
 #else
-  | ImportDecl {ideclHiding = Just (False, _)} <- imp =
+isExplicitImport ImportDecl {ideclHiding = Just (False, _)}       = True
 #endif
-    Nothing
-  | not (isQualifiedImport imp),
-    RealSrcSpan l _ <- src,
-    L _ mn <- ideclName imp,
-    pred mn,
-    Just rng <- toCurrentRange posMapping $ realSrcSpanToRange l =
-    Just $ TextEdit rng explicit
-  | otherwise =
-    Nothing
+isExplicitImport _                                                = False
 
 -- This number is somewhat arbitrarily chosen. Ideally the protocol would tell us these things,
 -- but at the moment I don't believe we know it.
@@ -291,23 +413,6 @@
 maxColumns :: Int
 maxColumns = 120
 
--- | Given an import declaration, generate a code lens unless it has an
--- explicit import list or it's qualified
-generateLens :: PluginId -> Uri -> TextEdit -> IO (Maybe CodeLens)
-generateLens pId uri importEdit@TextEdit {_range, _newText} = do
-  let
-      title = abbreviateImportTitle _newText
-      -- the code lens has no extra data
-      _xdata = Nothing
-      -- an edit that replaces the whole declaration with the explicit one
-      edit = WorkspaceEdit (Just editsMap) Nothing Nothing
-      editsMap = HashMap.fromList [(uri, List [importEdit])]
-      -- the command argument is simply the edit
-      _arguments = Just [toJSON $ ImportCommandParams edit]
-  -- create the command
-      _command = Just $ mkLspCommand pId importCommandId title _arguments
-  -- create and return the code lens
-  return $ Just CodeLens {..}
 
 -- | The title of the command is ideally the minimal explicit import decl, but
 -- we don't want to create a really massive code lens (and the decl can be extremely large!).
@@ -331,6 +436,7 @@
       numAdditionalItems = T.count "," actualSuffix + 1
       -- We want to make text like this: import Foo (AImport, BImport, ... (30 items))
       -- We also want it to look sensible if we end up splitting in the module name itself,
+      summaryText :: Int -> T.Text
       summaryText n = " ... (" <> fromString (show n) <> " items)"
       -- so we only add a trailing paren if we've split in the export list
       suffixText = summaryText numAdditionalItems <> if T.count "(" prefix > 0 then ")" else ""
@@ -343,10 +449,63 @@
 
 --------------------------------------------------------------------------------
 
--- | A helper to run ide actions
-runIde :: IdeState -> Action a -> IO a
-runIde = runAction "importLens"
 
-within :: Range -> SrcSpan -> Bool
-within (Range start end) span =
-  isInsideSrcSpan start span || isInsideSrcSpan end span
+filterByImport :: ImportDecl GhcRn -> Map.Map ModuleName [AvailInfo] -> Maybe (Map.Map ModuleName [AvailInfo])
+#if MIN_VERSION_ghc(9,5,0)
+filterByImport (ImportDecl{ideclImportList = Just (_, L _ names)})
+#else
+filterByImport (ImportDecl{ideclHiding = Just (_, L _ names)})
+#endif
+  avails =
+      -- if there is a function defined in the current module and is used
+      -- i.e. if a function is not reexported but defined in current
+      -- module then this import cannot be refined
+  if importedNames `S.isSubsetOf` allFilteredAvailsNames
+    then Just res
+    else Nothing
+  where importedNames = S.fromList $ map (ieName . unLoc) names
+        res = flip Map.filter avails $ \a ->
+                any (`S.member` importedNames)
+                  $ concatMap
+                      getAvailNames
+                      a
+        allFilteredAvailsNames = S.fromList
+          $ concatMap getAvailNames
+          $ mconcat
+          $ Map.elems res
+filterByImport _ _ = Nothing
+
+constructImport :: ImportDecl GhcRn -> ImportDecl GhcRn -> (ModuleName, [AvailInfo]) -> ImportDecl GhcRn
+#if MIN_VERSION_ghc(9,5,0)
+constructImport ImportDecl{ideclQualified = qualified, ideclImportList = origHiding} imd@ImportDecl{ideclImportList = Just (hiding, L _ names)}
+#else
+constructImport ImportDecl{ideclQualified = qualified, ideclHiding = origHiding} imd@ImportDecl{ideclHiding = Just (hiding, L _ names)}
+#endif
+  (newModuleName, avails) = imd
+    { ideclName = noLocA newModuleName
+#if MIN_VERSION_ghc(9,5,0)
+    , ideclImportList = if isNothing origHiding && qualified /= NotQualified
+                        then Nothing
+                        else Just (hiding, noLocA newNames)
+#else
+    , ideclHiding = if isNothing origHiding && qualified /= NotQualified
+                        then Nothing
+                        else Just (hiding, noLocA newNames)
+#endif
+    }
+    where newNames = filter (\n -> any (n `containsAvail`) avails) names
+          -- Check if a name is exposed by AvailInfo (the available information of a module)
+          containsAvail :: LIE GhcRn -> AvailInfo -> Bool
+          containsAvail name avail =
+            any (\an -> printOutputable an == (printOutputable . ieName . unLoc $ name))
+              $ getAvailNames avail
+
+constructImport _ lim _ = lim
+
+getAvailNames :: AvailInfo -> [Name]
+getAvailNames =
+#if MIN_VERSION_ghc(9,7,0)
+  availNames
+#else
+  availNamesWithSelectors
+#endif
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,40 +1,56 @@
 {-# LANGUAGE DisambiguateRecordFields #-}
+{-# LANGUAGE LambdaCase               #-}
 {-# LANGUAGE NamedFieldPuns           #-}
+{-# LANGUAGE OverloadedLabels         #-}
 {-# LANGUAGE OverloadedStrings        #-}
 {-# LANGUAGE TypeOperators            #-}
 {-# LANGUAGE ViewPatterns             #-}
-
 module Main
   ( main
   ) where
 
-import           Data.Foldable              (find, forM_)
-import           Data.Text                  (Text)
-import qualified Data.Text                  as T
-import qualified Ide.Plugin.ExplicitImports as ExplicitImports
-import           System.FilePath            ((<.>), (</>))
+import           Control.Lens                  ((^.))
+import           Data.Either.Extra
+import           Data.Foldable                 (find)
+import           Data.Row                      ((.+), (.==))
+import           Data.Text                     (Text)
+import qualified Data.Text                     as T
+import           Data.Traversable              (for)
+import qualified Ide.Plugin.ExplicitImports    as ExplicitImports
+import qualified Language.LSP.Protocol.Lens    as L
+import           Language.LSP.Protocol.Message
+import           System.FilePath               ((</>))
 import           Test.Hls
 
 explicitImportsPlugin :: PluginTestDescriptor ExplicitImports.Log
 explicitImportsPlugin = mkPluginTestDescriptor ExplicitImports.descriptor "explicitImports"
 
-longModule :: T.Text
-longModule = "F" <> T.replicate 80 "o"
-
 main :: IO ()
-main = defaultTestRunner $
+main = defaultTestRunner $ testGroup "import-actions"
+  [testGroup
+    "Refine Imports"
+    [ codeActionGoldenTest "RefineWithOverride" 3 1
+    , codeLensGoldenTest isRefineImports "RefineUsualCase" 1
+    , codeLensGoldenTest isRefineImports "RefineQualified" 0
+    , codeLensGoldenTest isRefineImports "RefineQualifiedExplicit" 0
+    ],
   testGroup
     "Make imports explicit"
-    [ codeActionGoldenTest "UsualCase" 3 0
-    , codeLensGoldenTest "UsualCase" 0
+    [ codeActionAllGoldenTest "ExplicitUsualCase" 3 0
+    , codeActionAllResolveGoldenTest "ExplicitUsualCase" 3 0
+    , codeActionOnlyGoldenTest "ExplicitOnlyThis" 3 0
+    , codeActionOnlyResolveGoldenTest "ExplicitOnlyThis" 3 0
+    , codeLensGoldenTest notRefineImports "ExplicitUsualCase" 0
+    , codeActionBreakFile "ExplicitBreakFile" 4 0
+    , codeActionStaleAction "ExplicitStaleAction" 4 0
     , testCase "No CodeAction when exported" $
-      runSessionWithServer explicitImportsPlugin testDataDir $ do
-        doc <- openDoc "Exported.hs" "haskell"
+      runSessionWithServer def explicitImportsPlugin testDataDir $ do
+        doc <- openDoc "ExplicitExported.hs" "haskell"
         action <- getCodeActions doc (pointRange 3 0)
         liftIO $ action @?= []
     , testCase "No CodeLens when exported" $
-      runSessionWithServer explicitImportsPlugin testDataDir $ do
-        doc <- openDoc "Exported.hs" "haskell"
+      runSessionWithServer def explicitImportsPlugin testDataDir $ do
+        doc <- openDoc "ExplicitExported.hs" "haskell"
         lenses <- getCodeLenses doc
         liftIO $ lenses @?= []
     , testGroup "Title abbreviation"
@@ -60,49 +76,102 @@
               o = "import " <> T.replicate 80 "F" <> " (Athing, Bthing, ... (3 items))"
           in ExplicitImports.abbreviateImportTitle i @?= o
       ]
-    ]
+    ]]
 
 -- code action tests
 
-codeActionGoldenTest :: FilePath -> Int -> Int -> TestTree
-codeActionGoldenTest fp l c = goldenWithExplicitImports fp $ \doc -> do
+codeActionAllGoldenTest :: FilePath -> Int -> Int -> TestTree
+codeActionAllGoldenTest fp l c = goldenWithImportActions " code action" fp codeActionNoResolveCaps $ \doc -> do
   actions <- getCodeActions doc (pointRange l c)
   case find ((== Just "Make all imports explicit") . caTitle) actions of
     Just (InR x) -> executeCodeAction x
     _            -> liftIO $ assertFailure "Unable to find CodeAction"
 
+codeActionBreakFile :: FilePath -> Int -> Int -> TestTree
+codeActionBreakFile fp l c = goldenWithImportActions " code action" fp codeActionNoResolveCaps $ \doc -> do
+  _ <- getCodeLenses doc
+  changeDoc doc [edit]
+  actions <- getCodeActions doc (pointRange l c)
+  case find ((== Just "Make all imports explicit") . caTitle) actions of
+    Just (InR x) -> executeCodeAction x
+    _            -> liftIO $ assertFailure "Unable to find CodeAction"
+  where edit = TextDocumentContentChangeEvent $ InL $ #range .== pointRange 2 29
+                                                   .+ #rangeLength .== Nothing
+                                                   .+ #text .== "x"
+
+codeActionStaleAction :: FilePath -> Int -> Int -> TestTree
+codeActionStaleAction fp l c = goldenWithImportActions " code action" fp codeActionResolveCaps $ \doc -> do
+  _ <- waitForDiagnostics
+  actions <- getCodeActions doc (pointRange l c)
+  changeDoc doc [edit]
+  _ <- waitForDiagnostics
+  case find ((== Just "Make this import explicit") . caTitle) actions of
+    Just (InR x) ->
+      maybeResolveCodeAction x >>=
+        \case Just _  -> liftIO $ assertFailure "Code action still valid"
+              Nothing -> pure ()
+    _            -> liftIO $ assertFailure "Unable to find CodeAction"
+  where edit = TextDocumentContentChangeEvent $ InL $ #range .== Range (Position 6 0) (Position 6 0)
+                                                   .+ #rangeLength .== Nothing
+                                                   .+ #text .== "\ntesting = undefined"
+
+codeActionAllResolveGoldenTest :: FilePath -> Int -> Int -> TestTree
+codeActionAllResolveGoldenTest fp l c = goldenWithImportActions " code action resolve" fp codeActionResolveCaps $ \doc -> do
+  actions <- getCodeActions doc (pointRange l c)
+  Just (InR x) <- pure $ find ((== Just "Make all imports explicit") . caTitle) actions
+  resolved <- resolveCodeAction x
+  executeCodeAction resolved
+
+codeActionOnlyGoldenTest :: FilePath -> Int -> Int -> TestTree
+codeActionOnlyGoldenTest fp l c = goldenWithImportActions " code action" fp codeActionNoResolveCaps $ \doc -> do
+  actions <- getCodeActions doc (pointRange l c)
+  case find ((== Just "Make this import explicit") . caTitle) actions of
+    Just (InR x) -> executeCodeAction x
+    _            -> liftIO $ assertFailure "Unable to find CodeAction"
+
+codeActionOnlyResolveGoldenTest :: FilePath -> Int -> Int -> TestTree
+codeActionOnlyResolveGoldenTest fp l c = goldenWithImportActions " code action resolve" fp codeActionResolveCaps $ \doc -> do
+  actions <- getCodeActions doc (pointRange l c)
+  Just (InR x) <- pure $ find ((== Just "Make this import explicit") . caTitle) actions
+  resolved <- resolveCodeAction x
+  executeCodeAction resolved
+
+maybeResolveCodeAction :: CodeAction -> Session (Maybe CodeAction)
+maybeResolveCodeAction ca = do
+  resolveResponse <- request SMethod_CodeActionResolve ca
+  let resolved = resolveResponse ^. L.result
+  pure $ eitherToMaybe resolved
+
 caTitle :: (Command |? CodeAction) -> Maybe Text
 caTitle (InR CodeAction {_title}) = Just _title
 caTitle _                         = Nothing
 
 -- code lens tests
 
-codeLensGoldenTest :: FilePath -> Int -> TestTree
-codeLensGoldenTest fp codeLensIdx = goldenWithExplicitImports fp $ \doc -> do
-  codeLens <- (!! codeLensIdx) <$> getCodeLensesBy isExplicitImports doc
-  mapM_ executeCmd
-    [c | CodeLens{_command = Just c} <- [codeLens]]
-
-getCodeLensesBy :: (CodeLens -> Bool) -> TextDocumentIdentifier -> Session [CodeLens]
-getCodeLensesBy f doc = filter f <$> getCodeLenses doc
+codeLensGoldenTest :: (CodeLens -> Bool) -> FilePath -> Int -> TestTree
+codeLensGoldenTest predicate fp i = goldenWithImportActions " code lens" fp codeActionNoResolveCaps $ \doc -> do
+  codeLenses <- getCodeLenses doc
+  resolvedCodeLenses <- for codeLenses resolveCodeLens
+  (CodeLens {_command = Just c}) <- pure (filter predicate resolvedCodeLenses !! i)
+  executeCmd c
 
-isExplicitImports :: CodeLens -> Bool
-isExplicitImports (CodeLens _ (Just (Command _ cmd _)) _)
-  | ":explicitImports:" `T.isInfixOf` cmd = True
-isExplicitImports _ = False
+notRefineImports :: CodeLens -> Bool
+notRefineImports (CodeLens _ (Just (Command text _ _)) _)
+  | "Refine imports to" `T.isPrefixOf` text = False
+notRefineImports _ = True
 
 -- Execute command and wait for result
 executeCmd :: Command -> Session ()
 executeCmd cmd = do
     executeCommand cmd
-    _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit)
+    _resp <- skipManyTill anyMessage (message SMethod_WorkspaceApplyEdit)
     -- liftIO $ print _resp
     return ()
 
 -- helpers
 
-goldenWithExplicitImports :: FilePath -> (TextDocumentIdentifier -> Session ()) -> TestTree
-goldenWithExplicitImports fp = goldenWithHaskellDoc explicitImportsPlugin (fp <> " (golden)") testDataDir fp "expected" "hs"
+goldenWithImportActions :: String -> FilePath -> ClientCapabilities -> (TextDocumentIdentifier -> Session ()) -> TestTree
+goldenWithImportActions title fp caps = goldenWithHaskellAndCaps def caps explicitImportsPlugin (fp <> title <> " (golden)") testDataDir fp "expected" "hs"
 
 testDataDir :: String
 testDataDir = "test" </> "testdata"
@@ -112,3 +181,18 @@
   (subtract 1 -> fromIntegral -> line)
   (subtract 1 -> fromIntegral -> col) =
     Range (Position line col) (Position line $ col + 1)
+
+-------------------------------------------------------------------------------
+-- code action tests
+
+codeActionGoldenTest :: FilePath -> Int -> Int -> TestTree
+codeActionGoldenTest fp l c = goldenWithImportActions "" fp codeActionNoResolveCaps $ \doc -> do
+  actions <- getCodeActions doc (pointRange l c)
+  case find ((== Just "Refine all imports") . caTitle) actions of
+    Just (InR x) -> executeCodeAction x
+    _            -> liftIO $ assertFailure "Unable to find CodeAction"
+
+isRefineImports :: CodeLens -> Bool
+isRefineImports (CodeLens _ (Just (Command txt _ _)) _)
+  | "Refine imports to" `T.isInfixOf` txt = True
+isRefineImports _ = False
diff --git a/test/testdata/A.hs b/test/testdata/A.hs
deleted file mode 100644
--- a/test/testdata/A.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module A where
-
-a1 :: String
-a1 = "a1"
-
-a2 :: String
-a2 = "a2"
diff --git a/test/testdata/ExplicitA.hs b/test/testdata/ExplicitA.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitA.hs
@@ -0,0 +1,7 @@
+module ExplicitA where
+
+a1 :: String
+a1 = "a1"
+
+a2 :: String
+a2 = "a2"
diff --git a/test/testdata/ExplicitB.hs b/test/testdata/ExplicitB.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitB.hs
@@ -0,0 +1,7 @@
+module ExplicitB where
+
+b1 :: String
+b1 = "b1"
+
+b2 :: String
+b2 = "b2"
diff --git a/test/testdata/ExplicitBreakFile.hs b/test/testdata/ExplicitBreakFile.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitBreakFile.hs
@@ -0,0 +1,6 @@
+{-# OPTIONS_GHC -Wall #-}
+module ExplicitBreakFile where
+
+import ExplicitA
+
+main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/ExplicitExported.hs b/test/testdata/ExplicitExported.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitExported.hs
@@ -0,0 +1,6 @@
+module ExplicitExported (module ExplicitA) where
+
+import ExplicitA
+
+main :: IO ()
+main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/ExplicitOnlyThis.hs b/test/testdata/ExplicitOnlyThis.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitOnlyThis.hs
@@ -0,0 +1,7 @@
+module ExplicitOnlyThis where
+
+import ExplicitA
+import ExplicitB
+
+main :: IO ()
+main = putStrLn $ "hello " ++ a1 ++ b1
diff --git a/test/testdata/ExplicitStaleAction.hs b/test/testdata/ExplicitStaleAction.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitStaleAction.hs
@@ -0,0 +1,6 @@
+{-# OPTIONS_GHC -Wall #-}
+module ExplicitStaleAction where
+
+import ExplicitA
+
+main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/ExplicitUsualCase.hs b/test/testdata/ExplicitUsualCase.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/ExplicitUsualCase.hs
@@ -0,0 +1,6 @@
+module ExplicitUsualCase where
+
+import ExplicitA
+
+main :: IO ()
+main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/Exported.hs b/test/testdata/Exported.hs
deleted file mode 100644
--- a/test/testdata/Exported.hs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Exported (module A) where
-
-import A
-
-main :: IO ()
-main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/RefineA.hs b/test/testdata/RefineA.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineA.hs
@@ -0,0 +1,7 @@
+module RefineA 
+  ( module RefineB
+  , module RefineC
+  ) where
+
+import RefineB
+import RefineC
diff --git a/test/testdata/RefineB.hs b/test/testdata/RefineB.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineB.hs
@@ -0,0 +1,7 @@
+module RefineB where 
+
+b1 :: String
+b1 = "b1"
+
+b2 :: String
+b2 = "b2"
diff --git a/test/testdata/RefineC.hs b/test/testdata/RefineC.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineC.hs
@@ -0,0 +1,4 @@
+module RefineC where
+
+c1 :: String
+c1 = "c1"
diff --git a/test/testdata/RefineD.hs b/test/testdata/RefineD.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineD.hs
@@ -0,0 +1,7 @@
+module RefineD (module RefineE, module RefineD) where
+
+import RefineE hiding (e1)
+import qualified RefineE
+
+e1 :: String 
+e1 = RefineE.e1 <> " but overrided"
diff --git a/test/testdata/RefineE.hs b/test/testdata/RefineE.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineE.hs
@@ -0,0 +1,7 @@
+module RefineE where
+
+e1 :: String
+e1 = "e1"
+
+e2 :: String
+e2 = "e2"
diff --git a/test/testdata/RefineF.hs b/test/testdata/RefineF.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineF.hs
@@ -0,0 +1,7 @@
+module RefineF (module RefineF, module RefineG) where
+
+import RefineG
+
+f1 :: String 
+f1 = "f1"
+
diff --git a/test/testdata/RefineG.hs b/test/testdata/RefineG.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineG.hs
@@ -0,0 +1,4 @@
+module RefineG where
+
+g1 :: String 
+g1 = "g1"
diff --git a/test/testdata/RefineQualified.hs b/test/testdata/RefineQualified.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineQualified.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import qualified RefineA as RA
+import RefineD
+import Data.List (intercalate)
+
+main :: IO ()
+main = putStrLn 
+     $ "hello " 
+    <> intercalate ", " [RA.b1, RA.c1, e2]
diff --git a/test/testdata/RefineQualifiedExplicit.hs b/test/testdata/RefineQualifiedExplicit.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineQualifiedExplicit.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import qualified RefineA as RA (b1, c1)
+import RefineD
+import Data.List (intercalate)
+
+main :: IO ()
+main = putStrLn 
+     $ "hello " 
+    <> intercalate ", " [RA.b1, RA.c1, e2]
diff --git a/test/testdata/RefineUsualCase.hs b/test/testdata/RefineUsualCase.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineUsualCase.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import RefineA
+import RefineD
+import Data.List (intercalate)
+
+main :: IO ()
+main = putStrLn 
+     $ "hello " 
+    <> intercalate ", " [b1, c1, e2]
diff --git a/test/testdata/RefineWithOverride.hs b/test/testdata/RefineWithOverride.hs
new file mode 100644
--- /dev/null
+++ b/test/testdata/RefineWithOverride.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import RefineA
+import RefineD
+import RefineF
+import Data.List (intercalate)
+
+main :: IO ()
+main = putStrLn 
+     $ "hello " 
+    <> intercalate ", " [b1, c1, e1, f1, g1]
diff --git a/test/testdata/UsualCase.hs b/test/testdata/UsualCase.hs
deleted file mode 100644
--- a/test/testdata/UsualCase.hs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
-import A
-
-main :: IO ()
-main = putStrLn $ "hello " ++ a1
diff --git a/test/testdata/hie.yaml b/test/testdata/hie.yaml
--- a/test/testdata/hie.yaml
+++ b/test/testdata/hie.yaml
@@ -1,6 +1,20 @@
 cradle:
   direct:
     arguments:
-    - UsualCase.hs
-    - Exported.hs
-    - A.hs
+    - ExplicitOnlyThis.hs
+    - ExplicitStaleAction.hs
+    - ExplicitUsualCase.hs
+    - ExplicitExported.hs
+    - ExplicitA.hs
+    - ExplicitB.hs
+    - RefineUsualCase.hs
+    - RefineQualified.hs
+    - RefineQualifiedExplicit.hs
+    - RefineWithOverride.hs
+    - RefineA.hs
+    - RefineB.hs
+    - RefineC.hs
+    - RefineD.hs
+    - RefineE.hs
+    - RefineF.hs
+    - RefineG.hs
