<commit_before>{-# LANGUAGE ViewPatterns, PatternGuards, FlexibleContexts, TupleSections #-}

{-
    Find and match:

<TEST>
yes = 1:2:[] -- [1,2]
yes = ['h','e','l','l','o'] -- "hello"
yes (1:2:[]) = 1 -- [1,2]
yes ['h','e'] = 1 -- "he"

-- [a]++b -> a : b, but only if not in a chain of ++'s
yes = [x] ++ xs -- x : xs
no = "x" ++ xs
no = [x] ++ xs ++ ys
no = xs ++ [x] ++ ys
yes = [if a then b else c] ++ xs -- (if a then b else c) : xs
yes = [1] : [2] : [3] : [4] : [5] : [] -- [[1], [2], [3], [4], [5]]
yes = if x == e then l2 ++ xs else [x] ++ check_elem xs -- x : check_elem xs
data Yes = Yes (Maybe [Char]) -- Maybe String
yes = y :: [Char] -> a -- String -> a
instance C [Char]
foo = [a b] ++ xs -- a b : xs
</TEST>
-}


module Hint.List(listHint) where

import Control.Applicative
import Hint.Type
import Prelude
import Refact.Types


listHint :: DeclHint
listHint _ _ = listDecl

listDecl :: Decl_ -> [Idea]
listDecl x = concatMap (listExp False) (childrenBi x) ++ stringType x ++ concatMap listPat (childrenBi x)

-- boolean = are you in a ++ chain
listExp :: Bool -> Exp_ -> [Idea]
listExp b (fromParen -> x) =
        if null res then concatMap (listExp $ isAppend x) $ children x else [head res]
    where
        -- I think this is wrong for useCons, useList
        res = [warn' name x x2 subts temp | (name,f) <- checks, Just (x2, subts, temp) <- [f b x]]

listPat :: Pat_ -> [Idea]
listPat x = if null res then concatMap listPat $ children x else [head res]
    where res = [changeRefactType Pattern (warn' name x x2 subts temp)
                  | (name,f) <- pchecks, Just (x2, subts, temp) <- [f x]]

isAppend (view -> App2 op _ _) = op ~= "++"
isAppend _ = False


checks = let (*) = (,) in
         ["Use string literal" * useString
         ,"Use list literal" * useList
         ,"Use :" * useCons
         ]

pchecks = let (*) = (,) in
          ["Use string literal pattern" * usePString
          ,"Use list literal pattern" * usePList
          ]


usePString (PList _ xs) | xs /= [], Just s <- mapM fromPChar xs =
  let literal = PLit an (Signless an) $ String an s (show s)
  in Just (literal, [], prettyPrint literal)
usePString _ = Nothing

usePList = fmap (\(e, s) -> (PList an e, map (fmap ann) s, prettyPrint (PList an (map snd s))))
    . fmap unzip . f True ['a'..'z']
    where
        f first _ x | x ~= "[]" = if first then Nothing else Just []
        f first (ident: cs) (view -> PApp_ ":" [a,b]) =
          ((a, g ident a) :) <$> f False cs b
        f first _ _ = Nothing

        g :: Char -> Pat_ -> (String, Pat_)
        g c p = ([c], PVar (ann p) (toNamed [c]))

useString b (List _ xs) | xs /= [], Just s <- mapM fromChar xs =
  let literal = Lit an $ String an s (show s)
  in Just (literal , [], prettyPrint literal)
useString b _ = Nothing

useList b = fmap (\(e, s) -> (List an e, map (fmap ann) s, prettyPrint (List an (map snd s))))
              . fmap unzip . f True ['a'..'z']
    where
        f first _ x | x ~= "[]" = if first then Nothing else Just []
        f first (ident:cs) (view -> App2 c a b) | c ~= ":" =
          ((a, g ident a) :) <$> f False cs b
        f first _ _ = Nothing

        g :: Char -> Exp_ -> (String, Exp_)
        g c p = ([c], Var (ann p) (toNamed [c]))

useCons False (view -> App2 op x y) | op ~= "++", Just x2 <- f x, not $ isAppend y = Just (gen x2 y, [("x", ann x2), ("xs", ann y)], prettyPrint $ gen (toNamed "x") (toNamed "xs"))
    where
        f (List _ [x]) = Just $ if isApp x then x else paren x
        f _ = Nothing

        gen x xs = InfixApp an x (QConOp an $ list_cons_name an) xs
useCons _ _ = Nothing



typeListChar = TyList an (TyCon an (toNamed "Char"))
typeString = TyCon an (toNamed "String")


stringType :: Decl_ -> [Idea]
stringType x = case x of
    InstDecl _ _ _ x -> f x
    _ -> f x
    where
        f x = concatMap g $ childrenBi x

        g :: Type_ -> [Idea]
        g (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]
            where f x = if x =~= typeListChar then typeString else x<commit_msg>Add [Char] -> String refactoring<commit_after>{-# LANGUAGE ViewPatterns, PatternGuards, FlexibleContexts, TupleSections #-}

{-
    Find and match:

<TEST>
yes = 1:2:[] -- [1,2]
yes = ['h','e','l','l','o'] -- "hello"
yes (1:2:[]) = 1 -- [1,2]
yes ['h','e'] = 1 -- "he"

-- [a]++b -> a : b, but only if not in a chain of ++'s
yes = [x] ++ xs -- x : xs
no = "x" ++ xs
no = [x] ++ xs ++ ys
no = xs ++ [x] ++ ys
yes = [if a then b else c] ++ xs -- (if a then b else c) : xs
yes = [1] : [2] : [3] : [4] : [5] : [] -- [[1], [2], [3], [4], [5]]
yes = if x == e then l2 ++ xs else [x] ++ check_elem xs -- x : check_elem xs
data Yes = Yes (Maybe [Char]) -- Maybe String
yes = y :: [Char] -> a -- String -> a
instance C [Char]
foo = [a b] ++ xs -- a b : xs
</TEST>
-}


module Hint.List(listHint) where

import Control.Applicative
import Hint.Type
import Prelude
import Refact.Types


listHint :: DeclHint
listHint _ _ = listDecl

listDecl :: Decl_ -> [Idea]
listDecl x = concatMap (listExp False) (childrenBi x) ++ stringType x ++ concatMap listPat (childrenBi x)

-- boolean = are you in a ++ chain
listExp :: Bool -> Exp_ -> [Idea]
listExp b (fromParen -> x) =
        if null res then concatMap (listExp $ isAppend x) $ children x else [head res]
    where
        -- I think this is wrong for useCons, useList
        res = [warn' name x x2 subts temp | (name,f) <- checks, Just (x2, subts, temp) <- [f b x]]

listPat :: Pat_ -> [Idea]
listPat x = if null res then concatMap listPat $ children x else [head res]
    where res = [changeRefactType Pattern (warn' name x x2 subts temp)
                  | (name,f) <- pchecks, Just (x2, subts, temp) <- [f x]]

isAppend (view -> App2 op _ _) = op ~= "++"
isAppend _ = False


checks = let (*) = (,) in
         ["Use string literal" * useString
         ,"Use list literal" * useList
         ,"Use :" * useCons
         ]

pchecks = let (*) = (,) in
          ["Use string literal pattern" * usePString
          ,"Use list literal pattern" * usePList
          ]


usePString (PList _ xs) | xs /= [], Just s <- mapM fromPChar xs =
  let literal = PLit an (Signless an) $ String an s (show s)
  in Just (literal, [], prettyPrint literal)
usePString _ = Nothing

usePList = fmap (\(e, s) -> (PList an e, map (fmap ann) s, prettyPrint (PList an (map snd s))))
    . fmap unzip . f True ['a'..'z']
    where
        f first _ x | x ~= "[]" = if first then Nothing else Just []
        f first (ident: cs) (view -> PApp_ ":" [a,b]) =
          ((a, g ident a) :) <$> f False cs b
        f first _ _ = Nothing

        g :: Char -> Pat_ -> (String, Pat_)
        g c p = ([c], PVar (ann p) (toNamed [c]))

useString b (List _ xs) | xs /= [], Just s <- mapM fromChar xs =
  let literal = Lit an $ String an s (show s)
  in Just (literal , [], prettyPrint literal)
useString b _ = Nothing

useList b = fmap (\(e, s) -> (List an e, map (fmap ann) s, prettyPrint (List an (map snd s))))
              . fmap unzip . f True ['a'..'z']
    where
        f first _ x | x ~= "[]" = if first then Nothing else Just []
        f first (ident:cs) (view -> App2 c a b) | c ~= ":" =
          ((a, g ident a) :) <$> f False cs b
        f first _ _ = Nothing

        g :: Char -> Exp_ -> (String, Exp_)
        g c p = ([c], Var (ann p) (toNamed [c]))

useCons False (view -> App2 op x y) | op ~= "++", Just x2 <- f x, not $ isAppend y = Just (gen x2 y, [("x", ann x2), ("xs", ann y)], prettyPrint $ gen (toNamed "x") (toNamed "xs"))
    where
        f (List _ [x]) = Just $ if isApp x then x else paren x
        f _ = Nothing

        gen x xs = InfixApp an x (QConOp an $ list_cons_name an) xs
useCons _ _ = Nothing



typeListChar = TyList an (TyCon an (toNamed "Char"))
typeString = TyCon an (toNamed "String")


stringType :: Decl_ -> [Idea]
stringType x = case x of
    InstDecl _ _ _ x -> f x
    _ -> f x
    where
        f x = concatMap g $ childrenBi x

        g :: Type_ -> [Idea]
        g e@(fromTyParen -> x) = [(warn "Use String" x (transform f x))
                                    { ideaRefactoring = rs} | not . null $ rs]
            where f x = if x =~= typeListChar then typeString else x
                  toSS = toRefactSrcSpan . toSrcSpan . ann
                  rs = [Replace Type (toSS t) [] (prettyPrint typeString) | t <- universe x, t =~= typeListChar]
{'fraction_non_alphanumeric': 0.16478017395448588, 'fraction_numerical': 0.007387108304539497, 'mean_word_length': 2.2674192292720905, 'pattern_counts': {'":': 4, '<': 26, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1407896', 'n_tokens_mistral': 3102, 'n_tokens_neox': 2986, 'n_words': 1163}