packages feed

hlint 3.2.3 → 3.2.4

raw patch · 30 files changed

+1000/−27 lines, 30 filesdep ~extradep ~ghc-lib-parser-exPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: extra, ghc-lib-parser-ex

API changes (from Hackage documentation)

Files

+ .hlint.yaml view
@@ -0,0 +1,68 @@+# HLint configuration file+# https://github.com/ndmitchell/hlint+##########################++# Hints that apply only to the HLint source code++#####################################################################+## RESTRICTIONS++- extensions:+  - default: false+  - name: [DeriveDataTypeable, DeriveFunctor, GeneralizedNewtypeDeriving, NoMonomorphismRestriction, OverloadedStrings]+  - name: [MultiWayIf, PatternGuards, RecordWildCards, ViewPatterns, PatternSynonyms, TupleSections, LambdaCase]+  - name: [Rank2Types, ScopedTypeVariables]+  - name: [ExistentialQuantification, MultiParamTypeClasses, NamedFieldPuns]+  - name: [FlexibleContexts, FlexibleInstances]+  - name: [PackageImports]+  - name: [ConstraintKinds, RankNTypes, TypeFamilies]+  - name: [TemplateHaskell]+  - {name: CPP, within: [HsColour, Config.Yaml, Test.Annotations]} # so it can be disabled to avoid GPL code++- flags:+  - default: false+  - {name: [-Wno-missing-fields, -fno-cse, -O0], within: CmdLine} # for cmdargs+  - {name: [-Wno-incomplete-patterns, -Wno-overlapping-patterns]} # the pattern match checker is not very good++- modules:+  - {name: [Data.Set, Data.HashSet], as: Set}+  - {name: [Data.Map, Data.HashMap.Strict, Data.HashMap.Lazy], as: Map}+  - {name: Control.Arrow, within: []}++- functions:+  - {name: unsafeInterleaveIO, within: Parallel}+  - {name: unsafePerformIO, within: [Util.exitMessageImpure, Test.Util.ref, Timing]}+  - {name: unsafeCoerce, within: [Util.gzip, GHC.Util.Refact.Utils]}+  - {name: Data.List.nub, within: []}+  - {name: Data.List.nubBy, within: []}+  - {name: Data.List.NonEmpty.nub, within: []}+  - {name: Data.List.NonEmpty.nubBy, within: []}+++#####################################################################+## OTHER HINTS++- warn: {name: Use explicit module export list}+++#####################################################################+## HINTS++- error: {lhs: idea Warning, rhs: warn}+- error: {lhs: idea Suggestion, rhs: suggest}+- error: {lhs: ideaN Warning, rhs: warnN}+- error: {lhs: ideaN Suggestion, rhs: suggestN}++- error: {lhs: occNameString (occName (unLoc x)), rhs: rdrNameStr x}+- error: {lhs: occNameString (occName x), rhs: occNameStr x}+- error: {lhs: noLoc (HsVar noExtField (noLoc (mkRdrUnqual (mkVarOcc x)))), rhs: strToVar x}++#####################################################################+## IGNORES++# doesn't fit with the other statements+- ignore: {name: Use let, within: [HLint, Test.All]}+# this const has meaingful argument names+- ignore: {name: Use const, within: Config.Yaml}+# TEMPORARY: this lint is deleted on HEAD+- ignore: {name: Use String}
CHANGES.txt view
@@ -1,5 +1,12 @@ Changelog for HLint (* = breaking change) +3.2.4, released 2020-12-30+    #1193, add warnings for redundant flip+    #1183, allow matches where users specify unnecessary brackets+    #1177, remove suggestions for fromMaybe False/fromMaybe True+    #1176, suggest use of unzip+    #1159, spot redundant brackets due to fixities, default ignored+    #1172, suggest reusing fromLeft/fromRight 3.2.3, released 2020-11-23     #1160, never consult the .hscolour file for color preferences     #1171, do not refactor redundant lambda with case
README.md view
@@ -1,4 +1,4 @@-# HLint [![Hackage version](https://img.shields.io/hackage/v/hlint.svg?label=Hackage)](https://hackage.haskell.org/package/hlint) [![Stackage version](https://www.stackage.org/package/hlint/badge/nightly?label=Stackage)](https://www.stackage.org/package/hlint) [![Linux build status](https://img.shields.io/travis/ndmitchell/hlint/master.svg?label=Linux%20build)](https://travis-ci.org/ndmitchell/hlint) [![Windows build status](https://img.shields.io/appveyor/ci/ndmitchell/hlint/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/ndmitchell/hlint)+# HLint [![Hackage version](https://img.shields.io/hackage/v/hlint.svg?label=Hackage)](https://hackage.haskell.org/package/hlint) [![Stackage version](https://www.stackage.org/package/hlint/badge/nightly?label=Stackage)](https://www.stackage.org/package/hlint) [![Build status](https://img.shields.io/github/workflow/status/ndmitchell/hlint/ci.svg)](https://github.com/ndmitchell/hlint/actions)  HLint is a tool for suggesting possible improvements to Haskell code. These suggestions include ideas such as using alternative functions, simplifying code and spotting redundancies. This document is structured as follows: 
+ data/hlint-restrict-extensions.yaml view
@@ -0,0 +1,3 @@+- extensions:+  - {name: DeriveFunctor, within: []}+  - {name: DeriveTraversable, within: [], message: "Custom message"}
data/hlint.yaml view
@@ -168,6 +168,7 @@     - warn: {lhs: all f (map g x), rhs: all (f . g) x}     - warn: {lhs: "zipWith (,)", rhs: zip}     - warn: {lhs: "zipWith3 (,,)", rhs: zip3}+    - hint: {lhs: map fst &&& map snd, rhs: unzip}     - hint: {lhs: length x == 0, rhs: null x, note: IncreasesLaziness}     - hint: {lhs: 0 == length x, rhs: null x, note: IncreasesLaziness}     - hint: {lhs: length x < 1, rhs: null x, note: IncreasesLaziness}@@ -319,6 +320,11 @@     - warn: {lhs: x . id, rhs: x, name: Redundant id}     - warn: {lhs: "((,) x)", rhs: "(_noParen_ x,)", name: Use tuple-section, note: RequiresExtension TupleSections}     - warn: {lhs: "flip (,) x", rhs: "(,_noParen_ x)", name: Use tuple-section, note: RequiresExtension TupleSections}+    - warn: {lhs: flip (flip f), rhs: f, note: DecreasesLaziness}+    - warn: {lhs: flip f <*> g, rhs: f =<< g, name: Redundant flip}+    - warn: {lhs: g <**> flip f, rhs: g >>= f, name: Redundant flip}+    - warn: {lhs: flip f =<< g, rhs: f <*> g, name: Redundant flip}+    - warn: {lhs: g >>= flip f, rhs: g Control.Applicative.<**> f, name: Redundant flip}      # CHAR @@ -560,8 +566,10 @@     - warn: {lhs: maybe True (x /=), rhs: (Just x /=)}     - warn: {lhs: maybe False (== x), rhs: (Just x ==), note: ValidInstance Eq x}     - warn: {lhs: maybe True (/= x), rhs: (Just x /=), note: ValidInstance Eq x}-    - warn: {lhs: fromMaybe False x, rhs: Just True == x} # Eta expanded, see https://github.com/ndmitchell/hlint/issues/970#issuecomment-643645053-    - warn: {lhs: fromMaybe True x, rhs: Just False /= x}+    # The following two hints seem to be somewhat unwelcome, e.g.+    # https://github.com/ndmitchell/hlint/issues/1177+    - ignore: {lhs: fromMaybe False x, rhs: Just True == x} # Eta expanded, see https://github.com/ndmitchell/hlint/issues/970#issuecomment-643645053+    - ignore: {lhs: fromMaybe True x, rhs: Just False /= x}     - warn: {lhs: not (isNothing x), rhs: isJust x}     - warn: {lhs: not (isJust x), rhs: isNothing x}     - warn: {lhs: "maybe [] (:[])", rhs: maybeToList}@@ -609,6 +617,8 @@     - 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}+    - warn: {lhs: either (const x) id, rhs: fromRight x}+    - warn: {lhs: either id (const x), rhs: fromLeft x}      # INFIX @@ -856,6 +866,7 @@     - warn: {lhs: "sequence [a]", rhs: "pure <$> a"}     - warn: {lhs: "x /= []", rhs: not (null x), name: Use null}     - warn: {lhs: "[] /= x", rhs: not (null x), name: Use null}+    - warn: {lhs: "maybe []", rhs: foldMap}  - group:     name: generalise-for-conciseness@@ -1200,6 +1211,8 @@ # issue1049 = elem True -- or # issue1062 = bar (\(f, x) -> baz () () . f $ x) -- uncurry ((.) (baz () ())) # issue1058 n = [] ++ issue1058 (n+1) -- issue1058 (n+1)+# issue1183 = (a >= 'a') && a <= 'z' -- isAsciiLower a+# issue1183 = (a >= 'a') && (a <= 'z') -- isAsciiLower a  # import Prelude \ # yes = flip mapM -- Control.Monad.forM
+ data/test-restrict.yaml view
@@ -0,0 +1,17 @@+- modules:+  - {name: Restricted.Module, within: []}+  - {name: Restricted.Module.Message, within: [], message: "Custom message"}++- functions:+  - {name: restricted, within: []}+  - {name: restrictedMessage, within: [], message: "Custom message"}++- extensions:+  - {name: DeriveFunctor, within: []}+  - {name: DeriveTraversable, within: [], message: "Custom message"}+++# Test https://github.com/ndmitchell/hlint/issues/766+- warn:+    lhs: "[hamlet| |]"+    rhs: "mempty"
+ data/wildcard.yaml view
@@ -0,0 +1,1 @@+- ignore: { name: Use const, within: '**.*Spec' }
hlint.cabal view
@@ -1,7 +1,7 @@ cabal-version:      >= 1.18 build-type:         Simple name:               hlint-version:            3.2.3+version:            3.2.4 license:            BSD3 license-file:       LICENSE category:           Development@@ -24,6 +24,11 @@     hlint.ghci     HLint_QuickCheck.hs     HLint_TypeCheck.hs+extra-source-files:+    .hlint.yaml+    data/*.hs+    data/*.yaml+    tests/*.test extra-doc-files:     README.md     CHANGES.txt@@ -80,7 +85,7 @@       build-depends:           ghc-lib-parser == 8.10.*     build-depends:-        ghc-lib-parser-ex >= 8.10.0.16 && < 8.10.1+        ghc-lib-parser-ex >= 8.10.0.17 && < 8.10.1      if flag(gpl)         build-depends: hscolour >= 1.21@@ -140,6 +145,7 @@         Hint.Duplicate         Hint.Export         Hint.Extensions+        Hint.Fixities         Hint.Import         Hint.Lambda         Hint.List
src/GHC/Util/Brackets.hs view
@@ -7,6 +7,7 @@ import SrcLoc import BasicTypes import Language.Haskell.GhclibParserEx.GHC.Hs.Expr+import Refact.Types  class Brackets a where   remParen :: a -> Maybe a -- Remove one paren or nothing if there is no paren.@@ -17,6 +18,7 @@   -- | Is the child safe free from brackets in the parent   -- position. Err on the side of caution, True = don't know.   needBracket :: Int -> a -> a -> Bool+  findType :: a -> RType  instance Brackets (LHsExpr GhcPs) where   -- When GHC parses a section in concrete syntax, it will produce an@@ -88,6 +90,8 @@      | L _ HsPar{} <- parent = False      | otherwise = True +  findType _ = Expr+ -- | Am I an HsApp such that having me in an infix doesn't require brackets. --   Before BlockArguments that was _all_ HsApps. Now, imagine: --@@ -133,6 +137,8 @@     | L _ ListPat{} <- parent = False     | otherwise = True +  findType _ = Pattern+ instance Brackets (LHsType GhcPs) where   remParen (L _ (HsParTy _ x)) = Just x   remParen _ = Nothing@@ -164,3 +170,5 @@     | L _ HsOpTy{} <- parent, L _ HsAppTy{} <- child = False     | L _ HsParTy{} <- parent = False     | otherwise = True++  findType _ = Type
src/GHC/Util/Unify.hs view
@@ -189,13 +189,15 @@ -- dot at the root, since otherwise you get two matches because of -- 'readRule' (Bug #570). unifyExp' :: NameMatch -> Bool -> LHsExpr GhcPs -> LHsExpr GhcPs -> Maybe (Subst (LHsExpr GhcPs))--- Brackets are not added when expanding '$' in user code, so tolerate--- them in the match even if they aren't in the user code.-unifyExp' nm root x y | not root, isPar x, not $ isPar y = unifyExp' nm root (fromParen x) y -- Don't subsitute for type apps, since no one writes rules imagining -- they exist. unifyExp' nm root (L _ (HsVar _ (rdrNameStr -> v))) y | isUnifyVar v, not $ isTypeApp y = Just $ Subst [(v, y)] unifyExp' nm root (L _ (HsVar _ x)) (L _ (HsVar _ y)) | nm x y = Just mempty++-- Brackets are not added when expanding '$' in user code, so tolerate+-- them in the match even if they aren't in the user code.+-- Also, allow the user to put in more brackets than they strictly need (e.g. with infix).+unifyExp' nm root x y | not root, isPar x || isPar y = unifyExp' nm root (fromParen x) (fromParen y)  unifyExp' nm root x@(L _ (OpApp _ lhs1 (L _ (HsVar _ (rdrNameStr -> v))) rhs1))                   y@(L _ (OpApp _ lhs2 (L _ (HsVar _ op2)) rhs2)) =
src/Hint/All.hs view
@@ -19,6 +19,7 @@ import Hint.Monad import Hint.Lambda import Hint.Bracket+import Hint.Fixities import Hint.Naming import Hint.Pattern import Hint.Import@@ -35,7 +36,7 @@ -- | A list of the builtin hints wired into HLint. --   This list is likely to grow over time. data HintBuiltin =-    HintList | HintListRec | HintMonad | HintLambda |+    HintList | HintListRec | HintMonad | HintLambda | HintFixities |     HintBracket | HintNaming | HintPattern | HintImport | HintExport |     HintPragma | HintExtensions | HintUnsafe | HintDuplicate | HintRestrict |     HintComment | HintNewType | HintSmell@@ -61,6 +62,7 @@     HintListRec    -> decl listRecHint     HintNaming     -> decl namingHint     HintBracket    -> decl bracketHint+    HintFixities   -> mempty{hintDecl=fixitiesHint}     HintSmell      -> mempty{hintDecl=smellHint,hintModule=smellModuleHint}     HintPattern    -> decl patternHint     HintMonad      -> decl monadHint
src/Hint/Bracket.hs view
@@ -138,17 +138,6 @@ prettyExpr s@(L _ SectionR{}) = unsafePrettyPrint (noLoc (HsPar noExtField s) :: LHsExpr GhcPs) prettyExpr x = unsafePrettyPrint x --- Dirty, should add to Brackets type class I think-tyConToRtype :: String -> RType-tyConToRtype "Exp"    = Expr-tyConToRtype "Type"   = Type-tyConToRtype "HsType" = Type-tyConToRtype "Pat"    = Pattern-tyConToRtype _        = Expr--findType :: (Data a) => a -> RType-findType = tyConToRtype . dataTypeName . dataTypeOf- -- 'Just _' if at least one set of parens were removed. 'Nothing' if -- zero parens were removed. remParens' :: Brackets a => a -> Maybe a@@ -162,7 +151,7 @@ isPartialAtom (L _ (HsSpliceE _ (HsUntypedSplice _ HasDollar _ _) )) = True isPartialAtom x = isRecConstr x || isRecUpdate x -bracket :: forall a . (Data a, Data (SrcSpanLess a), HasSrcSpan a, Outputable a, Brackets a) => (a -> String) -> (a -> Bool) -> Bool -> a -> [Idea]+bracket :: forall a . (Data a, HasSrcSpan a, Outputable a, Brackets a) => (a -> String) -> (a -> Bool) -> Bool -> a -> [Idea] bracket pretty isPartialAtom root = f Nothing   where     msg = "Redundant bracket"@@ -188,7 +177,7 @@       | not $ needBracket i o x, not $ isPartialAtom x =           rawIdea Suggestion msg (getLoc v) (pretty o) (Just (pretty (gen x))) [] [r] : g x       where-        typ = findType (unLoc v)+        typ = findType v         r = Replace typ (toSS v) [("x", toSS x)] "x"     -- Regardless of the context, there are no parentheses to remove     -- from 'x'.@@ -199,13 +188,13 @@     -- redundant parentheses in each.     g o = concat [f (Just (i, o, gen)) x | (i, (x, gen)) <- zipFrom 0 $ holes o] -bracketWarning :: (HasSrcSpan a, HasSrcSpan b, Data (SrcSpanLess b), Outputable a, Outputable b) => String -> a -> b -> Idea+bracketWarning :: (HasSrcSpan a, HasSrcSpan b, Outputable a, Outputable b, Brackets b)  => String -> a -> b -> Idea bracketWarning msg o x =-  suggest msg o x [Replace (findType (unLoc x)) (toSS o) [("x", toSS x)] "x"]+  suggest msg o x [Replace (findType x) (toSS o) [("x", toSS x)] "x"] -bracketError :: (HasSrcSpan a, HasSrcSpan b, Data (SrcSpanLess b), Outputable a, Outputable b ) => String -> a -> b -> Idea+bracketError :: (HasSrcSpan a, HasSrcSpan b, Outputable a, Outputable b, Brackets b) => String -> a -> b -> Idea bracketError msg o x =-  warn msg o x [Replace (findType (unLoc x)) (toSS o) [("x", toSS x)] "x"]+  warn msg o x [Replace (findType x) (toSS o) [("x", toSS x)] "x"]  fieldDecl ::  LConDeclField GhcPs -> [Idea] fieldDecl o@(L loc f@ConDeclField{cd_fld_type=v@(L l (HsParTy _ c))}) =
+ src/Hint/Fixities.hs view
@@ -0,0 +1,79 @@+{-++Raise a warning if you have redundant brackets in nested infix expressions.++<TEST>+yes = 1 + (2 * 3) -- @Ignore 1 + 2 * 3+yes = (2 * 3) + 1 -- @Ignore 2 * 3 + 1+no = (1 + 2) * 3+no = 3 * (1 + 2)+no = 1 + 2 * 3+no = 2 * 3 + 1+yes = (a >>= f) >>= g -- @Ignore a >>= f >>= g+no = (a >>= \x -> b) >>= g+</TEST>+-}++module Hint.Fixities(fixitiesHint) where++import Hint.Type(DeclHint,Idea(..),rawIdea,toSS)+import Config.Type+import Control.Monad+import Data.List.Extra+import Data.Map+import Data.Generics.Uniplate.DataOnly+import Refact.Types++import BasicTypes (compareFixity)+import Fixity+import GHC.Hs+import GHC.Util+import Language.Haskell.GhclibParserEx.GHC.Utils.Outputable+import OccName+import SrcLoc+import RdrName++fixitiesHint :: [Setting] -> DeclHint+fixitiesHint settings _ _ x =+  concatMap (infixBracket fixities) (childrenBi x :: [LHsExpr GhcPs])+   where+     fixities = foldMap getFixity settings `mappend` fromList (toFixity <$> defaultFixities)+     getFixity (Infix x) = uncurry singleton (toFixity x)+     getFixity _ = mempty++infixBracket :: Map String Fixity -> LHsExpr GhcPs -> [Idea]+infixBracket fixities = f Nothing+  where+    msg = "Redundant bracket due to operator fixities"+    f p o = cur p o <> concat [f (Just (i, o, gen)) x | (i, (x, gen)) <- zipFrom 0 $ holes o]+    cur p v = do+      Just (i, o, gen) <- [p]+      Just x <- [remParen v]+      guard $ redundantInfixBracket fixities i o x+      pure $+        rawIdea Ignore msg (getLoc v) (unsafePrettyPrint o)+        (Just (unsafePrettyPrint (gen x))) [] [Replace (findType v) (toSS v) [("x", toSS x)] "x"]++redundantInfixBracket :: Map String Fixity -> Int -> LHsExpr GhcPs -> LHsExpr GhcPs -> Bool+redundantInfixBracket fixities i parent child+    | L _ (OpApp _ _ (L _ (HsVar _ (L _ (Unqual p)))) _) <- parent+    , L _ (OpApp _ _ (L _ (HsVar _ (L _ (Unqual c)))) (L _ cr)) <- child =+    let (lop, rop)+            | i == 0 = (c, p)+            | otherwise = (p, c)+    in+    case compareFixity <$> (fixities !? occNameString lop) <*> (fixities !? occNameString rop) of+    Just (False, r)+        | i == 0 -> not (needParenAsChild cr || r)+        | otherwise -> r+    _ -> False+    | otherwise = False++needParenAsChild :: HsExpr p -> Bool+needParenAsChild HsLet{} = True+needParenAsChild HsDo{} = True+needParenAsChild HsLam{} = True+needParenAsChild HsLamCase{} = True+needParenAsChild HsCase{} = True+needParenAsChild HsIf{} = True+needParenAsChild _ = False
src/Test/All.hs view
@@ -43,7 +43,7 @@             pure (file, hints ++ (if takeBaseName file /= "Test" then [] else map (Builtin . fst) builtinHints))         let wrap msg act = do liftIO $ putStr (msg ++ " "); act; liftIO $ putStrLn "" -        liftIO $ putStrLn "Testing"+        liftIO $ putStrLn $ "Testing (" ++ (if isRight rpath then "with" else "WITHOUT") ++ " refactoring)"         liftIO $ checkCommentedYaml $ dataDir </> "default.yaml"         when useSrc $ wrap "Source annotations" $ do             config <- liftIO $ readFilesConfig [(".hlint.yaml",Nothing)]
+ tests/bracket.test view
@@ -0,0 +1,29 @@+---------------------------------------------------------------------+RUN tests/bracket-slice.hs+FILE tests/bracket-slice.hs++fAnd :: [a -> Bool] -> a -> Bool+fAnd fs x = all ($x) fs++OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/bracket-slice-spaced.hs+FILE tests/bracket-slice-spaced.hs++fAnd :: [a -> Bool] -> a -> Bool+fAnd fs x = all ($ x) fs++OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/bracket-slice-plus.hs+FILE tests/bracket-slice-plus.hs++incAll :: [Int] -> Int -> [Int]+incAll ys x = map (+x) fs++OUTPUT+No hints
+ tests/cmdline.test view
@@ -0,0 +1,29 @@+---------------------------------------------------------------------+RUN lint tests/cmdline-lint.hs+FILE tests/cmdline-lint.hs++foo = map f (map g xs)++OUTPUT+tests/cmdline-lint.hs:2:7-22: Suggestion: Use map once+Found:+  map f (map g xs)+Perhaps:+  map (f . g) xs++1 hint++---------------------------------------------------------------------+RUN tests/cmdline-bare.hs+FILE tests/cmdline-bare.hs++foo = map f (map g xs)++OUTPUT+tests/cmdline-bare.hs:2:7-22: Suggestion: Use map once+Found:+  map f (map g xs)+Perhaps:+  map (f . g) xs++1 hint
+ tests/cpp.test view
@@ -0,0 +1,131 @@+---------------------------------------------------------------------+RUN tests/cpp-full.hs+FILE tests/cpp-full.hs+/* this is a test */++main = putStrLn $ show "Hello"+OUTPUT+tests/cpp-full.hs:3:8-30: Warning: Use print+Found:+  putStrLn $ show "Hello"+Perhaps:+  print "Hello"++1 hint++---------------------------------------------------------------------+RUN -XNoCPP tests/cpp-none.hs+FILE tests/cpp-none.hs+#include "Any/File.h"++main = print "Hello"+EXIT 0+OUTPUT+No hints++---------------------------------------------------------------------+RUN -XNoCPP tests/cpp-must-not-run.hs+FILE tests/cpp-must-not-run.hs+{-+#error Cpp has run+-}+main = undefined+EXIT 0+OUTPUT+No hints++---------------------------------------------------------------------+RUN --cpp-define FOO tests/cpp-ext-enable.hs+FILE tests/cpp-ext-enable.hs+{-# LANGUAGE CPP #-}+#if defined(FOO)+{-# LANGUAGE Foo #-}+#endif+main = undefined+EXIT 1+OUTPUT+tests/cpp-ext-enable.hs:1:1: Error: Parse error: Unsupported extension: Foo++Found:+  {-# LANGUAGE CPP #-}++  {-# LANGUAGE Foo #-}++  main = undefined++1 hint++---------------------------------------------------------------------+RUN tests/cpp-ext-disable.hs+FILE tests/cpp-ext-disable.hs+{-# LANGUAGE CPP #-}+#if defined(FOO)+{-# LANGUAGE Foo #-}+#endif+main = undefined+EXIT 1+OUTPUT+tests/cpp-ext-disable.hs:1:1-20: Warning: Avoid restricted extensions+Found:+  {-# LANGUAGE CPP #-}+Note: may break the code++1 hint++---------------------------------------------------------------------+RUN --cpp-simple tests/cpp-simple.hs+FILE tests/cpp-simple.hs+#include "Any/File.h"++main = print "Hello"+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/cpp-file1.hs+FILE tests/cpp-file1.hs+import Network.Wai+#if MIN_VERSION_wai(2, 0, 0)+import Network.Wai.Internal+#endif+OUTPUT+No hints++---------------------------------------------------------------------+RUN --cpp-file=tests/cabal_macros.h tests/cpp-file2.hs+FILE tests/cabal_macros.h+#define MIN_VERSION_wai(a,b,c) 1+FILE tests/cpp-file2.hs+import Network.Wai+#if MIN_VERSION_wai(2, 0, 0)+import Network.Wai.Internal+#endif+foo = map f . map g+OUTPUT+tests/cpp-file2.hs:5:7-19: Suggestion: Use map once+Found:+  map f . map g+Perhaps:+  map (f . g)++1 hint++---------------------------------------------------------------------+RUN --cpp-simple tests/cpp-file3.hs+FILE tests/cpp-file3.hs+import Network.Wai+#if MIN_VERSION_wai(2, 0, 0)+import Network.Wai.Internal+#endif+OUTPUT+No hints++---------------------------------------------------------------------+RUN --cpp-simple tests/cpp-file4.hs+FILE tests/cpp-file4.hs+import Network.Wai+#if defined(MIN_VERSION_wai) && MIN_VERSION_wai(2, 0, 0)+import Network.Wai.Internal+#endif+OUTPUT+No hints
+ tests/cross.test view
@@ -0,0 +1,25 @@+---------------------------------------------------------------------+RUN tests/cross.hs1 tests/cross.hs2 --cross+FILE tests/cross.hs1++module B(bar) where+++bar = 1+    where+        a = 1+        b = 2+        c = 3++FILE tests/cross.hs2++module A(foo) where++foo = 1+    where+        a = 1+        b = 2+        c = 3++OUTPUT+No hints
+ tests/find.test view
@@ -0,0 +1,42 @@+---------------------------------------------------------------------+RUN --find=tests/find.hs+FILE tests/find.hs+{-# LANGUAGE CPP, ExistentialQuantification, Rank2Types #-}++module Util where++import Control.Arrow+import Control.Monad.Trans.State+import Data.Char+import Data.Function++infixr 4 %^&, `wheeeee`++instance Foo a where+    bar = baz + qux++listM' :: Monad m => [a] -> m [a]+listM' x = length x `seq` return x++notNull = not . null++headDef :: a -> [a] -> a+headDef x [] = x+headDef x (y:ys) = y++isLeft Left{} = True; isLeft _ = False+isRight = not . isLeft++swap :: (a,b) -> (b,a)+swap (a,b) = (b,a)++defaultExtensions = knownExtensions \\ badExtensions+OUTPUT+# hints found in tests/find.hs+- fixity: "infixr 4 %^&"+- fixity: "infixr 4 `wheeeee`"+- warn: {lhs: "baz + qux", rhs: "bar"}+- warn: {lhs: "length a `seq` return a", rhs: "listM' a"}+- warn: {lhs: "not (null a)", rhs: "notNull a"}+- warn: {lhs: "not (isLeft a)", rhs: "isRight a"}+- warn: {lhs: "knownExtensions \\\\ badExtensions", rhs: "defaultExtensions"}
+ tests/flag-extension.test view
@@ -0,0 +1,31 @@+---------------------------------------------------------------------+RUN tests/directory+FILE tests/directory/File1.hs+ foo = map f . map g+FILE tests/directory/File2.lhs+> foo = map f . map g+OUTPUT+tests/directory/File1.hs:1:8-20: Suggestion: Use map once+Found:+  map f . map g+Perhaps:+  map (f . g)++tests/directory/File2.lhs:1:9-21: Suggestion: Use map once+Found:+  map f . map g+Perhaps:+  map (f . g)++2 hints++---------------------------------------------------------------------+RUN tests/directory --extension=lhs+OUTPUT+tests/directory/File2.lhs:1:9-21: Suggestion: Use map once+Found:+  map f . map g+Perhaps:+  map (f . g)++1 hint
+ tests/flag-no-summary.test view
@@ -0,0 +1,18 @@+---------------------------------------------------------------------+RUN tests/flag-no-summary1.hs --no-summary+FILE tests/flag-no-summary1.hs+main = map f $ map g xs+OUTPUT+tests/flag-no-summary1.hs:1:8-23: Suggestion: Use map once+Found:+  map f $ map g xs+Perhaps:+  map (f . g) xs++EXIT 1+---------------------------------------------------------------------+RUN tests/flag-no-summary2.hs --no-summary+FILE tests/flag-no-summary2.hs+main = return ()+OUTPUT+EXIT 0
+ tests/flag-only.test view
@@ -0,0 +1,30 @@+---------------------------------------------------------------------+RUN tests/flag-only-one-arg.hs --only="Redundant bracket"+FILE tests/flag-only-one-arg.hs+foo xs = if length xs == 0 then 42 else (666) -- should result in 2 suggestions+OUTPUT+tests/flag-only-one-arg.hs:1:41-45: Warning: Redundant bracket+Found:+  (666)+Perhaps:+  666++1 hint+---------------------------------------------------------------------+RUN tests/flag-only-many-args.hs --only="Redundant bracket" --only="Use ++"+FILE tests/flag-only-many-args.hs+foo xs = if length xs == 0 then concat ["foo", "bar"] else (666) -- should result in 3 suggestions+OUTPUT+tests/flag-only-many-args.hs:1:33-53: Suggestion: Use +++Found:+  concat ["foo", "bar"]+Perhaps:+  "foo" ++ "bar"++tests/flag-only-many-args.hs:1:60-64: Warning: Redundant bracket+Found:+  (666)+Perhaps:+  666++2 hints
+ tests/flag-quiet.test view
@@ -0,0 +1,6 @@+---------------------------------------------------------------------+RUN tests/flag-quiet.hs --quiet+FILE tests/flag-quiet.hs+main = map f $ map g xs+OUTPUT+EXIT 1
+ tests/flag-with-group.test view
@@ -0,0 +1,22 @@+---------------------------------------------------------------------+FILE tests/flag-with-group.hs+foo = map (+1) . maybe mempty reverse+RUN "--with-group=generalise" tests/flag-with-group.hs+OUTPUT+tests/flag-with-group.hs:1:7-9: Warning: Use fmap+Found:+  map+Perhaps:+  fmap++1 hint+---------------------------------------------------------------------+RUN "--with-group=generalise-for-conciseness" tests/flag-with-group.hs+OUTPUT+tests/flag-with-group.hs:1:18-29: Warning: Use foldMap+Found:+  maybe mempty+Perhaps:+  foldMap++1 hint
+ tests/hint.test view
@@ -0,0 +1,165 @@+---------------------------------------------------------------------+RUN tests/newtype-derive.hs --hint=data/hlint.yaml+FILE tests/newtype-derive.hs+{-# LANGUAGE DeriveTraversable #-} -- Implies DeriveFoldable and DeriveFunctor+{-# LANGUAGE DeriveDataTypeable #-}+module Test(A) where++import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+import Data.Typeable (Typeable)++newtype A f = A f+  deriving (Foldable, Functor, Traversable, Typeable)+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/note.hs+FILE tests/note.hs+{-# LANGUAGE RecordWildCards #-}++module Sample(test) where++test xs = length xs == 0+OUTPUT+tests/note.hs:1:1-32: Warning: Unused LANGUAGE pragma+Found:+  {-# LANGUAGE RecordWildCards #-}+Perhaps you should remove it.+Note: may require `{-# LANGUAGE DisambiguateRecordFields #-}` adding to the top of the file++tests/note.hs:5:11-24: Suggestion: Use null+Found:+  length xs == 0+Perhaps:+  null xs+Note: increases laziness++2 hints++---------------------------------------------------------------------+RUN tests/brackets.hs+FILE tests/brackets.hs+test = if isNothing x then (-1.0) else fromJust x+OUTPUT+tests/brackets.hs:1:8-49: Warning: Use fromMaybe+Found:+  if isNothing x then (- 1.0) else fromJust x+Perhaps:+  fromMaybe (- 1.0) x++1 hint++---------------------------------------------------------------------+RUN tests/typesig-ignore.hs+FILE tests/typesig-ignore.hs+-- Bug #563+module Foo(foobar) where+{-# ANN foobar "HLint: ignore Use String" #-}++foobar :: [Char]+foobar = []+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/typesig-ignore2.hs+FILE tests/typesig-ignore2.hs+-- Bug #563+module Foo(foobar) where+{-# HLINT ignore foobar "Use String" #-}++foobar :: [Char]+foobar = []+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/restricted-module.lhs --hint=data/test-restrict.yaml+FILE tests/restricted-module.lhs+> import Restricted.Module+OUTPUT+tests/restricted-module.lhs:1:3-26: Warning: Avoid restricted module+Found:+  import Restricted.Module+Note: may break the code++1 hint++---------------------------------------------------------------------+RUN tests/restricted-module-message.lhs --hint=data/test-restrict.yaml+FILE tests/restricted-module-message.lhs+> import Restricted.Module.Message+OUTPUT+tests/restricted-module-message.lhs:1:3-34: Warning: Avoid restricted module+Found:+  import Restricted.Module.Message+Note: Custom message++1 hint++---------------------------------------------------------------------+RUN tests/restricted-function.lhs --hint=data/test-restrict.yaml+FILE tests/restricted-function.lhs+> main = restricted ()+OUTPUT+tests/restricted-function.lhs:1:10-19: Warning: Avoid restricted function+Found:+  restricted+Note: may break the code++1 hint++---------------------------------------------------------------------+RUN tests/restricted-function-message.lhs --hint=data/test-restrict.yaml+FILE tests/restricted-function-message.lhs+> main = restrictedMessage ()+OUTPUT+tests/restricted-function-message.lhs:1:10-26: Warning: Avoid restricted function+Found:+  restrictedMessage+Note: Custom message++1 hint++---------------------------------------------------------------------+RUN tests/restricted-extension.hs --hint=data/test-restrict.yaml+FILE tests/restricted-extension.hs+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Test(A) where++import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+import Data.Typeable (Typeable)++newtype A f = A f+  deriving (Foldable, Functor, Traversable, Typeable)+OUTPUT+OUTPUT+tests/restricted-extension.hs:1:1-31: Warning: Unused LANGUAGE pragma+Found:+  {-# LANGUAGE DeriveFoldable #-}+Perhaps you should remove it.+Note: Extension DeriveFoldable is implied by DeriveTraversable++tests/restricted-extension.hs:2:1-30: Warning: Unused LANGUAGE pragma+Found:+  {-# LANGUAGE DeriveFunctor #-}+Perhaps you should remove it.+Note: Extension DeriveFunctor is implied by DeriveTraversable++tests/restricted-extension.hs:2:1-30: Warning: Avoid restricted extensions+Found:+  {-# LANGUAGE DeriveFunctor #-}+Note: may break the code++tests/restricted-extension.hs:3:1-34: Warning: Avoid restricted extensions+Found:+  {-# LANGUAGE DeriveTraversable #-}+Note: Custom message++4 hints
+ tests/json.test view
@@ -0,0 +1,40 @@+---------------------------------------------------------------------+RUN tests/json-none.hs --json+FILE tests/json-none.hs+foo = (+1)+OUTPUT+[]++---------------------------------------------------------------------+RUN tests/json-one.hs --json+FILE tests/json-one.hs+foo = (+1)+bar x = foo x+OUTPUT+[{"module":["Main"],"decl":["bar"],"severity":"Warning","hint":"Eta reduce","file":"tests/json-one.hs","startLine":2,"startColumn":1,"endLine":2,"endColumn":14,"from":"bar x = foo x","to":"bar = foo","note":[],"refactorings":"[Replace {rtype = Decl, pos = SrcSpan {startLine = 2, startCol = 1, endLine = 2, endCol = 14}, subts = [(\"body\",SrcSpan {startLine = 2, startCol = 9, endLine = 2, endCol = 12})], orig = \"bar = body\"}]"}]++---------------------------------------------------------------------+RUN tests/json-two.hs --json+FILE tests/json-two.hs+foo = (+1)+bar x = foo x+baz = getLine >>= return . map toUpper+OUTPUT+[{"module":["Main"],"decl":["bar"],"severity":"Warning","hint":"Eta reduce","file":"tests/json-two.hs","startLine":2,"startColumn":1,"endLine":2,"endColumn":14,"from":"bar x = foo x","to":"bar = foo","note":[],"refactorings":"[Replace {rtype = Decl, pos = SrcSpan {startLine = 2, startCol = 1, endLine = 2, endCol = 14}, subts = [(\"body\",SrcSpan {startLine = 2, startCol = 9, endLine = 2, endCol = 12})], orig = \"bar = body\"}]"}+,{"module":["Main"],"decl":["baz"],"severity":"Suggestion","hint":"Use <&>","file":"tests/json-two.hs","startLine":3,"startColumn":7,"endLine":3,"endColumn":39,"from":"getLine >>= return . map toUpper","to":"getLine Data.Functor.<&> map toUpper","note":[],"refactorings":"[Replace {rtype = Expr, pos = SrcSpan {startLine = 3, startCol = 7, endLine = 3, endCol = 39}, subts = [(\"f\",SrcSpan {startLine = 3, startCol = 28, endLine = 3, endCol = 39}),(\"m\",SrcSpan {startLine = 3, startCol = 7, endLine = 3, endCol = 14})], orig = \"m Data.Functor.<&> f\"}]"}]++---------------------------------------------------------------------+RUN tests/json-parse-error.hs --json+FILE tests/json-parse-error.hs+@+OUTPUT+[{"module":[],"decl":[],"severity":"Error","hint":"Parse error: on input `@'","file":"tests/json-parse-error.hs","startLine":1,"startColumn":1,"endLine":1,"endColumn":2,"from":"> @\n","to":null,"note":[],"refactorings":"[]"}]++---------------------------------------------------------------------+RUN tests/json-note.hs --json+FILE tests/json-note.hs+foo = any (a ==)+bar = foldl (&&) True+OUTPUT+[{"module":["Main"],"decl":["foo"],"severity":"Warning","hint":"Use elem","file":"tests/json-note.hs","startLine":1,"startColumn":7,"endLine":1,"endColumn":17,"from":"any (a ==)","to":"elem a","note":["requires a valid `Eq` instance for `a`"],"refactorings":"[Replace {rtype = Expr, pos = SrcSpan {startLine = 1, startCol = 7, endLine = 1, endCol = 17}, subts = [(\"a\",SrcSpan {startLine = 1, startCol = 12, endLine = 1, endCol = 13})], orig = \"elem a\"}]"}+,{"module":["Main"],"decl":["bar"],"severity":"Warning","hint":"Use and","file":"tests/json-note.hs","startLine":2,"startColumn":7,"endLine":2,"endColumn":22,"from":"foldl (&&) True","to":"and","note":["increases laziness"],"refactorings":"[Replace {rtype = Expr, pos = SrcSpan {startLine = 2, startCol = 7, endLine = 2, endCol = 22}, subts = [], orig = \"and\"}]"}]
+ tests/lhs.test view
@@ -0,0 +1,47 @@+---------------------------------------------------------------------+RUN tests/lhs-line-numbers.lhs+FILE tests/lhs-line-numbers.lhs+BUG 331++> main = print ([1] ++ [2, 3])+OUTPUT+tests/lhs-line-numbers.lhs:3:17-29: Suggestion: Use :+Found:+  [1] ++ [2, 3]+Perhaps:+  1 : [2, 3]++1 hint++---------------------------------------------------------------------+RUN tests/lhs-line-numbers2.lhs+FILE tests/lhs-line-numbers2.lhs+BUG 331+%  Blah1+%  Blah2+%  Blah3++\begin{code}+module+\end{code}+OUTPUT+tests/lhs-line-numbers2.lhs:10:1: Error: Parse error: possibly incorrect indentation or mismatched brackets+Found:+    \end{code}++  >++1 hint++---------------------------------------------------------------------+RUN tests/lhs-first-line.lhs+FILE tests/lhs-first-line.lhs+> main = print ([1] ++ [2, 3])+OUTPUT+tests/lhs-first-line.lhs:1:17-29: Suggestion: Use :+Found:+  [1] ++ [2, 3]+Perhaps:+  1 : [2, 3]++1 hint
+ tests/parse-error.test view
@@ -0,0 +1,33 @@+---------------------------------------------------------------------+RUN "--ignore=Parse error" tests/ignore-parse-error.hs+FILE tests/ignore-parse-error.hs+where+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/ignore-parse-error2.hs+FILE tests/ignore-parse-error2.hs+module Foo where++where+OUTPUT+tests/ignore-parse-error2.hs:3:1-5: Error: Parse error: on input `where'+Found:+    module Foo where++  > where++1 hint++---------------------------------------------------------------------+RUN tests/ignore-parse-error3.hs+FILE tests/ignore-parse-error3.hs+{-# LANGUAGE InvalidExtension #-}+OUTPUT+tests/ignore-parse-error3.hs:1:1: Error: Parse error: Unsupported extension: InvalidExtension++Found:+  {-# LANGUAGE InvalidExtension #-}++1 hint
+ tests/serialise.test view
@@ -0,0 +1,85 @@+---------------------------------------------------------------------+RUN tests/serialise-none.hs --serialise+FILE tests/serialise-none.hs+foo = (+1)+OUTPUT+[]++---------------------------------------------------------------------+RUN tests/serialise-one.hs --serialise+FILE tests/serialise-one.hs+foo = (+1)+bar x = foo x+OUTPUT+[("tests/serialise-one.hs:2:1-13: Warning: Eta reduce\nFound:\n  bar x = foo x\nPerhaps:\n  bar = foo\n",[Replace {rtype = Decl, pos = SrcSpan {startLine = 2, startCol = 1, endLine = 2, endCol = 14}, subts = [("body",SrcSpan {startLine = 2, startCol = 9, endLine = 2, endCol = 12})], orig = "bar = body"}])]++---------------------------------------------------------------------+RUN tests/serialise-two.hs --serialise+FILE tests/serialise-two.hs+foo = (+1)+bar x = foo x+baz = getLine >>= return . map toUpper+OUTPUT+[("tests/serialise-two.hs:2:1-13: Warning: Eta reduce\nFound:\n  bar x = foo x\nPerhaps:\n  bar = foo\n",[Replace {rtype = Decl, pos = SrcSpan {startLine = 2, startCol = 1, endLine = 2, endCol = 14}, subts = [("body",SrcSpan {startLine = 2, startCol = 9, endLine = 2, endCol = 12})], orig = "bar = body"}]),("tests/serialise-two.hs:3:7-38: Suggestion: Use <&>\nFound:\n  getLine >>= return . map toUpper\nPerhaps:\n  getLine Data.Functor.<&> map toUpper\n",[Replace {rtype = Expr, pos = SrcSpan {startLine = 3, startCol = 7, endLine = 3, endCol = 39}, subts = [("f",SrcSpan {startLine = 3, startCol = 28, endLine = 3, endCol = 39}),("m",SrcSpan {startLine = 3, startCol = 7, endLine = 3, endCol = 14})], orig = "m Data.Functor.<&> f"}])]+++---------------------------------------------------------------------+RUN tests/serialise-three.hs --serialise+FILE tests/serialise-three.hs+foo = concat (map f (let x = x in x))+OUTPUT+[("tests/serialise-three.hs:1:7-37: Warning: Use concatMap\nFound:\n  concat (map f (let x = x in x))\nPerhaps:\n  concatMap f (let x = x in x)\n",[Replace {rtype = Expr, pos = SrcSpan {startLine = 1, startCol = 7, endLine = 1, endCol = 38}, subts = [("f",SrcSpan {startLine = 1, startCol = 19, endLine = 1, endCol = 20}),("x",SrcSpan {startLine = 1, startCol = 21, endLine = 1, endCol = 37})], orig = "concatMap f x"}])]+++---------------------------------------------------------------------+RUN tests/serialise-four.hs --serialise --hint=data/hlint.yaml+FILE tests/serialise-four.hs+{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-}+OUTPUT+[("tests/serialise-four.hs:1:1-20: Warning: Use fewer LANGUAGE pragmas\nFound:\n  {-# LANGUAGE CPP #-}\n  {-# LANGUAGE CPP #-}\nPerhaps:\n  {-# LANGUAGE CPP #-}\n",[ModifyComment {pos = SrcSpan {startLine = 1, startCol = 1, endLine = 1, endCol = 21}, newComment = "{-# LANGUAGE CPP #-}"},ModifyComment {pos = SrcSpan {startLine = 2, startCol = 1, endLine = 2, endCol = 21}, newComment = ""}])]+++---------------------------------------------------------------------+RUN tests/serialise-five.hs --serialise+FILE tests/serialise-five.hs+import qualified GHC as GHC+OUTPUT+[("tests/serialise-five.hs:1:1-27: Suggestion: Redundant as\nFound:\n  import qualified GHC as GHC\nPerhaps:\n  import qualified GHC\n",[RemoveAsKeyword {pos = SrcSpan {startLine = 1, startCol = 1, endLine = 1, endCol = 28}}])]+++---------------------------------------------------------------------+RUN tests/serialise-six.hs --serialise+FILE tests/serialise-six.hs+foo = qux (\x -> f (g x))+OUTPUT+[("tests/serialise-six.hs:1:12-24: Suggestion: Avoid lambda\nFound:\n  / x -> f (g x)\nPerhaps:\n  f . g\n",[Replace {rtype = Expr, pos = SrcSpan {startLine = 1, startCol = 12, endLine = 1, endCol = 25}, subts = [("a",SrcSpan {startLine = 1, startCol = 18, endLine = 1, endCol = 19}),("b",SrcSpan {startLine = 1, startCol = 21, endLine = 1, endCol = 22})], orig = "a . b"}])]+++---------------------------------------------------------------------+RUN tests/serialise-seven.hs --serialise+FILE tests/serialise-seven.hs+foo = if baz+        then qux+        else if baz'+             then qux'+             else qux''+OUTPUT+[("tests/serialise-seven.hs:(1,1)-(5,23): Suggestion: Use guards\nFound:\n  foo = if baz then qux else if baz' then qux' else qux''\nPerhaps:\n  foo\n    | baz = qux\n    | baz' = qux'\n    | otherwise = qux''\n",[Replace {rtype = Match, pos = SrcSpan {startLine = 1, startCol = 1, endLine = 5, endCol = 24}, subts = [("g1001",SrcSpan {startLine = 1, startCol = 10, endLine = 1, endCol = 13}),("g1002",SrcSpan {startLine = 3, startCol = 17, endLine = 3, endCol = 21}),("e1001",SrcSpan {startLine = 2, startCol = 14, endLine = 2, endCol = 17}),("e1002",SrcSpan {startLine = 4, startCol = 19, endLine = 4, endCol = 23}),("e1003",SrcSpan {startLine = 5, startCol = 19, endLine = 5, endCol = 24})], orig = "foo\n  | g1001 = e1001\n  | g1002 = e1002\n  | otherwise = e1003"}])]+++---------------------------------------------------------------------+RUN tests/serialise-eight.hs --serialise+FILE tests/serialise-eight.hs+foo = do x <- baz+         x+OUTPUT+[("tests/serialise-eight.hs:(1,7)-(2,10): Warning: Use join\nFound:\n  do x <- baz\n     x\nPerhaps:\n  do join baz\n",[Replace {rtype = Stmt, pos = SrcSpan {startLine = 1, startCol = 10, endLine = 1, endCol = 18}, subts = [("x",SrcSpan {startLine = 1, startCol = 15, endLine = 1, endCol = 18})], orig = "join x"},Delete {rtype = Stmt, pos = SrcSpan {startLine = 2, startCol = 10, endLine = 2, endCol = 11}}])]+++---------------------------------------------------------------------+RUN tests/serialise-nine.hs --serialise+FILE tests/serialise-nine.hs+foo | True = baz+OUTPUT+[("tests/serialise-nine.hs:1:1-16: Suggestion: Redundant guard\nFound:\n  foo | True = baz\nPerhaps:\n  foo = baz\n",[Delete {rtype = Stmt, pos = SrcSpan {startLine = 1, startCol = 7, endLine = 1, endCol = 11}}])]
+ tests/wildcard.test view
@@ -0,0 +1,45 @@+---------------------------------------------------------------------+RUN tests/wildcard-1.hs --hint=data/wildcard.yaml+FILE tests/wildcard-1.hs+module SpecNoMatch where+main = print $ (\ _ -> 'a') ()+OUTPUT+tests/wildcard-1.hs:2:17-26: Suggestion: Use const+Found:+  \ _ -> 'a'+Perhaps:+  const 'a'++1 hint++---------------------------------------------------------------------+RUN tests/wildcard-2.hs --hint=data/wildcard.yaml+FILE tests/wildcard-2.hs+module Spec where+main = print $ (\ _ -> 'a') ()+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/wildcard-3.hs --hint=data/wildcard.yaml+FILE tests/wildcard-3.hs+module PrefixedSpec where+main = print $ (\ _ -> 'a') ()+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/wildcard-4.hs --hint=data/wildcard.yaml+FILE tests/wildcard-4.hs+module Namespaced.Spec where+main = print $ (\ _ -> 'a') ()+OUTPUT+No hints++---------------------------------------------------------------------+RUN tests/wildcard-5.hs --hint=data/wildcard.yaml+FILE tests/wildcard-5.hs+module Deeply.Nested.Spec where+main = print $ (\ _ -> 'a') ()+OUTPUT+No hints