hlint 2.1.24 → 2.1.25
raw patch · 8 files changed
+89/−9 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGES.txt +7/−0
- data/hlint.yaml +17/−1
- hlint.cabal +1/−1
- src/GHC/Util.hs +24/−4
- src/HLint.hs +1/−0
- src/HSE/All.hs +15/−1
- src/Hint/NewType.hs +22/−1
- src/Idea.hs +2/−1
CHANGES.txt view
@@ -1,5 +1,12 @@ Changelog for HLint (* = breaking change) +2.1.25, released 2019-06-26+ #681, fix for extensions on the command line not being used+ #686, suggest head (drop n x) ==> x !! max 0 n+ #683, add Use DerivingStrategies hint, ignored by default+ #685, skip running refactoring tool if there are no hints+ #675, warn about redundant fmaps on Eithers and Maybes+ Add back two $ hints removed in error 2.1.24, released 2019-06-10 Add Language.Haskell.HLint4 #658, ignore the previously undocumented {- LINT -} comments
data/hlint.yaml view
@@ -128,6 +128,7 @@ - warn: {lhs: "cycle [x]", rhs: repeat x} - warn: {lhs: head (reverse x), rhs: last x} - warn: {lhs: head (drop n x), rhs: x !! n, side: isNat n}+ - warn: {lhs: head (drop n x), rhs: x !! max 0 n, side: not (isNat n) && not (isNeg n)} - warn: {lhs: reverse (tail (reverse x)), rhs: init x, note: IncreasesLaziness} - warn: {lhs: reverse (reverse x), rhs: x, note: IncreasesLaziness, name: Avoid reverse} - warn: {lhs: isPrefixOf (reverse x) (reverse y), rhs: isSuffixOf x y}@@ -264,6 +265,8 @@ - hint: {lhs: "\\x y -> f (x,y)", rhs: curry f} - hint: {lhs: "\\(x,y) -> f x y", rhs: uncurry f, note: IncreasesLaziness} - warn: {lhs: f (fst p) (snd p), rhs: uncurry f p}+ - warn: {lhs: ($) . f, rhs: f, name: Redundant $}+ - warn: {lhs: (f $), rhs: f, name: Redundant $} - warn: {lhs: (Data.Function.& f), rhs: f, name: Redundant Data.Function.&} - hint: {lhs: \x -> y, rhs: const y, side: isAtom y && not (isWildcard y)} # If any isWildcard recursively then x may be used but not mentioned explicitly@@ -443,6 +446,7 @@ # LIST COMP - hint: {lhs: "if b then [x] else []", rhs: "[x | b]", name: Use list comprehension}+ - hint: {lhs: "if b then [] else [x]", rhs: "[x | not b]", name: Use list comprehension} - hint: {lhs: "[x | x <- y]", rhs: "y", side: isVar x, name: Redundant list comprehension} # SEQ@@ -497,12 +501,22 @@ - hint: {lhs: maybe Nothing id, rhs: join} - hint: {lhs: maybe Nothing f x, rhs: f =<< x} - hint: {lhs: maybe (f x) (f . g), rhs: f . maybe x g, note: IncreasesLaziness, name: Too strict maybe}+ - warn: {lhs: maybe x f (fmap g y), rhs: maybe x (f . g) y, name: Redundant fmap}+ - warn: {lhs: isJust (fmap f x), rhs: isJust x}+ - warn: {lhs: isNothing (fmap f x), rhs: isNothing x}+ - warn: {lhs: fromJust (fmap f x), rhs: f (fromJust x)}+ - warn: {lhs: mapMaybe f (fmap g x), rhs: mapMaybe (f . g) x, name: Redundant fmap} # EITHER - warn: {lhs: "[a | Left a <- a]", rhs: lefts a} - warn: {lhs: "[a | Right a <- a]", rhs: rights a} - warn: {lhs: either Left (Right . f), rhs: fmap f}+ - warn: {lhs: either f g (fmap h x), rhs: either f (g . h) x, name: Redundant fmap}+ - warn: {lhs: isLeft (fmap f x), rhs: isLeft x}+ - warn: {lhs: isRight (fmap f x), rhs: isRight x}+ - warn: {lhs: fromLeft x (fmap f y), rhs: fromLeft x y}+ - warn: {lhs: fromRight x (fmap f y), rhs: either (const x) f y} # INFIX @@ -759,6 +773,8 @@ rules: - hint: {lhs: "x /= []", rhs: not (null x), name: Use null} - hint: {lhs: "[] /= x", rhs: not (null x), name: Use null}+ - hint: {lhs: "not (x || y)", rhs: "not x && not y", name: Apply De Morgan law}+ - hint: {lhs: "not (x && y)", rhs: "not x || not y", name: Apply De Morgan law} # <TEST>@@ -857,7 +873,7 @@ # fooer input = catMaybes . map Just $ input -- mapMaybe Just # yes = mapMaybe id -- catMaybes # main = print $ map (\_->5) [2,3,5] -- const 5-# main = head $ drop n x+# main = head $ drop n x -- x !! max 0 n # main = head $ drop (-3) x -- x # main = head $ drop 2 x -- x !! 2 # main = drop 0 x -- x
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.18 build-type: Simple name: hlint-version: 2.1.24+version: 2.1.25 license: BSD3 license-file: LICENSE category: Development
src/GHC/Util.hs view
@@ -11,6 +11,7 @@ , getMessages , SDoc , Located+ , hseToGhcExtension -- Temporary : Export these so GHC doesn't consider them unused and -- tell weeder to ignore them. , isAtom, addParen, paren, isApp, isOpApp, isAnyApp, isDot, isSection, isDotApp@@ -38,6 +39,8 @@ import Data.List import System.FilePath import Language.Preprocessor.Unlit+import qualified Language.Haskell.Exts.Extension as HSE+import qualified Data.Map.Strict as Map fakeSettings :: Settings fakeSettings = Settings@@ -83,13 +86,21 @@ baseDynFlags = foldl' xopt_set (defaultDynFlags fakeSettings fakeLlvmConfig) enabledExtensions -parsePragmasIntoDynFlags ::- DynFlags -> FilePath -> String -> IO (Either String DynFlags)-parsePragmasIntoDynFlags flags filepath str =+-- | Adjust the input 'DynFlags' to take into account language+-- extensions to explicitly enable/disable as well as language+-- extensions enabled by pragma in the source.+parsePragmasIntoDynFlags :: DynFlags+ -> ([Extension], [Extension])+ -> FilePath+ -> String+ -> IO (Either String DynFlags)+parsePragmasIntoDynFlags flags (enable, disable) filepath str = catchErrors $ do let opts = getOptions flags (stringToStringBuffer str) filepath (flags, _, _) <- parseDynamicFilePragma flags opts- return $ Right flags+ let flags' = foldl' xopt_set flags enable+ let flags'' = foldl' xopt_unset flags' disable+ return $ Right flags'' where catchErrors :: IO (Either String DynFlags) -> IO (Either String DynFlags) catchErrors act = handleGhcException reportErr@@ -195,3 +206,12 @@ isDotApp :: HsExpr GhcPs -> Bool isDotApp (OpApp _ _ (L _ op) _) = isDot op isDotApp _ = False++-- | A mapping from 'HSE.KnownExtension' values to their+-- 'GHC.LanguageExtensions.Type.Extension' equivalents.+hseToGhcExtension :: Map.Map HSE.KnownExtension Extension+hseToGhcExtension =+ let ghcExts = Map.fromList [(show x, x) | x <- [Cpp .. StarIsType]]+ in+ Map.fromList [ (x, ext) | x <- [minBound .. maxBound]+ , Just ext <- [Map.lookup (show x) ghcExts] ]
src/HLint.hs view
@@ -205,6 +205,7 @@ else ideas handleRefactoring :: [Idea] -> [String] -> Cmd -> IO ()+handleRefactoring [] _ _ = pure () -- No refactorings to apply handleRefactoring ideas files cmd@CmdMain{..} = case cmdFiles of [file] -> do
src/HSE/All.hs view
@@ -24,6 +24,7 @@ import Data.Maybe import Timing import Language.Preprocessor.Cpphs+import Data.Either import Data.Set (Set) import qualified Data.Map as Map import qualified Data.Set as Set@@ -37,6 +38,7 @@ import qualified "ghc-lib-parser" SrcLoc as GHC import qualified "ghc-lib-parser" ErrUtils import qualified "ghc-lib-parser" Outputable+import qualified "ghc-lib-parser" GHC.LanguageExtensions.Type as GHC vars :: FreeVars a => a -> [String] freeVars :: FreeVars a => a -> Set String@@ -229,6 +231,17 @@ ErrUtils.pprLocErrMsg (ErrUtils.mkPlainErrMsg baseDynFlags loc err) return $ Left $ ParseError sl msg pe +-- | Produce a pair of lists from a 'ParseFlags' value representing+-- language extensions to explicitly enable/disable.+ghcExtensionsFromParseFlags :: ParseFlags+ -> ([GHC.Extension], [GHC.Extension])+ghcExtensionsFromParseFlags ParseFlags {hseFlags=ParseMode {extensions=exts}}=+ partitionEithers $ mapMaybe toEither exts+ where+ toEither ke = case ke of+ EnableExtension e -> Left <$> Map.lookup e hseToGhcExtension+ DisableExtension e -> Right <$> Map.lookup e hseToGhcExtension+ -- | Parse a Haskell module. Applies the C pre processor, and uses -- best-guess fixity resolution if there are ambiguities. The -- filename @-@ is treated as @stdin@. Requires some flags (often@@ -242,7 +255,8 @@ | otherwise -> readFileUTF8' file str <- return $ fromMaybe str $ stripPrefix "\65279" str -- remove the BOM if it exists, see #130 ppstr <- runCpp (cppFlags flags) file str- dynFlags <- parsePragmasIntoDynFlags baseDynFlags file ppstr+ let enableDisableExts = ghcExtensionsFromParseFlags flags+ dynFlags <- parsePragmasIntoDynFlags baseDynFlags enableDisableExts file ppstr case dynFlags of Right ghcFlags -> case (parseFileContentsWithComments (mkMode flags file) ppstr, parseFileGhcLib file ppstr ghcFlags) of
src/Hint/NewType.hs view
@@ -19,6 +19,9 @@ data A = A Int# {-# LANGUAGE UnboxedTuples #-}; data WithAnn x = WithAnn (# Ann, x #) data A = A () -- newtype A = A ()+newtype Foo = Foo Int deriving (Show, Eq) -- newtype Foo = Foo Int deriving newtype (Show, Eq)+newtype Foo = Foo { getFoo :: Int } deriving (Show, Eq) -- newtype Foo = Foo { getFoo :: Int } deriving newtype (Show, Eq)+newtype Foo = Foo Int deriving stock Show </TEST> -} module Hint.NewType (newtypeHint) where@@ -26,7 +29,7 @@ import Hint.Type newtypeHint :: DeclHint-newtypeHint _ _ = newtypeHintDecl+newtypeHint _ _ x = newtypeHintDecl x ++ newTypeDerivingStrategiesHintDecl x newtypeHintDecl :: Decl_ -> [Idea] newtypeHintDecl x@@ -44,3 +47,21 @@ f (RecDecl x1 x2 [FieldDecl y1 [y2] t]) = Just (t, \t -> RecDecl x1 x2 [FieldDecl y1 [y2] t]) f _ = Nothing singleSimpleField _ = Nothing++newTypeDerivingStrategiesHintDecl :: Decl_ -> [Idea]+newTypeDerivingStrategiesHintDecl x = [ignoreN "Use DerivingStrategies" x new | Just new <- [newtypeDecl x]]++newtypeDecl :: Decl_ -> Maybe Decl_+newtypeDecl (DataDecl x1 x2@(NewType _) x3 x4 x5 x6)+ | any hasNoStrategy x6 = Just $ DataDecl x1 x2 x3 x4 x5 (withNewtype <$> x6)+newtypeDecl (GDataDecl x1 x2@(NewType _) x3 x4 x5 x6 x7)+ | any hasNoStrategy x7 = Just $ GDataDecl x1 x2 x3 x4 x5 x6 (withNewtype <$> x7)+newtypeDecl _ = Nothing++hasNoStrategy :: Deriving a -> Bool+hasNoStrategy (Deriving _ Nothing _) = True+hasNoStrategy _ = False++withNewtype :: Deriving a -> Deriving a+withNewtype (Deriving l Nothing rs) = Deriving l (Just $ DerivNewtype l) rs+withNewtype d = d
src/Idea.hs view
@@ -3,7 +3,7 @@ module Idea( Idea(..), rawIdea, idea, suggest, warn, ignore,- rawIdeaN, suggestN,+ rawIdeaN, suggestN, ignoreN, showIdeasJson, showANSI, Note(..), showNotes, Severity(..)@@ -92,3 +92,4 @@ ideaN severity hint from to = idea severity hint from to [] suggestN = ideaN Suggestion+ignoreN = ideaN Ignore