module Hint.Extensions(extensionsHint) where
import Hint.Type
import Data.Maybe
import Data.List
import Util
extensionsHint :: ModuHint
extensionsHint _ x = [rawIdea Error "Unused LANGUAGE pragma" (toSrcSpan sl)
(prettyPrint o) (Just $ if null new then "" else prettyPrint $ LanguagePragma sl $ map (toNamed . prettyExtension) new)
(warnings old new)
| not $ used TemplateHaskell x
, o@(LanguagePragma sl exts) <- modulePragmas x
, let old = map (parseExtension . prettyPrint) exts
, let new = minimalExtensions x old
, sort new /= sort old]
minimalExtensions :: Module_ -> [Extension] -> [Extension]
minimalExtensions x es = nub $ concatMap f es
where f e = [e | usedExt e x]
warnings old new | wildcards `elem` old && wildcards `notElem` new = [Note "you may need to add DisambiguateRecordFields"]
where wildcards = EnableExtension RecordWildCards
warnings _ _ = []
noNewtypeDeriving :: [String]
noNewtypeDeriving = ["Read","Show","Data","Typeable","Generic","Generic1"]
usedExt :: Extension -> Module_ -> Bool
usedExt (UnknownExtension "DeriveGeneric") = hasDerive ["Generic","Generic1"]
usedExt (EnableExtension x) = used x
usedExt _ = const True
used :: KnownExtension -> Module_ -> Bool
used RecursiveDo = hasS isMDo
used ParallelListComp = hasS isParComp
used FunctionalDependencies = hasT (un :: FunDep S)
used ImplicitParams = hasT (un :: IPName S)
used EmptyDataDecls = hasS f
where f (DataDecl _ _ _ _ [] _) = True
f (GDataDecl _ _ _ _ _ [] _) = True
f _ = False
used KindSignatures = hasT (un :: Kind S)
used BangPatterns = hasS isPBangPat
used TemplateHaskell = hasT2 (un :: (Bracket S, Splice S)) & hasS f & hasS isSpliceDecl
where f VarQuote{} = True
f TypQuote{} = True
f _ = False
used ForeignFunctionInterface = hasT (un :: CallConv S)
used PatternGuards = hasS f1 & hasS f2
where f1 (GuardedRhs _ xs _) = g xs
f2 (GuardedAlt _ xs _) = g xs
g [] = False
g [Qualifier{}] = False
g _ = True
used StandaloneDeriving = hasS isDerivDecl
used PatternSignatures = hasS isPatTypeSig
used RecordWildCards = hasS isPFieldWildcard & hasS isFieldWildcard
used RecordPuns = hasS isPFieldPun & hasS isFieldPun
used UnboxedTuples = has (not . isBoxed)
used PackageImports = hasS (isJust . importPkg)
used QuasiQuotes = hasS isQuasiQuote
used ViewPatterns = hasS isPViewPat
used DeriveDataTypeable = hasDerive ["Data","Typeable"]
used DeriveFunctor = hasDerive ["Functor"]
used DeriveFoldable = hasDerive ["Foldable"]
used DeriveTraversable = hasDerive ["Traversable"]
used GeneralizedNewtypeDeriving = any (`notElem` noNewtypeDeriving) . fst . derives
used Arrows = hasS f
where f Proc{} = True
f LeftArrApp{} = True
f RightArrApp{} = True
f LeftArrHighApp{} = True
f RightArrHighApp{} = True
f _ = False
used TransformListComp = hasS f
where f QualStmt{} = False
f _ = True
used x = usedExt $ UnknownExtension $ show x
hasDerive :: [String] -> Module_ -> Bool
hasDerive want m = any (`elem` want) $ new ++ dat
where (new,dat) = derives m
derives :: Module_ -> ([String],[String])
derives = concatUnzip . map f . childrenBi
where
f :: Decl_ -> ([String], [String])
f (DataDecl _ dn _ _ _ ds) = g dn ds
f (GDataDecl _ dn _ _ _ _ ds) = g dn ds
f (DataInsDecl _ dn _ _ ds) = g dn ds
f (GDataInsDecl _ dn _ _ _ ds) = g dn ds
f (DerivDecl _ _ hd) = (xs, xs)
where xs = [h hd]
f _ = ([], [])
g dn ds = if isNewType dn then (xs,[]) else ([],xs)
where xs = maybe [] (map h . fromDeriving) ds
h (IHead _ a _) = prettyPrint $ unqual a
h (IHInfix _ _ a _) = prettyPrint $ unqual a
h (IHParen _ a) = h a
un = undefined
(&) f g x = f x || g x
hasT t x = notNull (universeBi x `asTypeOf` [t])
hasT2 ~(t1,t2) = hasT t1 & hasT t2
hasS :: Biplate x (f S) => (f S -> Bool) -> x -> Bool
hasS test = any test . universeBi
has f = any f . universeBi