{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Importify.Resolution.Qualified
( removeUnusedQualifiedImports
) where
import Universum
import Data.List (partition)
import Language.Haskell.Exts (ImportDecl (..), ModuleHead (..),
ModuleName (..), QName (..))
import Language.Haskell.Names (NameInfo (GlobalSymbol), Scoped)
import Language.Haskell.Names.SyntaxUtils (dropAnn)
import Extended.Data.Bool ((==>))
import Importify.Syntax (getImportModuleName, isInsideExport,
scopedNameInfo, scopedNameInfo)
removeUnusedQualifiedImports :: [ImportDecl l]
-> Maybe (ModuleHead l)
-> [Scoped l]
-> [ModuleName ()]
-> [ImportDecl l]
removeUnusedQualifiedImports imports moduleHead annotations unusedImplicits =
let (possiblyUnused, others) = partition (possiblyUnusedImport unusedImplicits) imports
isImportNeeded name = isInsideExport moduleHead name
|| isInsideModule annotations name
byModuleName = maybe True isImportNeeded
. fmap dropAnn
. qualifiedName
neededQualified = filter byModuleName possiblyUnused
in neededQualified ++ others
possiblyUnusedImport :: [ModuleName ()] -> ImportDecl l -> Bool
possiblyUnusedImport unusedImplicits decl = isNothing (importSpecs decl)
&& isNotImplicitUnused
where
isNotImplicitUnused = (isJust (importAs decl) && not (importQualified decl))
==> getImportModuleName decl `elem` unusedImplicits
qualifiedName :: ImportDecl l -> Maybe (ModuleName l)
qualifiedName ImportDecl{ importAs = as@(Just _) } = as
qualifiedName ImportDecl{ importQualified = True, .. } = Just importModule
qualifiedName _ = Nothing
isInsideModule :: forall l. [Scoped l] -> ModuleName () -> Bool
isInsideModule annotations moduleName = any isNameUsed annotations
where
isNameUsed :: Scoped l -> Bool
isNameUsed (scopedNameInfo -> nameInfo) = case nameInfo of
GlobalSymbol _ (Qual _ usedName _) -> moduleName == usedName
_ -> False