hlint 1.8.8 → 1.8.9
raw patch · 14 files changed
+125/−67 lines, 14 filesdep ~haskell-src-extsPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: haskell-src-exts
API changes (from Hackage documentation)
Files
- data/Default.hs +1/−0
- hlint.cabal +2/−2
- src/Apply.hs +63/−30
- src/CmdLine.hs +5/−1
- src/HLint.hs +4/−1
- src/HSE/All.hs +8/−11
- src/HSE/Util.hs +4/−2
- src/Hint/All.hs +12/−9
- src/Hint/Duplicate.hs +3/−2
- src/Hint/Extensions.hs +3/−1
- src/Hint/List.hs +12/−5
- src/Hint/Type.hs +4/−1
- src/Test.hs +2/−2
- src/Util.hs +2/−0
data/Default.hs view
@@ -197,6 +197,7 @@ error = (if isNothing x then y else fromJust x) ==> fromMaybe y x error = (if isJust x then fromJust x else y) ==> fromMaybe y x error = isJust x && (fromJust x == y) ==> x == Just y+error = mapMaybe f (map g x) ==> mapMaybe (f . g) x -- INFIX
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.6 build-type: Simple name: hlint-version: 1.8.8+version: 1.8.9 -- license is GPL v2 only license: GPL license-file: LICENSE@@ -38,7 +38,7 @@ transformers >= 0.0 && < 0.3, hscolour == 1.17.*, cpphs == 1.11.*,- haskell-src-exts >= 1.9.6 && < 1.11,+ haskell-src-exts >= 1.11 && < 1.12, uniplate >= 1.5 && < 1.7 hs-source-dirs: src
src/Apply.hs view
@@ -1,8 +1,9 @@ -module Apply(applyHint, applyHintStr) where+module Apply(applyHintFile, applyHintFiles, applyHintString) where import HSE.All import Hint.All+import Control.Arrow import Data.Char import Data.List import Data.Maybe@@ -12,32 +13,72 @@ import Util -applyHint :: ParseFlags -> [Setting] -> FilePath -> IO [Idea]-applyHint flags s file = do+-- | Apply hints to a single file.+applyHintFile :: ParseFlags -> [Setting] -> FilePath -> IO [Idea]+applyHintFile flags s file = do+ res <- parseModuleFile flags s file+ return $ case res of+ Left err -> [err]+ Right m -> executeHints s [m]+++-- | Apply hints to the contents of a single file.+applyHintString :: ParseFlags -> [Setting] -> FilePath -> String -> IO [Idea]+applyHintString flags s file src = do+ res <- parseModuleString flags s file src+ return $ case res of+ Left err -> [err]+ Right m -> executeHints s [m]+++-- | Apply hints to multiple files, allowing cross-file hints to fire.+applyHintFiles :: ParseFlags -> [Setting] -> [FilePath] -> IO [Idea]+applyHintFiles flags s files = do+ (err, ms) <- fmap unzipEither $ mapM (parseModuleFile flags s) files+ return $ err ++ executeHints s ms+++-- | Given a list of settings (a way to classify) and a list of hints, run them over a list of modules.+executeHints :: [Setting] -> [Module_] -> [Idea]+executeHints s ms = concat $+ [ map (classify $ s ++ mapMaybe readPragma (moduleDecls m)) $+ order "" [i | ModuHint h <- hints, i <- h nm m] +++ concat [order (fromNamed d) [i | h <- decHints, i <- h d] | d <- moduleDecls m]+ | (nm,m) <- mns+ , let decHints = [h nm m | DeclHint h <- hints] -- partially apply+ , let order n = map (\i -> i{func = (moduleName m,n)}) . sortBy (comparing loc)] +++ [map (classify s) $ op mns | CrossHint op <- hints]+ where+ mns = map (moduleScope &&& id) ms++ hints = for (allHints s) $ \x -> case x of+ CrossHint op | length ms <= 1 -> ModuHint $ \a b -> op [(a,b)]+ _ -> x+++-- | Like 'parseModuleString', but also load the file from disk.+parseModuleFile :: ParseFlags -> [Setting] -> FilePath -> IO (Either Idea Module_)+parseModuleFile flags s file = do src <- readFileEncoding (encoding flags) file- applyHintStr flags s file src+ parseModuleString flags s file src -applyHintStr :: ParseFlags -> [Setting] -> FilePath -> String -> IO [Idea]-applyHintStr flags s file src = do+-- | Return either an idea (a parse error) or the module. In IO because might call the C pre processor.+parseModuleString :: ParseFlags -> [Setting] -> FilePath -> String -> IO (Either Idea Module_)+parseModuleString flags s file src = do res <- parseString flags{infixes=[x | Infix x <- s]} file src case snd res of- ParseFailed sl msg | length src `seq` True -> map (classify s) `fmap` parseFailed flags sl msg src- ParseOk m -> return $- let settings = mapMaybe readPragma $ moduleDecls m- in map (classify $ s ++ settings) $ parseOk (allHints s) m---parseFailed :: ParseFlags -> SrcLoc -> String -> String -> IO [Idea]-parseFailed flags sl msg src = do- -- figure out the best line number to grab context from, by reparsing- (str2,pr2) <- parseString (parseFlagsNoLocations flags) "" src- let ctxt = case pr2 of- ParseFailed sl2 _ -> context (srcLine sl2) str2- _ -> context (srcLine sl) src- return [ParseError Warning "Parse error" sl msg ctxt]+ ParseOk m -> return $ Right m+ ParseFailed sl msg | length src `seq` True -> do+ -- figure out the best line number to grab context from, by reparsing+ (str2,pr2) <- parseString (parseFlagsNoLocations flags) "" src+ let ctxt = case pr2 of+ ParseFailed sl2 _ -> context (srcLine sl2) str2+ _ -> context (srcLine sl) src+ return $ Left $ classify s $ ParseError Warning "Parse error" sl msg ctxt +-- | Given a line number, and some source code, put bird ticks around the appropriate bit. context :: Int -> String -> String context lineNo src = unlines $ trimBy (all isSpace) $@@ -45,22 +86,14 @@ where ticks = [" "," ","> "," "," "] -parseOk :: [Hint] -> Module_ -> [Idea]-parseOk h m =- order "" [i | ModuHint h <- h, i <- h nm m] ++- concat [order (fromNamed d) [i | h <- decHints, i <- h d] | d <- moduleDecls m]- where- decHints = [h nm m | DeclHint h <- h] -- partially apply- order n = map (\i -> i{func = (moduleName m,n)}) . sortBy (comparing loc)- nm = moduleScope m--+-- | Find which hints a list of settings implies. allHints :: [Setting] -> [Hint] allHints xs = dynamicHints xs : map f builtin where builtin = nub $ concat [if x == "All" then map fst staticHints else [x] | Builtin x <- xs] f x = fromMaybe (error $ "Unknown builtin hints: HLint.Builtin." ++ x) $ lookup x staticHints +-- | Given some settings, make sure the severity field of the Idea is correct. classify :: [Setting] -> Idea -> Idea classify xs i = i{severity = foldl' (f i) (severity i) $ filter isClassify xs} where
src/CmdLine.hs view
@@ -35,10 +35,11 @@ ,cmdColor :: Bool -- ^ color the result ,cmdCpp :: CppFlags -- ^ options for CPP ,cmdDataDir :: FilePath -- ^ the data directory- ,cmdEncoding :: Encoding -- ^ the text encoding+ ,cmdEncoding :: Encoding -- ^ the text encoding ,cmdFindHints :: [FilePath] -- ^ source files to look for hints in ,cmdLanguage :: [Extension] -- ^ the extensions (may be prefixed by "No") ,cmdQuiet :: Bool -- ^ supress all console output+ ,cmdCross :: Bool -- ^ work between source files } @@ -59,6 +60,7 @@ | FindHints FilePath | Language String | Quiet+ | Cross deriving Eq @@ -73,6 +75,7 @@ ,Option "X" ["language"] (ReqArg Language "lang") "Language extensions (Arrows, NoCPP)" ,Option "u" ["utf8"] (NoArg $ Encoding "UTF-8") "Use UTF-8 text encoding" ,Option "" ["encoding"] (ReqArg Encoding "encoding") "Choose the text encoding"+ ,Option "x" ["cross"] (NoArg Cross) "Work between modules" ,Option "f" ["find"] (ReqArg FindHints "file") "Find hints in a Haskell file" ,Option "t" ["test"] (NoArg Test) "Run in test mode" ,Option "d" ["datadir"] (ReqArg DataDir "dir") "Override the data directory"@@ -137,6 +140,7 @@ ,cmdFindHints = findHints ,cmdLanguage = languages ,cmdQuiet = Quiet `elem` opt+ ,cmdCross = Cross `elem` opt }
src/HLint.hs view
@@ -67,7 +67,10 @@ settings3 <- return [Classify Ignore x ("","") | x <- cmdIgnore] let settings = settings1 ++ settings2 ++ settings3 - ideas <- fmap concat $ parallel [listM' =<< applyHint flags settings x | x <- fromMaybe [] cmdFiles]+ let files = fromMaybe [] cmdFiles+ ideas <- if cmdCross+ then applyHintFiles flags settings files+ else fmap concat $ parallel [listM' =<< applyHintFile flags settings x | x <- files] let (showideas,hideideas) = partition (\i -> cmdShowAll || severity i /= Ignore) ideas showItem <- if cmdColor then showANSI else return show mapM_ (outStrLn . showItem) showideas
src/HSE/All.hs view
@@ -1,23 +1,20 @@ module HSE.All(- module HSE.Util, module HSE.Evaluate,- module HSE.Bracket, module HSE.Match,- module HSE.Type,- module HSE.NameMatch,+ module X, ParseFlags(..), parseFlags, parseFlagsNoLocations, parseFile, parseString, parseResult ) where +import HSE.Util as X+import HSE.Evaluate as X+import HSE.Type as X+import HSE.Bracket as X+import HSE.Match as X+import HSE.NameMatch as X import Util import CmdLine import Data.List import Data.Maybe-import HSE.Util-import HSE.Evaluate-import HSE.Type-import HSE.Bracket-import HSE.Match-import HSE.NameMatch import Language.Preprocessor.Cpphs @@ -52,7 +49,7 @@ mode = defaultParseMode {parseFilename = file ,extensions = language flags- ,fixities = []+ ,fixities = Nothing ,ignoreLinePragmas = False }
src/HSE/Util.hs view
@@ -7,7 +7,7 @@ import Data.Maybe import System.FilePath import HSE.Type-import Language.Haskell.Exts.Annotated.Simplify(sOp, sAssoc)+import Language.Haskell.Exts.Annotated.Simplify(sQName, sAssoc) ---------------------------------------------------------------------@@ -302,5 +302,7 @@ -- FIXITIES getFixity :: Decl a -> [Fixity]-getFixity (InfixDecl _ a mp ops) = [Fixity (sAssoc a) (fromMaybe 9 mp) (sOp op) | op <- ops]+getFixity (InfixDecl sl a mp ops) = [Fixity (sAssoc a) (fromMaybe 9 mp) (sQName $ UnQual sl $ f op) | op <- ops]+ where f (VarOp _ x) = x+ f (ConOp _ x) = x getFixity _ = []
src/Hint/All.hs view
@@ -23,19 +23,22 @@ staticHints :: [(String,Hint)] staticHints =- 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+ ["List" ! listHint+ ,"ListRec" ! listRecHint+ ,"Monad" ! monadHint+ ,"Lambda" ! lambdaHint+ ,"Bracket" ! bracketHint+ ,"Naming" ! namingHint+ ,"Structure" ! structureHint ,"Import" + importHint ,"Pragma" + pragmaHint ,"Extensions" + extensionsHint- ,"Duplicate" + duplicateHint+ ,"Duplicate" * duplicateHint ]+ where+ x!y = (x,DeclHint y)+ x+y = (x,ModuHint y)+ x*y = (x,CrossHint y) dynamicHints :: [Setting] -> Hint dynamicHints = DeclHint . readMatch
src/Hint/Duplicate.hs view
@@ -24,10 +24,11 @@ import qualified Data.Map as Map -duplicateHint :: ModuHint-duplicateHint _ modu =+duplicateHint :: CrossHint+duplicateHint ms = dupes [y | Do _ y :: Exp S <- universeBi modu] ++ dupes [y | BDecls l y :: Binds S <- universeBi modu]+ where modu = map snd ms dupes ys =
src/Hint/Extensions.hs view
@@ -27,6 +27,8 @@ record field = Record{..} {-# LANGUAGE RecordWildCards #-} \ record = 1 --+{-# LANGUAGE UnboxedTuples #-} \+record = 1 -- </TEST> -} @@ -55,7 +57,7 @@ minimalExtensions :: Module_ -> [Extension] -> [Extension] minimalExtensions x es = nub $ concatMap f es- where f e = if used e x then [e] else []+ where f e = [e | used e x] -- RecordWildCards implies DisambiguateRecordFields, but most people probably don't want it
src/Hint/List.hs view
@@ -17,6 +17,7 @@ yes = if x == e then l2 ++ xs else [x] ++ check_elem xs -- x : check_elem xs data Yes = Yes (Maybe [Char]) -- Maybe String yes = y :: [Char] -> a -- String -> a+instance C [Char] </TEST> -} @@ -30,8 +31,7 @@ listHint _ _ = listDecl listDecl :: Decl_ -> [Idea]-listDecl x = concatMap (listExp False) (childrenBi x) ++- concatMap stringType (childrenBi x)+listDecl x = concatMap (listExp False) (childrenBi x) ++ stringType x -- boolean = are you in a ++ chain listExp :: Bool -> Exp_ -> [Idea]@@ -76,6 +76,13 @@ typeString = TyCon an (toNamed "String") -stringType :: Type_ -> [Idea]-stringType (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]- where f x = if x =~= typeListChar then typeString else x+stringType :: Decl_ -> [Idea]+stringType x = case x of+ InstDecl _ _ _ x -> f x+ _ -> f x+ where+ f x = concatMap g $ childrenBi x++ g :: Type_ -> [Idea]+ g (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]+ where f x = if x =~= typeListChar then typeString else x
src/Hint/Type.hs view
@@ -7,5 +7,8 @@ type DeclHint = Scope -> Module_ -> Decl_ -> [Idea] type ModuHint = Scope -> Module_ -> [Idea]+type CrossHint = [(Scope, Module_)] -> [Idea] -data Hint = DeclHint {declHint :: DeclHint} | ModuHint {moduHint :: ModuHint}+data Hint = DeclHint {declHint :: DeclHint}+ | ModuHint {moduHint :: ModuHint}+ | CrossHint {crossHint :: CrossHint}
src/Test.hs view
@@ -138,7 +138,7 @@ return $ Result (length failures) (length tests) where f (Test loc inp out) = do- ideas <- applyHintStr parseFlags setting file inp+ ideas <- applyHintString parseFlags setting file inp let good = case out of Nothing -> null ideas Just x -> length ideas == 1 &&@@ -201,7 +201,7 @@ else error "checkInputOutput, couldn't find or figure out flags" got <- fmap (fmap lines) $ captureOutput $- handle (\(e::SomeException) -> print $ e) $+ handle (\(e::SomeException) -> print e) $ handle (\(e::ExitCode) -> return ()) $ main flags want <- fmap lines $ reader "output"
src/Util.hs view
@@ -81,6 +81,8 @@ unzipEither [] = ([], []) +for = flip map+ --------------------------------------------------------------------- -- DATA.STRING