@@ -50,6 +50,10 @@ main = do _ <- forM_ f xs; bar -- forM_ f xs
5050main = do bar; forM_ f xs; return () -- do bar; forM_ f xs
5151main = do a; when b c; return () -- do a; when b c
5252bar = 1 * do {\x -> x+x} + y
53+ issue978 = do \
54+ print "x" \
55+ if False then main else do \
56+ return ()
5357</TEST>
5458-}
5559
@@ -70,22 +74,37 @@ import Language.Haskell.GhclibParserEx.GHC.Hs.Expr
7074import Language.Haskell.GhclibParserEx.GHC.Utils.Outputable
7175import GHC.Util
7276
77+ import Data.Generics.Uniplate.Data
7378import Data.Tuple.Extra
7479import Data.Maybe
7580import Data.List.Extra
7681import Refact.Types hiding (Match )
7782import qualified Refact.Types as R
7883
84+
7985badFuncs :: [String ]
8086badFuncs = [" mapM" ," foldM" ," forM" ," replicateM" ," sequence" ," zipWithM" ," traverse" ," for" ," sequenceA" ]
8187unitFuncs :: [String ]
8288unitFuncs = [" when" ," unless" ," void" ]
8389
8490monadHint :: DeclHint'
85- monadHint _ _ d = concatMap (monadExp d) $ universeParentExp' d
91+ monadHint _ _ d = concatMap (f Nothing Nothing ) $ childrenBi d
92+ where
93+ decl = declName d
94+ f parentDo parentExpr x =
95+ monadExp decl parentDo parentExpr x ++
96+ concat [f (if isHsDo x then Just x else parentDo) (Just (i, x)) c | (i, c) <- zipFrom 0 $ children x]
97+
98+ isHsDo (L _ HsDo {}) = True
99+ isHsDo _ = False
100+
86101
87- monadExp :: LHsDecl GhcPs -> (Maybe (Int , LHsExpr GhcPs ), LHsExpr GhcPs ) -> [Idea ]
88- monadExp (declName -> decl) (parent, x) =
102+ -- | Call with the name of the declaration,
103+ -- the nearest enclosing `do` expression
104+ -- the nearest enclosing expression
105+ -- the expression of interest
106+ monadExp :: Maybe String -> Maybe (LHsExpr GhcPs ) -> Maybe (Int , LHsExpr GhcPs ) -> LHsExpr GhcPs -> [Idea ]
107+ monadExp decl parentDo parentExpr x =
89108 case x of
90109 (view' -> App2' op x1 x2) | isTag " >>" op -> f x1
91110 (view' -> App2' op x1 (view' -> LamConst1' _)) | isTag " >>=" op -> f x1
@@ -94,7 +113,9 @@ monadExp (declName -> decl) (parent, x) =
94113 (L loc (HsDo _ ctx (L loc2 [L loc3 (BodyStmt _ y _ _ )]))) ->
95114 let doOrMDo = case ctx of MDoExpr -> " mdo" ; _ -> " do"
96115 in [ warnRemove (" Redundant " ++ doOrMDo) (doSpan doOrMDo loc) doOrMDo [Replace Expr (toSS' x) [(" y" , toSS' y)] " y" ]
97- | not $ doAsBrackets parent y ]
116+ | not $ doAsBrackets parentExpr y
117+ , not $ doAsAvoidingIndentation parentDo x
118+ ]
98119 (L loc (HsDo _ DoExpr (L _ xs))) ->
99120 monadSteps (cL loc . HsDo noExtField DoExpr . noLoc) xs ++
100121 [suggest' " Use let" from to [r] | (from, to, r) <- monadLet xs] ++
@@ -121,6 +142,15 @@ doAsBrackets (Just (i, o)) x = needBracket' i o x
121142doAsBrackets Nothing x = False
122143
123144
145+ -- Sometimes people write do, to avoid identation, see
146+ -- https://github.com/ndmitchell/hlint/issues/978
147+ -- Return True if they are using do as avoiding identation
148+ doAsAvoidingIndentation :: Maybe (LHsExpr GhcPs ) -> LHsExpr GhcPs -> Bool
149+ doAsAvoidingIndentation (Just (L _ (HsDo _ _ (L (RealSrcSpan a) _)))) (L _ (HsDo _ _ (L (RealSrcSpan b) _)))
150+ = srcSpanStartCol a == srcSpanStartCol b
151+ doAsAvoidingIndentation parent self = False
152+
153+
124154returnsUnit :: LHsExpr GhcPs -> Bool
125155returnsUnit (L _ (HsPar _ x)) = returnsUnit x
126156returnsUnit (L _ (HsApp _ x _)) = returnsUnit x
0 commit comments