hlint 2.1.6 → 2.1.7
raw patch · 14 files changed
+67/−163 lines, 14 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 SrcSpanInfo)] -> [Idea]) -> ([Setting] -> Scope -> Module SrcSpanInfo -> [Idea]) -> ([Setting] -> Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [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
Files
- CHANGES.txt +15/−0
- README.md +4/−3
- data/hlint.yaml +13/−6
- data/hs-lint.el +3/−3
- hlint.cabal +1/−1
- src/CC.hs +1/−1
- src/Hint/Extensions.hs +1/−1
- src/Hint/Import.hs +2/−139
- src/Hint/Lambda.hs +12/−2
- src/Hint/Match.hs +6/−0
- src/Hint/Pragma.hs +5/−4
- src/Idea.hs +2/−2
- src/Report.hs +1/−1
- src/Test/Annotations.hs +1/−0
CHANGES.txt view
@@ -1,5 +1,20 @@ Changelog for HLint (* = breaking change) +2.1.7, released 2018-07-03+ #483, don't break quasi quotes when suggesting const+ #404, remove the "Unnecessary hiding" hint introduced in #338+ #162, make avoiding lambda with `infix` give a different name+ #507, rename id x ==> x to redundant id+ #286, improve the duplicate pragma message+ #399, suggest (& f) ==> f+ #136, don't suggest eta-reducing runST+ #345, add catMaybes/fmap ==> mapMaybe+ #345, add foldMap id ==> fold+ #364, suggest >> instead of >>= \_ ->+ #502, DeriveTraversable implies DeriveFoldable and DeriveFunctor+ Add hints about fusing traverse/map+ Better names for mapM/map fusion hints and others+ #498, change the output to say "Perhaps:" rather than "Why not:" 2.1.6, released 2018-06-16 Match on explicit brackets at the root of a match expression #470, suggest TupleSections
README.md view
@@ -16,6 +16,7 @@ * Some transformed programs may require additional type signatures, particularly if the transformations trigger the monomorphism restriction or involve rank-2 types. * The `RebindableSyntax` extension can cause HLint to suggest incorrect changes. * HLint turns on many language extensions so it can parse more documents, occasionally some break otherwise legal syntax - e.g. `{-#INLINE foo#-}` doesn't work with `MagicHash`, `foo $bar` means something different with `TemplateHaskell`. These extensions can be disabled with `-XNoMagicHash` or `-XNoTemplateHaskell` etc.+* HLint doesn't run any custom preprocessors, e.g. [markdown-unlit](https://hackage.haskell.org/package/markdown-unlit) or [record-dot-preprocessor](https://hackage.haskell.org/package/record-dot-preprocessor), so code making use of them will usually fail to parse. ## Installing and running HLint @@ -29,19 +30,19 @@ darcs-2.1.2\src\CommandLine.lhs:94:1: Warning: Use concatMap Found: concat $ map escapeC s-Why not:+Perhaps: concatMap escapeC s darcs-2.1.2\src\CommandLine.lhs:103:1: Suggestion: Use fewer brackets Found: ftable ++ (map (\ (c, x) -> (toUpper c, urlEncode x)) ftable)-Why not:+Perhaps: ftable ++ map (\ (c, x) -> (toUpper c, urlEncode x)) ftable darcs-2.1.2\src\Darcs\Patch\Test.lhs:306:1: Warning: Use a more efficient monadic variant Found: mapM (delete_line (fn2fp f) line) old-Why not:+Perhaps: mapM_ (delete_line (fn2fp f) line) old ... lots more hints ...
data/hlint.yaml view
@@ -95,7 +95,7 @@ - warn: {lhs: reverse (sortOn f x), rhs: sortOn (Data.Ord.Down . f) x, name: Avoid reverse} - warn: {lhs: reverse (sort x), rhs: sortOn Data.Ord.Down x, name: Avoid reverse} - hint: {lhs: flip (g `on` h), rhs: flip g `on` h, name: Move flip}- - hint: {lhs: (f `on` g) `on` h, rhs: f `on` (g . h)}+ - hint: {lhs: (f `on` g) `on` h, rhs: f `on` (g . h), name: Fuse on/on} # READ/SHOW@@ -153,7 +153,7 @@ - warn: {lhs: map (uncurry f) (zip x y), rhs: zipWith f x y} - hint: {lhs: map f (zip x y), rhs: zipWith (curry f) x y, side: isVar f} - warn: {lhs: not (elem x y), rhs: notElem x y}- - hint: {lhs: foldr f z (map g x), rhs: foldr (f . g) z x}+ - hint: {lhs: foldr f z (map g x), rhs: foldr (f . g) z x, name: Fuse foldr/map} - warn: {lhs: "x ++ concatMap (' ':) y", rhs: "unwords (x:y)"} - warn: {lhs: intercalate " ", rhs: unwords} - hint: {lhs: concat (intersperse x y), rhs: intercalate x y, side: notEq x " "}@@ -198,6 +198,7 @@ - warn: {lhs: sequence (fmap f x), rhs: traverse f x} - warn: {lhs: sequenceA_ (map f x), rhs: traverse_ f x} - warn: {lhs: sequenceA_ (fmap f x), rhs: traverse_ f x}+ - warn: {lhs: foldMap id, rhs: fold} # BY @@ -246,10 +247,11 @@ - hint: {lhs: "\\(x,y) -> f x y", rhs: uncurry f, note: IncreasesLaziness, name: Use uncurry} - 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)} # isWildcard because some people like to put brackets round them even though they are atomic - warn: {lhs: flip f x y, rhs: f y x, side: isApp original, name: Redundant flip}- - warn: {lhs: id x, rhs: x, side: not (isTypeApp x), name: Evaluate}+ - warn: {lhs: id x, rhs: x, side: not (isTypeApp x), name: Redundant id} - warn: {lhs: id . x, rhs: x, name: Redundant id} - warn: {lhs: x . id, rhs: x, name: Redundant id} - warn: {lhs: "((,) x)", rhs: "(_noParen_ x,)", name: Use tuple-section, note: RequiresExtension TupleSections}@@ -365,6 +367,7 @@ - warn: {lhs: mapM (uncurry f) (zip l m), rhs: zipWithM f l m} - warn: {lhs: mapM_ (void . f), rhs: mapM_ f} - warn: {lhs: forM_ x (void . f), rhs: forM_ x f}+ - warn: {lhs: a >>= \_ -> b, rhs: a >> b} # STATE MONAD @@ -380,8 +383,10 @@ - warn: {lhs: sequence_ (replicate n x), rhs: Control.Monad.replicateM_ n x} - warn: {lhs: mapM f (replicate n x), rhs: Control.Monad.replicateM n (f x)} - warn: {lhs: mapM_ f (replicate n x), rhs: Control.Monad.replicateM_ n (f x)}- - warn: {lhs: mapM f (map g x), rhs: mapM (f . g) x}- - warn: {lhs: mapM_ f (map g x), rhs: mapM_ (f . g) x}+ - warn: {lhs: mapM f (map g x), rhs: mapM (f . g) x, name: Fuse mapM/map}+ - warn: {lhs: mapM_ f (map g x), rhs: mapM_ (f . g) x, name: Fuse mapM_/map}+ - warn: {lhs: traverse f (map g x), rhs: traverse (f . g) x, name: Fuse traverse/map}+ - warn: {lhs: traverse_ f (map g x), rhs: traverse_ (f . g) x, name: Fuse traverse_/map} - warn: {lhs: mapM id, rhs: sequence} - warn: {lhs: mapM_ id, rhs: sequence_} - warn: {lhs: sequence (return a), rhs: return <$> a}@@ -431,6 +436,7 @@ - warn: {lhs: not (isJust x), rhs: isNothing x} - warn: {lhs: "maybe [] (:[])", rhs: maybeToList} - warn: {lhs: catMaybes (map f x), rhs: mapMaybe f x}+ - warn: {lhs: catMaybes (fmap f x), rhs: mapMaybe f x} - hint: {lhs: case x of Nothing -> y; Just a -> a , rhs: fromMaybe y x} - warn: {lhs: if isNothing x then y else f (fromJust x), rhs: maybe y f x} - warn: {lhs: if isJust x then f (fromJust x) else y, rhs: maybe y f x}@@ -447,7 +453,7 @@ - warn: {lhs: if isNothing x then y else fromJust x, rhs: fromMaybe y x} - warn: {lhs: if isJust x then fromJust x else y, rhs: fromMaybe y x} - warn: {lhs: isJust x && (fromJust x == y), rhs: x == Just y}- - warn: {lhs: mapMaybe f (map g x), rhs: mapMaybe (f . g) x}+ - warn: {lhs: mapMaybe f (map g x), rhs: mapMaybe (f . g) x, name: Fuse mapMaybe/map} - warn: {lhs: fromMaybe a (fmap f x), rhs: maybe a f x} - warn: {lhs: fromMaybe a (f <$> x), rhs: maybe a f x} - warn: {lhs: mapMaybe id, rhs: catMaybes}@@ -809,6 +815,7 @@ # yes = foldr (\ curr acc -> (+ 1) curr : acc) [] -- map (\ curr -> (+ 1) curr) # yes = foldr (\ curr acc -> curr + curr : acc) [] -- map (\ curr -> curr + curr) # no = foo $ (,) x $ do {this is a test; and another test}+# {-# LANGUAGE QuasiQuotes #-}; no = f (\url -> [hamlet|foo @{url}|]) # # import Prelude \ # yes = flip mapM -- Control.Monad.forM
data/hs-lint.el view
@@ -12,7 +12,7 @@ ;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce ;; Found: ;; count1 p l = length (filter p l)-;; Why not:+;; Perhaps: ;; count1 p = length . filter p @@ -52,11 +52,11 @@ ;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .* ;; Found: ;; \s +\(.*\)-;; Why not:+;; Perhaps: ;; \s +\(.*\) (defvar hs-lint-regex- "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"+ "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Perhaps:[\n\C-m]\\s +\\(.*\\)[\n\C-m]" "Regex for HLint messages") (defun make-short-string (str maxlen)
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.18 build-type: Simple name: hlint-version: 2.1.6+version: 2.1.7 license: BSD3 license-file: LICENSE category: Development
src/CC.hs view
@@ -99,7 +99,7 @@ , T.pack from , "```" , ""- , "Why not"+ , "Perhaps" , "" , "```" , T.pack to
src/Hint/Extensions.hs view
@@ -210,7 +210,7 @@ used DeriveDataTypeable = hasDerive ["Data","Typeable"] used DeriveFunctor = hasDerive ["Functor"] used DeriveFoldable = hasDerive ["Foldable"]-used DeriveTraversable = hasDerive ["Traversable"]+used DeriveTraversable = hasDerive ["Traversable","Foldable","Functor"] used DeriveGeneric = hasDerive ["Generic","Generic1"] used GeneralizedNewtypeDeriving = not . null . derivesNewtype . derives used LambdaCase = hasS isLCase
src/Hint/Import.hs view
@@ -33,73 +33,6 @@ import Char(foo) -- import Data.Char(foo) import IO(foo) import IO as X -- import System.IO as X; import System.IO.Error as X; import Control.Exception as X (bracket,bracket_)-import A hiding (a) -- import A-import A hiding (a, b); foo = a -- import A hiding (a)-import A hiding (a, b); foo = A.a -- import A hiding (a)-import A as B hiding (a) -- import A as B-import A as B hiding (a, b); foo = a -- import A as B hiding (a)-import A as B hiding (a, b); foo = B.a -- import A as B hiding (a)-import qualified A hiding (a) -- import qualified A-import qualified A hiding (a, b); foo = A.a -- import qualified A hiding (a)-import qualified A as B hiding (a, b); foo = B.a -- import qualified A as B hiding (a)-import A hiding ((+)) -- import A-import A hiding ((+), (*)); foo = (+) -- import A hiding ((+))-import A hiding ((+), (*)); foo = (+x) -- import A hiding ((+))-import A hiding ((+), (*)); foo = (x+) -- import A hiding ((+))-import A hiding ((+), (*)); foo = x+y -- import A hiding ((+))-import A hiding ((+), (*)); foo = (A.+) -- import A hiding ((+))-import A hiding ((+), (*)); foo = (A.+ x) -- import A hiding ((+))-import A hiding ((+), (*)); foo = (x A.+) -- import A hiding ((+))-import A hiding ((+), (*)); foo = x A.+ y -- import A hiding ((+))-import A as B hiding ((+)) -- import A as B-import A as B hiding ((+), (*)); foo = (+) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = (x+) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = (+x) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = x+y -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = (B.+) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = (x B.+) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = (B.+ x) -- import A as B hiding ((+))-import A as B hiding ((+), (*)); foo = x B.+ y -- import A as B hiding ((+))-import qualified A hiding ((+)) -- import qualified A-import qualified A hiding ((+), (*)); foo = (A.+) -- import qualified A hiding ((+))-import qualified A hiding ((+), (*)); foo = (x A.+) -- import qualified A hiding ((+))-import qualified A hiding ((+), (*)); foo = (A.+ x) -- import qualified A hiding ((+))-import qualified A hiding ((+), (*)); foo = x A.+ y -- import qualified A hiding ((+))-import qualified A as B hiding ((+), (*)); foo = (B.+) -- import qualified A as B hiding ((+))-import qualified A as B hiding ((+), (*)); foo = (x B.+) -- import qualified A as B hiding ((+))-import qualified A as B hiding ((+), (*)); foo = (B.+ x) -- import qualified A as B hiding ((+))-import qualified A as B hiding ((+), (*)); foo = x B.+ y -- import qualified A as B hiding ((+))-module Foo (a) where; import A hiding (a)-module Foo (a) where; import A hiding (a, b) -- import A hiding (a)-module Foo (A.a) where; import A hiding (a, b) -- import A hiding (a)-module Foo (a) where; import A as B hiding (a)-module Foo (a) where; import A as B hiding (a, b) -- import A as B hiding (a)-module Foo (B.a) where; import A as B hiding (a, b) -- import A as B hiding (a)-module Foo (a) where; import qualified A hiding (a) -- import qualified A-module Foo (A.a) where; import qualified A hiding (a, b) -- import qualified A hiding (a)-module Foo (B.a) where; import qualified A as B hiding (a, b) -- import qualified A as B hiding (a)-module Foo (module A) where; import A hiding (a, b, c)-module Foo (module B) where; import A as B hiding (a, b, c)-module Foo (module A) where; import qualified A hiding (a, b, c) -- import qualified A-module Foo (module B) where; import qualified A as B hiding (a, b, c) -- import qualified A as B-module Foo ((+)) where; import A hiding ((+))-module Foo ((+)) where; import A hiding ((+), (*)) -- import A hiding ((+))-module Foo ((A.+)) where; import A hiding ((+), (*)) -- import A hiding ((+))-module Foo ((+)) where; import A as B hiding ((+))-module Foo ((+)) where; import A as B hiding ((+), (*)) -- import A as B hiding ((+))-module Foo ((B.+)) where; import A as B hiding ((+), (*)) -- import A as B hiding ((+))-module Foo ((+)) where; import qualified A hiding ((+)) -- import qualified A-module Foo ((A.+)) where; import qualified A hiding ((+), (*)) -- import qualified A hiding ((+))-module Foo ((B.+)) where; import qualified A as B hiding ((+), (*)) -- import qualified A as B hiding ((+))-module Foo (module A) where; import A hiding ((+), (*), (/))-module Foo (module B) where; import A as B hiding ((+), (*), (/))-module Foo (module A) where; import qualified A hiding ((+), (*), (/)) -- import qualified A-module Foo (module B) where; import qualified A as B hiding ((+), (*), (/)) -- import qualified A as B-{-# LANGUAGE QuasiQuotes #-}; import A hiding (a); [a||]-{-# LANGUAGE QuasiQuotes #-}; import A hiding (a); [A.a||]-{-# LANGUAGE QuasiQuotes #-}; import A as B hiding (a); [B.a||]-{-# LANGUAGE QuasiQuotes #-}; import qualified A hiding (a); [A.a||]-{-# LANGUAGE QuasiQuotes #-}; import qualified A as B hiding (a); [B.a||] </TEST> -} @@ -112,53 +45,16 @@ import Refact.Types hiding (ModuleName) import qualified Refact.Types as R import Data.List.Extra-import Data.Either (partitionEithers) import Data.Maybe import Prelude-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Set (Set)-import qualified Data.Set as Set importHint :: ModuHint importHint _ x = concatMap (wrap . snd) (groupSort [((fromNamed $ importModule i,importPkg i),i) | i <- universeBi x, not $ importSrc i]) ++- concatMap (\x -> hierarchy x ++ combine1 x ++ hidden reexported unqual quals x) (universeBi x)- where- -- Names of all re-exported modules- reexported :: Set String- reexported = Set.fromList [ fromModuleName n | EModuleContents _ n <- universeBi x ]+ concatMap (\x -> hierarchy x ++ combine1 x) (universeBi x) - -- Unqualified expressions and exported expressions- unqual :: Set String- unqual = Set.fromList (mapMaybe f qnames) `Set.union` Set.fromList qqUnqual- where f :: QName S -> Maybe String- f (UnQual _ n) = Just (fromNamed n)- f _ = Nothing - -- Qualified expressions and exported expressions- quals :: Map String (Set String)- quals = Map.fromListWith Set.union (map (second Set.singleton) qqQuals ++ mapMaybe f qnames)- where f (Qual _ m n) = Just (fromModuleName m, Set.singleton (fromNamed n))- f _ = Nothing-- -- Unqualified quasi-quoters like [foo|...|]- qqUnqual :: [String]- -- Qualified quasi-quoters like [Foo.bar|...|]- qqQuals :: [(String, String)]- (qqUnqual, qqQuals) = partitionEithers [ f n | QuasiQuote (_ :: S) n _ <- universeBi x ]- where f :: String -> Either String (String, String)- f n = maybe (Left n) Right (stripInfixEnd "." n)-- qnames :: [QName S]- qnames = concat- [ [ n | Var (_ :: S) n <- universeBi x ]- , [ n | VarQuote (_ :: S) n <- universeBi x ]- , [ n | QVarOp (_ :: S) n <- universeBi x ]- , [ n | EVar (_ :: S) n <- universeBi x ]- ]- wrap :: [ImportDecl S] -> [Idea] wrap o = [ rawIdea Warning "Use fewer imports" (srcInfoSpan $ ann $ head o) (f o) (Just $ f x) [] rs | Just (x, rs) <- [simplify o]]@@ -215,7 +111,7 @@ ,"Data" * "Ratio" ,"System" * "Directory" - -- Special, see bug #393+ -- Special, see bug https://code.google.com/archive/p/ndmitchell/issues/393 -- ,"System" * "IO" -- Do not encourage use of old-locale/old-time over haskell98@@ -247,36 +143,3 @@ desugarQual :: ImportDecl S -> ImportDecl S desugarQual x | importQualified x && isNothing (importAs x) = x{importAs=Just (importModule x)} | otherwise = x---- Suggest removing unnecessary "hiding" clauses in imports. Currently this only--- works for expressions.-hidden :: Set String -> Set String -> Map String (Set String) -> ImportDecl S -> [Idea]-hidden reexported unqual quals i@ImportDecl{importSpecs = Just (ImportSpecList loc True xs)}- -- If the module is re-exported and not imported qualified, we can't prune- -- any identifiers from the hiding clause- | not (importQualified i) && as `Set.member` reexported = []- | otherwise =- case partition isUsed xs of- (_, []) -> []- ([], _) -> [suggest "Unnecessary hiding" i i{importSpecs = Nothing} [Delete Import (toSS i)]]- (xs, _) ->- let newImp = i{importSpecs = Just (ImportSpecList loc True xs)}- in [suggest "Unnecessary hiding" i newImp [Replace Import (toSS i) [] (prettyPrint newImp)]]- where- isUsed :: ImportSpec S -> Bool- isUsed (IVar _ n) = Set.member (fromNamed n) vars- isUsed _ = True-- vars :: Set String- vars =- if importQualified i- then qual- else qual `Set.union` unqual-- qual :: Set String- qual = fromMaybe Set.empty (Map.lookup as quals)-- as :: String- as = fromModuleName (fromMaybe (importModule i) (importAs i))--hidden _ _ _ _ = []
src/Hint/Lambda.hs view
@@ -31,9 +31,13 @@ fun mr = y mr fun x = f . g $ x -- fun = f . g f = foo (\y -> g x . h $ y) -- g x . h+f = foo (\y -> g x . h $ y) -- @Message Avoid lambda f = foo ((*) x) -- (x *) f = (*) x f = foo (flip op x) -- (`op` x)+f = foo (flip op x) -- @Message Use section+foo x = bar (\ d -> search d table) -- (`search` table)+foo x = bar (\ d -> search d table) -- @Message Avoid lambda using `infix` f = flip op x f = foo (flip (*) x) -- (* x) f = foo (flip (-) x)@@ -70,6 +74,7 @@ no = blah (\ x -> case x of A -> a x; B -> b x) yes = blah (\ x -> (y, x, z+q)) -- (y, , z+q) yes = blah (\ x -> (y, x, z+x))+tmp = map (\ x -> runST $ action x) {-# LANGUAGE QuasiQuotes #-}; authOAuth2 name = authOAuth2Widget [whamlet|Login via #{name}|] name {-# LANGUAGE QuasiQuotes #-}; authOAuth2 = foo (\name -> authOAuth2Widget [whamlet|Login via #{name}|] name) </TEST>@@ -83,6 +88,7 @@ import Util import Data.List.Extra import Data.Maybe+import qualified Data.Set as Set import Refact.Types hiding (RType(Match)) @@ -138,8 +144,12 @@ -- subts = [("a", toSS y), ("*", toSS v)] lambdaExp p o@(Paren _ (App _ (App _ (view -> Var_ "flip") (Var _ x)) y)) | allowRightSection $ fromNamed x = [suggestN "Use section" o $ RightSection an (QVarOp an x) y]-lambdaExp p o@Lambda{} | maybe True (not . isInfixApp) p, (res, refact) <- niceLambdaR [] o, not $ isLambda res, not $ any isQuasiQuote $ universe res =- [(if isVar res || isCon res then warn else suggest) "Avoid lambda" o res (refact $ toSS o)]+lambdaExp p o@Lambda{}+ | maybe True (not . isInfixApp) p, (res, refact) <- niceLambdaR [] o+ , not $ isLambda res, not $ any isQuasiQuote $ universe res, not $ "runST" `Set.member` freeVars o+ , let name = "Avoid lambda" ++ (if countInfixNames res > countInfixNames o then " using `infix`" else "") =+ [(if isVar res || isCon res then warn else suggest) name o res (refact $ toSS o)]+ where countInfixNames x = length [() | RightSection _ (QVarOp _ (UnQual _ (Ident _ _))) _ <- universe x] lambdaExp p o@(Lambda _ pats x) | isLambda (fromParen x), null (universeBi pats :: [Exp_]), maybe True (not . isLambda) p = [suggest "Collapse lambdas" o (Lambda an pats body) [Replace Expr (toSS o) subts template]] where
src/Hint/Match.hs view
@@ -111,6 +111,12 @@ guard $ (freeVars e Set.\\ Set.filter (not . isUnifyVar) (freeVars hintRuleRHS)) `Set.isSubsetOf` freeVars x -- check no unexpected new free variables++ -- check it isn't going to get broken by QuasiQuotes as per #483+ -- if we have lambdas we might be moving, and QuasiQuotes, we might inadvertantly break free vars+ -- because quasi quotes don't show what free vars they make use of+ guard $ not (any isLambda $ universe hintRuleLHS) || not (any isQuasiQuote $ universe x)+ guard $ checkSide hintRuleSide $ ("original",x) : ("result",res) : fromSubst u guard $ checkDefine decl parent res return (res, hintRuleNotes, [(s, toSS pos) | (s, pos) <- fromSubst u, ann pos /= an])
src/Hint/Pragma.hs view
@@ -68,21 +68,22 @@ pragmaIdea pidea = case pidea of SingleComment old new ->- mkIdea (srcInfoSpan . ann $ old)+ mkFewer (srcInfoSpan . ann $ old) (prettyPrint old) (Just $ prettyPrint new) [] [ModifyComment (toSS old) (prettyPrint new)] MultiComment repl delete new ->- mkIdea (srcInfoSpan . ann $ repl)+ mkFewer (srcInfoSpan . ann $ repl) (f [repl, delete]) (Just $ prettyPrint new) [] [ ModifyComment (toSS repl) (prettyPrint new) , ModifyComment (toSS delete) ""] OptionsToComment old new r ->- mkIdea (srcInfoSpan . ann . head $ old)+ mkLanguage (srcInfoSpan . ann . head $ old) (f old) (Just $ f new) [] r where f = unlines . map prettyPrint- mkIdea = rawIdea Warning "Use better pragmas"+ mkFewer = rawIdea Warning "Use fewer LANGUAGE pragmas"+ mkLanguage = rawIdea Warning "Use LANGUAGE pragmas" languageDupes :: [ModulePragma S] -> [Idea]
src/Idea.hs view
@@ -70,11 +70,11 @@ showEx :: (String -> String) -> Idea -> String showEx tt Idea{..} = unlines $ [showSrcLoc (getPointLoc ideaSpan) ++ ": " ++ (if ideaHint == "" then "" else show ideaSeverity ++ ": " ++ ideaHint)] ++- f "Found" (Just ideaFrom) ++ f "Why not" ideaTo +++ f "Found" (Just ideaFrom) ++ f "Perhaps" ideaTo ++ ["Note: " ++ n | let n = showNotes ideaNote, n /= ""] where f msg Nothing = []- f msg (Just x) | null xs = [msg ++ " remove it."]+ f msg (Just x) | null xs = [msg ++ " you should remove it."] | otherwise = (msg ++ ":") : map (" "++) xs where xs = lines $ tt x
src/Report.hs view
@@ -56,7 +56,7 @@ (case ideaTo of Nothing -> [] Just to ->- ["Why not" ++ (if to == "" then " remove it." else "") ++ "<br/>"+ ["Perhaps" ++ (if to == "" then " you should remove it." else "") ++ "<br/>" ,hsColourHTML to]) ++ [let n = showNotes ideaNote in if n /= "" then "<span class='note'>Note: " ++ writeNote n ++ "</span>" else "" ,"</div>"
src/Test/Annotations.hs view
@@ -56,6 +56,7 @@ if null bad then passed else sequence_ bad match "???" _ = True+ match (word1 -> ("@Message",msg)) i = ideaHint i == msg match (word1 -> ("@Note",note)) i = map show (ideaNote i) == [note] match "@NoNote" i = null (ideaNote i) match (word1 -> ('@':sev, msg)) i = sev == show (ideaSeverity i) && match msg i