    {-

    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,toSSA)
    import Config.Type
    import Control.Monad
    import Data.List.Extra
    import Data.Map
    import Data.Generics.Uniplate.DataOnly
    import Refact.Types

    import GHC.Types.Fixity(compareFixity)
    import Fixity
    import GHC.Hs
    import GHC.Util
    import Language.Haskell.GhclibParserEx.GHC.Utils.Outputable
    import GHC.Types.SrcLoc
    import GHC.Types.Name.Reader
    import GHC.Types.Name.Occurrence

    fixitiesHint :: [Setting] -> DeclHint
    fixitiesHint :: [Setting] -> DeclHint
    fixitiesHint [Setting]
    settings Scope
    _ ModuleEx
    _ LHsDecl GhcPs
    x =
      (GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea])
    -> [GenLocated SrcSpanAnnA (HsExpr GhcPs)] -> [Idea]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (Map String Fixity -> LHsExpr GhcPs -> [Idea]
    infixBracket Map String Fixity
    fixities) (GenLocated SrcSpanAnnA (HsDecl GhcPs)
    -> [GenLocated SrcSpanAnnA (HsExpr GhcPs)]
    forall from to. Biplate from to => from -> [to]
    childrenBi LHsDecl GhcPs
    GenLocated SrcSpanAnnA (HsDecl GhcPs)
    x :: [LHsExpr GhcPs])
       where
         fixities :: Map String Fixity
    fixities = (Setting -> Map String Fixity) -> [Setting] -> Map String Fixity
    forall m a. Monoid m => (a -> m) -> [a] -> m
    forall (t :: * -> *) m a.
    (Foldable t, Monoid m) =>
    (a -> m) -> t a -> m
    foldMap Setting -> Map String Fixity
    getFixity [Setting]
    settings Map String Fixity -> Map String Fixity -> Map String Fixity
    forall a. Monoid a => a -> a -> a
    `mappend` [(String, Fixity)] -> Map String Fixity
    forall k a. Ord k => [(k, a)] -> Map k a
    fromList (FixityInfo -> (String, Fixity)
    toFixity (FixityInfo -> (String, Fixity))
    -> [FixityInfo] -> [(String, Fixity)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [FixityInfo]
    defaultFixities)
         getFixity :: Setting -> Map String Fixity
    getFixity (Infix FixityInfo
    x) = (String -> Fixity -> Map String Fixity)
    -> (String, Fixity) -> Map String Fixity
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry String -> Fixity -> Map String Fixity
    forall k a. k -> a -> Map k a
    Data.Map.singleton (FixityInfo -> (String, Fixity)
    toFixity FixityInfo
    x)
         getFixity Setting
    _ = Map String Fixity
    forall a. Monoid a => a
    mempty

    infixBracket :: Map String Fixity -> LHsExpr GhcPs -> [Idea]
    infixBracket :: Map String Fixity -> LHsExpr GhcPs -> [Idea]
    infixBracket Map String Fixity
    fixities = Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    f Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    forall a. Maybe a
    Nothing
      where
        msg :: String
    msg = String
    "Redundant bracket due to operator fixities"
        f :: Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    f Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    p GenLocated SrcSpanAnnA (HsExpr GhcPs)
    o = Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    forall {a}.
    Outputable a =>
    Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs) -> a)
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    cur Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    p GenLocated SrcSpanAnnA (HsExpr GhcPs)
    o [Idea] -> [Idea] -> [Idea]
    forall a. Semigroup a => a -> a -> a
    <> [[Idea]] -> [Idea]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat [Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    f ((Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
     GenLocated SrcSpanAnnA (HsExpr GhcPs)
     -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    -> Maybe
         (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
          GenLocated SrcSpanAnnA (HsExpr GhcPs)
          -> GenLocated SrcSpanAnnA (HsExpr GhcPs))
    forall a. a -> Maybe a
    Just (Int
    i, GenLocated SrcSpanAnnA (HsExpr GhcPs)
    o, GenLocated SrcSpanAnnA (HsExpr GhcPs)
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs)
    gen)) GenLocated SrcSpanAnnA (HsExpr GhcPs)
    x | (Int
    i, (GenLocated SrcSpanAnnA (HsExpr GhcPs)
    x, GenLocated SrcSpanAnnA (HsExpr GhcPs)
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs)
    gen)) <- Int
    -> [(GenLocated SrcSpanAnnA (HsExpr GhcPs),
         GenLocated SrcSpanAnnA (HsExpr GhcPs)
         -> GenLocated SrcSpanAnnA (HsExpr GhcPs))]
    -> [(Int,
         (GenLocated SrcSpanAnnA (HsExpr GhcPs),
          GenLocated SrcSpanAnnA (HsExpr GhcPs)
          -> GenLocated SrcSpanAnnA (HsExpr GhcPs)))]
    forall a b. Enum a => a -> [b] -> [(a, b)]
    zipFrom Int
    0 ([(GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs)
       -> GenLocated SrcSpanAnnA (HsExpr GhcPs))]
     -> [(Int,
          (GenLocated SrcSpanAnnA (HsExpr GhcPs),
           GenLocated SrcSpanAnnA (HsExpr GhcPs)
           -> GenLocated SrcSpanAnnA (HsExpr GhcPs)))])
    -> [(GenLocated SrcSpanAnnA (HsExpr GhcPs),
         GenLocated SrcSpanAnnA (HsExpr GhcPs)
         -> GenLocated SrcSpanAnnA (HsExpr GhcPs))]
    -> [(Int,
         (GenLocated SrcSpanAnnA (HsExpr GhcPs),
          GenLocated SrcSpanAnnA (HsExpr GhcPs)
          -> GenLocated SrcSpanAnnA (HsExpr GhcPs)))]
    forall a b. (a -> b) -> a -> b
    $ GenLocated SrcSpanAnnA (HsExpr GhcPs)
    -> [(GenLocated SrcSpanAnnA (HsExpr GhcPs),
         GenLocated SrcSpanAnnA (HsExpr GhcPs)
         -> GenLocated SrcSpanAnnA (HsExpr GhcPs))]
    forall on. Uniplate on => on -> [(on, on -> on)]
    holes GenLocated SrcSpanAnnA (HsExpr GhcPs)
    o]
        cur :: Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs) -> a)
    -> GenLocated SrcSpanAnnA (HsExpr GhcPs) -> [Idea]
    cur Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs) -> a)
    p GenLocated SrcSpanAnnA (HsExpr GhcPs)
    v = do
          Just (i, o, gen) <- [Maybe
      (Int, GenLocated SrcSpanAnnA (HsExpr GhcPs),
       GenLocated SrcSpanAnnA (HsExpr GhcPs) -> a)
    p]
          Just x <- [remParen v]
          guard $ redundantInfixBracket fixities i o x
          pure $
            rawIdea Ignore msg (locA (getLoc v)) (unsafePrettyPrint o)
            (Just (unsafePrettyPrint (gen x))) [] [Replace (findType v) (toSSA v) [("x", toSSA x)] "x"]

    redundantInfixBracket :: Map String Fixity -> Int -> LHsExpr GhcPs -> LHsExpr GhcPs -> Bool
    redundantInfixBracket :: Map String Fixity -> Int -> LHsExpr GhcPs -> LHsExpr GhcPs -> Bool
    redundantInfixBracket Map String Fixity
    fixities Int
    i LHsExpr GhcPs
    parent LHsExpr GhcPs
    child
        | L SrcSpanAnnA
    _ (OpApp XOpApp GhcPs
    _ LHsExpr GhcPs
    _ (L SrcSpanAnnA
    _ (HsVar XVar GhcPs
    _ (L SrcSpanAnnN
    _ (Unqual OccName
    p)))) LHsExpr GhcPs
    _) <- LHsExpr GhcPs
    parent
        , L SrcSpanAnnA
    _ (OpApp XOpApp GhcPs
    _ LHsExpr GhcPs
    _ (L SrcSpanAnnA
    _ (HsVar XVar GhcPs
    _ (L SrcSpanAnnN
    _ (Unqual OccName
    c)))) (L SrcSpanAnnA
    _ HsExpr GhcPs
    cr)) <- LHsExpr GhcPs
    child =
        let (OccName
    lop, OccName
    rop)
                | Int
    i Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 = (OccName
    c, OccName
    p)
                | Bool
    otherwise = (OccName
    p, OccName
    c)
        in
        case Fixity -> Fixity -> (Bool, Bool)
    compareFixity (Fixity -> Fixity -> (Bool, Bool))
    -> Maybe Fixity -> Maybe (Fixity -> (Bool, Bool))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Map String Fixity
    fixities Map String Fixity -> String -> Maybe Fixity
    forall k a. Ord k => Map k a -> k -> Maybe a
    Data.Map.!? OccName -> String
    occNameString OccName
    lop) Maybe (Fixity -> (Bool, Bool))
    -> Maybe Fixity -> Maybe (Bool, Bool)
    forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> (Map String Fixity
    fixities Map String Fixity -> String -> Maybe Fixity
    forall k a. Ord k => Map k a -> k -> Maybe a
    Data.Map.!? OccName -> String
    occNameString OccName
    rop) of
        Just (Bool
    False, Bool
    r)
            | Int
    i Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0 -> Bool -> Bool
    not (HsExpr GhcPs -> Bool
    forall p. HsExpr p -> Bool
    needParenAsChild HsExpr GhcPs
    cr Bool -> Bool -> Bool
    || Bool
    r)
            | Bool
    otherwise -> Bool
    r
        Maybe (Bool, Bool)
    _ -> Bool
    False
        | Bool
    otherwise = Bool
    False

    needParenAsChild :: HsExpr p -> Bool
    needParenAsChild :: forall p. HsExpr p -> Bool
    needParenAsChild HsLet{} = Bool
    True
    needParenAsChild HsDo{} = Bool
    True
    needParenAsChild HsLam{} = Bool
    True
    needParenAsChild HsCase{} = Bool
    True
    needParenAsChild HsIf{} = Bool
    True
    needParenAsChild HsExpr p
    _ = Bool
    False