module Hint.All(
    Hint(..), HintBuiltin(..), DeclHint, ModuHint,
    resolveHints, hintRules, builtinHints
    ) where

import Data.Monoid
import Config.Type
import Data.Either
import Data.List.Extra
import Hint.Type
import Timing
import Util
import Prelude

import Hint.Match
import Hint.List
import Hint.ListRec
import Hint.Monad
import Hint.Lambda
import Hint.Bracket
import Hint.Naming
import Hint.Pattern
import Hint.Import
import Hint.Export
import Hint.Pragma
import Hint.Restrict
import Hint.Extensions
import Hint.Duplicate
import Hint.Comment
import Hint.Unsafe
import Hint.NewType
import Hint.Smell

-- | A list of the builtin hints wired into HLint.
--   This list is likely to grow over time.
data HintBuiltin =
    HintList | HintListRec | HintMonad | HintLambda |
    HintBracket | HintNaming | HintPattern | HintImport | HintExport |
    HintPragma | HintExtensions | HintUnsafe | HintDuplicate | HintRestrict |
    HintComment | HintNewType | HintSmell
    deriving (Int -> HintBuiltin -> ShowS
[HintBuiltin] -> ShowS
HintBuiltin -> String
(Int -> HintBuiltin -> ShowS)
-> (HintBuiltin -> String)
-> ([HintBuiltin] -> ShowS)
-> Show HintBuiltin
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HintBuiltin] -> ShowS
$cshowList :: [HintBuiltin] -> ShowS
show :: HintBuiltin -> String
$cshow :: HintBuiltin -> String
showsPrec :: Int -> HintBuiltin -> ShowS
$cshowsPrec :: Int -> HintBuiltin -> ShowS
Show,HintBuiltin -> HintBuiltin -> Bool
(HintBuiltin -> HintBuiltin -> Bool)
-> (HintBuiltin -> HintBuiltin -> Bool) -> Eq HintBuiltin
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HintBuiltin -> HintBuiltin -> Bool
$c/= :: HintBuiltin -> HintBuiltin -> Bool
== :: HintBuiltin -> HintBuiltin -> Bool
$c== :: HintBuiltin -> HintBuiltin -> Bool
Eq,Eq HintBuiltin
Eq HintBuiltin =>
(HintBuiltin -> HintBuiltin -> Ordering)
-> (HintBuiltin -> HintBuiltin -> Bool)
-> (HintBuiltin -> HintBuiltin -> Bool)
-> (HintBuiltin -> HintBuiltin -> Bool)
-> (HintBuiltin -> HintBuiltin -> Bool)
-> (HintBuiltin -> HintBuiltin -> HintBuiltin)
-> (HintBuiltin -> HintBuiltin -> HintBuiltin)
-> Ord HintBuiltin
HintBuiltin -> HintBuiltin -> Bool
HintBuiltin -> HintBuiltin -> Ordering
HintBuiltin -> HintBuiltin -> HintBuiltin
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: HintBuiltin -> HintBuiltin -> HintBuiltin
$cmin :: HintBuiltin -> HintBuiltin -> HintBuiltin
max :: HintBuiltin -> HintBuiltin -> HintBuiltin
$cmax :: HintBuiltin -> HintBuiltin -> HintBuiltin
>= :: HintBuiltin -> HintBuiltin -> Bool
$c>= :: HintBuiltin -> HintBuiltin -> Bool
> :: HintBuiltin -> HintBuiltin -> Bool
$c> :: HintBuiltin -> HintBuiltin -> Bool
<= :: HintBuiltin -> HintBuiltin -> Bool
$c<= :: HintBuiltin -> HintBuiltin -> Bool
< :: HintBuiltin -> HintBuiltin -> Bool
$c< :: HintBuiltin -> HintBuiltin -> Bool
compare :: HintBuiltin -> HintBuiltin -> Ordering
$ccompare :: HintBuiltin -> HintBuiltin -> Ordering
$cp1Ord :: Eq HintBuiltin
Ord,HintBuiltin
HintBuiltin -> HintBuiltin -> Bounded HintBuiltin
forall a. a -> a -> Bounded a
maxBound :: HintBuiltin
$cmaxBound :: HintBuiltin
minBound :: HintBuiltin
$cminBound :: HintBuiltin
Bounded,Int -> HintBuiltin
HintBuiltin -> Int
HintBuiltin -> [HintBuiltin]
HintBuiltin -> HintBuiltin
HintBuiltin -> HintBuiltin -> [HintBuiltin]
HintBuiltin -> HintBuiltin -> HintBuiltin -> [HintBuiltin]
(HintBuiltin -> HintBuiltin)
-> (HintBuiltin -> HintBuiltin)
-> (Int -> HintBuiltin)
-> (HintBuiltin -> Int)
-> (HintBuiltin -> [HintBuiltin])
-> (HintBuiltin -> HintBuiltin -> [HintBuiltin])
-> (HintBuiltin -> HintBuiltin -> [HintBuiltin])
-> (HintBuiltin -> HintBuiltin -> HintBuiltin -> [HintBuiltin])
-> Enum HintBuiltin
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: HintBuiltin -> HintBuiltin -> HintBuiltin -> [HintBuiltin]
$cenumFromThenTo :: HintBuiltin -> HintBuiltin -> HintBuiltin -> [HintBuiltin]
enumFromTo :: HintBuiltin -> HintBuiltin -> [HintBuiltin]
$cenumFromTo :: HintBuiltin -> HintBuiltin -> [HintBuiltin]
enumFromThen :: HintBuiltin -> HintBuiltin -> [HintBuiltin]
$cenumFromThen :: HintBuiltin -> HintBuiltin -> [HintBuiltin]
enumFrom :: HintBuiltin -> [HintBuiltin]
$cenumFrom :: HintBuiltin -> [HintBuiltin]
fromEnum :: HintBuiltin -> Int
$cfromEnum :: HintBuiltin -> Int
toEnum :: Int -> HintBuiltin
$ctoEnum :: Int -> HintBuiltin
pred :: HintBuiltin -> HintBuiltin
$cpred :: HintBuiltin -> HintBuiltin
succ :: HintBuiltin -> HintBuiltin
$csucc :: HintBuiltin -> HintBuiltin
Enum)


