hlint 1.6.12 → 1.6.13
raw patch · 19 files changed
+138/−32 lines, 19 files
Files
- data/Default.hs +12/−1
- data/HLint.hs +10/−0
- hlint.cabal +1/−1
- src/CmdLine.hs +7/−4
- src/HSE/Bracket.hs +1/−0
- src/HSE/Util.hs +8/−0
- src/Hint/All.hs +5/−1
- src/Hint/Bracket.hs +3/−1
- src/Hint/Lambda.hs +2/−2
- src/Hint/List.hs +1/−1
- src/Hint/ListRec.hs +1/−1
- src/Hint/Match.hs +11/−3
- src/Hint/Monad.hs +1/−1
- src/Hint/Naming.hs +10/−4
- src/Hint/Structure.hs +24/−3
- src/Main.hs +18/−0
- src/Settings.hs +7/−6
- src/Type.hs +4/−3
- src/Util.hs +12/−0
data/Default.hs view
@@ -62,11 +62,21 @@ error = map (uncurry f) (zip x y) ==> zipWith f x y error = not (elem x y) ==> notElem x y +warn = foldr f z (map g x) ==> foldr (f . g) z x+warn = foldl f z (map g x) ==> foldl (f . g) z x+warn = foldl' f z (map g x) ==> foldl' (f . g) z x+warn = foldl1 f (map g x) ==> foldl1 (f . g) x+warn = foldl1' f (map g x) ==> foldl1' (f . g) x+warn = foldr1' f (map g x) ==> foldr1' (f . g) x+warn = foldr1 f (map g x) ==> foldr1 (f . g) x+ -- FOLDS error = foldr (&&) True ==> and-error = foldr (>>) (return ()) ==> sequence_+error = foldl (&&) True ==> and error = foldr (||) False ==> or+error = foldl (||) False ==> or+error = foldr (>>) (return ()) ==> sequence_ error = foldl (+) 0 ==> sum warn = foldl (*) 1 ==> product @@ -252,6 +262,7 @@ no = flip f x $ \y -> y*y+y no = \x -> f x (g x) yes = \x -> f x (g y) -- flip f (g y)+no = foo (\ v -> f v . g) import Prelude \ yes = flip mapM -- Control.Monad.forM
data/HLint.hs view
@@ -2,3 +2,13 @@ module HLint.HLint where import HLint.Default+import HLint.Builtin.List+import HLint.Builtin.ListRec+import HLint.Builtin.Monad+import HLint.Builtin.Lambda+import HLint.Builtin.Bracket+import HLint.Builtin.Naming+import HLint.Builtin.Structure+import HLint.Builtin.Import+import HLint.Builtin.Pragma+import HLint.Builtin.Extensions
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.6 build-type: Simple name: hlint-version: 1.6.12+version: 1.6.13 -- license is GPL v2 only license: GPL license-file: LICENSE
src/CmdLine.hs view
@@ -35,6 +35,7 @@ | Color | Define String | Include String+ | Ext String deriving Eq @@ -45,6 +46,7 @@ ,Option "c" ["color","colour"] (NoArg Color) "Color the output (requires ANSI terminal)" ,Option "i" ["ignore"] (ReqArg Skip "message") "Ignore a particular hint" ,Option "s" ["show"] (NoArg ShowAll) "Show all ignored ideas"+ ,Option "e" ["extension"] (ReqArg Ext "ext") "File extensions to search (defaults to hs and lhs)" ,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"@@ -68,7 +70,8 @@ putStr helpText exitWith ExitSuccess - files <- concatMapM getFile files+ let exts = [x | Ext x <- opt]+ files <- concatMapM (getFile $ if null exts then ["hs","lhs"] else exts) files let hintFiles = [x | Hints x <- opt] hints <- mapM getHintFile $ hintFiles ++ ["HLint" | null hintFiles]@@ -106,12 +109,12 @@ ] -getFile :: FilePath -> IO [FilePath]-getFile file = do+getFile :: [String] -> FilePath -> IO [FilePath]+getFile exts file = do b <- doesDirectoryExist file if b then do xs <- getDirectoryContentsRecursive file- return [x | x <- xs, takeExtension x `elem` [".hs",".lhs"]]+ return [x | x <- xs, drop 1 (takeExtension x) `elem` exts] else do b <- doesFileExist file unless b $ error $ "Couldn't find file: " ++ file
src/HSE/Bracket.hs view
@@ -40,6 +40,7 @@ | isAtom child = False | InfixApp{} <- parent, isApp child = False | ListComp{} <- parent = False+ | List{} <- parent = False | If{} <- parent, isAnyApp child = False | App{} <- parent, i == 0, isApp child = False | ExpTypeSig{} <- parent, i == 0 = False
src/HSE/Util.hs view
@@ -57,6 +57,7 @@ isInfixApp InfixApp{} = True; isInfixApp _ = False isAnyApp x = isApp x || isInfixApp x isParen Paren{} = True; isParen _ = False+isLambda Lambda{} = True; isLambda _ = False isMDo MDo{} = True; isMDo _ = False isBoxed Boxed{} = True; isBoxed _ = False isDerivDecl DerivDecl{} = True; isDerivDecl _ = False@@ -69,6 +70,13 @@ isParComp ParComp{} = True; isParComp _ = False isPatTypeSig PatTypeSig{} = True; isPatTypeSig _ = False isQuasiQuote QuasiQuote{} = True; isQuasiQuote _ = False+++-- which names are bound by a declaration+declBind :: Decl -> [Name]+declBind (FunBind (Match _ x _ _ _ _ : _)) = [x]+declBind (PatBind _ x _ _ _) = [x | PVar x <- universe x]+declBind _ = [] --------------------------------------------------------------------- -- HSE FUNCTIONS
src/Hint/All.hs view
@@ -2,6 +2,8 @@ module Hint.All where import Type+import Data.List+import Data.Maybe import Hint.Match import Hint.List@@ -36,4 +38,6 @@ allHints :: [Setting] -> [Hint]-allHints xs = dynamicHints xs : map snd staticHints+allHints xs = dynamicHints xs : map f builtin+ where builtin = nub [x | Builtin x <- xs]+ f x = fromMaybe (error $ "Unknown builtin hints: HLint.Builtin." ++ x) $ lookup x staticHints
src/Hint/Bracket.hs view
@@ -2,6 +2,7 @@ <TEST> yes = (f x) x -- f x x no = f (x x)+yes = (foo) -- foo yes = (f x) ||| y -- f x ||| y yes = if (f x) then y else z -- if f x then y else z yes = if x then (f y) else z -- if x then f y else z@@ -15,6 +16,7 @@ yes = (b $ c d) ++ e -- b (c d) ++ e yes = (a b $ c d) ++ e -- a b (c d) ++ e no = (f . g $ a) ++ e+yes = [(foo bar)] -- [foo bar] </TEST> -} @@ -27,7 +29,7 @@ bracketHint :: DeclHint-bracketHint _ = concatMap bracketExp . children0Exp nullSrcLoc+bracketHint _ _ = concatMap bracketExp . children0Exp nullSrcLoc bracketExp :: (SrcLoc,Exp) -> [Idea] bracketExp (loc,x) =
src/Hint/Lambda.hs view
@@ -51,8 +51,8 @@ lambdaHint :: DeclHint-lambdaHint _ x@TypeDecl{} = lambdaType x-lambdaHint _ x = concatMap (uncurry lambdaExp) (universeExp nullSrcLoc x) ++ concatMap lambdaDecl (universe x)+lambdaHint _ _ x@TypeDecl{} = lambdaType x+lambdaHint _ _ x = concatMap (uncurry lambdaExp) (universeExp nullSrcLoc x) ++ concatMap lambdaDecl (universe x) lambdaExp :: SrcLoc -> Exp -> [Idea]
src/Hint/List.hs view
@@ -28,7 +28,7 @@ listHint :: DeclHint-listHint _ = listDecl+listHint _ _ = listDecl listDecl :: Decl -> [Idea] listDecl x = concatMap (listExp False) (children0Exp nullSrcLoc x) ++
src/Hint/ListRec.hs view
@@ -36,7 +36,7 @@ listRecHint :: DeclHint-listRecHint _ = concatMap f . universe+listRecHint _ _ = concatMap f . universe where f o = maybeToList $ do let x = o
src/Hint/Match.hs view
@@ -27,8 +27,8 @@ readMatch = findIdeas . filter isMatchExp -findIdeas :: [Setting] -> NameMatch -> Decl -> [Idea]-findIdeas matches nm decl =+findIdeas :: [Setting] -> NameMatch -> Module -> Decl -> [Idea]+findIdeas matches nm _ decl = [ idea (rankS m) (hintS m) loc x y | (loc, x) <- universeExp nullSrcLoc decl, not $ isParen x , m <- matches, Just y <- [matchIdea nm m x]]@@ -39,7 +39,9 @@ u <- unify nm lhs x u <- check u guard $ checkSide side u- return $ unqualify nm $ dotContract $ performEval $ subst u rhs+ let rhs2 = subst u rhs+ guard $ checkDot lhs rhs2+ return $ unqualify nm $ dotContract $ performEval rhs2 -- unify a b = c, a[c] = b@@ -102,6 +104,12 @@ x2 <- lookup (fromNamed x) bind y2 <- lookup (fromNamed y) bind return $ x2 `notElem` universe y2+++-- If they have have a lambda in the pattern+-- don't allow dot contraction to happen, as it's usually wrong+checkDot :: Exp -> Exp -> Bool+checkDot lhs rhs2 = not $ any isLambda (universeBi lhs) && toNamed "?" `elem` universe rhs2 -- perform a substitution
src/Hint/Monad.hs view
@@ -42,7 +42,7 @@ monadHint :: DeclHint-monadHint _ = concatMap monadExp . universeExp nullSrcLoc+monadHint _ _ = concatMap monadExp . universeExp nullSrcLoc monadExp :: (SrcLoc,Exp) -> [Idea] monadExp (loc,x) = case x of
src/Hint/Naming.hs view
@@ -5,7 +5,8 @@ _*[A-Za-z]*_?'? Apply this to things that would get exported by default only- Also disallow prop_ as it's a standard QuickCheck idiom+ Also allow prop_ as it's a standard QuickCheck idiom+ Also don't suggest anything mentioned elsewhere in the module <TEST> data Yes = Foo | Bar'Test -- data Yes = Foo | BarTest@@ -16,22 +17,27 @@ yes_foo = yes_foo + yes_foo -- yesFoo = ... no = 1 where yes_foo = 2 a -== b = 1+myTest = 1; my_test = 1 </TEST> -} -module Hint.Naming where+module Hint.Naming(namingHint) where import HSE.All import Type import Data.List import Data.Char import Data.Maybe+import qualified Data.Set as Set 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]]+namingHint _ modu = naming $ Set.fromList [x | Ident x <- universeBi modu]++naming :: Set.Set String -> Decl -> [Idea]+naming seen 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], not $ y `Set.member` seen] x2 = shorten x
src/Hint/Structure.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns, PatternGuards #-} {- Improve the structure of code@@ -8,6 +8,13 @@ no x y = if a then b else c yes x = case x of {True -> a ; False -> b} -- if x then a else b yes x = case x of {False -> a ; _ -> b} -- if x then b else a+foo b | c <- f b = c -- foo (f -> c) = c+foo x y b z | c:cs <- f g b = c -- foo x y (f g -> c:cs) z = c+foo b | c <- f b = c + b+foo b | c <- f b = c where f = here+foo b | c <- f b = c where foo = b+foo b | c <- f b = c \+ | c <- f b = c </TEST> -} @@ -16,13 +23,14 @@ import HSE.All import Type+import Util import Data.List import Data.Maybe structureHint :: DeclHint-structureHint _ x = concat [concatMap useGuards xs | FunBind xs <- [x]] ++- concatMap useIf (universeExp nullSrcLoc x)+structureHint _ _ x = concat [concatMap useGuards xs | FunBind xs <- [x]] +++ concatMap useIf (universeExp nullSrcLoc x) useGuards :: Match -> [Idea]@@ -31,6 +39,19 @@ where guards = asGuards bod x2 = Match a b c d (GuardedRhss guards) e++useGuards o@(Match sl b pats d (GuardedRhss [GuardedRhs _ [Generator _ pat (App op (Var (UnQual p)))] bod]) (BDecls decs))+ | Just i <- findIndex (== PVar p) pats+ , p `notElem` (vr bod ++ vr decs)+ , vr op `disjoint` decsBind, pvr pats `disjoint` vr op, pvr pat `disjoint` pvr pats+ = [warn "Use view patterns" sl o $+ Match sl b (take i pats ++ [PParen $ PViewPat op pat] ++ drop (i+1) pats) d (UnGuardedRhs bod) (BDecls decs)]+ where+ decsBind = nub $ concatMap declBind decs++ vr x = [y | Var (UnQual y) <- universeBi x]+ pvr x = [y | PVar y <- universeBi x]+ useGuards _ = []
src/Main.hs view
@@ -1,3 +1,21 @@+{-+HLint, Haskell source code suggestions+Copyright (C) 2006-2009, Neil Mitchell++This program is free software; you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation; version 2 of the License.++This program is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with this program; if not, write to the Free Software+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA+-}+ {-# LANGUAGE RecordWildCards #-} module Main where
src/Settings.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE PatternGuards, ViewPatterns #-} -module Settings where+module Settings(readSettings, classify) where import HSE.All import Paths_hlint@@ -16,20 +16,21 @@ -- Return the list of settings commands readSettings :: [FilePath] -> IO [Setting] readSettings xs = do- mods <- concatMapM readHints xs- return $ concatMap (concatMap readSetting . concatMap getEquations . moduleDecls) mods+ (builtin,mods) <- fmap unzipEither $ concatMapM readHints xs+ return $ map Builtin builtin ++ concatMap (concatMap readSetting . concatMap getEquations . moduleDecls) mods -- read all the files -- in future this should also do import chasing, but -- currently it doesn't-readHints :: FilePath -> IO [Module]+readHints :: FilePath -> IO [Either String Module] readHints file = do y <- fromParseResult `fmap` parseFile parseFlags{implies=True} file ys <- concatMapM (f . fromNamed . importModule) $ moduleImports y- return $ y:ys+ return $ Right y:ys where- f x | "HLint." `isPrefixOf` x = do+ f x | "HLint.Builtin." `isPrefixOf` x = return [Left $ drop 14 x]+ | "HLint." `isPrefixOf` x = do dat <- getDataDir readHints $ dat </> drop 6 x <.> "hs" | otherwise = readHints $ x <.> "hs"
src/Type.hs view
@@ -30,6 +30,7 @@ data Setting = Classify {rankS :: Rank, hintS :: String, funcS :: FuncName} | MatchExp {rankS :: Rank, hintS :: String, lhs :: Exp, rhs :: Exp, side :: Maybe Exp}+ | Builtin String -- use a builtin hint set deriving Show data Idea@@ -76,8 +77,8 @@ --------------------------------------------------------------------- -- HINTS -type DeclHint = NameMatch -> Decl -> [Idea]-type ModuHint = NameMatch -> Module -> [Idea]+type DeclHint = NameMatch -> Module -> Decl -> [Idea]+type ModuHint = NameMatch -> Module -> [Idea] data Hint = DeclHint {declHint :: DeclHint} | ModuHint {moduHint :: ModuHint} @@ -101,4 +102,4 @@ nm = nameMatch $ moduleImports m order n = map (\i -> i{func = (name,n)}) . sortBy (comparing loc) in order "" [i | ModuHint h <- h, i <- h nm m] ++- concat [order (fromNamed d) [i | DeclHint h <- h, i <- h nm d] | d <- moduleDecls m]+ concat [order (fromNamed d) [i | DeclHint h <- h, i <- h nm m d] | d <- moduleDecls m]
src/Util.hs view
@@ -46,9 +46,21 @@ isRight = not . isLeft +unzipEither :: [Either a b] -> ([a], [b])+unzipEither (x:xs) = case x of+ Left y -> (y:a,b)+ Right y -> (a,y:b)+ where (a,b) = unzipEither xs+unzipEither [] = ([], [])++ listM' :: Monad m => [a] -> m [a] listM' x = length x `seq` return x groupSortFst :: Ord a => [(a,b)] -> [(a,[b])] groupSortFst = map (fst . head &&& map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst)+++disjoint :: Eq a => [a] -> [a] -> Bool+disjoint xs = null . intersect xs