{-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} module Language.Haskell.Refact.Refactoring.DeleteDef (deleteDef, compDeleteDef) where import qualified Data.Generics as SYB import qualified GHC.SYB.Utils as SYB import BasicTypes import qualified GHC import Control.Monad import Control.Monad.State import GhcMod import Language.Haskell.Refact.API import Data.Generics.Strafunski.StrategyLib.StrategyLib import qualified GhcMod as GM import qualified GhcMod.Types as GM import System.Directory import Language.Haskell.GHC.ExactPrint import Language.Haskell.GHC.ExactPrint.Types deleteDef :: RefactSettings -> GM.Options -> FilePath -> SimpPos -> IO [FilePath] deleteDef settings cradle fileName (row,col) = do absFileName <- canonicalizePath fileName runRefacSession settings cradle (compDeleteDef absFileName (row,col)) compDeleteDef ::FilePath -> SimpPos -> RefactGhc [ApplyRefacResult] compDeleteDef fileName (row,col) = do parseSourceFileGhc fileName renamed <- getRefactRenamed parsed <- getRefactParsed targetModule <- getRefactTargetModule m <- getModule let (Just (modName,_)) = getModuleName parsed maybeRdrPn = locToRdrName (row,col) parsed case maybeRdrPn of Just pn@(GHC.L _ n) -> do logm $ "DeleteDef.comp: before isPNUsed" Just ghcn <- locToNameRdr (row,col) parsed pnIsUsedLocal <- isPNUsed ghcn targetModule fileName clients <- clientModsAndFiles targetModule pnUsedClients <- isPNUsedInClients ghcn n targetModule if (pnIsUsedLocal || pnUsedClients) then error "The def to be deleted is still being used" else do logm $ "Result of is used: " ++ (show pnIsUsedLocal) ++ " pnUsedClients: " ++ (show pnUsedClients) (refRes@((_fp,ismod), (anns,ps)),()) <- applyRefac (doDeletion ghcn) RSAlreadyLoaded case (ismod) of RefacUnmodifed -> do error "The def deletion failed" RefacModified -> return () logm $ "Res after delete === " ++ (exactPrint ps anns) return [refRes] Nothing -> error "Invalid cursor position!" isPNUsed :: GHC.Name -> GM.ModulePath -> FilePath -> RefactGhc Bool isPNUsed pn modPath filePath = do renamed <- getRefactRenamed pnUsedInScope pn renamed pnUsedInScope :: (SYB.Data t) => GHC.Name -> t -> RefactGhc Bool pnUsedInScope pn t' = do logm $ "Start of pnUsedInScope" res <- applyTU (stop_tdTU (failTU `adhocTU` bind `adhocTU` var)) t' return $ (length res) > 0 where #if __GLASGOW_HASKELL__ <= 710 bind ((GHC.FunBind (GHC.L l name) _ match _ _ _) :: GHC.HsBindLR GHC.Name GHC.Name) #else bind ((GHC.FunBind (GHC.L l name) match _ _ _) :: GHC.HsBindLR GHC.Name GHC.Name) #endif | name == pn = do logm $ "Found Binding at: " ++ (showGhc l) return [] bind other = do mzero #if __GLASGOW_HASKELL__ <= 710 var ((GHC.HsVar name) :: GHC.HsExpr GHC.Name) #else var ((GHC.HsVar (GHC.L _ name)) :: GHC.HsExpr GHC.Name) #endif | name == pn = do logm $ "Found var" return [pn] var other = do mzero isPNUsedInClients :: GHC.Name -> GHC.RdrName -> GM.ModulePath -> RefactGhc Bool isPNUsedInClients pn rdrn modPath = do pnIsExported <- isExported pn if pnIsExported then do clients <- clientModsAndFiles modPath logm $ "DeleteDef : clients: " ++ (showGhc clients) res <- foldM (pnUsedInClientScope pn) False clients return res else do return False pnUsedInClientScope :: GHC.Name -> Bool -> TargetModule -> RefactGhc Bool pnUsedInClientScope name b mod = do getTargetGhc mod isInScope <- isInScopeAndUnqualifiedGhc (nameToString name) Nothing logm $ "The module file path: " ++ (show (GM.mpPath mod)) ++ "\n is pn in scope: " ++ (show isInScope) return (b || isInScope) doDeletion :: GHC.Name -> RefactGhc () doDeletion n = do parsed <- getRefactParsed (res, _decl, _mSig) <- rmDecl n True parsed putRefactParsed res emptyAnns return ()