builtin :: HintBuiltin -> Hint
builtin :: HintBuiltin -> Hint
builtin x :: HintBuiltin
x = case HintBuiltin
x of
    HintList       -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
listHint
    HintListRec    -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
listRecHint
    HintMonad      -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
monadHint
    HintLambda     -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
lambdaHint
    HintBracket    -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
bracketHint
    HintNaming     -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
namingHint
    HintPattern    -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
patternHint
    HintImport     -> (Scope -> Module SrcSpanInfo -> [Idea]) -> Hint
modu Scope -> Module SrcSpanInfo -> [Idea]
importHint
    HintExport     -> (Scope -> Module SrcSpanInfo -> [Idea]) -> Hint
modu Scope -> Module SrcSpanInfo -> [Idea]
exportHint
    HintPragma     -> (Scope -> Module SrcSpanInfo -> [Idea]) -> Hint
modu Scope -> Module SrcSpanInfo -> [Idea]
pragmaHint
    HintExtensions -> (Scope -> Module SrcSpanInfo -> [Idea]) -> Hint
modu Scope -> Module SrcSpanInfo -> [Idea]
extensionsHint
    HintUnsafe     -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
unsafeHint
    HintDuplicate  -> ([(Scope, Module SrcSpanInfo)] -> [Idea]) -> Hint
mods [(Scope, Module SrcSpanInfo)] -> [Idea]
duplicateHint
    HintComment    -> (Comment -> [Idea]) -> Hint
comm Comment -> [Idea]
commentHint
    HintNewType    -> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
newtypeHint
    HintRestrict   -> Hint
