hlint 2.0.10 → 2.0.11
raw patch · 13 files changed
+64/−36 lines, 13 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Language.Haskell.HLint3: Hint :: ([Setting] -> [(Scope, Module_)] -> [Idea]) -> ([Setting] -> Scope -> Module_ -> [Idea]) -> ([Setting] -> Scope -> Module_ -> Decl_ -> [Idea]) -> ([Setting] -> Comment -> [Idea]) -> Hint
+ Language.Haskell.HLint3: Hint :: ([Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea]) -> ([Setting] -> Scope -> Module SrcSpanInfo -> [Idea]) -> ([Setting] -> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]) -> ([Setting] -> Comment -> [Idea]) -> Hint
- Language.Haskell.HLint3: HintRule :: Severity -> String -> Scope -> Exp_ -> Exp_ -> Maybe Exp_ -> [Note] -> HintRule
+ Language.Haskell.HLint3: HintRule :: Severity -> String -> Scope -> Exp SrcSpanInfo -> Exp SrcSpanInfo -> Maybe (Exp SrcSpanInfo) -> [Note] -> HintRule
- Language.Haskell.HLint3: [hintDecl] :: Hint -> [Setting] -> Scope -> Module_ -> Decl_ -> [Idea]
+ Language.Haskell.HLint3: [hintDecl] :: Hint -> [Setting] -> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
- Language.Haskell.HLint3: [hintModule] :: Hint -> [Setting] -> Scope -> Module_ -> [Idea]
+ Language.Haskell.HLint3: [hintModule] :: Hint -> [Setting] -> Scope -> Module SrcSpanInfo -> [Idea]
- Language.Haskell.HLint3: [hintModules] :: Hint -> [Setting] -> [(Scope, Module_)] -> [Idea]
+ Language.Haskell.HLint3: [hintModules] :: Hint -> [Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea]
- Language.Haskell.HLint3: [hintRuleLHS] :: HintRule -> Exp_
+ Language.Haskell.HLint3: [hintRuleLHS] :: HintRule -> Exp SrcSpanInfo
- Language.Haskell.HLint3: [hintRuleRHS] :: HintRule -> Exp_
+ Language.Haskell.HLint3: [hintRuleRHS] :: HintRule -> Exp SrcSpanInfo
- Language.Haskell.HLint3: [hintRuleSide] :: HintRule -> Maybe Exp_
+ Language.Haskell.HLint3: [hintRuleSide] :: HintRule -> Maybe (Exp SrcSpanInfo)
- Language.Haskell.HLint3: applyHints :: [Classify] -> Hint -> [(Module_, [Comment])] -> [Idea]
+ Language.Haskell.HLint3: applyHints :: [Classify] -> Hint -> [(Module SrcSpanInfo, [Comment])] -> [Idea]
- Language.Haskell.HLint3: parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module_, [Comment]))
+ Language.Haskell.HLint3: parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module SrcSpanInfo, [Comment]))
- Language.Haskell.HLint3: scopeCreate :: Module_ -> Scope
+ Language.Haskell.HLint3: scopeCreate :: Module SrcSpanInfo -> Scope
Files
- CHANGES.txt +5/−0
- README.md +3/−1
- hlint.cabal +1/−1
- src/Apply.hs +1/−1
- src/Config/Type.hs +4/−4
- src/Config/Yaml.hs +10/−9
- src/HLint.hs +1/−1
- src/HSE/All.hs +1/−1
- src/HSE/Scope.hs +1/−1
- src/HSE/Util.hs +8/−0
- src/Hint/Extensions.hs +16/−9
- src/Hint/Type.hs +4/−4
- src/Language/Haskell/HLint3.hs +9/−4
CHANGES.txt view
@@ -1,5 +1,10 @@ Changelog for HLint +2.0.11+ #411, parse the YAML file with lots of HSE extensions turned on+ #408, use the same config file logic in argsSettings as in hlint+ Don't use unexported type synonyms in the public API+ #405, fix false positives on MagicHash due to unboxed literals 2.0.10 #377, suggest lambda case Add CodeClimate support
README.md view
@@ -224,10 +224,12 @@ Some of the hints are subjective, and some users believe they should be ignored. Some hints are applicable usually, but occasionally don't always make sense. The ignoring mechanism provides features for suppressing certain hints. Ignore directives can either be written as pragmas in the file being analysed, or in the hint files. Examples of pragmas are: -* `{-# ANN module "HLint: ignore Eta reduce" #-}` - ignore all eta reduction suggestions in this module (use `module` literally, not the name of the module).+* `{-# ANN module "HLint: ignore Eta reduce" #-}` - ignore all eta reduction suggestions in this module (use `module` literally, not the name of the module). Put this annotation _after_ the `import` statements. * `{-# ANN myFunction "HLint: ignore" #-}` - don't give any hints in the function `myFunction`. * `{-# ANN myFunction "HLint: error" #-}` - any hint in the function `myFunction` is an error. * `{-# ANN module "HLint: error Use concatMap" #-}` - the hint to use `concatMap` is an error (you may also use `warn` or `suggest` in place of `error` for other severity levels).++If you have the `OverloadedStrings` extension enabled you will need to give an explicit type to the annotation, e.g. `{-# ANN myFunction ("HLint: ignore" :: String) #-}`. Ignore directives can also be written in the hint files:
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.18 build-type: Simple name: hlint-version: 2.0.10+version: 2.0.11 license: BSD3 license-file: LICENSE category: Development
src/Apply.hs view
@@ -39,7 +39,7 @@ -- When given multiple modules at once this function attempts to find hints between modules, -- which is slower and often pointless (by default HLint passes modules singularly, using -- @--cross@ to pass all modules together).-applyHints :: [Classify] -> Hint -> [(Module_, [Comment])] -> [Idea]+applyHints {- PUBLIC -} :: [Classify] -> Hint -> [(Module SrcSpanInfo, [Comment])] -> [Idea] applyHints cs = applyHintsReal $ map SettingClassify cs applyHintsReal :: [Setting] -> Hint -> [(Module_, [Comment])] -> [Idea]
src/Config/Type.hs view
@@ -83,13 +83,13 @@ deriving Show -- | A @LHS ==> RHS@ style hint rule.-data HintRule = HintRule+data HintRule {- PUBLIC -} = HintRule {hintRuleSeverity :: Severity -- ^ Default severity for the hint. ,hintRuleName :: String -- ^ Name for the hint. ,hintRuleScope :: Scope -- ^ Module scope in which the hint operates.- ,hintRuleLHS :: Exp_ -- ^ LHS- ,hintRuleRHS :: Exp_ -- ^ RHS- ,hintRuleSide :: Maybe Exp_ -- ^ Side condition, typically specified with @where _ = ...@.+ ,hintRuleLHS :: Exp SrcSpanInfo -- ^ LHS+ ,hintRuleRHS :: Exp SrcSpanInfo -- ^ RHS+ ,hintRuleSide :: Maybe (Exp SrcSpanInfo) -- ^ Side condition, typically specified with @where _ = ...@. ,hintRuleNotes :: [Note] -- ^ Notes about application of the hint. } deriving Show
src/Config/Yaml.hs view
@@ -21,6 +21,7 @@ import HSE.All hiding (Rule, String) import Data.Functor import Data.Monoid+import Util import Prelude @@ -135,10 +136,10 @@ when (bad /= []) $ parseFail v $ "Not allowed keys: " ++ unwords bad -parseHSE :: (String -> ParseResult v) -> Val -> Parser v+parseHSE :: (ParseMode -> String -> ParseResult v) -> Val -> Parser v parseHSE parser v = do x <- parseString v- case parser x of+ case parser defaultParseMode{extensions=defaultExtensions} x of ParseOk x -> return x ParseFailed loc s -> parseFail v $ "Failed to parse " ++ s ++ ", when parsing:\n " ++ x @@ -167,12 +168,12 @@ parsePackage :: Val -> Parser Package parsePackage v = do packageName <- parseField "name" v >>= parseString- packageModules <- parseField "modules" v >>= parseArray >>= mapM (parseHSE parseImportDecl)+ packageModules <- parseField "modules" v >>= parseArray >>= mapM (parseHSE parseImportDeclWithMode) allowFields v ["name","modules"] return Package{..} parseFixity :: Val -> Parser [Setting]-parseFixity v = parseArray v >>= concatMapM (parseHSE parseDecl >=> f)+parseFixity v = parseArray v >>= concatMapM (parseHSE parseDeclWithMode >=> f) where f x@InfixDecl{} = return $ map Infix $ getFixity x f _ = parseFail v "Expected fixity declaration"@@ -190,7 +191,7 @@ x <- parseString v case word1 x of ("package", x) -> return $ Left x- _ -> Right <$> parseHSE parseImportDecl v+ _ -> Right <$> parseHSE parseImportDeclWithMode v ruleToGroup :: [Either HintRule Classify] -> Group ruleToGroup = Group "" True []@@ -200,11 +201,11 @@ (severity, v) <- parseSeverityKey v isRule <- isJust <$> parseFieldOpt "lhs" v if isRule then do- hintRuleLHS <- parseField "lhs" v >>= parseHSE parseExp- hintRuleRHS <- parseField "rhs" v >>= parseHSE parseExp+ hintRuleLHS <- parseField "lhs" v >>= parseHSE parseExpWithMode+ hintRuleRHS <- parseField "rhs" v >>= parseHSE parseExpWithMode hintRuleNotes <- parseFieldOpt "note" v >>= maybe (return []) (fmap (map asNote) . parseArrayString) hintRuleName <- parseFieldOpt "name" v >>= maybe (return $ guessName hintRuleLHS hintRuleRHS) parseString- hintRuleSide <- parseFieldOpt "side" v >>= maybe (return Nothing) (fmap Just . parseHSE parseExp)+ hintRuleSide <- parseFieldOpt "side" v >>= maybe (return Nothing) (fmap Just . parseHSE parseExpWithMode) allowFields v ["lhs","rhs","note","name","side"] let hintRuleScope = mempty return [Left HintRule{hintRuleSeverity=severity, ..}]@@ -230,7 +231,7 @@ parseWithin :: Val -> Parser [(String, String)] -- (module, decl) parseWithin v = do- x <- parseHSE parseExp v+ x <- parseHSE parseExpWithMode v case x of Var _ (UnQual _ name) -> return [("",fromNamed name)] Var _ (Qual _ (ModuleName _ mod) name) -> return [(mod, fromNamed name)]
src/HLint.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE RecordWildCards, TupleSections #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} -module HLint(hlint) where+module HLint(hlint, readAllSettings) where import Control.Applicative import Control.Monad.Extra
src/HSE/All.hs view
@@ -88,7 +88,7 @@ -- | 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 'defaultParseFlags'), the filename, and optionally the contents of that file.-parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module_, [Comment]))+parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module SrcSpanInfo, [Comment])) parseModuleEx flags file str = do str <- case str of Just x -> return x
src/HSE/Scope.hs view
@@ -41,7 +41,7 @@ mappend (Scope xs) (Scope ys) = Scope $ xs ++ ys -- | Create a 'Scope' value from a module, based on the modules imports.-scopeCreate :: Module_ -> Scope+scopeCreate :: Module SrcSpanInfo -> Scope scopeCreate xs = Scope $ [prelude | not $ any isPrelude res] ++ res where res = [x | x <- moduleImports xs, importPkg x /= Just "hint"]
src/HSE/Util.hs view
@@ -122,6 +122,14 @@ isSection RightSection{} = True isSection _ = False +isPrimLiteral PrimInt{} = True+isPrimLiteral PrimWord{} = True+isPrimLiteral PrimFloat{} = True+isPrimLiteral PrimDouble{} = True+isPrimLiteral PrimChar{} = True+isPrimLiteral PrimString{} = True+isPrimLiteral _ = False+ allowRightSection x = x `notElem` ["-","#"] allowLeftSection x = x /= "#"
src/Hint/Extensions.hs view
@@ -101,6 +101,14 @@ {-# LANGUAGE MagicHash #-} \ foo# = id {-# LANGUAGE MagicHash #-} \+main = "foo"#+{-# LANGUAGE MagicHash #-} \+main = 5#+{-# LANGUAGE MagicHash #-} \+main = 'a'#+{-# LANGUAGE MagicHash #-} \+main = 5.6#+{-# LANGUAGE MagicHash #-} \ foo = id -- </TEST> -}@@ -109,6 +117,7 @@ module Hint.Extensions(extensionsHint) where import Hint.Type+import Control.Monad.Extra import Data.Maybe import Data.List.Extra import Data.Ratio@@ -166,7 +175,7 @@ used :: KnownExtension -> Module_ -> Bool-used RecursiveDo = hasS isMDo & hasS isRecStmt+used RecursiveDo = hasS isMDo ||^ hasS isRecStmt used ParallelListComp = hasS isParComp used FunctionalDependencies = hasT (un :: FunDep S) used ImplicitParams = hasT (un :: IPName S)@@ -177,7 +186,7 @@ f _ = False used KindSignatures = hasT (un :: Kind S) used BangPatterns = hasS isPBangPat-used TemplateHaskell = hasT2 (un :: (Bracket S, Splice S)) & hasS f & hasS isSpliceDecl+used TemplateHaskell = hasT2 (un :: (Bracket S, Splice S)) ||^ hasS f ||^ hasS isSpliceDecl where f VarQuote{} = True f TypQuote{} = True f _ = False@@ -189,11 +198,11 @@ g _ = True used StandaloneDeriving = hasS isDerivDecl used PatternSignatures = hasS isPatTypeSig-used RecordWildCards = hasS isPFieldWildcard & hasS isFieldWildcard-used RecordPuns = hasS isPFieldPun & hasS isFieldPun+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 & hasS isTyQuasiQuote+used QuasiQuotes = hasS isQuasiQuote ||^ hasS isTyQuasiQuote used ViewPatterns = hasS isPViewPat used DefaultSignatures = hasS isClsDefSig used DeriveDataTypeable = hasDerive ["Data","Typeable"]@@ -217,7 +226,7 @@ used TransformListComp = hasS f where f QualStmt{} = False f _ = True-used MagicHash = hasS f+used MagicHash = hasS f ||^ hasS isPrimLiteral where f (Ident _ s) = "#" `isSuffixOf` s f _ = False @@ -271,10 +280,8 @@ un = undefined -(&) f g x = f x || g x- hasT t x = not $ null (universeBi x `asTypeOf` [t])-hasT2 ~(t1,t2) = hasT t1 & hasT t2+hasT2 ~(t1,t2) = hasT t1 ||^ hasT t2 hasS :: (Data x, Data (f S)) => (f S -> Bool) -> x -> Bool hasS test = any test . universeBi
src/Hint/Type.hs view
@@ -17,10 +17,10 @@ type CrossHint = [(Scope, Module_)] -> [Idea] -- | Functions to generate hints, combined using the 'Monoid' instance.-data Hint = Hint- {hintModules :: [Setting] -> [(Scope, Module_)] -> [Idea] -- ^ Given a list of modules (and their scope information) generate some 'Idea's.- ,hintModule :: [Setting] -> Scope -> Module_ -> [Idea] -- ^ Given a single module and its scope information generate some 'Idea's.- ,hintDecl :: [Setting] -> Scope -> Module_ -> Decl_ -> [Idea]+data Hint {- PUBLIC -} = Hint+ {hintModules :: [Setting] -> [(Scope, Module SrcSpanInfo)] -> [Idea] -- ^ Given a list of modules (and their scope information) generate some 'Idea's.+ ,hintModule :: [Setting] -> Scope -> Module SrcSpanInfo -> [Idea] -- ^ Given a single module and its scope information generate some 'Idea's.+ ,hintDecl :: [Setting] -> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea] -- ^ Given a declaration (with a module and scope) generate some 'Idea's. -- This function will be partially applied with one module/scope, then used on multiple 'Decl' values. ,hintComment :: [Setting] -> Comment -> [Idea] -- ^ Given a comment generate some 'Idea's.
src/Language/Haskell/HLint3.hs view
@@ -74,7 +74,8 @@ case cmd of CmdMain{..} -> do -- FIXME: Two things that could be supported (but aren't) are 'cmdGivenHints' and 'cmdWithHints'.- (fixities, classify, hints) <- findSettings (readSettingsFile $ Just cmdDataDir) Nothing+ (_,settings) <- readAllSettings args cmd+ let (fixities, classify, hints) = splitSettings settings let flags = parseFlagsSetLanguage (cmdExtensions cmd) $ parseFlagsAddFixities fixities $ defaultParseFlags{cppFlags = cmdCpp cmd} let ignore = [Classify Ignore x "" "" | x <- cmdIgnore]@@ -105,10 +106,14 @@ findSettings load start = do (file,contents) <- load $ fromMaybe "hlint.yaml" start xs <- readFilesConfig [(file,contents)]- return ([x | Infix x <- xs]- ,[x | SettingClassify x <- xs]- ,[Right x | SettingMatchExp x <- xs] ++ map Left [minBound..maxBound])+ return $ splitSettings xs +-- | Split a list of 'Setting' for separate use in parsing and hint resolution+splitSettings :: [Setting] -> ([Fixity], [Classify], [Either HintBuiltin HintRule])+splitSettings xs =+ ([x | Infix x <- xs]+ ,[x | SettingClassify x <- xs]+ ,[Right x | SettingMatchExp x <- xs] ++ map Left [minBound..maxBound]) -- | Snippet from the documentation, if this changes, update the documentation _docs :: IO ()