{-
    Suggest using better export declarations

<TEST>
main = 1
module Foo where foo = 1 -- module Foo(module Foo) where
module Foo(foo) where foo = 1
module Foo(module Foo) where foo = 1 -- @Ignore module Foo(...) where
module Foo(module Foo, foo) where foo = 1 -- module Foo(..., foo) where
</TEST>
-}
{-# LANGUAGE TypeFamilies #-}

module Hint.Export(exportHint) where

import Hint.Type(ModuHint, ModuleEx(..),ideaNote,ignore,Note(..))

import GHC.Hs
import Module
import SrcLoc
import OccName
import RdrName

exportHint :: ModuHint
exportHint :: ModuHint
exportHint Scope
_ (ModuleEx (L SrcSpan
s m :: HsModule GhcPs
m@HsModule {hsmodName :: forall pass. HsModule pass -> Maybe (Located ModuleName)
hsmodName = Just Located ModuleName
name, hsmodExports :: forall pass. HsModule pass -> Maybe (Located [LIE pass])
hsmodExports = Maybe (Located [LIE GhcPs])
exports}) ApiAnns
_)
  | Maybe (Located [LIE GhcPs])
Nothing <- Maybe (Located [LIE GhcPs])
exports =
      let r :: HsModule GhcPs
r = HsModule GhcPs
o{ hsmodExports :: Maybe (Located [LIE GhcPs])
hsmodExports = Located [LIE GhcPs] -> Maybe (Located [LIE GhcPs])
forall a. a -> Maybe a
Just (SrcSpanLess (Located [LIE GhcPs]) -> Located [LIE GhcPs]
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc [SrcSpanLess (LIE GhcPs) -> LIE GhcPs
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (XIEModuleContents GhcPs -> Located ModuleName -> IE GhcPs
forall pass.
XIEModuleContents pass -> Located ModuleName -> IE pass
IEModuleContents NoExtField
XIEModuleContents GhcPs
noExtField Located ModuleName
name)] )} in
      [(String
-> GenLocated SrcSpan (HsModule GhcPs)
-> GenLocated SrcSpan (HsModule GhcPs)
-> [Refactoring SrcSpan]
-> Idea
forall a.
(HasSrcSpan a, Outputable a) =>
String -> a -> a -> [Refactoring SrcSpan] -> Idea
ignore String
"Use module export list" (SrcSpan -> HsModule GhcPs -> GenLocated SrcSpan (HsModule GhcPs)
forall l e. l -> e -> GenLocated l e
L SrcSpan
s HsModule GhcPs
o) (SrcSpanLess (GenLocated SrcSpan (HsModule GhcPs))
-> GenLocated SrcSpan (HsModule GhcPs)
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc HsModule GhcPs
SrcSpanLess (GenLocated SrcSpan (HsModule GhcPs))
r) []){ideaNote :: [Note]
ideaNote = [String -> Note
Note String
"an explicit list is usually better"]}]
  | Just (L SrcSpan
_ [LIE GhcPs]
xs) <- Maybe (Located [LIE GhcPs])
exports
  , [LIE GhcPs]
mods <- [LIE GhcPs
x | LIE GhcPs
x <- [LIE GhcPs]
xs, LIE GhcPs -> Bool
forall l pass. GenLocated l (IE pass) -> Bool
isMod LIE GhcPs
x]
  , String
modName <- ModuleName -> String
moduleNameString (Located ModuleName -> SrcSpanLess (Located ModuleName)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Located ModuleName
name)
  , [String]
names <- [ ModuleName -> String
moduleNameString (Located ModuleName -> SrcSpanLess (Located ModuleName)
forall a. HasSrcSpan a => a -> SrcSpanLess a
unLoc Located ModuleName
n) | (L SrcSpan
_ (IEModuleContents XIEModuleContents GhcPs
_ Located ModuleName
n)) <- [LIE GhcPs]
mods]
  , [LIE GhcPs]
exports' <- [LIE GhcPs
x | LIE GhcPs
x <- [LIE GhcPs]
xs, Bool -> Bool
not (String -> LIE GhcPs -> Bool
forall l pass. String -> GenLocated l (IE pass) -> Bool
matchesModName String
modName LIE GhcPs
x)]
  , String
modName String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
names =
      let dots :: RdrName
dots = OccName -> RdrName
mkRdrUnqual (String -> OccName
mkVarOcc String
" ... ")
          r :: HsModule GhcPs
r = HsModule GhcPs
o{ hsmodExports :: Maybe (Located [LIE GhcPs])
hsmodExports = Located [LIE GhcPs] -> Maybe (Located [LIE GhcPs])
forall a. a -> Maybe a
Just (SrcSpanLess (Located [LIE GhcPs]) -> Located [LIE GhcPs]
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (SrcSpanLess (LIE GhcPs) -> LIE GhcPs
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc (XIEVar GhcPs -> LIEWrappedName (IdP GhcPs) -> IE GhcPs
forall pass. XIEVar pass -> LIEWrappedName (IdP pass) -> IE pass
IEVar NoExtField
XIEVar GhcPs
noExtField (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 RdrName
SrcSpanLess (Located RdrName)
dots)))) LIE GhcPs -> [LIE GhcPs] -> [LIE GhcPs]
forall a. a -> [a] -> [a]
: [LIE GhcPs]
exports') )}
      in
        [String
-> GenLocated SrcSpan (HsModule GhcPs)
-> GenLocated SrcSpan (HsModule GhcPs)
-> [Refactoring SrcSpan]
-> Idea
forall a.
(HasSrcSpan a, Outputable a) =>
String -> a -> a -> [Refactoring SrcSpan] -> Idea
ignore String
"Use explicit module export list" (SrcSpan -> HsModule GhcPs -> GenLocated SrcSpan (HsModule GhcPs)
forall l e. l -> e -> GenLocated l e
L SrcSpan
s HsModule GhcPs
o) (SrcSpanLess (GenLocated SrcSpan (HsModule GhcPs))
-> GenLocated SrcSpan (HsModule GhcPs)
forall a. HasSrcSpan a => SrcSpanLess a -> a
noLoc HsModule GhcPs
SrcSpanLess (GenLocated SrcSpan (HsModule GhcPs))
r) []]
      where
          o :: HsModule GhcPs
o = HsModule GhcPs
m{hsmodImports :: [LImportDecl GhcPs]
hsmodImports=[], hsmodDecls :: [LHsDecl GhcPs]
hsmodDecls=[], hsmodDeprecMessage :: Maybe (Located WarningTxt)
hsmodDeprecMessage=Maybe (Located WarningTxt)
forall a. Maybe a
Nothing, hsmodHaddockModHeader :: Maybe LHsDocString
hsmodHaddockModHeader=Maybe LHsDocString
forall a. Maybe a
Nothing }
          isMod :: GenLocated l (IE pass) -> Bool
isMod (L l
_ (IEModuleContents XIEModuleContents pass
_ Located ModuleName
_)) = Bool
True
          isMod GenLocated l (IE pass)
_ = Bool
False

          matchesModName :: String -> GenLocated l (IE pass) -> Bool
matchesModName String
m (L l
_ (IEModuleContents XIEModuleContents pass
_ (L SrcSpan
_ ModuleName
n))) = ModuleName -> String
moduleNameString ModuleName
n String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
m
          matchesModName String
_ GenLocated l (IE pass)
_ = Bool
False

exportHint Scope
_ ModuleEx
_ = []