module Language.Haskell.Refact.Refactoring.AddRmParam
( addOneParameter, compAddOneParameter
, rmOneParameter, compRmOneParameter
) where
import qualified Data.Generics as SYB
import qualified GHC.SYB.Utils as SYB
import qualified GHC
import qualified Name as GHC
import qualified Outputable as GHC
import qualified Language.Haskell.GhcMod as GM
import Language.Haskell.GhcMod.Internal as GM
import Language.Haskell.Refact.API
import Language.Haskell.GHC.ExactPrint.Types
import Language.Haskell.GHC.ExactPrint.Transform
import Language.Haskell.GHC.ExactPrint.Utils
import System.Directory
import Data.Char
import Data.Foldable
import Data.Maybe
import Data.List hiding (delete)
import Data.Generics.Strafunski.StrategyLib.StrategyLib
addOneParameter :: RefactSettings -> GM.Options -> FilePath -> String -> SimpPos -> IO [FilePath]
addOneParameter settings opts fileName paramName (row,col) = do
absFileName <- canonicalizePath fileName
runRefacSession settings opts (compAddOneParameter absFileName paramName (row,col))
compAddOneParameter :: FilePath -> String -> SimpPos -> RefactGhc [ApplyRefacResult]
compAddOneParameter fileName paramName (row, col) = do
if isVarId paramName
then
do
parseSourceFileGhc fileName
parsed <- getRefactParsed
nm <- getRefactNameMap
logParsedSource "compAdd entry"
targetModule <- getRefactTargetModule
logm $ "AddRmParam.compAdd:got targetModule"
let maybePn = locToNameRdrPure nm (row, col) parsed
case maybePn of
Just pn ->
do
logm $ "AddRmParam.compAdd:about to applyRefac for:pn=" ++ SYB.showData SYB.Parser 0 pn
if isFunOrPatName nm pn parsed
then do
exported <- isExported pn
if exported
then do
clients <- clientModsAndFiles targetModule
decls <- liftT $ hsDecls parsed
let inscopes = []
defaultArg <- mkTopLevelDefaultArgName pn paramName inscopes decls
logm $ "compAdd:defaultArg=" ++ showGhc defaultArg
(refactoredMod,_) <- applyRefac (doAddingParam pn paramName (Just defaultArg) True) RSAlreadyLoaded
refactoredClients <- mapM (addArgInClientMod pn defaultArg) clients
return $ refactoredMod:refactoredClients
else do
logm $ "compAdd:not exported"
(refactoredMod,_) <- applyRefac (doAddingParam pn paramName Nothing False) (RSFile fileName)
return [refactoredMod]
else error "Invalid cursor position or identifier is not a function/pattern name defined in this module!\n"
Nothing -> error "Invalid cursor position or identifier is not a function/pattern name defined in this module!\n"
else error $ "Invalid parameter name:" ++ paramName ++ "!"
doAddingParam :: GHC.Name -> String -> Maybe (GHC.Located GHC.RdrName) -> Bool
-> RefactGhc ()
doAddingParam pn newParam defaultArg isExported' = do
logm $ "doAddingParam entered:defaultArg=" ++ showGhc defaultArg
parsed <- getRefactParsed
r <- applyTP (once_tdTP (failTP `adhocTP` inMod
`adhocTP` inMatch
`adhocTP` inLet
`adhocTP` inLetStmt
)
`choiceTP` failure) parsed
putRefactParsed r emptyAnns
return ()
where
inMod :: GHC.ParsedSource -> RefactGhc GHC.ParsedSource
inMod modu = do
nm <- getRefactNameMap
decls <- liftT $ hsDecls modu
if not ( null (definingDeclsRdrNames nm [pn] decls False False))
then
do
logm $ "doAddingParam.inMod doing it"
ds <- liftT $ hsDecls modu
modu' <- doAdding modu ds
if isExported' && isExplicitlyExported nm pn modu
then addItemsToExport modu' (Just pn) False (Left [GHC.unLoc (fromJust defaultArg)])
else return modu'
else mzero
inMatch ::GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName)
-> RefactGhc (GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName))
inMatch match
= do
nm <- getRefactNameMap
decls <- liftT $ hsDecls match
logm $ "doAddingParam.inMatch:decls=" ++ showGhc decls
if not ( null (definingDeclsRdrNames nm [pn] decls False False))
then doAdding match decls
else mzero
inLet (letExp@(GHC.L _ (GHC.HsLet _ds _e)) :: GHC.LHsExpr GHC.RdrName)
= do
nm <- getRefactNameMap
decls <- liftT $ hsDecls letExp
if not ( null (definingDeclsRdrNames nm [pn] decls False False))
then doAdding letExp decls
else mzero
#if __GLASGOW_HASKELL__ <= 710
inLet ((GHC.L l (GHC.HsDo ctx stmts ptt)) :: GHC.LHsExpr GHC.RdrName)
#else
inLet ((GHC.L l (GHC.HsDo ctx (GHC.L ls stmts) ptt)) :: GHC.LHsExpr GHC.RdrName)
#endif
= do
nm <- getRefactNameMap
if not ( null (definingDeclsRdrNames' nm [pn] stmts))
then do
stmts' <- doAddingStmts stmts
stmts2 <- applyTP (once_tdTP (failTP `adhocTP` inMod
`adhocTP` inMatch
`adhocTP` inLet
`adhocTP` inLetStmt
)
`choiceTP` failure) stmts'
#if __GLASGOW_HASKELL__ <= 710
return (GHC.L l (GHC.HsDo ctx stmts2 ptt))
#else
return (GHC.L l (GHC.HsDo ctx (GHC.L ls stmts2) ptt))
#endif
else mzero
inLet _ = mzero
inLetStmt (letStmt@(GHC.L _ (GHC.LetStmt _stmts)):: GHC.ExprLStmt GHC.RdrName)
= do
nm <- getRefactNameMap
decls <- liftT $ hsDecls letStmt
if not ( null (definingDeclsRdrNames nm [pn] decls False False))
then doAdding letStmt decls
else mzero
inLetStmt _ = mzero
failure = idTP `adhocTP` modu
where modu (_::GHC.ParsedSource) = error "Refactoring failed"
doAdding :: (HasDecls t) => t -> [GHC.LHsDecl GHC.RdrName] -> RefactGhc t
doAdding parent ds = do
nm <- getRefactNameMap
if paramNameOk nm pn newParam ds
then do
ds' <- addParamsToDecls ds pn [mkRdrName newParam]
defaultParamPName <-if isNothing defaultArg
then mkLocalDefaultArgName pn newParam parent
else return (gfromJust "doAdding" defaultArg)
parent1 <- liftT $ replaceDecls parent ds'
parent' <- addDefaultActualArg False pn defaultParamPName parent1
parent''<- addDefaultActualArgDecl defaultParamPName parent' pn isExported'
ds2 <- liftT $ hsDecls parent''
ds'' <- addArgToSig pn ds2
parent3 <- liftT $ replaceDecls parent'' ds''
return parent3
else error " Refactoring failed."
doAddingStmts :: [GHC.ExprLStmt GHC.RdrName] -> RefactGhc [GHC.ExprLStmt GHC.RdrName]
doAddingStmts stmts = do
logDataWithAnns "doAddingStmts:stmts:" stmts
nm <- getRefactNameMap
if paramNameOk nm pn newParam stmts
then do
defaultParamPName <-if isNothing defaultArg
then mkLocalDefaultArgName pn newParam stmts
else return (gfromJust "doAddingStmts" defaultArg)
stmts' <- addDefaultActualArg False pn defaultParamPName stmts
return stmts'
else error " Refactoring failed."
paramNameOk :: (SYB.Data t) => NameMap -> GHC.Name -> String -> t -> Bool
paramNameOk nm pn newParam t
= (fromMaybe True) (applyTU (once_tdTU (failTU `adhocTU` decl
`adhocTU` bind)) t)
where
decl :: GHC.LHsDecl GHC.RdrName -> Maybe Bool
decl (GHC.L l (GHC.ValD d)) = bind (GHC.L l d)
decl _ = mzero
bind :: GHC.LHsBind GHC.RdrName -> Maybe Bool
#if __GLASGOW_HASKELL__ <= 710
bind (GHC.L _ (GHC.FunBind n _i (GHC.MG matches _a _ptt _o) _co _fvs _))
#else
bind (GHC.L _ (GHC.FunBind n (GHC.MG matches _a _ptt _o) _co _fvs _))
#endif
| rdrName2NamePure nm n == pn
= do results' <- mapM checkInMatch matches
Just (all (==True) results')
bind (GHC.L _ (GHC.PatBind _pat _rhs _ty _fvs _t))
= error "Parameter can not be added to complex pattern binding"
bind _ = mzero
checkInMatch match
= do let (f,d) = hsFDNamesFromInsideRdrPure nm match
if elem newParam (f `union` d)
then error "The new parameter name will cause name clash or semantics change, please choose another name!"
else return True
addDefaultActualArgDecl :: (SYB.Data t) => GHC.Located GHC.RdrName -> t -> GHC.Name -> Bool -> RefactGhc t
addDefaultActualArgDecl defaultParamPName parent pn isExported' = do
defaultArgDecl <- parseDeclWithAnns ((showGhc defaultParamPName) ++ " = undefined")
nm <- getRefactNameMap
let inParent = findLRdrName nm pn parent
if not inParent && not isExported'
then return parent
else addDecl parent (Just pn) ([defaultArgDecl],Nothing)
mkLocalDefaultArgName :: (SYB.Data t)
=> GHC.Name -> String -> t -> RefactGhc (GHC.Located GHC.RdrName)
mkLocalDefaultArgName fun paramName t = do
logm $ "mkLocalDefaultArgName"
(f,d) <- hsFDNamesFromInsideRdr t
vs <- hsVisibleNamesRdr fun t
let name = mkNewName ((showGhc fun)++"_"++paramName) (nub (f `union` d `union` vs)) 0
loc <- liftT $ uniqueSrcSpanT
let vn = (GHC.L loc (mkRdrName name))
liftT $ addSimpleAnnT vn (DP (0,1)) [((G GHC.AnnVal),DP (0,0))]
return vn
mkTopLevelDefaultArgName :: (SYB.Data t,GHC.Outputable a)
=> a -> String -> [String] -> t
-> RefactGhc (GHC.Located GHC.RdrName)
mkTopLevelDefaultArgName fun paramName inscopeNames t = do
(f,d) <- hsFDNamesFromInsideRdr t
let name = mkNewName ((showGhc fun)++"_"++paramName) (nub (f `union` d `union` inscopeNames)) 0
loc <- liftT $ uniqueSrcSpanT
let vn = (GHC.L loc (mkRdrName name))
liftT $ addSimpleAnnT vn (DP (0,1)) [((G GHC.AnnVal),DP (0,0))]
return vn
addDefaultActualArg :: (SYB.Data t)
=> Bool
-> GHC.Name
-> GHC.Located GHC.RdrName
-> t
-> RefactGhc t
addDefaultActualArg recursion pn argPName t = do
logm $ "addDefaultActualArg:(recursion,pn,argPName):" ++ showGhc (recursion,pn,argPName)
logDataWithAnns "addDefaultActualArg:t=:" t
nm <- getRefactNameMap
if recursion then (applyTP (stop_tdTP (failTP `adhocTP` (funApp nm)))) t
else (applyTP (stop_tdTP (failTP `adhocTP` (inDecl nm)
`adhocTP` (funApp nm)))) t
where
inDecl :: NameMap -> GHC.LHsDecl GHC.RdrName -> RefactGhc (GHC.LHsDecl GHC.RdrName)
#if __GLASGOW_HASKELL__ <= 710
inDecl nm fun@(GHC.L _ (GHC.ValD (GHC.FunBind n _i _ _co _fvs _)))
#else
inDecl nm fun@(GHC.L _ (GHC.ValD (GHC.FunBind n _ _co _fvs _)))
#endif
| rdrName2NamePure nm n == pn
= return fun
inDecl _ _ = mzero
funApp :: NameMap -> GHC.LHsExpr GHC.RdrName -> RefactGhc (GHC.LHsExpr GHC.RdrName)
#if __GLASGOW_HASKELL__ <= 710
funApp nm (expr@(GHC.L l (GHC.HsVar n))::GHC.LHsExpr GHC.RdrName)
#else
funApp nm (expr@(GHC.L l (GHC.HsVar (GHC.L _ n)))::GHC.LHsExpr GHC.RdrName)
#endif
| rdrName2NamePure nm (GHC.L l n) == pn = do
logm $ "addDefaultActualArg.funApp:expr=" ++ showGhc expr
addParamToExp expr (GHC.unLoc argPName)
funApp _ _ = mzero
addParamToExp :: GHC.LHsExpr GHC.RdrName -> GHC.RdrName
-> RefactGhc (GHC.LHsExpr GHC.RdrName)
addParamToExp (expr@(GHC.L _ (GHC.HsVar _))) argPName = do
lp <- liftT uniqueSrcSpanT
la <- liftT uniqueSrcSpanT
lv <- liftT uniqueSrcSpanT
#if __GLASGOW_HASKELL__ <= 710
let e2 = GHC.L lv (GHC.HsVar argPName)
liftT $ addSimpleAnnT e2 (DP (0,1)) [((G GHC.AnnVal),DP (0,0))]
#else
let lname = GHC.L lv argPName
let e2 = GHC.L lv (GHC.HsVar lname)
liftT $ addSimpleAnnT e2 (DP (0,1)) [((G GHC.AnnVal),DP (0,0))]
#endif
let ret = GHC.L lp (GHC.HsPar (GHC.L la (GHC.HsApp expr e2)))
liftT $ addSimpleAnnT ret (DP (0,0)) [((G GHC.AnnOpenP),DP (0,0)),((G GHC.AnnCloseP),DP (0,0))]
liftT $ transferEntryDPT expr ret
liftT $ setEntryDPT expr (DP (0,0))
return ret
addParamToExp x _
= error $ "AddRmParam.addParamToExp: can only add param to HsVar, got:" ++ showGhc x
addArgToSig :: GHC.Name -> [GHC.LHsDecl GHC.RdrName] -> RefactGhc [GHC.LHsDecl GHC.RdrName]
addArgToSig pn decls = do
nm <- getRefactNameMap
let (before,after) = break (\d -> definesSigDRdr nm pn d) decls
in if null after
then return decls
else do newSig<-addArgToSig' [(head after)]
return (before++newSig++(tail after))
where
addArgToSig' :: [GHC.LHsDecl GHC.RdrName] -> RefactGhc [GHC.LHsDecl GHC.RdrName]
#if __GLASGOW_HASKELL__ <= 710
addArgToSig' sig@[(GHC.L l (GHC.SigD (GHC.TypeSig is tp pr)))] = do
#else
addArgToSig' sig@[(GHC.L l (GHC.SigD (GHC.TypeSig is typ@(GHC.HsIB ivs (GHC.HsWC wcs mwc tp)))))] = do
#endif
nm <- getRefactNameMap
let tVar = mkNewTypeVarName sig
#if __GLASGOW_HASKELL__ <= 710
typeVar <- newTypeVar tVar tp
#else
typeVar' <- newTypeVar tVar tp
let typeVar = GHC.HsIB ivs (GHC.HsWC wcs mwc typeVar')
#endif
let newSig=if length is==1
#if __GLASGOW_HASKELL__ <= 710
then
[GHC.L l (GHC.SigD (GHC.TypeSig is typeVar pr))]
else
[GHC.L l (GHC.SigD (GHC.TypeSig (filter (\x->rdrName2NamePure nm x/=pn) is) tp pr)),
GHC.L l (GHC.SigD (GHC.TypeSig (filter (\x->rdrName2NamePure nm x==pn) is) typeVar pr))]
#else
then
[GHC.L l (GHC.SigD (GHC.TypeSig is typeVar))]
else
[GHC.L l (GHC.SigD (GHC.TypeSig (filter (\x->rdrName2NamePure nm x/=pn) is) typ)),
GHC.L l (GHC.SigD (GHC.TypeSig (filter (\x->rdrName2NamePure nm x==pn) is) typeVar))]
#endif
return newSig
addArgToSig' sig = do
logm $ "addArgToSig':not processing " ++ showGhc sig
return sig
newTypeVar :: String -> GHC.LHsType GHC.RdrName -> RefactGhc (GHC.LHsType GHC.RdrName)
newTypeVar tVar tp = do
ls <- liftT $ uniqueSrcSpanT
lv <- liftT $ uniqueSrcSpanT
#if __GLASGOW_HASKELL__ <= 710
let tv = GHC.L lv (GHC.HsTyVar (mkRdrName tVar))
liftT $ addSimpleAnnT tv (DP (0,0)) [((G GHC.AnnVal),DP (0,0))]
#else
let lname = GHC.L lv (mkRdrName tVar)
let tv = GHC.L lv (GHC.HsTyVar lname)
liftT $ addSimpleAnnT lname (DP (0,0)) [((G GHC.AnnVal),DP (0,0))]
#endif
let typ = GHC.L ls (GHC.HsFunTy tv tp)
liftT $ addSimpleAnnT typ (DP (0,1)) [((G GHC.AnnRarrow),DP (0,1))]
return typ
mkNewTypeVarName :: [GHC.LHsDecl GHC.RdrName] -> String
mkNewTypeVarName sig
=mkANewName "a" $ map showGhc $ (snd.hsTypeVbls) sig
where mkANewName initName v
=if elem initName v
then mkANewName ((intToDigit (digitToInt(head initName)+1)):tail initName) v
else initName
addArgInClientMod :: GHC.Name -> GHC.Located GHC.RdrName -> TargetModule -> RefactGhc ApplyRefacResult
addArgInClientMod pnt defaultArg serverModName = do
(r,_) <- applyRefac (addArgInClientMod' pnt defaultArg (GM.mpModule serverModName)) (RSTarget serverModName)
return r
addArgInClientMod' :: GHC.Name -> GHC.Located GHC.RdrName -> GHC.ModuleName -> RefactGhc ()
addArgInClientMod' pnt defaultArg serverModName = do
parsed <- getRefactParsed
let pn = pnt
qual <- hsQualifier pnt
if qual == []
then return ()
else do
mod' <- addItemsToImport serverModName (Just pn) (Left [GHC.unLoc defaultArg]) parsed
mod'' <- addItemsToExport mod' (Just pn) False (Left [GHC.unLoc defaultArg])
mod3 <- addDefaultActualArgInClientMod pn defaultArg mod''
putRefactParsed mod3 emptyAnns
return ()
addDefaultActualArgInClientMod :: (SYB.Data t)
=> GHC.Name -> GHC.Located GHC.RdrName -> t
-> RefactGhc t
addDefaultActualArgInClientMod pn argPName t = do
logm $ "addDefaultActualArgInClientMod entered:argPName=" ++ showGhc argPName
nm <- getRefactNameMap
r <- applyTP (stop_tdTP (failTP `adhocTP` (funApp nm))) t
return r
where
#if __GLASGOW_HASKELL__ <= 710
funApp nm (expr@((GHC.L l (GHC.HsVar pname )))::GHC.LHsExpr GHC.RdrName)
#else
funApp nm (expr@((GHC.L l (GHC.HsVar (GHC.L _ pname) )))::GHC.LHsExpr GHC.RdrName)
#endif
| GHC.nameUnique (rdrName2NamePure nm (GHC.L l pname)) == GHC.nameUnique pn
= do
logm $ "addDefaultActualArgInClientMod:hit"
let argExp = GHC.unLoc argPName
addParamToExp expr argExp
funApp _ _ = mzero
rmOneParameter :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> IO [FilePath]
rmOneParameter settings opts fileName (row,col) = do
absFileName <- canonicalizePath fileName
runRefacSession settings opts (compRmOneParameter absFileName (row,col))
compRmOneParameter :: FilePath -> SimpPos -> RefactGhc [ApplyRefacResult]
compRmOneParameter fileName (row, col) = do
parseSourceFileGhc fileName
mp <- getParam (row,col)
case mp of
Nothing -> error "Invalid cursor position!"
Just (pn,pnth) -> do
logm $ "compRm:(pn,pnth)=" ++ showGhc (pn,pnth)
exported <- isExported pn
if exported
then do
logm $ "compRm: exported"
(refactoredMod,_) <- applyRefac (doRmParam pn pnth) (RSFile fileName)
targetModule <- getRefactTargetModule
clients <- clientModsAndFiles targetModule
logm $ "compRm: clients:" ++ showGhc clients
refactoredClients <- mapM (rmParamInClientMod pn pnth) clients
return $ refactoredMod:refactoredClients
else do
logm $ "compRm:not exported"
(refactoredMod,_) <- applyRefac (doRmParam pn pnth) (RSFile fileName)
return [refactoredMod]
doRmParam :: GHC.Name -> Int -> RefactGhc ()
doRmParam pn nTh = do
logm $ "doRmParam entered:(pn,nth)=" ++ showGhc (pn,nTh)
parsed <- getRefactParsed
r <- applyTP ((once_tdTP (failTP `adhocTP` inMod
`adhocTP` inMatch
`adhocTP` inLet
`adhocTP` inLetStmt
))
`choiceTP` failure) parsed
logm $ "doRmParam after applyTP"
putRefactParsed r emptyAnns
logParsedSource "doRmParam:parsed after"
return ()
where
inMod :: GHC.ParsedSource -> RefactGhc GHC.ParsedSource
inMod modu = doRemoving' modu
inMatch :: GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName) -> RefactGhc (GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName))
#if __GLASGOW_HASKELL__ <= 710
inMatch match@(GHC.L _ (GHC.Match (Just (_fun,_)) _pats _mtyp (GHC.GRHSs _rhs _ds)))
#else
inMatch match@(GHC.L _ (GHC.Match (GHC.FunBindMatch _fun _) _pats _mtyp (GHC.GRHSs _rhs _ds)))
#endif
= doRemoving' match
inMatch _ = mzero
inLet :: GHC.LHsExpr GHC.RdrName -> RefactGhc (GHC.LHsExpr GHC.RdrName)
inLet letExp@(GHC.L _ (GHC.HsLet _bs _e))
= doRemoving' letExp
#if __GLASGOW_HASKELL__ <= 710
inLet (GHC.L l (GHC.HsDo ctx stmts ptt))
#else
inLet (GHC.L l (GHC.HsDo ctx (GHC.L ls stmts) ptt))
#endif
= do
nm <- getRefactNameMap
if not ( null (definingDeclsRdrNames' nm [pn] stmts))
then do
stmts' <- doRemovingStmts stmts
#if __GLASGOW_HASKELL__ <= 710
return (GHC.L l (GHC.HsDo ctx stmts' ptt))
#else
return (GHC.L l (GHC.HsDo ctx (GHC.L ls stmts') ptt))
#endif
else mzero
inLet _ = mzero
inLetStmt :: GHC.ExprLStmt GHC.RdrName -> RefactGhc (GHC.ExprLStmt GHC.RdrName)
inLetStmt letStmt@(GHC.L _ (GHC.LetStmt _))
= doRemoving' letStmt
inLetStmt _ = mzero
failure = idTP `adhocTP` modu
where modu (_m::GHC.ParsedSource) = error "Refactoring failed"
doRemoving' parent = do
nm <- getRefactNameMap
decls <- liftT $ hsDecls parent
if not ( null (definingDeclsRdrNames nm [pn] decls False False))
then doRemoving parent decls
else mzero
doRemoving :: (HasDecls t) => t -> [GHC.LHsDecl GHC.RdrName] -> RefactGhc t
doRemoving parent ds
=do
void $ rmFormalArg pn nTh False True =<< rmNthArgInFunCall pn nTh ds
ds' <- rmNthArgInSig pn nTh =<< rmFormalArg pn nTh True False ds
ds'' <- liftT $ replaceDecls parent ds'
rmNthArgInFunCall pn nTh ds''
doRemovingStmts :: [GHC.ExprLStmt GHC.RdrName] -> RefactGhc [GHC.ExprLStmt GHC.RdrName]
doRemovingStmts stmts
=do
void $ rmFormalArg pn nTh False True =<< rmNthArgInFunCall pn nTh stmts
stmts' <- rmFormalArg pn nTh True False stmts
rmNthArgInFunCall pn nTh stmts'
rmFormalArg :: (SYB.Data t) => GHC.Name -> Int -> Bool -> Bool -> t -> RefactGhc t
rmFormalArg pn' nTh' updateToks checking t = do
logm $ "rmFormalArg:(pn,nTh,updateToks,checking)=" ++ showGhc (pn',nTh',updateToks,checking)
nm <- getRefactNameMap
applyTP (stop_tdTP (failTP `adhocTP` (rmInMatch nm))) t
where
#if __GLASGOW_HASKELL__ <= 710
rmInMatch nm (match@(GHC.L l (GHC.Match (Just (fun,b)) pats typ (GHC.GRHSs rhs decls)))::GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName))
#else
rmInMatch nm (match@(GHC.L l (GHC.Match (GHC.FunBindMatch fun b) pats typ (GHC.GRHSs rhs decls)))::GHC.LMatch GHC.RdrName (GHC.LHsExpr GHC.RdrName))
#endif
| rdrName2NamePure nm fun == pn' =
let pat = pats!!nTh'
pats' = take nTh' pats ++ drop (nTh' + 1) pats
pNames = map (rdrName2NamePure nm) $ hsNamessRdr pat
in if checking && not ( all (==False) ((map (flip (findNameInRdr nm) rhs) pNames)) &&
all (==False) ((map (flip (findNameInRdr nm) decls) pNames)))
then error "This parameter can not be removed, as it is used!"
else do
when (null pats') $ do
dp <- liftT $ getEntryDPT (ghead "rmFormalArg" pats)
logm $ "rmFormalArg.rmInMatch:dp=" ++ show dp
liftT $ setAnnKeywordDP match (G GHC.AnnEqual) dp
#if __GLASGOW_HASKELL__ <= 710
return (GHC.L l (GHC.Match (Just (fun,b)) pats' typ (GHC.GRHSs rhs decls)))
#else
return (GHC.L l (GHC.Match (GHC.FunBindMatch fun b) pats' typ (GHC.GRHSs rhs decls)))
#endif
rmInMatch _ _ = mzero
rmNthArgInFunCall :: (SYB.Data t) => GHC.Name -> Int -> t -> RefactGhc t
rmNthArgInFunCall pn nTh t = do
nm <- getRefactNameMap
applyTP (stop_tdTP (failTP `adhocTP` (funApp nm))) t
where
funApp nm (expr@(GHC.L _ (GHC.HsPar (GHC.L _ (GHC.HsApp e1 _e2))))::GHC.LHsExpr GHC.RdrName)
| nTh == 0 && Just pn == expToNameRdr nm e1
= do
liftT $ transferEntryDPT expr e1
return e1
funApp nm (expr@(GHC.L _ (GHC.HsApp _e1 _e2))) = do
let expu = unfoldHsApp expr
ed <- liftT $ getEntryDPT expr
if Just pn == (expToNameRdr nm.snd.(ghead "rmNthArgInFunCall")) expu
then do
let (before,after)=splitAt (nTh+1) expu
let exp' = (foldHsApp (before++tail after))
liftT $ setEntryDPT exp' ed
return exp'
else mzero
funApp _ _ = mzero
unfoldHsApp :: GHC.LHsExpr GHC.RdrName -> [(GHC.SrcSpan, GHC.LHsExpr GHC.RdrName)]
unfoldHsApp expr =
case expr of
(GHC.L l (GHC.HsApp e1 e2)) -> unfoldHsApp e1 ++ [(l,e2)]
_ -> [(GHC.noSrcSpan,expr)]
foldHsApp :: [(GHC.SrcSpan, GHC.LHsExpr GHC.RdrName)] -> GHC.LHsExpr GHC.RdrName
foldHsApp [] = error "foldHsApp:empty list"
foldHsApp exps = snd $ foldl1 (\(_l1,e1) (l2,e2) -> (l2,GHC.L l2 (GHC.HsApp e1 e2))) exps
rmNthArgInSig :: GHC.Name -> Int -> [GHC.LHsDecl GHC.RdrName] -> RefactGhc [GHC.LHsDecl GHC.RdrName]
rmNthArgInSig pn nTh decls = do
nm <- getRefactNameMap
let (before,after)=break (\d ->definesSigDRdr nm pn d) decls
if null after
then return decls
else do newSig<-rmNthArgInSig' nm [(head after)]
return (before++newSig++(tail after))
where
#if __GLASGOW_HASKELL__ <= 710
rmNthArgInSig' nm [GHC.L l (GHC.SigD (GHC.TypeSig is typ@(GHC.L lt (GHC.HsForAllTy ex wc bnd ctx tp)) c))]
#else
rmNthArgInSig' nm [GHC.L l (GHC.SigD (GHC.TypeSig is typ@(GHC.HsIB ivs (GHC.HsWC wcs mwc tp))))]
#endif
=do
ed <- liftT $ getEntryDPT tp
let (GHC.L lp tp') = rmNth tp
lp' <- liftT uniqueSrcSpanT
liftT $ modifyAnnsT $ copyAnn (GHC.L lp tp') (GHC.L lp' tp')
liftT $ setEntryDPT (GHC.L lp' tp') ed
#if __GLASGOW_HASKELL__ <= 710
let typ' = GHC.L lt (GHC.HsForAllTy ex wc bnd ctx (GHC.L lp' tp'))
#else
let typ' = GHC.HsIB ivs (GHC.HsWC wcs mwc (GHC.L lp' tp'))
#endif
newSig <- liftT $ if length is ==1
then
#if __GLASGOW_HASKELL__ <= 710
return [GHC.L l (GHC.SigD (GHC.TypeSig is typ' c))]
#else
return [GHC.L l (GHC.SigD (GHC.TypeSig is typ'))]
#endif
else do
let otherNames = filter (\x->rdrName2NamePure nm x/=pn) is
[thisName] = filter (\x->rdrName2NamePure nm x==pn) is
removeTrailingCommaT thisName
removeTrailingCommaT (last otherNames)
ls <- uniqueSrcSpanT
#if __GLASGOW_HASKELL__ <= 710
let otherSig = GHC.L l (GHC.SigD (GHC.TypeSig otherNames typ c))
thisSig = GHC.L ls (GHC.SigD (GHC.TypeSig [thisName] typ' c))
#else
let otherSig = GHC.L l (GHC.SigD (GHC.TypeSig otherNames typ))
thisSig = GHC.L ls (GHC.SigD (GHC.TypeSig [thisName] typ'))
#endif
modifyAnnsT $ copyAnn otherSig thisSig
clearPriorComments thisSig
setEntryDPT thisSig (DP (2,0))
return [otherSig,thisSig]
return newSig
rmNthArgInSig' _nm sig = return sig
rmNth tp = let (before,after)=splitAt nTh (unfoldHsTypApp tp)
in (foldHsTypApp (before ++ tail after))
unfoldHsTypApp :: GHC.LHsType GHC.RdrName -> [(GHC.SrcSpan,GHC.LHsType GHC.RdrName)]
unfoldHsTypApp typ =
case typ of (GHC.L l (GHC.HsFunTy t1 t2)) ->(l,t1):unfoldHsTypApp t2
_ ->[(GHC.noSrcSpan,typ)]
foldHsTypApp :: [(GHC.SrcSpan,GHC.LHsType GHC.RdrName)] -> GHC.LHsType GHC.RdrName
foldHsTypApp [] = error "foldHsTypApp:empty list"
foldHsTypApp ts=snd $ foldr1 (\(l1,t1) (_l2,t2)->(l1,GHC.L l1 (GHC.HsFunTy t1 t2))) ts
getParam :: SimpPos -> RefactGhc (Maybe (GHC.Name,Int))
getParam pos = do
nm <- getRefactNameMap
parsed <- getRefactParsed
let r = applyTU (once_tdTU (failTU `adhocTU` inMatch)) parsed
case r of
Nothing -> return Nothing
Just (ln,i) -> return $ Just (rdrName2NamePure nm ln,i)
where
#if __GLASGOW_HASKELL__ <= 710
inMatch ((GHC.Match (Just (fun,_)) pats _mtyp _grhs)::GHC.Match GHC.RdrName (GHC.LHsExpr GHC.RdrName))
#else
inMatch ((GHC.Match (GHC.FunBindMatch fun _) pats _mtyp _grhs)::GHC.Match GHC.RdrName (GHC.LHsExpr GHC.RdrName))
#endif
= case locToRdrName pos pats of
Nothing -> Nothing
Just _ln -> if isNothing element
then error "Invalid cursor position!"
else Just (fun, fromJust (elemIndex (fromJust element) paramPosRanges))
where
paramPosRanges = map GHC.getLoc pats
element = find (inRange pos) paramPosRanges
inMatch _ = Nothing
inRange pos' ss = pos' >= startPos && pos'<=endPos
where (startPos,endPos) = (ss2pos ss,ss2posEnd ss)
rmParamInClientMod :: GHC.Name -> Int -> TargetModule -> RefactGhc ApplyRefacResult
rmParamInClientMod pn nTh serverModName = do
logm $ "rmParamInClientMod:serverModName" ++ showGhc serverModName
(r,_) <- applyRefac (rmNthArgInFunCallMod pn nTh) (RSTarget serverModName)
return r
rmNthArgInFunCallMod :: GHC.Name -> Int -> RefactGhc ()
rmNthArgInFunCallMod pn nTh = do
parsed <- getRefactParsed
newNames <- equivalentNameInNewMod pn
logm $ "rmNthArgInFunCallMod:(newNames)=" ++ showGhcQual newNames
case newNames of
[] -> return ()
[_pnt] -> do
parsed' <- rmNthArgInFunCall pn nTh parsed
putRefactParsed parsed' emptyAnns
return ()
_ns -> error "HaRe: rmParam: more than one name matches"