forall a. Monoid a => a
mempty{hintModule :: [Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
hintModule=[Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
restrictHint}
    HintSmell      -> Hint
forall a. Monoid a => a
mempty{hintDecl :: [Setting]
-> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
hintDecl=[Setting]
-> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
smellHint,hintModule :: [Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
hintModule=[Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
smellModuleHint}
    where
        wrap :: [a] -> [a]
wrap = String -> String -> [a] -> [a]
forall a. String -> String -> a -> a
timed "Hint" (Int -> ShowS
forall a. Int -> [a] -> [a]
drop 4 ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ HintBuiltin -> String
forall a. Show a => a -> String
show HintBuiltin
x) ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
forceList
        decl :: (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> Hint
decl f :: Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
f = Hint
forall a. Monoid a => a
mempty{hintDecl :: [Setting]
-> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
hintDecl=(Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
-> [Setting]
-> Scope
-> Module SrcSpanInfo
-> Decl SrcSpanInfo
-> [Idea]
forall a b. a -> b -> a
const ((Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
 -> [Setting]
 -> Scope
 -> Module SrcSpanInfo
 -> Decl SrcSpanInfo
 -> [Idea])
-> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
-> [Setting]
-> Scope
-> Module SrcSpanInfo
-> Decl SrcSpanInfo
-> [Idea]
forall a b. (a -> b) -> a -> b
$ \a :: Scope
a b :: Module SrcSpanInfo
b c :: Decl SrcSpanInfo
c -> [Idea] -> [Idea]
forall a. [a] -> [a]
wrap ([Idea] -> [Idea]) -> [Idea] -> [Idea]
forall a b. (a -> b) -> a -> b
$ Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
f Scope
a Module SrcSpanInfo
b Decl SrcSpanInfo
c}
        modu :: (Scope -> Module SrcSpanInfo -> [Idea]) -> Hint
modu f :: Scope -> Module SrcSpanInfo -> [Idea]
f = Hint
forall a. Monoid a => a
mempty{hintModule :: [Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
hintModule=(Scope -> Module SrcSpanInfo -> [Idea])
-> [Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
forall a b. a -> b -> a
const ((Scope -> Module SrcSpanInfo -> [Idea])
 -> [Setting] -> Scope -> Module SrcSpanInfo -> [Idea])
-> (Scope -> Module SrcSpanInfo -> [Idea])
-> [Setting]
-> Scope
-> Module SrcSpanInfo
-> [Idea]
forall a b. (a -> b) -> a -> b
$ \a :: Scope
a b :: Module SrcSpanInfo
b -> [Idea] -> [Idea]
forall a. [a] -> [a]
wrap ([Idea] -> [Idea]) -> [Idea] -> [Idea]
forall a b. (a -> b) -> a -> b
$ Scope -> Module SrcSpanInfo -> [Idea]
f Scope
a Module SrcSpanInfo
b}
        mods :: ([(Scope, Module SrcSpanInfo)] -> [Idea]) -> Hint
mods f :: [(Scope, Module SrcSpanInfo)] -> [Idea]
f = Hint
forall a. Monoid a => a
mempty{hintModules :: [Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea]
hintModules=([(Scope, Module SrcSpanInfo)] -> [Idea])
-> [Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea]
forall a b. a -> b -> a
const (([(Scope, Module SrcSpanInfo)] -> [Idea])
 -> [Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea])
-> ([(Scope, Module SrcSpanInfo)] -> [Idea])
-> [Setting]
-> [(Scope, Module SrcSpanInfo)]
-> [Idea]
forall a b. (a -> b) -> a -> b
$ \a :: [(Scope, Module SrcSpanInfo)]
a -> [Idea] -> [Idea]
forall a. [a] -> [a]
wrap ([Idea] -> [Idea]) -> [Idea] -> [Idea]
forall a b. (a -> b) -> a -> b
$ [(Scope, Module SrcSpanInfo)] -> [Idea]
f [(Scope, Module SrcSpanInfo)]
a}
        comm :: (Comment -> [Idea]) -> Hint
comm f :: Comment -> [Idea]
f = Hint
forall a. Monoid a => a
mempty{hintComment :: [Setting] -> Comment -> [Idea]
hintComment=(Comment -> [Idea]) -> [Setting] -> Comment -> [Idea]
forall a b. a -> b -> a
const ((Comment -> [Idea]) -> [Setting] -> Comment -> [Idea])
-> (Comment -> [Idea]) -> [Setting] -> Comment -> [Idea]
forall a b. (a -> b) -> a -> b
$ \a :: Comment
a -> [Idea] -> [Idea]
forall a. [a] -> [a]
wrap ([Idea] -> [Idea]) -> [Idea] -> [Idea]
forall a b. (a -> b) -> a -> b
$ Comment -> [Idea]
f Comment
a}

-- | A list of builtin hints, currently including entries such as @\"List\"@ and @\"Bracket\"@.
builtinHints :: [(String, Hint)]
builtinHints :: [(String, Hint)]
builtinHints = [(Int -> ShowS
forall a. Int -> [a] -> [a]
drop 4 ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ HintBuiltin -> String
forall a. Show a => a -> String
show HintBuiltin
h, HintBuiltin -> Hint
builtin HintBuiltin
h) | HintBuiltin
h <- [HintBuiltin
forall a. Bounded a => a
minBound .. HintBuiltin
forall a. Bounded a => a
maxBound]]

-- | Transform a list of 'HintBuiltin' or 'HintRule' into a 'Hint'.
resolveHints :: [Either HintBuiltin HintRule] -> Hint
resolveHints :: [Either HintBuiltin HintRule] -> Hint
resolveHints xs :: [Either HintBuiltin HintRule]
xs = [Hint] -> Hint
forall a. Monoid a => [a] -> a
mconcat ([Hint] -> Hint) -> [Hint] -> Hint
forall a b. (a -> b) -> a -> b
$ Hint
forall a. Monoid a => a
mempty{hintDecl :: [Setting]
-> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
hintDecl=(Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
-> [Setting]
-> Scope
-> Module SrcSpanInfo
-> Decl SrcSpanInfo
-> [Idea]
forall a b. a -> b -> a
const ((Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
 -> [Setting]
 -> Scope
 -> Module SrcSpanInfo
 -> Decl SrcSpanInfo
 -> [Idea])
-> (Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea])
-> [Setting]
-> Scope
-> Module SrcSpanInfo
-> Decl SrcSpanInfo
-> [Idea]
forall a b. (a -> b) -> a -> b
$ [HintRule]
-> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
readMatch [HintRule]
rights} Hint -> [Hint] -> [Hint]
forall a. a -> [a] -> [a]
: (HintBuiltin -> Hint) -> [HintBuiltin] -> [Hint]
forall a b. (a -> b) -> [a] -> [b]
map HintBuiltin -> Hint
builtin ([HintBuiltin] -> [HintBuiltin]
forall a. Ord a => [a] -> [a]
nubOrd [HintBuiltin]
lefts)
    where (lefts :: [HintBuiltin]
lefts,rights :: [HintRule]
rights) = [Either HintBuiltin HintRule] -> ([HintBuiltin], [HintRule])
forall a b. [Either a b] -> ([a], [b])
partitionEithers [Either HintBuiltin HintRule]
xs

-- | Transform a list of 'HintRule' into a 'Hint'.
hintRules :: [HintRule] -> Hint
hintRules :: [HintRule] -> Hint
hintRules = [Either HintBuiltin HintRule] -> Hint
resolveHints ([Either HintBuiltin HintRule] -> Hint)
-> ([HintRule] -> [Either HintBuiltin HintRule])
-> [HintRule]
-> Hint
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HintRule -> Either HintBuiltin HintRule)
-> [HintRule] -> [Either HintBuiltin HintRule]
forall a b. (a -> b) -> [a] -> [b]
map HintRule -> Either HintBuiltin HintRule
forall a b. b -> Either a b
Right