{-# LANGUAGE PatternGuards, ScopedTypeVariables, RecordWildCards #-}
{-
    Reduce the number of import declarations.
    Two import declarations can be combined if:
      (note, A[] is A with whatever import list, or none)

    import A[]; import A[] = import A[]
    import A(B); import A(C) = import A(B,C)
    import A; import A(C) = import A
    import A; import A hiding (C) = import A
    import A[]; import A[] as Y = import A[] as Y

<TEST>
import A; import A -- import A
import A; import A; import A -- import A
import A(Foo) ; import A -- import A
import A ;import A(Foo) -- import A
import A(Bar(..)); import {-# SOURCE #-} A
import A; import B
import A(B) ; import A(C) -- import A(B,C)
import A; import A hiding (C) -- import A
import A; import A as Y -- import A as Y
import A; import qualified A as Y
import A as B; import A as C
import A as A -- import A
import qualified A as A -- import qualified A
import A; import B; import A -- import A
import qualified A; import A
import B; import A; import A -- import A
import A hiding(Foo); import A hiding(Bar)
import List -- import Data.List
import qualified List -- import qualified Data.List as List
import Char(foo) -- import Data.Char(foo)
import IO(foo)
import IO as X -- import System.IO as X; import System.IO.Error as X; import Control.Exception  as X (bracket,bracket_)
</TEST>
-}


module Hint.Import(importHint) where

import Hint.Type(ModuHint,ModuleEx(..),Idea(..),Severity(..),suggest',toSS',rawIdea',rawIdeaN')
import Refact.Types hiding (ModuleName)
import qualified Refact.Types as R
import Data.Tuple.Extra
import Data.List.Extra
import Data.Generics.Uniplate.Operations
import Data.Maybe
import Control.Applicative
import Prelude

import FastString
import BasicTypes
import RdrName
import Module
import HsSyn
import SrcLoc
import GHC.Util

importHint :: ModuHint
importHint :: ModuHint
importHint _ ModuleEx {ghcModule :: ModuleEx -> Located (HsModule GhcPs)
ghcModule=L _ HsModule{hsmodImports :: forall pass. HsModule pass -> [LImportDecl pass]
hsmodImports=[LImportDecl GhcPs]
ms}} =
  -- Ideas for combining multiple imports.
  (((ModuleName, Maybe String), [LImportDecl GhcPs]) -> [Idea])
-> [((ModuleName, Maybe String), [LImportDecl GhcPs])] -> [Idea]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([LImportDecl GhcPs] -> [Idea]
reduceImports ([LImportDecl GhcPs] -> [Idea])
-> (((ModuleName, Maybe String), [LImportDecl GhcPs])
    -> [LImportDecl GhcPs])
-> ((ModuleName, Maybe String), [LImportDecl GhcPs])
-> [Idea]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ModuleName, Maybe String), [LImportDecl GhcPs])
-> [LImportDecl GhcPs]
forall a b. (a, b) -> b
snd) (
    [((ModuleName, Maybe String), LImportDecl GhcPs)]
-> [((ModuleName, Maybe String), [LImportDecl GhcPs])]
forall k v. Ord k => [(k, v)] -> [(k, [v])]
groupSort [((ModuleName
n, Maybe String
pkg), LImportDecl GhcPs
i) | LImportDecl GhcPs
i <- [LImportDecl GhcPs]
ms
              , Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ImportDecl GhcPs -> Bool
forall pass. ImportDecl pass -> Bool
ideclSource (LImportDecl GhcPs -> SrcSpanLess (LImportDecl GhcPs)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc LImportDecl GhcPs
i)
              , let i' :: SrcSpanLess (LImportDecl GhcPs)
i' = LImportDecl GhcPs -> SrcSpanLess (LImportDecl GhcPs)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc LImportDecl GhcPs
i
              , let n :: SrcSpanLess (Located ModuleName)
n = Located ModuleName -> SrcSpanLess (Located ModuleName)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc (Located ModuleName -> SrcSpanLess (Located ModuleName))
-> Located ModuleName -> SrcSpanLess (Located ModuleName)
forall a b. (a -> b) -> a -> b
$ ImportDecl GhcPs -> Located ModuleName
forall pass. ImportDecl pass -> Located ModuleName
ideclName ImportDecl GhcPs
i'
              , let pkg :: Maybe String
pkg  = FastString -> String
unpackFS (FastString -> String)
-> (StringLiteral -> FastString) -> StringLiteral -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StringLiteral -> FastString
sl_fs (StringLiteral -> String) -> Maybe StringLiteral -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ImportDecl GhcPs -> Maybe StringLiteral
forall pass. ImportDecl pass -> Maybe StringLiteral
ideclPkgQual ImportDecl GhcPs
i']) [Idea] -> [Idea] -> [Idea]
forall a. [a] -> [a] -> [a]
++
  -- Ideas for removing redundant 'as' clauses.
  (LImportDecl GhcPs -> [Idea]) -> [LImportDecl GhcPs] -> [Idea]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LImportDecl GhcPs -> [Idea]
stripRedundantAlias [LImportDecl GhcPs]
ms [Idea] -> [Idea] -> [Idea]
forall a. [a] -> [a] -> [a]
++
  -- Ideas for replacing deprecated imports by their preferred
  -- equivalents.
  (LImportDecl GhcPs -> [Idea]) -> [LImportDecl GhcPs] -> [Idea]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap LImportDecl GhcPs -> [Idea]
preferHierarchicalImports [LImportDecl GhcPs]
ms

reduceImports :: [LImportDecl GhcPs] -> [Idea]
reduceImports :: [LImportDecl GhcPs] -> [Idea]
reduceImports [] = []
reduceImports ms :: [LImportDecl GhcPs]
ms@(m :: LImportDecl GhcPs
m:_) =
  [Severity
-> String
-> SrcSpan
-> String
-> Maybe String
-> [Note]
-> [Refactoring SrcSpan]
-> Idea
rawIdea' Severity
Hint.Type.Warning "Use fewer imports" (LImportDecl GhcPs -> SrcSpan
forall a. HasSrcSpan a => a -> SrcSpan
getLoc LImportDecl GhcPs
m) ([LImportDecl GhcPs] -> String
f [LImportDecl GhcPs]
ms) (String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ [LImportDecl GhcPs] -> String
f [LImportDecl GhcPs]
x) [] [Refactoring SrcSpan]
rs
  | Just (x :: [LImportDecl GhcPs]
x, rs :: [Refactoring SrcSpan]
rs) <- [[LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplify [LImportDecl GhcPs]
ms]]
  where f :: [LImportDecl GhcPs] -> String
f = [String] -> String
unlines ([String] -> String)
-> ([LImportDecl GhcPs] -> [String])
-> [LImportDecl GhcPs]
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LImportDecl GhcPs -> String) -> [LImportDecl GhcPs] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map LImportDecl GhcPs -> String
forall a. Outputable a => a -> String
unsafePrettyPrint

simplify :: [LImportDecl GhcPs]
         -> Maybe ([LImportDecl GhcPs], [Refactoring R.SrcSpan])
simplify :: [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplify [] = Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a. Maybe a
Nothing
simplify (x :: LImportDecl GhcPs
x : xs :: [LImportDecl GhcPs]
xs) = case LImportDecl GhcPs
-> [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplifyHead LImportDecl GhcPs
x [LImportDecl GhcPs]
xs of
    Nothing -> ([LImportDecl GhcPs] -> [LImportDecl GhcPs])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a a' b. (a -> a') -> (a, b) -> (a', b)
first (LImportDecl GhcPs
xLImportDecl GhcPs -> [LImportDecl GhcPs] -> [LImportDecl GhcPs]
forall a. a -> [a] -> [a]
:) (([LImportDecl GhcPs], [Refactoring SrcSpan])
 -> ([LImportDecl GhcPs], [Refactoring SrcSpan]))
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplify [LImportDecl GhcPs]
xs
    Just (xs :: [LImportDecl GhcPs]
xs, rs :: [Refactoring SrcSpan]
rs) -> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (([LImportDecl GhcPs], [Refactoring SrcSpan])
 -> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan]))
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a b. (a -> b) -> a -> b
$ ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> (([LImportDecl GhcPs], [Refactoring SrcSpan])
    -> ([LImportDecl GhcPs], [Refactoring SrcSpan]))
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([LImportDecl GhcPs]
xs, [Refactoring SrcSpan]
rs) (([Refactoring SrcSpan] -> [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall b b' a. (b -> b') -> (a, b) -> (a, b')
second ([Refactoring SrcSpan]
-> [Refactoring SrcSpan] -> [Refactoring SrcSpan]
forall a. [a] -> [a] -> [a]
++ [Refactoring SrcSpan]
rs)) (Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
 -> ([LImportDecl GhcPs], [Refactoring SrcSpan]))
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a b. (a -> b) -> a -> b
$ [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplify [LImportDecl GhcPs]
xs

simplifyHead :: LImportDecl GhcPs
             -> [LImportDecl GhcPs]
             -> Maybe ([LImportDecl GhcPs], [Refactoring R.SrcSpan])
simplifyHead :: LImportDecl GhcPs
-> [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplifyHead x :: LImportDecl GhcPs
x (y :: LImportDecl GhcPs
y : ys :: [LImportDecl GhcPs]
ys) = case LImportDecl GhcPs
-> LImportDecl GhcPs
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
combine LImportDecl GhcPs
x LImportDecl GhcPs
y of
    Nothing -> ([LImportDecl GhcPs] -> [LImportDecl GhcPs])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a a' b. (a -> a') -> (a, b) -> (a', b)
first (LImportDecl GhcPs
yLImportDecl GhcPs -> [LImportDecl GhcPs] -> [LImportDecl GhcPs]
forall a. a -> [a] -> [a]
:) (([LImportDecl GhcPs], [Refactoring SrcSpan])
 -> ([LImportDecl GhcPs], [Refactoring SrcSpan]))
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LImportDecl GhcPs
-> [LImportDecl GhcPs]
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
simplifyHead LImportDecl GhcPs
x [LImportDecl GhcPs]
ys
    Just (xy :: LImportDecl GhcPs
xy, rs :: [Refactoring SrcSpan]
rs) -> ([LImportDecl GhcPs], [Refactoring SrcSpan])
-> Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (LImportDecl GhcPs
xy LImportDecl GhcPs -> [LImportDecl GhcPs] -> [LImportDecl GhcPs]
forall a. a -> [a] -> [a]
: [LImportDecl GhcPs]
ys, [Refactoring SrcSpan]
rs)
simplifyHead x :: LImportDecl GhcPs
x [] = Maybe ([LImportDecl GhcPs], [Refactoring SrcSpan])
forall a. Maybe a
Nothing

combine :: LImportDecl GhcPs
        -> LImportDecl GhcPs
        -> Maybe (LImportDecl GhcPs, [Refactoring R.SrcSpan])
combine :: LImportDecl GhcPs
-> LImportDecl GhcPs
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
combine x :: LImportDecl GhcPs
x@(LL _ x' :: SrcSpanLess (LImportDecl GhcPs)
x') y :: LImportDecl GhcPs
y@(LL _ y' :: SrcSpanLess (LImportDecl GhcPs)
y')
  -- Both (un/)qualified, common 'as', same names : Delete the second.
  | Bool
qual, Bool
as, Bool
specs = (LImportDecl GhcPs, [Refactoring SrcSpan])
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (LImportDecl GhcPs
x, [RType -> SrcSpan -> Refactoring SrcSpan
forall a. RType -> a -> Refactoring a
Delete RType
Import (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
y)])
    -- Both (un/)qualified, common 'as', different names : Merge the
    -- second into the first and delete it.
  | Bool
qual, Bool
as
  , Just (False, xs :: Located [LIE GhcPs]
xs) <- ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x'
  , Just (False, ys :: Located [LIE GhcPs]
ys) <- ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y' =
      let newImp :: LImportDecl GhcPs
newImp = SrcSpanLess (LImportDecl GhcPs) -> LImportDecl GhcPs
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x'{ideclHiding :: Maybe (Bool, Located [LIE GhcPs])
ideclHiding = (Bool, Located [LIE GhcPs]) -> Maybe (Bool, Located [LIE GhcPs])
forall a. a -> Maybe a
Just (Bool
False, SrcSpanLess (Located [LIE GhcPs]) -> Located [LIE GhcPs]
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (Located [LIE GhcPs] -> SrcSpanLess (Located [LIE GhcPs])
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Located [LIE GhcPs]
xs [LIE GhcPs] -> [LIE GhcPs] -> [LIE GhcPs]
forall a. [a] -> [a] -> [a]
++ Located [LIE GhcPs] -> SrcSpanLess (Located [LIE GhcPs])
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Located [LIE GhcPs]
ys))}
      in (LImportDecl GhcPs, [Refactoring SrcSpan])
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (LImportDecl GhcPs
newImp, [RType
-> SrcSpan -> [(String, SrcSpan)] -> String -> Refactoring SrcSpan
forall a. RType -> a -> [(String, a)] -> String -> Refactoring a
Replace RType
Import (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
x) [] (ImportDecl GhcPs -> String
forall a. Outputable a => a -> String
unsafePrettyPrint (LImportDecl GhcPs -> SrcSpanLess (LImportDecl GhcPs)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc LImportDecl GhcPs
newImp))
                       , RType -> SrcSpan -> Refactoring SrcSpan
forall a. RType -> a -> Refactoring a
Delete RType
Import (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
y)])
  -- Both (un/qualified), common 'as', one has names the other doesn't
  -- : Delete the one with names.
  | Bool
qual, Bool
as, Maybe (Bool, Located [LIE GhcPs]) -> Bool
forall a. Maybe a -> Bool
isNothing (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x') Bool -> Bool -> Bool
|| Maybe (Bool, Located [LIE GhcPs]) -> Bool
forall a. Maybe a -> Bool
isNothing (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y') =
       let (newImp :: LImportDecl GhcPs
newImp, toDelete :: LImportDecl GhcPs
toDelete) = if Maybe (Bool, Located [LIE GhcPs]) -> Bool
forall a. Maybe a -> Bool
isNothing (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x') then (LImportDecl GhcPs
x, LImportDecl GhcPs
y) else (LImportDecl GhcPs
y, LImportDecl GhcPs
x)
       in (LImportDecl GhcPs, [Refactoring SrcSpan])
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (LImportDecl GhcPs
newImp, [RType -> SrcSpan -> Refactoring SrcSpan
forall a. RType -> a -> Refactoring a
Delete RType
Import (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
toDelete)])
  -- Both unqualified, same names, one (and only one) has an 'as'
  -- clause : Delete the one without an 'as'.
  | Bool -> Bool
not (ImportDecl GhcPs -> Bool
forall pass. ImportDecl pass -> Bool
ideclQualified SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x'), Bool
qual, Bool
specs, [Located ModuleName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Located ModuleName]
ass Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 1 =
       let (newImp :: LImportDecl GhcPs
newImp, toDelete :: LImportDecl GhcPs
toDelete) = if Maybe (Located ModuleName) -> Bool
forall a. Maybe a -> Bool
isJust (ImportDecl GhcPs -> Maybe (Located ModuleName)
forall pass. ImportDecl pass -> Maybe (Located ModuleName)
ideclAs SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x') then (LImportDecl GhcPs
x, LImportDecl GhcPs
y) else (LImportDecl GhcPs
y, LImportDecl GhcPs
x)
       in (LImportDecl GhcPs, [Refactoring SrcSpan])
-> Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. a -> Maybe a
Just (LImportDecl GhcPs
newImp, [RType -> SrcSpan -> Refactoring SrcSpan
forall a. RType -> a -> Refactoring a
Delete RType
Import (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
toDelete)])
  -- No hints.
  | Bool
otherwise = Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. Maybe a
Nothing
    where
        eqMaybe:: Eq a => Maybe (Located a) -> Maybe (Located a) -> Bool
        eqMaybe :: Maybe (Located a) -> Maybe (Located a) -> Bool
eqMaybe (Just x :: Located a
x) (Just y :: Located a
y) = Located a
x Located a -> Located a -> Bool
forall a. (HasSrcSpan a, Eq (SrcSpanLess a)) => a -> a -> Bool
`eqLocated` Located a
y
        eqMaybe Nothing Nothing = Bool
True
        eqMaybe _ _ = Bool
False

        qual :: Bool
qual = ImportDecl GhcPs -> Bool
forall pass. ImportDecl pass -> Bool
ideclQualified SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x' Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== ImportDecl GhcPs -> Bool
forall pass. ImportDecl pass -> Bool
ideclQualified SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y'
        as :: Bool
as = ImportDecl GhcPs -> Maybe (Located ModuleName)
forall pass. ImportDecl pass -> Maybe (Located ModuleName)
ideclAs SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x' Maybe (Located ModuleName) -> Maybe (Located ModuleName) -> Bool
forall a. Eq a => Maybe (Located a) -> Maybe (Located a) -> Bool
`eqMaybe` ImportDecl GhcPs -> Maybe (Located ModuleName)
forall pass. ImportDecl pass -> Maybe (Located ModuleName)
ideclAs SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y'
        ass :: [Located ModuleName]
ass = (ImportDecl GhcPs -> Maybe (Located ModuleName))
-> [ImportDecl GhcPs] -> [Located ModuleName]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ImportDecl GhcPs -> Maybe (Located ModuleName)
forall pass. ImportDecl pass -> Maybe (Located ModuleName)
ideclAs [SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x', SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y']
        specs :: Bool
specs = (SrcSpan -> SrcSpan)
-> Maybe (Bool, Located [LIE GhcPs])
-> Maybe (Bool, Located [LIE GhcPs])
forall from to. Biplate from to => (to -> to) -> from -> from
transformBi (SrcSpan -> SrcSpan -> SrcSpan
forall a b. a -> b -> a
const SrcSpan
noSrcSpan) (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
x') Maybe (Bool, Located [LIE GhcPs])
-> Maybe (Bool, Located [LIE GhcPs]) -> Bool
forall a. Eq a => a -> a -> Bool
==
                    (SrcSpan -> SrcSpan)
-> Maybe (Bool, Located [LIE GhcPs])
-> Maybe (Bool, Located [LIE GhcPs])
forall from to. Biplate from to => (to -> to) -> from -> from
transformBi (SrcSpan -> SrcSpan -> SrcSpan
forall a b. a -> b -> a
const SrcSpan
noSrcSpan) (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
y')
combine _ _ = Maybe (LImportDecl GhcPs, [Refactoring SrcSpan])
forall a. Maybe a
Nothing -- {-# COMPLETE LL #-}

stripRedundantAlias :: LImportDecl GhcPs -> [Idea]
stripRedundantAlias :: LImportDecl GhcPs -> [Idea]
stripRedundantAlias x :: LImportDecl GhcPs
x@(LL loc :: SrcSpan
loc i :: SrcSpanLess (LImportDecl GhcPs)
i@ImportDecl {..})
  -- Suggest 'import M as M' be just 'import M'.
  | ModuleName -> Maybe ModuleName
forall a. a -> Maybe a
Just (Located ModuleName -> SrcSpanLess (Located ModuleName)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Located ModuleName
ideclName) Maybe ModuleName -> Maybe ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
== (Located ModuleName -> ModuleName)
-> Maybe (Located ModuleName) -> Maybe ModuleName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Located ModuleName -> ModuleName
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Maybe (Located ModuleName)
ideclAs =
      [String
-> LImportDecl GhcPs
-> LImportDecl GhcPs
-> [Refactoring SrcSpan]
-> Idea
forall a b.
(HasSrcSpan a, Outputable a, HasSrcSpan b, Outputable b) =>
String -> a -> b -> [Refactoring SrcSpan] -> Idea
suggest' "Redundant as" LImportDecl GhcPs
x (SrcSpan -> SrcSpanLess (LImportDecl GhcPs) -> LImportDecl GhcPs
forall a. HasSrcSpan a => SrcSpan -> SrcSpanLess a -> a
cL SrcSpan
loc SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
i{ideclAs :: Maybe (Located ModuleName)
ideclAs=Maybe (Located ModuleName)
forall a. Maybe a
Nothing} :: LImportDecl GhcPs) [SrcSpan -> Refactoring SrcSpan
forall a. a -> Refactoring a
RemoveAsKeyword (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
x)]]
stripRedundantAlias _ = []

preferHierarchicalImports :: LImportDecl GhcPs -> [Idea]
preferHierarchicalImports :: LImportDecl GhcPs -> [Idea]
preferHierarchicalImports x :: LImportDecl GhcPs
x@(LL loc :: SrcSpan
loc i :: SrcSpanLess (LImportDecl GhcPs)
i@ImportDecl{ideclName=L _ n,ideclPkgQual=Nothing})
  -- Suggest 'import IO' be rewritten 'import System.IO, import
  -- System.IO.Error, import Control.Exception(bracket, bracket_)'.
  | ModuleName
n ModuleName -> ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
== String -> ModuleName
mkModuleName "IO" Bool -> Bool -> Bool
&& Maybe (Bool, Located [LIE GhcPs]) -> Bool
forall a. Maybe a -> Bool
isNothing (ImportDecl GhcPs -> Maybe (Bool, Located [LIE GhcPs])
forall pass. ImportDecl pass -> Maybe (Bool, Located [LIE pass])
ideclHiding SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
i) =
      [Severity
-> String -> SrcSpan -> String -> Maybe String -> [Note] -> Idea
rawIdeaN' Severity
Suggestion "Use hierarchical imports" SrcSpan
loc
      (String -> String
trimStart (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ ImportDecl GhcPs -> String
forall a. Outputable a => a -> String
unsafePrettyPrint SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
i) (
          String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (ImportDecl GhcPs -> String) -> [ImportDecl GhcPs] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String
trimStart (String -> String)
-> (ImportDecl GhcPs -> String) -> ImportDecl GhcPs -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ImportDecl GhcPs -> String
forall a. Outputable a => a -> String
unsafePrettyPrint)
          [ String -> Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs
f "System.IO" Maybe (Bool, Located [LIE GhcPs])
forall a. Maybe a
Nothing, String -> Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs
f "System.IO.Error" Maybe (Bool, Located [LIE GhcPs])
forall a. Maybe a
Nothing
          , String -> Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs
f "Control.Exception" (Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs)
-> Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs
forall a b. (a -> b) -> a -> b
$ (Bool, Located [LIE GhcPs]) -> Maybe (Bool, Located [LIE GhcPs])
forall a. a -> Maybe a
Just (Bool
False, SrcSpanLess (Located [LIE GhcPs]) -> Located [LIE GhcPs]
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc [String -> LIE GhcPs
mkLIE String
x | String
x <- ["bracket","bracket_"]])]) []]
  -- Suggest that a module import like 'Monad' should be rewritten with
  -- its hiearchical equivalent e.g. 'Control.Monad'.
  | Just y :: String
y <- String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup (ModuleName -> String
moduleNameString ModuleName
n) [(String, String)]
newNames =
    let newModuleName :: String
newModuleName = String
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ "." String -> String -> String
forall a. [a] -> [a] -> [a]
++ ModuleName -> String
moduleNameString ModuleName
n
        r :: [Refactoring SrcSpan]
r = [RType
-> SrcSpan -> [(String, SrcSpan)] -> String -> Refactoring SrcSpan
forall a. RType -> a -> [(String, a)] -> String -> Refactoring a
Replace RType
R.ModuleName (LImportDecl GhcPs -> SrcSpan
forall e. HasSrcSpan e => e -> SrcSpan
toSS' LImportDecl GhcPs
x) [] String
newModuleName] in
    [String
-> LImportDecl GhcPs
-> LImportDecl GhcPs
-> [Refactoring SrcSpan]
-> Idea
forall a b.
(HasSrcSpan a, Outputable a, HasSrcSpan b, Outputable b) =>
String -> a -> b -> [Refactoring SrcSpan] -> Idea
suggest' "Use hierarchical imports"
     LImportDecl GhcPs
x (SrcSpanLess (LImportDecl GhcPs) -> LImportDecl GhcPs
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (ImportDecl GhcPs -> ImportDecl GhcPs
desugarQual SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
i){ideclName :: Located ModuleName
ideclName=SrcSpanLess (Located ModuleName) -> Located ModuleName
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (String -> ModuleName
mkModuleName String
newModuleName)} :: LImportDecl GhcPs) [Refactoring SrcSpan]
r]
  where
    -- Substitute a new module name.
    f :: String -> Maybe (Bool, Located [LIE GhcPs]) -> ImportDecl GhcPs
f a :: String
a b :: Maybe (Bool, Located [LIE GhcPs])
b = (ImportDecl GhcPs -> ImportDecl GhcPs
desugarQual SrcSpanLess (LImportDecl GhcPs)
ImportDecl GhcPs
i){ideclName :: Located ModuleName
ideclName=SrcSpanLess (Located ModuleName) -> Located ModuleName
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (String -> ModuleName
mkModuleName String
a), ideclHiding :: Maybe (Bool, Located [LIE GhcPs])
ideclHiding=Maybe (Bool, Located [LIE GhcPs])
b}
    -- Wrap a literal name into an 'IE' (import/export) value.
    mkLIE :: String -> LIE GhcPs
    mkLIE :: String -> LIE GhcPs
mkLIE n :: String
n = SrcSpanLess (LIE GhcPs) -> LIE GhcPs
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (SrcSpanLess (LIE GhcPs) -> LIE GhcPs)
-> SrcSpanLess (LIE GhcPs) -> LIE GhcPs
forall a b. (a -> b) -> a -> b
$ XIEVar GhcPs -> LIEWrappedName (IdP GhcPs) -> IE GhcPs
forall pass. XIEVar pass -> LIEWrappedName (IdP pass) -> IE pass
IEVar NoExt
XIEVar GhcPs
noExt (SrcSpanLess (LIEWrappedName RdrName) -> LIEWrappedName RdrName
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (Located RdrName -> IEWrappedName RdrName
forall name. Located name -> IEWrappedName name
IEName (SrcSpanLess (Located RdrName) -> Located RdrName
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (FastString -> RdrName
mkVarUnqual (String -> FastString
fsLit String
n)))))
    -- Rewrite 'import qualified X' as 'import qualified X as X'.
    desugarQual :: ImportDecl GhcPs -> ImportDecl GhcPs
    desugarQual :: ImportDecl GhcPs -> ImportDecl GhcPs
desugarQual i :: ImportDecl GhcPs
i
      | ImportDecl GhcPs -> Bool
forall pass. ImportDecl pass -> Bool
ideclQualified ImportDecl GhcPs
i Bool -> Bool -> Bool
&& Maybe (Located ModuleName) -> Bool
forall a. Maybe a -> Bool
isNothing (ImportDecl GhcPs -> Maybe (Located ModuleName)
forall pass. ImportDecl pass -> Maybe (Located ModuleName)
ideclAs ImportDecl GhcPs
i) = ImportDecl GhcPs
i{ideclAs :: Maybe (Located ModuleName)
ideclAs = Located ModuleName -> Maybe (Located ModuleName)
forall a. a -> Maybe a
Just (ImportDecl GhcPs -> Located ModuleName
forall pass. ImportDecl pass -> Located ModuleName
ideclName ImportDecl GhcPs
i)}
      | Bool
otherwise = ImportDecl GhcPs
i

preferHierarchicalImports _ = []

newNames :: [(String, String)]
newNames :: [(String, String)]
newNames = let * :: b -> a -> (a, b)
(*) = (a -> b -> (a, b)) -> b -> a -> (a, b)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (,) in
    ["Control" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "Monad"
    ,"Data" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "Char"
    ,"Data" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "List"
    ,"Data" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "Maybe"
    ,"Data" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "Ratio"
    ,"System" String -> String -> (String, String)
forall b a. b -> a -> (a, b)
* "Directory"

    -- Special, see bug https://code.google.com/archive/p/ndmitchell/issues/393
    -- ,"System" * "IO"

    -- Do not encourage use of old-locale/old-time over haskell98
    -- ,"System" * "Locale"
    -- ,"System" * "Time"
    ]