packages feed

hlint 1.6.5 → 1.6.6

raw patch · 26 files changed

+309/−58 lines, 26 filesdep +cpphsdep −paralleldep ~haskell-src-extsdep ~hscolour

Dependencies added: cpphs

Dependencies removed: parallel

Dependency ranges changed: haskell-src-exts, hscolour

Files

data/Default.hs view
@@ -98,18 +98,25 @@ warn  = (\(x,y) -> (f x,y)) ==> first f where _ = notIn [x,y] f warn  = (\(x,y) -> (x,f y)) ==> second f where _ = notIn [x,y] f +-- FUNCTOR++error "Functor law" = fmap f (fmap g x) ==> fmap (f . g) x+error "Functor law" = fmap id ==> id+ -- MONAD  error "Monad law, left identity" = return a >>= f ==> f a error "Monad law, right identity" = m >>= return ==> m warn  = m >>= return . f ==> liftM f m error = (if x then y else return ()) ==> when x $ _noParen_ y+error = (if x then return () else y) ==> unless x $ _noParen_ y error = sequence (map f x) ==> mapM f x error = sequence_ (map f x) ==> mapM_ f x warn  = flip mapM ==> forM warn  = flip mapM_ ==> forM_ error = when (not x) ==> unless x error = x >>= id ==> join x+error = liftM f (liftM g x) ==> liftM (f . g) x  -- MONAD LIST 
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.6 build-type:         Simple name:               hlint-version:            1.6.5+version:            1.6.6 license:            GPL license-file:       LICENSE category:           Development@@ -29,8 +29,8 @@  executable hlint     build-depends:-        base == 4.*, syb, filepath, directory, mtl, containers, hscolour >= 1.10,-        haskell-src-exts >= 1 && < 1.1, uniplate == 1.2.* && >= 1.2.0.2, parallel+        base == 4.*, syb, filepath, directory, mtl, containers, hscolour >= 1.15, cpphs >= 1.7,+        haskell-src-exts == 1.1.*, uniplate == 1.2.* && >= 1.2.0.2      ghc-options:        -fno-warn-overlapping-patterns -threaded @@ -57,10 +57,13 @@         HSE.NameMatch         Hint.All         Hint.Bracket+        Hint.Extensions+        Hint.Import         Hint.Lambda         Hint.List         Hint.ListRec         Hint.Match         Hint.Monad         Hint.Naming+        Hint.Pragma         Hint.Structure
hlint.htm view
@@ -86,6 +86,7 @@ <ul> 	<li>The presence of <tt>seq</tt> may cause some hints (i.e. eta-reduction) to change the semantics of the program.</li> 	<li>The monomorphism restriction or uses of rank-2 types may sometimes cause transformed programs to become ill-typed.</li>+	<li>Files using <tt>#include</tt> may have incorrect line numbering.</li> </ul>  <h2>Installing and running HLint</h2>@@ -151,6 +152,17 @@ <p> 	To run HLint on <i>n</i> processors append the flags <tt>+RTS -N<i>n</i></tt>, as described in the <a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/runtime-control.html">GHC user manual</a>. HLint will usually perform fastest if <i>n</i> is equal to the number of physical processors. </p>++<h3>C preprocesor support</h3>++<p>+	HLint always runs the <a href="http://hackage.haskell.org/package/cpphs">cpphs C preprocessor</a> over all input files, by default using the current directory as the include path with no defined macros. These settings can be modified using the flags <tt>--cpp-include</tt> and <tt>--cpp-define</tt>. There are a number of limitations to the C preprocessor support:+</p>+<ul>+	<li>HLint will only check one branch of an <tt>#if</tt>, based on which macros have been defined.</li>+	<li>Any line numbers after a <tt>#include</tt> directive may be wrong.</li>+	<li>Any missing <tt>#include</tt> files will produce a warning on the console, but no information in the reports.</li>+</ul>  <h2>FAQ</h2> 
src/CmdLine.hs view
@@ -9,6 +9,7 @@ import System.Environment import System.Exit import System.FilePath+import Language.Preprocessor.Cpphs  import Util import Paths_hlint@@ -23,6 +24,7 @@     ,cmdIgnore :: [String]           -- ^ the hints to ignore     ,cmdShowAll :: Bool              -- ^ display all skipped items     ,cmdColor :: Bool                -- ^ color the result+    ,cmdCpphs :: CpphsOptions        -- ^ options for cpphs     }  @@ -31,6 +33,8 @@           | Report FilePath           | Skip String | ShowAll           | Color+          | Define String+          | Include String             deriving Eq  @@ -42,6 +46,8 @@        ,Option "i" ["ignore"] (ReqArg Skip "message") "Ignore a particular hint"        ,Option "s" ["show"] (NoArg ShowAll) "Show all ignored ideas"        ,Option "t" ["test"] (NoArg Test) "Run in test mode"+       ,Option ""  ["cpp-define"] (ReqArg Define "name[=value]") "CPP #define"+       ,Option ""  ["cpp-include"] (ReqArg Include "dir") "CPP include path"        ]  @@ -67,6 +73,12 @@     let hintFiles = [x | Hints x <- opt]     hints <- mapM getHintFile $ hintFiles ++ ["HLint" | null hintFiles] +    let cpphs = defaultCpphsOptions+            {boolopts=defaultBoolOptions{locations=False}+            ,includes = [x | Include x <- opt]+            ,defines = [(a,drop 1 b) | Define x <- opt, let (a,b) = break (== '=') x]+            }+     return Cmd         {cmdTest = test         ,cmdFiles = files@@ -75,6 +87,7 @@         ,cmdIgnore = [x | Skip x <- opt]         ,cmdShowAll = ShowAll `elem` opt         ,cmdColor = Color `elem` opt+        ,cmdCpphs = cpphs         }  
src/HSE/All.hs view
@@ -5,7 +5,7 @@     module HSE.Bracket, module HSE.Match,     module HSE.Generics,     module HSE.NameMatch,-    parseFile, parseString, fromParseResult+    ParseFlags(..), parseFlags, parseFile, parseString, fromParseResult     ) where  import Language.Haskell.Exts hiding (parse, parseFile, paren, fromParseResult)@@ -20,27 +20,34 @@ import Util import Data.Char import Data.List+import Language.Preprocessor.Cpphs  +data ParseFlags = ParseFlags+    {cpphs :: Maybe CpphsOptions+    ,implies :: Bool+    }++parseFlags :: ParseFlags+parseFlags = ParseFlags Nothing False++ -- | Parse a Haskell module-parseString :: Bool -> FilePath -> String -> ParseResult Module-parseString implies file = parseFileContentsWithMode mode . unlines . map f . lines+parseString :: ParseFlags -> FilePath -> String -> ParseResult Module+parseString flags file = parseFileContentsWithMode mode . maybe id (`runCpphs` file) (cpphs flags)     where-        f x | "#" `isPrefixOf` dropWhile isSpace x = ""-            | otherwise = x-             mode = defaultParseMode             {parseFilename = file             ,extensions = extension-            ,fixities = concat [infix_ (-1) ["==>"] | implies] ++ baseFixities+            ,fixities = concat [infix_ (-1) ["==>"] | implies flags] ++ baseFixities             }   -- | On failure returns an empty module and prints to the console-parseFile :: Bool -> FilePath -> IO (ParseResult Module)-parseFile implies file = do+parseFile :: ParseFlags -> FilePath -> IO (ParseResult Module)+parseFile flags file = do     src <- readFile file-    return $ parseString implies file src+    return $ parseString flags file src   -- | TODO: Use the fromParseResult in HSE once it gives source location@@ -67,4 +74,3 @@     -- NOT: TransformListComp - steals the group keyword     -- NOT: XmlSyntax, RegularPatterns - steals a-b     ]-
src/HSE/Bracket.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternGuards, ViewPatterns, MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-}  module HSE.Bracket where 
src/HSE/Match.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternGuards, ViewPatterns, MultiParamTypeClasses #-}+{-# LANGUAGE ViewPatterns, MultiParamTypeClasses #-}  module HSE.Match where 
src/HSE/Operators.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE PatternGuards, ViewPatterns, MultiParamTypeClasses, FlexibleContexts #-}  module HSE.Operators(     FixityDecl(..), preludeFixities, baseFixities,
src/HSE/Util.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternGuards, ViewPatterns, MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-}  module HSE.Util where @@ -27,6 +27,9 @@ moduleImports :: Module -> [ImportDecl] moduleImports (Module _ _ _ _ _ x _) = x +modulePragmas :: Module -> [OptionPragma]+modulePragmas (Module _ _ x _ _ _ _) = x+ isChar :: Exp -> Bool isChar (Lit (Char _)) = True isChar _ = False@@ -54,7 +57,18 @@ isInfixApp InfixApp{} = True; isInfixApp _ = False isAnyApp x = isApp x || isInfixApp x isParen Paren{} = True; isParen _ = False-+isMDo MDo{} = True; isMDo _ = False+isBoxed Boxed{} = True; isBoxed _ = False+isDerivDecl DerivDecl{} = True; isDerivDecl _ = False+isFunDep FunDep{} = True; isFunDep _ = False+isPBangPat PBangPat{} = True; isPBangPat _ = False+isPExplTypeArg PExplTypeArg{} = True; isPExplTypeArg _ = False+isPFieldPun PFieldPun{} = True; isPFieldPun _ = False+isPFieldWildcard PFieldWildcard{} = True; isPFieldWildcard _ = False+isPViewPat PViewPat{} = True; isPViewPat _ = False+isParComp ParComp{} = True; isParComp _ = False+isPatTypeSig PatTypeSig{} = True; isPatTypeSig _ = False+isQuasiQuote QuasiQuote{} = True; isQuasiQuote _ = False  --------------------------------------------------------------------- -- HSE FUNCTIONS
src/Hint/All.hs view
@@ -11,23 +11,29 @@ import Hint.Bracket import Hint.Naming import Hint.Structure+import Hint.Import+import Hint.Pragma+import Hint.Extensions   staticHints :: [(String,Hint)] staticHints =-    let (*) = (,) in-    ["List"      * listHint-    ,"ListRec"   * listRecHint-    ,"Monad"     * monadHint-    ,"Lambda"    * lambdaHint-    ,"Bracket"   * bracketHint-    ,"Naming"    * namingHint-    ,"Structure" * structureHint+    let x*y = (x,DeclHint y) ; x+y = (x,ModuHint y) in+    ["List"       * listHint+    ,"ListRec"    * listRecHint+    ,"Monad"      * monadHint+    ,"Lambda"     * lambdaHint+    ,"Bracket"    * bracketHint+    ,"Naming"     * namingHint+    ,"Structure"  * structureHint+    ,"Import"     + importHint+    ,"Pragma"     + pragmaHint+    ,"Extensions" + extensionsHint     ]  dynamicHints :: [Setting] -> Hint-dynamicHints = readMatch+dynamicHints = DeclHint . readMatch  -allHints :: [Setting] -> Hint-allHints xs = concatHints $ dynamicHints xs : map snd staticHints+allHints :: [Setting] -> [Hint]+allHints xs = dynamicHints xs : map snd staticHints
src/Hint/Bracket.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE PatternGuards #-}- {- <TEST> yes = (f x) x where res = f x x@@ -28,7 +26,7 @@ import HSE.All  -bracketHint :: Hint+bracketHint :: DeclHint bracketHint _ = concatMap bracketExp . children0Exp nullSrcLoc  bracketExp :: (SrcLoc,Exp) -> [Idea]
+ src/Hint/Extensions.hs view
@@ -0,0 +1,61 @@+{-+    Suggest removal of unnecessary extensions+    i.e. They have {-# LANGUAGE RecursiveDo #-} but no mdo keywords+<TEST>+</TEST>+-}+++module Hint.Extensions where++import HSE.All+import Type+import Data.List+import Data.Maybe+import Data.Function+++extensionsHint :: ModuHint+extensionsHint _ x = [idea Error "Unused LANGUAGE pragma" sl o (LanguagePragma sl new)+    | o@(LanguagePragma sl old) <- modulePragmas x+    , let new = filter (flip used x . classifyExtension . prettyPrint) old+    , length new /= length old]+++used :: Extension -> Module -> Bool+used RecursiveDo x = any isMDo $ universeBi x+used ParallelListComp x = any isParComp $ universeBi x+used FunctionalDependencies x = any isFunDep $ universeBi x+used ImplicitParams x = not $ null (universeBi x :: [IPName])+used EmptyDataDecls x = any f $ universeBi x+    where f (DataDecl _ _ _ _ _ [] _) = True+          f (GDataDecl _ _ _ _ _ _ [] _) = True+          f _ = False+used KindSignatures x = not $ null (universeBi x :: [Kind])+used BangPatterns x = any isPBangPat $ universeBi x+used TemplateHaskell x = not (null (universeBi x :: [Bracket])) && not (null (universeBi x :: [Splice]))+used ForeignFunctionInterface x = not $ null (universeBi x :: [CallConv])+used Generics x = any isPExplTypeArg $ universeBi x+used PatternGuards x = any f $ universeBi x+    where f (GuardedRhs _ [] _) = False+          f (GuardedRhs _ [Qualifier _] _) = False+          f _ = True+used StandaloneDeriving x = any isDerivDecl $ universeBi x+used PatternSignatures x = any isPatTypeSig $ universeBi x+used RecordWildCards x = any isPFieldWildcard $ universeBi x+used RecordPuns x = any isPFieldPun $ universeBi x+used UnboxedTuples x = any isBoxed $ universeBi x+used PackageImports x = any (isJust . importPkg) $ universeBi x+used QuasiQuotes x = any isQuasiQuote $ universeBi x+used ViewPatterns x = any isPViewPat $ universeBi x+used Arrows x = any f $ universeBi x+    where f Proc{} = True+          f LeftArrApp{} = True+          f RightArrApp{} = True+          f LeftArrHighApp{} = True+          f RightArrHighApp{} = True+used TransformListComp x = any f $ universeBi x+    where f QualStmt{} = False+          f _ = True++used _ _ = True
+ src/Hint/Import.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE PatternGuards #-}+{-+    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>+</TEST>+-}+++module Hint.Import where++import HSE.All+import Type+import Data.List+import Data.Maybe+import Data.Function+++importHint :: ModuHint+importHint _ x = concatMap (wrap . map snd) $ groupBy ((==) `on` fst) $ sortBy (compare `on` fst)+                 [((importModule i,importPkg i),i) | i <- universeBi x, not $ importSrc i]+++wrap :: [ImportDecl] -> [Idea]+wrap o = [ rawIdea Error "Use fewer imports" (importLoc $ head x) (f o) (f x)+         | Just x <- [simplify o]]+    where f = unlines . map prettyPrint+++simplify :: [ImportDecl] -> Maybe [ImportDecl]+simplify [] = Nothing+simplify (x:xs) = case simplifyHead x xs of+    Nothing -> fmap (x:) $ simplify xs+    Just xs -> Just $ fromMaybe xs $ simplify xs+++simplifyHead :: ImportDecl -> [ImportDecl] -> Maybe [ImportDecl]+simplifyHead x [] = Nothing+simplifyHead x (y:ys) = case reduce x y of+    Nothing -> fmap (y:) $ simplifyHead x ys+    Just xy -> Just $ xy : ys+++-- Useful fields in import are:+-- importModule :: ModuleName [same]+-- importPkg :: Maybe String [same]+-- importQualified :: Bool+-- importSrc :: Bool [False]+-- importAs :: Maybe ModuleName+-- importSpecs :: Maybe (Bool, [ImportSpec])++reduce :: ImportDecl -> ImportDecl -> Maybe ImportDecl+reduce x y | qual, as, specs = Just x+           | qual, as, Just (False, xs) <- importSpecs x, Just (False, ys) <- importSpecs y =+                Just x{importSpecs = Just (False, nub $ xs ++ ys)}+           | qual, as, isNothing (importSpecs x) || isNothing (importSpecs y) = Just x{importSpecs=Nothing}+           | not (importQualified x), qual, specs, isNothing (importAs x) || isNothing (importAs y) = Just x{importAs=Nothing}+    where+        qual = importQualified x == importQualified y+        as = importAs x == importAs y+        specs = importSpecs x == importSpecs y++reduce _ _ = Nothing
src/Hint/Lambda.hs view
@@ -40,7 +40,7 @@ import Data.Maybe  -lambdaHint :: Hint+lambdaHint :: DeclHint lambdaHint _ x@TypeDecl{} = lambdaType x lambdaHint _ x = concatMap lambdaExp (universeBi x) ++ concatMap lambdaDecl (universe x) 
src/Hint/List.hs view
@@ -27,7 +27,7 @@ import Type  -listHint :: Hint+listHint :: DeclHint listHint _ = listDecl  listDecl :: Decl -> [Idea]
src/Hint/ListRec.hs view
@@ -35,7 +35,7 @@ import Data.Generics.PlateData  -listRecHint :: Hint+listRecHint :: DeclHint listRecHint _ = concatMap f . universe     where         f o = maybeToList $ do
src/Hint/Match.hs view
@@ -22,7 +22,7 @@ --------------------------------------------------------------------- -- PERFORM MATCHING -readMatch :: [Setting] -> Hint+readMatch :: [Setting] -> DeclHint readMatch = findIdeas . filter isMatchExp  
src/Hint/Monad.hs view
@@ -33,7 +33,7 @@ badFuncs = ["mapM","foldM","forM","replicateM","sequence","zipWithM"]  -monadHint :: Hint+monadHint :: DeclHint monadHint _ = concatMap monadExp . universeExp nullSrcLoc  monadExp :: (SrcLoc,Exp) -> [Idea]
src/Hint/Naming.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE ViewPatterns, PatternGuards #-}- {-     Suggest the use of camelCase @@ -31,7 +29,7 @@ import Data.Maybe  -namingHint :: Hint+namingHint :: DeclHint namingHint _ x = [warn "Use camelCase" (declSrcLoc x) x2 (replaceNames res x2) | not $ null res]     where res = [(n,y) | n <- nub $ getNames x, Just y <- [suggestName n]]           x2 = shorten x
+ src/Hint/Pragma.hs view
@@ -0,0 +1,60 @@+{-+    Suggest better pragmas+    OPTIONS_GHC -cpp => LANGUAGE CPP+    OPTIONS_GHC -fglasgow-exts => LANGUAGE ... (in HSE)+    OPTIONS_GHC -XFoo => LANGUAGE Foo+    LANGUAGE A, A => LANGUAGE A+    -- do not do LANGUAGE A, LANGUAGE B to combine+<TEST>+</TEST>+-}+++module Hint.Pragma where++import HSE.All+import Type+import Data.List+import Data.Maybe+import Data.Function+++pragmaHint :: ModuHint+pragmaHint _ x = languageDupes lang ++ [pragmaIdea old $ [LanguagePragma nullSrcLoc ns2 | ns2 /= []] ++ catMaybes new | old /= []]+    where+        lang = [x | x@LanguagePragma{} <- modulePragmas x]+        (old,new,ns) = unzip3 [(old,new,ns) | old <- modulePragmas x, Just (new,ns) <- [optToLanguage old]]+        ns2 = nub (concat ns) \\ concat [n | LanguagePragma _ n <- lang]+++pragmaIdea :: [OptionPragma] -> [OptionPragma] -> Idea+pragmaIdea xs ys = rawIdea Error "Use better pragmas" (fromJust $ getSrcLoc $ head xs) (f xs) (f ys)+    where f = unlines . map prettyPrint+++languageDupes :: [OptionPragma] -> [Idea]+languageDupes [] = []+languageDupes (a@(LanguagePragma sl x):xs) =+    (if nub x /= x+        then [pragmaIdea [a] [LanguagePragma sl $ nub x]]+        else [pragmaIdea [a,b] [LanguagePragma sl (nub $ x ++ y)] | b@(LanguagePragma _ y) <- xs, not $ null $ intersect x y]) +++    languageDupes xs+++-- Given a pragma, can you extract some language features out+strToLanguage :: String -> Maybe [Name]+strToLanguage "-cpp" = Just [Ident "CPP"]+strToLanguage x | "-X" `isPrefixOf` x = Just [Ident $ drop 2 x]+strToLanguage "-fglasgow-exts" = Just $ map (Ident . show) glasgowExts+strToLanguage _ = Nothing+++optToLanguage :: OptionPragma -> Maybe (Maybe OptionPragma, [Name])+optToLanguage (OptionsPragma sl tool val)+    | maybe True (== GHC) tool && any isJust vs = Just (res, concat $ catMaybes vs)+    where+        strs = words val+        vs = map strToLanguage strs+        keep = concat $ zipWith (\v s -> [s | isNothing v]) vs strs+        res = if null keep then Nothing else Just $ OptionsPragma sl tool (unwords keep)+optToLanguage _ = Nothing
src/Hint/Structure.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ViewPatterns, PatternGuards #-}+{-# LANGUAGE ViewPatterns #-}  {-     Improve the structure of code@@ -20,7 +20,7 @@ import Data.Maybe  -structureHint :: Hint+structureHint :: DeclHint structureHint _ x = concat [concatMap useGuards xs | FunBind xs <- [x]] ++                     concatMap useIf (universeExp nullSrcLoc x) 
src/Main.hs view
@@ -16,6 +16,7 @@ import Util import Parallel import Hint.All+import HSE.All   main = do@@ -24,7 +25,7 @@         settings <- readSettings cmdHintFiles         let extra = [Classify Ignore x ("","") | x <- cmdIgnore]         let apply :: FilePath -> IO [Idea]-            apply = fmap (fmap $ classify $ settings ++ extra) . applyHint (allHints settings)+            apply = fmap (fmap $ classify $ settings ++ extra) . applyHint parseFlags{cpphs=Just cmdCpphs} (allHints settings)         ideas <- liftM concat $ parallel [listM' =<< apply x | x <- cmdFiles]         showItem <- if cmdColor then showANSI else return show         mapM_ putStrLn [showItem i | i <- ideas, cmdShowAll || rank i /= Ignore]
src/Report.hs view
@@ -46,7 +46,7 @@                     where id = mode ++ show i  -code = hscolour False True ""+code = hscolour False   writeIdea :: String -> Idea -> [String]
src/Settings.hs view
@@ -25,7 +25,7 @@ -- currently it doesn't readHints :: FilePath -> IO [Module] readHints file = do-    y <- fromParseResult `fmap` parseFile True file+    y <- fromParseResult `fmap` parseFile parseFlags{implies=True} file     ys <- concatMapM (f . fromNamed . importModule) $ moduleImports y     return $ y:ys     where
src/Test.hs view
@@ -59,7 +59,7 @@                  concatMap ((++) " | " . show) ideas ++ "\n" ++                  prettyPrint inp | not good]             where-                ideas = hint nm inp+                ideas = declHint hint nm inp                 good = case out of                     Nothing -> ideas == []                     Just x -> length ideas == 1 && (null x || to (head ideas) == x)@@ -69,7 +69,7 @@ parseTestFile file = do     src <- readFile file     return [(nm, createTest eqn)-           | code <- f $ lines src, let modu = fromParseResult $ parseString False file code+           | code <- f $ lines src, let modu = fromParseResult $ parseString parseFlags file code            , let nm = nameMatch $ moduleImports modu            , eqn <- concatMap getEquations $ moduleDecls modu]     where
src/Type.hs view
@@ -62,7 +62,8 @@   -- The real key will be filled in by applyHint-idea rank hint loc from to = Idea ("","") rank hint loc (f from) (f to)+rawIdea = Idea ("","")+idea rank hint loc from to = rawIdea rank hint loc (f from) (f to)     where f = dropWhile isSpace . prettyPrint warn mr = idea Warning mr @@ -75,17 +76,16 @@ --------------------------------------------------------------------- -- HINTS -type Hint = NameMatch -> Decl -> [Idea]-+type DeclHint = NameMatch -> Decl   -> [Idea]+type ModuHint = NameMatch -> Module -> [Idea] -concatHints :: [Hint] -> Hint-concatHints hs nm x = concatMap (\h -> h nm x) hs+data Hint = DeclHint {declHint :: DeclHint} | ModuHint {moduHint :: ModuHint}  -applyHint :: Hint -> FilePath -> IO [Idea]-applyHint h file = do+applyHint :: ParseFlags -> [Hint] -> FilePath -> IO [Idea]+applyHint flags h file = do     src <- readFile file-    case parseString False file src of+    case parseString flags file src of         ParseFailed sl msg -> do             let ticks = ["  ","  ","> ","  ","  "]             let bad = zipWith (++) ticks $ take 5 $ drop (srcLine sl - 3) $ lines src ++ [""]@@ -94,5 +94,7 @@         ParseOk m -> do             let name = moduleName m             let nm = nameMatch $ moduleImports m-            return [ i{func = (name,fromNamed d)}-                   | d <- moduleDecls m, i <- sortBy (comparing loc) $ h nm d]+            let order n = map (\i -> i{func = (name,n)}) . sortBy (comparing loc)+            return $+                order "" [i | ModuHint h <- h, i <- h nm m] +++                concat [order (fromNamed d) [i | DeclHint h <- h, i <- h nm d] | d <- moduleDecls m]