haskell-tools-refactor 0.7.0.0 → 0.8.0.0
raw patch · 22 files changed
+328/−143 lines, 22 filesdep ~haskell-tools-astdep ~haskell-tools-backend-ghcdep ~haskell-tools-prettyprintPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: haskell-tools-ast, haskell-tools-backend-ghc, haskell-tools-prettyprint, haskell-tools-refactor, haskell-tools-rewrite
API changes (from Hackage documentation)
- Language.Haskell.Tools.Refactor.GetModules: BenchmarkMC :: String -> String -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: DirectoryMC :: FilePath -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: ExecutableMC :: String -> String -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: LibraryMC :: String -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: ModuleCodeGenerated :: UnnamedModule IdDom -> ModSummary -> ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: ModuleCollection :: ModuleCollectionId -> FilePath -> [FilePath] -> Map SourceFileKey ModuleRecord -> (DynFlags -> IO DynFlags) -> (DynFlags -> IO DynFlags) -> [ModuleCollectionId] -> ModuleCollection
- Language.Haskell.Tools.Refactor.GetModules: ModuleNotLoaded :: Bool -> ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: ModuleParsed :: UnnamedModule (Dom RdrName) -> ModSummary -> ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: ModuleRenamed :: UnnamedModule (Dom Name) -> ModSummary -> ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: ModuleTypeChecked :: UnnamedModule IdDom -> ModSummary -> ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: TestSuiteMC :: String -> String -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: [_mcDependencies] :: ModuleCollection -> [ModuleCollectionId]
- Language.Haskell.Tools.Refactor.GetModules: [_mcFlagSetup] :: ModuleCollection -> DynFlags -> IO DynFlags
- Language.Haskell.Tools.Refactor.GetModules: [_mcId] :: ModuleCollection -> ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: [_mcLoadFlagSetup] :: ModuleCollection -> DynFlags -> IO DynFlags
- Language.Haskell.Tools.Refactor.GetModules: [_mcModules] :: ModuleCollection -> Map SourceFileKey ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: [_mcRoot] :: ModuleCollection -> FilePath
- Language.Haskell.Tools.Refactor.GetModules: [_mcSourceDirs] :: ModuleCollection -> [FilePath]
- Language.Haskell.Tools.Refactor.GetModules: [_modRecMS] :: ModuleRecord -> ModSummary
- Language.Haskell.Tools.Refactor.GetModules: [_parsedRecModule] :: ModuleRecord -> UnnamedModule (Dom RdrName)
- Language.Haskell.Tools.Refactor.GetModules: [_recModuleWillNeedCode] :: ModuleRecord -> Bool
- Language.Haskell.Tools.Refactor.GetModules: [_renamedRecModule] :: ModuleRecord -> UnnamedModule (Dom Name)
- Language.Haskell.Tools.Refactor.GetModules: [_typedRecModule] :: ModuleRecord -> UnnamedModule IdDom
- Language.Haskell.Tools.Refactor.GetModules: data ModuleCollection
- Language.Haskell.Tools.Refactor.GetModules: data ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: data ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Classes.Eq Language.Haskell.Tools.Refactor.GetModules.ModuleCollection
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Classes.Eq Language.Haskell.Tools.Refactor.GetModules.ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Classes.Ord Language.Haskell.Tools.Refactor.GetModules.ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Show.Show Language.Haskell.Tools.Refactor.GetModules.ModuleCollection
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Show.Show Language.Haskell.Tools.Refactor.GetModules.ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: instance GHC.Show.Show Language.Haskell.Tools.Refactor.GetModules.ModuleRecord
- Language.Haskell.Tools.Refactor.GetModules: mcDependencies :: Lens ModuleCollection ModuleCollection [ModuleCollectionId] [ModuleCollectionId]
- Language.Haskell.Tools.Refactor.GetModules: mcFlagSetup :: Lens ModuleCollection ModuleCollection (DynFlags -> IO DynFlags) (DynFlags -> IO DynFlags)
- Language.Haskell.Tools.Refactor.GetModules: mcId :: Lens ModuleCollection ModuleCollection ModuleCollectionId ModuleCollectionId
- Language.Haskell.Tools.Refactor.GetModules: mcLoadFlagSetup :: Lens ModuleCollection ModuleCollection (DynFlags -> IO DynFlags) (DynFlags -> IO DynFlags)
- Language.Haskell.Tools.Refactor.GetModules: mcModules :: Lens ModuleCollection ModuleCollection (Map SourceFileKey ModuleRecord) (Map SourceFileKey ModuleRecord)
- Language.Haskell.Tools.Refactor.GetModules: mcRoot :: Lens ModuleCollection ModuleCollection FilePath FilePath
- Language.Haskell.Tools.Refactor.GetModules: mcSourceDirs :: Lens ModuleCollection ModuleCollection [FilePath] [FilePath]
- Language.Haskell.Tools.Refactor.GetModules: modRecMS :: Partial ModuleRecord ModuleRecord ModSummary ModSummary
- Language.Haskell.Tools.Refactor.GetModules: parsedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule (Dom RdrName)) (UnnamedModule (Dom RdrName))
- Language.Haskell.Tools.Refactor.GetModules: recModuleWillNeedCode :: Partial ModuleRecord ModuleRecord Bool Bool
- Language.Haskell.Tools.Refactor.GetModules: renamedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule (Dom Name)) (UnnamedModule (Dom Name))
- Language.Haskell.Tools.Refactor.GetModules: typedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule IdDom) (UnnamedModule IdDom)
- Language.Haskell.Tools.Refactor.RefactorBase: IsHsBoot :: IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: NormalHs :: IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: [_sfkIsBoot] :: SourceFileKey -> IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: data IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Classes.Eq Language.Haskell.Tools.Refactor.RefactorBase.IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Classes.Ord Language.Haskell.Tools.Refactor.RefactorBase.IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Show.Show Language.Haskell.Tools.Refactor.RefactorBase.IsBoot
- Language.Haskell.Tools.Refactor.RefactorBase: sfkIsBoot :: Lens SourceFileKey SourceFileKey IsBoot IsBoot
- Language.Haskell.Tools.Refactor.Session: class IsRefactSessionState st
- Language.Haskell.Tools.Refactor.Session: hscSourceToIsBoot :: HscSource -> IsBoot
- Language.Haskell.Tools.Refactor.Session: initSession :: IsRefactSessionState st => st
- Language.Haskell.Tools.Refactor.Session: instance Language.Haskell.Tools.Refactor.Session.IsRefactSessionState Language.Haskell.Tools.Refactor.Session.RefactorSessionState
- Language.Haskell.Tools.Refactor.Session: refSessMCs :: IsRefactSessionState st => Simple Lens st [ModuleCollection]
+ Language.Haskell.Tools.Refactor.GetModules: getMain :: BuildInfo -> String
+ Language.Haskell.Tools.Refactor.GetModules: getModuleSourceFiles :: ToModuleCollection t => t -> [(ModuleName, FilePath)]
+ Language.Haskell.Tools.Refactor.GetModules: instance GHC.Classes.Eq Language.Haskell.Tools.Refactor.RefactorBase.ModuleCollection
+ Language.Haskell.Tools.Refactor.GetModules: instance GHC.Show.Show Language.Haskell.Tools.Refactor.RefactorBase.ModuleCollection
+ Language.Haskell.Tools.Refactor.GetModules: instance GHC.Show.Show Language.Haskell.Tools.Refactor.RefactorBase.ModuleRecord
+ Language.Haskell.Tools.Refactor.GetModules: lookupModuleInSCs :: String -> [ModuleCollection] -> Maybe (SourceFileKey, ModuleRecord)
+ Language.Haskell.Tools.Refactor.GetModules: lookupSourceFileInSCs :: String -> [ModuleCollection] -> Maybe (SourceFileKey, ModuleRecord)
+ Language.Haskell.Tools.Refactor.GetModules: modRecLoaded :: ModuleRecord -> Bool
+ Language.Haskell.Tools.Refactor.GetModules: needsToCompile :: ToModuleCollection t => t -> ModuleName -> Bool
+ Language.Haskell.Tools.Refactor.RefactorBase: BenchmarkMC :: String -> String -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: DirectoryMC :: FilePath -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: ExecutableMC :: String -> String -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: LibraryMC :: String -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleCodeGenerated :: UnnamedModule IdDom -> ModSummary -> ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleCollection :: ModuleCollectionId -> FilePath -> [FilePath] -> Map SourceFileKey ModuleRecord -> (DynFlags -> IO DynFlags) -> (DynFlags -> IO DynFlags) -> [ModuleCollectionId] -> ModuleCollection
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleNotLoaded :: Bool -> Bool -> ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleParsed :: UnnamedModule (Dom RdrName) -> ModSummary -> ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleRenamed :: UnnamedModule (Dom Name) -> ModSummary -> ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: ModuleTypeChecked :: UnnamedModule IdDom -> ModSummary -> ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: TestSuiteMC :: String -> String -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcDependencies] :: ModuleCollection -> [ModuleCollectionId]
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcFlagSetup] :: ModuleCollection -> DynFlags -> IO DynFlags
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcId] :: ModuleCollection -> ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcLoadFlagSetup] :: ModuleCollection -> DynFlags -> IO DynFlags
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcModules] :: ModuleCollection -> Map SourceFileKey ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcRoot] :: ModuleCollection -> FilePath
+ Language.Haskell.Tools.Refactor.RefactorBase: [_mcSourceDirs] :: ModuleCollection -> [FilePath]
+ Language.Haskell.Tools.Refactor.RefactorBase: [_modRecMS] :: ModuleRecord -> ModSummary
+ Language.Haskell.Tools.Refactor.RefactorBase: [_parsedRecModule] :: ModuleRecord -> UnnamedModule (Dom RdrName)
+ Language.Haskell.Tools.Refactor.RefactorBase: [_recModuleExposed] :: ModuleRecord -> Bool
+ Language.Haskell.Tools.Refactor.RefactorBase: [_recModuleWillNeedCode] :: ModuleRecord -> Bool
+ Language.Haskell.Tools.Refactor.RefactorBase: [_renamedRecModule] :: ModuleRecord -> UnnamedModule (Dom Name)
+ Language.Haskell.Tools.Refactor.RefactorBase: [_sfkFileName] :: SourceFileKey -> FilePath
+ Language.Haskell.Tools.Refactor.RefactorBase: [_typedRecModule] :: ModuleRecord -> UnnamedModule IdDom
+ Language.Haskell.Tools.Refactor.RefactorBase: class IsRefactSessionState st
+ Language.Haskell.Tools.Refactor.RefactorBase: data ModuleCollection
+ Language.Haskell.Tools.Refactor.RefactorBase: data ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: data ModuleRecord
+ Language.Haskell.Tools.Refactor.RefactorBase: findModule :: (IsRefactSessionState st, Monad m) => String -> StateT st m [FilePath]
+ Language.Haskell.Tools.Refactor.RefactorBase: initSession :: IsRefactSessionState st => st
+ Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Classes.Eq Language.Haskell.Tools.Refactor.RefactorBase.ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Classes.Ord Language.Haskell.Tools.Refactor.RefactorBase.ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: instance GHC.Show.Show Language.Haskell.Tools.Refactor.RefactorBase.ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: mcDependencies :: Lens ModuleCollection ModuleCollection [ModuleCollectionId] [ModuleCollectionId]
+ Language.Haskell.Tools.Refactor.RefactorBase: mcFlagSetup :: Lens ModuleCollection ModuleCollection (DynFlags -> IO DynFlags) (DynFlags -> IO DynFlags)
+ Language.Haskell.Tools.Refactor.RefactorBase: mcId :: Lens ModuleCollection ModuleCollection ModuleCollectionId ModuleCollectionId
+ Language.Haskell.Tools.Refactor.RefactorBase: mcLoadFlagSetup :: Lens ModuleCollection ModuleCollection (DynFlags -> IO DynFlags) (DynFlags -> IO DynFlags)
+ Language.Haskell.Tools.Refactor.RefactorBase: mcModules :: Lens ModuleCollection ModuleCollection (Map SourceFileKey ModuleRecord) (Map SourceFileKey ModuleRecord)
+ Language.Haskell.Tools.Refactor.RefactorBase: mcRoot :: Lens ModuleCollection ModuleCollection FilePath FilePath
+ Language.Haskell.Tools.Refactor.RefactorBase: mcSourceDirs :: Lens ModuleCollection ModuleCollection [FilePath] [FilePath]
+ Language.Haskell.Tools.Refactor.RefactorBase: modRecMS :: Partial ModuleRecord ModuleRecord ModSummary ModSummary
+ Language.Haskell.Tools.Refactor.RefactorBase: moduleSourceFile :: String -> FilePath
+ Language.Haskell.Tools.Refactor.RefactorBase: parsedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule (Dom RdrName)) (UnnamedModule (Dom RdrName))
+ Language.Haskell.Tools.Refactor.RefactorBase: recModuleExposed :: Partial ModuleRecord ModuleRecord Bool Bool
+ Language.Haskell.Tools.Refactor.RefactorBase: recModuleWillNeedCode :: Partial ModuleRecord ModuleRecord Bool Bool
+ Language.Haskell.Tools.Refactor.RefactorBase: refSessMCs :: IsRefactSessionState st => Simple Lens st [ModuleCollection]
+ Language.Haskell.Tools.Refactor.RefactorBase: renamedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule (Dom Name)) (UnnamedModule (Dom Name))
+ Language.Haskell.Tools.Refactor.RefactorBase: sfkFileName :: Lens SourceFileKey SourceFileKey FilePath FilePath
+ Language.Haskell.Tools.Refactor.RefactorBase: sourceFileModule :: FilePath -> String
+ Language.Haskell.Tools.Refactor.RefactorBase: typedRecModule :: Partial ModuleRecord ModuleRecord (UnnamedModule IdDom) (UnnamedModule IdDom)
+ Language.Haskell.Tools.Refactor.Session: instance Language.Haskell.Tools.Refactor.RefactorBase.IsRefactSessionState Language.Haskell.Tools.Refactor.Session.RefactorSessionState
- Language.Haskell.Tools.Refactor.GetModules: class ToModuleCollection t
+ Language.Haskell.Tools.Refactor.GetModules: class ToModuleCollection t where getModuleSourceFiles _ = []
- Language.Haskell.Tools.Refactor.GetModules: getModules :: FilePath -> IO [ModuleCollection]
+ Language.Haskell.Tools.Refactor.GetModules: getModules :: [FilePath] -> FilePath -> IO [ModuleCollection]
- Language.Haskell.Tools.Refactor.GetModules: modulesFromCabalFile :: FilePath -> FilePath -> IO [ModuleCollection]
+ Language.Haskell.Tools.Refactor.GetModules: modulesFromCabalFile :: [FilePath] -> FilePath -> FilePath -> IO [ModuleCollection]
- Language.Haskell.Tools.Refactor.Predefined.OrganizeImports: type OrganizeImportsDomain dom = (HasNameInfo dom, HasImportInfo dom, HasModuleInfo dom)
+ Language.Haskell.Tools.Refactor.Predefined.OrganizeImports: type OrganizeImportsDomain dom = (HasNameInfo dom, HasImportInfo dom, HasModuleInfo dom, HasImplicitFieldsInfo dom)
- Language.Haskell.Tools.Refactor.Prepare: parseTyped :: ModSummary -> Ghc TypedModule
+ Language.Haskell.Tools.Refactor.Prepare: parseTyped :: FilePath -> ModSummary -> Ghc TypedModule
- Language.Haskell.Tools.Refactor.RefactorBase: ContentChanged :: (ModuleDom dom) -> RefactorChange dom
+ Language.Haskell.Tools.Refactor.RefactorBase: ContentChanged :: ModuleDom dom -> RefactorChange dom
- Language.Haskell.Tools.Refactor.RefactorBase: SourceFileKey :: IsBoot -> String -> SourceFileKey
+ Language.Haskell.Tools.Refactor.RefactorBase: SourceFileKey :: FilePath -> String -> SourceFileKey
- Language.Haskell.Tools.Refactor.RefactorBase: [fromContentChanged] :: RefactorChange dom -> (ModuleDom dom)
+ Language.Haskell.Tools.Refactor.RefactorBase: [fromContentChanged] :: RefactorChange dom -> ModuleDom dom
- Language.Haskell.Tools.Refactor.Session: getEvaluatedMods :: [ModSummary] -> Ghc [ModSummary]
+ Language.Haskell.Tools.Refactor.Session: getEvaluatedMods :: [ModSummary] -> (ModSummary -> DynFlags -> IO DynFlags) -> Ghc [ModSummary]
- Language.Haskell.Tools.Refactor.Session: loadPackagesFrom :: IsRefactSessionState st => (ModSummary -> IO a) -> ([ModSummary] -> IO ()) -> (st -> FilePath -> IO [FilePath]) -> [FilePath] -> StateT st Ghc (Either RefactorException ([a], [String]))
+ Language.Haskell.Tools.Refactor.Session: loadPackagesFrom :: IsRefactSessionState st => (ModSummary -> IO a) -> ([ModSummary] -> IO ()) -> (st -> FilePath -> IO [FilePath]) -> [FilePath] -> StateT st Ghc (Either RefactorException [a])
- Language.Haskell.Tools.Refactor.Session: type NodeKey = (ModuleName, IsBoot)
+ Language.Haskell.Tools.Refactor.Session: type NodeKey = (ModuleName, HscSource)
Files
- Language/Haskell/Tools/Refactor/ChangeAST.hs +4/−3
- Language/Haskell/Tools/Refactor/GetModules.hs +79/−61
- Language/Haskell/Tools/Refactor/Predefined/FloatOut.hs +2/−2
- Language/Haskell/Tools/Refactor/Predefined/InlineBinding.hs +1/−1
- Language/Haskell/Tools/Refactor/Predefined/OrganizeImports.hs +4/−3
- Language/Haskell/Tools/Refactor/Predefined/RenameDefinition.hs +3/−3
- Language/Haskell/Tools/Refactor/Prepare.hs +10/−6
- Language/Haskell/Tools/Refactor/RefactorBase.hs +63/−6
- Language/Haskell/Tools/Refactor/Session.hs +42/−40
- examples/CPP/BetweenImports.hs +10/−0
- examples/CPP/BetweenImports_res.hs +10/−0
- examples/Decl/InstanceFamily.hs +10/−0
- examples/Decl/ViewPatternSynonym.hs +8/−0
- examples/TH/CrossDef.hs +4/−0
- examples/TH/DoubleSplice.hs +4/−0
- examples/TH/LocalDefinition.hs +19/−0
- examples/TH/MultiImport.hs +7/−0
- examples/TH/NestedSplices.hs +6/−0
- examples/TH/Quoted.hs +6/−0
- examples/TH/WithWildcards.hs +8/−0
- haskell-tools-refactor.cabal +10/−10
- test/Main.hs +18/−8
Language/Haskell/Tools/Refactor/ChangeAST.hs view
@@ -13,12 +13,13 @@ import SrcLoc import Debug.Trace +import Data.Either -- | Remove a separator from the AST while keeping the textual parts of it that should not be removed (like preprocessor pragmas). removeSeparator :: ([SourceTemplateTextElem], SrcSpan) -> LocalRefactor dom () -removeSeparator (txts, range) = tell staying - where staying = mapMaybe (\case StayingText str lnEnd -> Just (Right (range, str, lnEnd)) - _ -> Nothing) txts +removeSeparator (txts, range) = tell [Right (range, intercalate lineEnd staying, lineEnd)] + where staying = catMaybes $ map (\case StayingText str _ -> Just str; _ -> Nothing) txts + lineEnd = head $ (catMaybes $ map (\case StayingText _ lnEnd -> Just lnEnd; _ -> Nothing) txts) ++ [""] -- | Remove an element from the AST while keeping the textual parts of it that should not be removed (like preprocessor pragmas). removeChild :: (SourceInfoTraversal e) => e dom SrcTemplateStage -> LocalRefactor dom ()
Language/Haskell/Tools/Refactor/GetModules.hs view
@@ -14,9 +14,9 @@ import Data.Function (on) import Data.List import qualified Data.Map as Map +import Data.Char import Data.Maybe import Distribution.Compiler -import Distribution.ModuleName (components) import Distribution.ModuleName import Distribution.Package (Dependency(..), PackageName(..), pkgName) import Distribution.PackageDescription @@ -26,9 +26,10 @@ import Distribution.Verbosity (silent) import Language.Haskell.Extension as Cabal import System.Directory -import System.FilePath.Posix +import System.FilePath import DynFlags +import Module (stringToUnitId) import qualified DynFlags as GHC import GHC hiding (ModuleName) import qualified Language.Haskell.TH.LanguageExtensions as GHC @@ -40,17 +41,6 @@ import Debug.Trace --- | The modules of a library, executable, test or benchmark. A package contains one or more module collection. -data ModuleCollection - = ModuleCollection { _mcId :: ModuleCollectionId - , _mcRoot :: FilePath - , _mcSourceDirs :: [FilePath] - , _mcModules :: Map.Map SourceFileKey ModuleRecord - , _mcFlagSetup :: DynFlags -> IO DynFlags -- ^ Sets up the ghc environment for compiling the modules of this collection - , _mcLoadFlagSetup :: DynFlags -> IO DynFlags -- ^ Sets up the ghc environment for dependency analysis - , _mcDependencies :: [ModuleCollectionId] - } - instance Eq ModuleCollection where (==) = (==) `on` _mcId @@ -61,30 +51,7 @@ containingMC :: FilePath -> Simple Traversal [ModuleCollection] ModuleCollection containingMC fp = traversal & filtered (\mc -> _mcRoot mc `isPrefixOf` fp) --- | The state of a module. -data ModuleRecord - = ModuleNotLoaded { _recModuleWillNeedCode :: Bool } - | ModuleParsed { _parsedRecModule :: UnnamedModule (Dom RdrName) - , _modRecMS :: ModSummary - } - | ModuleRenamed { _renamedRecModule :: UnnamedModule (Dom Name) - , _modRecMS :: ModSummary - } - | ModuleTypeChecked { _typedRecModule :: UnnamedModule IdDom - , _modRecMS :: ModSummary - } - | ModuleCodeGenerated { _typedRecModule :: UnnamedModule IdDom - , _modRecMS :: ModSummary - } --- | This data structure identifies a module collection. -data ModuleCollectionId = DirectoryMC FilePath - | LibraryMC String - | ExecutableMC String String - | TestSuiteMC String String - | BenchmarkMC String String - deriving (Eq, Ord, Show) - moduleCollectionIdString :: ModuleCollectionId -> String moduleCollectionIdString (DirectoryMC fp) = fp moduleCollectionIdString (LibraryMC id) = id @@ -99,37 +66,46 @@ moduleCollectionPkgId (TestSuiteMC id _) = Just id moduleCollectionPkgId (BenchmarkMC id _) = Just id -makeReferences ''ModuleCollection -makeReferences ''ModuleRecord - instance Show ModuleRecord where - show (ModuleNotLoaded code) = "ModuleNotLoaded " ++ show code + show (ModuleNotLoaded code exposed) = "ModuleNotLoaded " ++ show code ++ " " ++ show exposed show mr@(ModuleParsed {}) = "ModuleParsed (" ++ (GHC.moduleNameString $ GHC.moduleName $ GHC.ms_mod $ fromJust $ mr ^? modRecMS) ++ ")" show mr@(ModuleRenamed {}) = "ModuleRenamed (" ++ (GHC.moduleNameString $ GHC.moduleName $ GHC.ms_mod $ fromJust $ mr ^? modRecMS) ++ ")" show mr@(ModuleTypeChecked {}) = "ModuleTypeChecked (" ++ (GHC.moduleNameString $ GHC.moduleName $ GHC.ms_mod $ fromJust $ mr ^? modRecMS) ++ ")" show mr@(ModuleCodeGenerated {}) = "ModuleCodeGenerated (" ++ (GHC.moduleNameString $ GHC.moduleName $ GHC.ms_mod $ fromJust $ mr ^? modRecMS) ++ ")" +modRecLoaded :: ModuleRecord -> Bool +modRecLoaded ModuleTypeChecked{} = True +modRecLoaded ModuleCodeGenerated{} = True +modRecLoaded _ = False + -- | Find the module collection where the given module is. lookupModuleColl :: String -> [ModuleCollection] -> Maybe (ModuleCollection) lookupModuleColl moduleName = find (any ((moduleName ==) . (^. sfkModuleName)) . Map.keys . (^. mcModules)) lookupModInSCs :: SourceFileKey -> [ModuleCollection] -> Maybe (SourceFileKey, ModuleRecord) -lookupModInSCs moduleName = find ((moduleName ==) . fst) . concatMap (Map.assocs . (^. mcModules)) +lookupModInSCs moduleName = find (((moduleName ^. sfkFileName) ==) . (^. sfkFileName) . fst) . concatMap (Map.assocs . (^. mcModules)) +lookupSourceFileInSCs :: String -> [ModuleCollection] -> Maybe (SourceFileKey, ModuleRecord) +lookupSourceFileInSCs fileName = find ((fileName ==) . (^. sfkFileName) . fst) . concatMap (Map.assocs . (^. mcModules)) + +lookupModuleInSCs :: String -> [ModuleCollection] -> Maybe (SourceFileKey, ModuleRecord) +lookupModuleInSCs moduleName = find ((moduleName ==) . (^. sfkModuleName) . fst) . concatMap (Map.assocs . (^. mcModules)) + + removeModule :: String -> [ModuleCollection] -> [ModuleCollection] removeModule moduleName = map (mcModules .- Map.filterWithKey (\k _ -> moduleName /= (k ^. sfkModuleName))) hasGeneratedCode :: SourceFileKey -> [ModuleCollection] -> Bool -hasGeneratedCode key = maybe False (\case (_, ModuleCodeGenerated {}) -> True; _ -> False) - . find ((key ==) . fst) . concatMap (Map.assocs . (^. mcModules)) +hasGeneratedCode key = maybe False ((\case ModuleCodeGenerated {} -> True; _ -> False) . snd) + . lookupModInSCs key needsGeneratedCode :: SourceFileKey -> [ModuleCollection] -> Bool -needsGeneratedCode key = maybe False (\case (_, ModuleCodeGenerated {}) -> True; (_, ModuleNotLoaded True) -> True; _ -> False) - . find (((sfkIsBoot .= NormalHs $ key) ==) . fst) . concatMap (Map.assocs . (^. mcModules)) +needsGeneratedCode key = maybe False ((\case ModuleCodeGenerated {} -> True; ModuleNotLoaded True _ -> True; _ -> False) . snd) + . lookupModInSCs key codeGeneratedFor :: SourceFileKey -> [ModuleCollection] -> [ModuleCollection] codeGeneratedFor key = map (mcModules .- Map.adjust (\case (ModuleTypeChecked mod ms) -> ModuleCodeGenerated mod ms - ModuleNotLoaded _ -> ModuleNotLoaded True + ModuleNotLoaded _ exp -> ModuleNotLoaded True exp r -> r) key) isAlreadyLoaded :: SourceFileKey -> [ModuleCollection] -> Bool @@ -140,7 +116,7 @@ -- they can be loaded in the order they are defined (no backward imports). This matters in those cases because for them there can be -- special compilation flags. getAllModules :: [FilePath] -> IO [ModuleCollection] -getAllModules pathes = orderMCs . concat <$> mapM getModules pathes +getAllModules pathes = orderMCs . concat <$> mapM (getModules pathes) (map normalise pathes) -- | Sorts model collection in an order to remove all backward references. -- Works because module collections defined by directories cannot be recursive. @@ -157,13 +133,14 @@ -- | Get modules of the project with the indicated root directory. -- If there is a cabal file, it uses that, otherwise it just scans the directory recursively for haskell sourcefiles. -- Only returns the non-boot haskell modules, the boot modules will be found during loading. -getModules :: FilePath -> IO [ModuleCollection] -getModules root +getModules :: [FilePath] -> FilePath -> IO [ModuleCollection] +getModules allRoots root = do files <- listDirectory root case find (\p -> takeExtension p == ".cabal") files of - Just cabalFile -> modulesFromCabalFile root cabalFile + Just cabalFile -> modulesFromCabalFile allRoots root cabalFile Nothing -> do mods <- modulesFromDirectory root root - return [ModuleCollection (DirectoryMC root) root [root] (Map.fromList $ map ((, ModuleNotLoaded False) . SourceFileKey NormalHs) mods) return return []] + return [ModuleCollection (DirectoryMC root) root [root] (modKeys mods) return return []] + where modKeys mods = Map.fromList $ map (\m -> (SourceFileKey (root </> moduleSourceFile m) m, ModuleNotLoaded False True)) mods -- | Load the module giving a directory. All modules loaded from the folder and subfolders. modulesFromDirectory :: FilePath -> FilePath -> IO [String] @@ -184,10 +161,20 @@ -- | Load the module using a cabal file. The modules described in the cabal file will be loaded. -- The flags and extensions set in the cabal file will be used by default. -modulesFromCabalFile :: FilePath -> FilePath -> IO [ModuleCollection] +modulesFromCabalFile :: [FilePath] -> FilePath -> FilePath -> IO [ModuleCollection] -- now adding all conditional entries, regardless of flags -modulesFromCabalFile root cabal = getModules . setupFlags <$> readPackageDescription silent (root </> cabal) - where getModules pkg = maybe [] (maybe [] (:[]) . toModuleCollection pkg) (library pkg) +modulesFromCabalFile allRoots root cabal = (getModules . setupFlags <$> readPackageDescription silent (root </> cabal)) >>= filterModules + where filterModules :: [ModuleCollection] -> IO [ModuleCollection] + filterModules = traversal & mcModules !~ filterKeys + where filterKeys :: Show v => Map.Map SourceFileKey v -> IO (Map.Map SourceFileKey v) + filterKeys = (Map.fromList . concat . map snd + . map (\ls -> if null (snd ls) then error ("No source file found for module: " ++ (fst ls)) else ls) <$>) + . mapM (\(mn,ls) -> (mn,) <$> filterM (doesFileExist . (^. sfkFileName) . fst) ls) + . map (\ls -> ((fst $ head ls) ^. sfkModuleName, ls)) + . groupBy ((==) `on` (^. sfkModuleName) . fst) + . sortBy (compare `on` (^. sfkModuleName) . fst) . Map.assocs + + getModules pkg = maybe [] (maybe [] (:[]) . toModuleCollection pkg) (library pkg) ++ catMaybes (map (toModuleCollection pkg) (executables pkg)) ++ catMaybes (map (toModuleCollection pkg) (testSuites pkg)) ++ catMaybes (map (toModuleCollection pkg) (benchmarks pkg)) @@ -195,16 +182,26 @@ toModuleCollection :: ToModuleCollection tmc => PackageDescription -> tmc -> Maybe ModuleCollection toModuleCollection pkg tmc = let bi = getBuildInfo tmc + packageName = pkgName $ package pkg in if buildable bi - then Just $ ModuleCollection (mkModuleCollKey (pkgName $ package pkg) tmc) + then Just $ ModuleCollection (mkModuleCollKey packageName tmc) root (map (normalise . (root </>)) $ hsSourceDirs bi) - (Map.fromList $ map ((, ModuleNotLoaded False) . SourceFileKey NormalHs . moduleName) (getModuleNames tmc)) + (Map.fromList $ concatMap (modRecord (hsSourceDirs bi) allRoots) $ getModuleNames tmc) (flagsFromBuildInfo bi) (loadFlagsFromBuildInfo bi) (map (\(Dependency pkgName _) -> LibraryMC (unPackageName pkgName)) (targetBuildDepends bi)) else Nothing - + where modRecord srcs allRoots mn = map (\d -> ( SourceFileKey (getPath d mn) (moduleName mn) + , ModuleNotLoaded False (needsToCompile tmc mn) )) srcs + ++ map (\d -> ( SourceFileKey (getOtherRootPath d mn) (moduleName mn) + , ModuleNotLoaded False (needsToCompile tmc mn) )) allRoots + getPath d mn = case lookup mn (getModuleSourceFiles tmc) of + Just fp -> normalise (root </> d </> fp) + Nothing -> normalise (root </> d </> (moduleSourceFile $ moduleName mn)) + getOtherRootPath d mn = case lookup mn (getModuleSourceFiles tmc) of + Just fp -> normalise (d </> fp) + Nothing -> normalise (d </> (moduleSourceFile $ moduleName mn)) moduleName = concat . intersperse "." . components setupFlags = either (\deps -> error $ "Missing dependencies: " ++ show deps) fst . finalizePackageDescription [] (const True) buildPlatform @@ -214,27 +211,48 @@ mkModuleCollKey :: PackageName -> t -> ModuleCollectionId getBuildInfo :: t -> BuildInfo getModuleNames :: t -> [ModuleName] + getModuleSourceFiles :: t -> [(ModuleName, FilePath)] + getModuleSourceFiles _ = [] + needsToCompile :: t -> ModuleName -> Bool instance ToModuleCollection Library where mkModuleCollKey pn _ = LibraryMC (unPackageName pn) getBuildInfo = libBuildInfo getModuleNames = libModules + needsToCompile l m = m `elem` exposedModules l instance ToModuleCollection Executable where mkModuleCollKey pn exe = ExecutableMC (unPackageName pn) (exeName exe) getBuildInfo = buildInfo - getModuleNames e = {- fromString (toModuleName $ modulePath e) : -} exeModules e - where toModuleName = map (\case c | c `elem` pathSeparators -> '.'; c -> c) . dropExtension + getModuleNames exe = fromString (getMain (buildInfo exe)) : exeModules exe + needsToCompile exe mn = components mn == [getMain (buildInfo exe)] + getModuleSourceFiles exe = [(fromString (getMain (buildInfo exe)), modulePath exe)] instance ToModuleCollection TestSuite where mkModuleCollKey pn test = TestSuiteMC (unPackageName pn) (testName test) getBuildInfo = testBuildInfo - getModuleNames = testModules + getModuleNames exe = fromString (getMain (testBuildInfo exe)) : testModules exe + needsToCompile exe mn = components mn == [getMain (testBuildInfo exe)] + getModuleSourceFiles exe + = case testInterface exe of + TestSuiteExeV10 _ fp -> [(fromString (getMain (testBuildInfo exe)), fp)] + _ -> [] instance ToModuleCollection Benchmark where mkModuleCollKey pn test = BenchmarkMC (unPackageName pn) (benchmarkName test) getBuildInfo = benchmarkBuildInfo - getModuleNames = benchmarkModules + getModuleNames exe = fromString (getMain (benchmarkBuildInfo exe)) : benchmarkModules exe + needsToCompile exe mn = components mn == [getMain (benchmarkBuildInfo exe)] + getModuleSourceFiles exe + = case benchmarkInterface exe of + BenchmarkExeV10 _ fp -> [(fromString (getMain (benchmarkBuildInfo exe)), fp)] + _ -> [] + +getMain :: BuildInfo -> String +getMain bi + = case ls of _:e:_ -> intercalate "." $ filter (isUpper . head) $ groupBy ((==) `on` (== '.')) e + _ -> "Main" + where ls = dropWhile (/= "-main-is") (concatMap snd (options bi)) isDirectoryMC :: ModuleCollection -> Bool isDirectoryMC mc = case mc ^. mcId of DirectoryMC{} -> True; _ -> False
Language/Haskell/Tools/Refactor/Predefined/FloatOut.hs view
@@ -64,7 +64,7 @@ checkConflict bnd = (concatMap @[] getConflict bndNames, implicits) where bndNames = bnd ^? elementName getConflict bndName = filter ((== nameStr) . Just) $ map (occNameString . getOccName) outerScope - where outerScope = concat $ take 1 $ drop 2 $ semanticsScope bndName + where outerScope = map fst $ concat $ take 1 $ drop 2 $ semanticsScope bndName nameStr = fmap (occNameString . getOccName) $ semanticsName bndName implicits = map (occNameString . getOccName) (concatMap getPossibleImplicits bndNames `intersect` getQNames (bnd ^? biplateRef)) @@ -73,4 +73,4 @@ getQNames = catMaybes . map semanticsName getPossibleImplicits :: QualifiedName dom -> [GHC.Name] - getPossibleImplicits qn = concat (take 2 $ semanticsScope qn) \\ catMaybes (map semanticsName bndNames) + getPossibleImplicits qn = concat (map (map fst) $ take 2 $ semanticsScope qn) \\ catMaybes (map semanticsName bndNames)
Language/Haskell/Tools/Refactor/Predefined/InlineBinding.hs view
@@ -108,7 +108,7 @@ RealSrcSpan ownRange | bindingRange `containsSpan` ownRange -> lift $ refactError "Cannot inline definitions containing direct recursion." _ -> do put True - replacement (semanticsScope expr) <$> mapM (descendM (replaceInvocations bindingRange name replacement)) args + replacement (map (map fst) $ semanticsScope expr) <$> mapM (descendM (replaceInvocations bindingRange name replacement)) args | otherwise = descendM (replaceInvocations bindingRange name replacement) expr
Language/Haskell/Tools/Refactor/Predefined/OrganizeImports.hs view
@@ -36,7 +36,7 @@ import Debug.Trace -type OrganizeImportsDomain dom = ( HasNameInfo dom, HasImportInfo dom, HasModuleInfo dom ) +type OrganizeImportsDomain dom = ( HasNameInfo dom, HasImportInfo dom, HasModuleInfo dom, HasImplicitFieldsInfo dom ) projectOrganizeImports :: forall dom . OrganizeImportsDomain dom => Refactoring dom projectOrganizeImports mod mods @@ -62,10 +62,11 @@ where prelInstances = semanticsPrelOrphanInsts mod prelFamInsts = semanticsPrelFamInsts mod addFromString dfs = if xopt OverloadedStrings dfs then (GHC.fromStringName :) else id - usedNames = map getName $ catMaybes $ map semanticsName + usedNames = map getName $ (catMaybes $ map semanticsName -- obviously we don't want the names in the imports to be considered, but both from -- the declarations (used), both from the module head (re-exported) will count as usage - $ (universeBi (mod ^. modHead) ++ universeBi (mod ^. modDecl) :: [QualifiedName dom]) + (universeBi (mod ^. modHead) ++ universeBi (mod ^. modDecl) :: [QualifiedName dom])) + ++ concatMap (map fst . semanticsImplicitFlds) (universeBi (mod ^. modDecl) :: [FieldWildcard dom]) -- Prelude is not actually exported, but we don't want to remove it if it is explicitly there -- otherwise, we might add new imported elements that cause conflicts. exportedModules = "Prelude" : (mod ^? modHead & annJust & mhExports & annJust
Language/Haskell/Tools/Refactor/Predefined/RenameDefinition.hs view
@@ -55,7 +55,7 @@ $ mapM (\(name,mod) -> ContentChanged . (name,) <$> localRefactoringRes id mod (replaceModuleNames =<< alterNormalNames mod)) (m:mods) where alterChange from to (ContentChanged (mod,res)) | (mod ^. sfkModuleName) == from - = ModuleCreated to res (SourceFileKey NormalHs from) + = ModuleCreated to res mod alterChange _ _ c = c replaceModuleNames :: LocalRefactoring dom @@ -98,14 +98,14 @@ | maybe False (`elem` toChange) actualName && semanticsDefining name == False && any @[] (\n -> str == occNameString (getOccName n) && not (mergeableFields origId n)) - (scopeUpToDef (semanticsScope name) ^? traversal & traversal & filtered (sameNamespace toChangeOrig)) + (scopeUpToDef (map (map fst) $ semanticsScope name) ^? traversal & traversal & filtered (sameNamespace toChangeOrig)) = refactError $ "The definition clashes with an existing one at: " ++ shortShowSpan (getRange name) -- name clash with an external definition | maybe False (`elem` toChange) actualName = do put True -- state that something is changed in the local state when (actualName == Just toChangeOrig) $ lift $ modify (|| semanticsDefining name) -- state that the definition is renamed in the global state return $ unqualifiedName .= mkNamePart str $ name -- found the changed name (or a name that have to be changed too) - | let namesInScope = semanticsScope name + | let namesInScope = map (map fst) $ semanticsScope name in case semanticsName name of Just (getName -> exprName) -> str == occNameString (getOccName exprName) && sameNamespace toChangeOrig exprName
Language/Haskell/Tools/Refactor/Prepare.hs view
@@ -48,8 +48,8 @@ = runGhc (Just libdir) $ do initGhcFlags useDirs ["."] - mod <- loadModule "." moduleName >>= parseTyped - res <- runRefactor (SourceFileKey NormalHs moduleName, mod) [] + mod <- loadModule "." moduleName >>= parseTyped "." + res <- runRefactor (SourceFileKey (moduleSourceFile moduleName) moduleName, mod) [] $ refact $ correctRefactorSpan mod $ readSrcSpan span case res of Right r -> liftIO $ mapM_ (putStrLn . prettyPrint . snd . fromContentChanged) r Left err -> liftIO $ putStrLn err @@ -150,13 +150,17 @@ type TypedModule = Ann AST.UModule IdDom SrcTemplateStage -- | Get the typed representation from a type-correct program. -parseTyped :: ModSummary -> Ghc TypedModule -parseTyped modSum = withAlteredDynFlags (return . normalizeFlags) $ do +parseTyped :: FilePath -> ModSummary -> Ghc TypedModule +parseTyped wd modSum = withAlteredDynFlags (return . normalizeFlags) $ do let hasStaticFlags = StaticPointers `xopt` ms_hspp_opts modSum hasCppExtension = Cpp `xopt` ms_hspp_opts modSum - ms = if hasStaticFlags then forceAsmGen (modSumNormalizeFlags modSum) else (modSumNormalizeFlags modSum) + hasApplicativeDo = ApplicativeDo `xopt` ms_hspp_opts modSum + hasOverloadedLabels = OverloadedLabels `xopt` ms_hspp_opts modSum + ms = if hasStaticFlags then forceAsmGen (modSumNormalizeFlags modSum) else (modSumNormalizeFlags modSum)+ when hasApplicativeDo $ error "The ApplicativeDo extension is not supported" + when hasOverloadedLabels $ error "The OverloadedLabels extension is not supported" p <- parseModule ms - tc <- typecheckModule p + tc <- typecheckModule p -- template haskell needs the correct working directory in the type check phase void $ GHC.loadModule tc -- when used with loadModule, the module will be loaded twice let annots = pm_annotations p srcBuffer <- if hasCppExtension
Language/Haskell/Tools/Refactor/RefactorBase.hs view
@@ -9,6 +9,7 @@ , MultiWayIf , TemplateHaskell , ViewPatterns + , TypeApplications #-} -- | Basic utilities and types for defining refactorings. module Language.Haskell.Tools.Refactor.RefactorBase where @@ -21,7 +22,7 @@ import DynFlags (HasDynFlags(..)) import ErrUtils as GHC import Exception (ExceptionMonad(..)) -import GHC (Ghc, GhcMonad(..), TyThing(..), lookupName) +import GHC hiding (mkModuleName, moduleNameString) import qualified Module as GHC import qualified Name as GHC import Outputable @@ -40,10 +41,12 @@ import Data.Char import Data.Either import Data.Function (on) +import qualified Data.Map as Map import Data.List import Data.List.Split import Data.Maybe import Data.Typeable +import System.FilePath -- | A type for the input and result of refactoring a module type UnnamedModule dom = Ann AST.UModule dom SrcTemplateStage @@ -52,14 +55,11 @@ type ModuleDom dom = (SourceFileKey, UnnamedModule dom) -- | Module name and marker to separate .hs-boot module definitions. Specifies a source file in a working directory. -data SourceFileKey = SourceFileKey { _sfkIsBoot :: IsBoot +data SourceFileKey = SourceFileKey { _sfkFileName :: FilePath , _sfkModuleName :: String } deriving (Eq, Ord, Show) --- | Decides if a module is a .hs-boot file or a normal .hs file -data IsBoot = NormalHs | IsHsBoot deriving (Eq, Ord, Show) - -- | A refactoring that only affects one module type LocalRefactoring dom = UnnamedModule dom -> LocalRefactor dom (UnnamedModule dom) @@ -67,7 +67,7 @@ type Refactoring dom = ModuleDom dom -> [ModuleDom dom] -> Refactor [RefactorChange dom] -- | Change in the project, modification or removal of a module. -data RefactorChange dom = ContentChanged { fromContentChanged :: (ModuleDom dom) } +data RefactorChange dom = ContentChanged { fromContentChanged :: ModuleDom dom } | ModuleRemoved { removedModuleName :: String } | ModuleCreated { createdModuleName :: String , createdModuleContent :: UnnamedModule dom @@ -81,6 +81,55 @@ | UnknownException String deriving (Show, Typeable) +moduleSourceFile :: String -> FilePath +moduleSourceFile m = (foldl1 (</>) (splitOn "." m)) <.> "hs" + +sourceFileModule :: FilePath -> String +sourceFileModule fp = intercalate "." $ splitDirectories $ dropExtension fp + + +-- | The modules of a library, executable, test or benchmark. A package contains one or more module collection. +data ModuleCollection + = ModuleCollection { _mcId :: ModuleCollectionId + , _mcRoot :: FilePath + , _mcSourceDirs :: [FilePath] + , _mcModules :: Map.Map SourceFileKey ModuleRecord + , _mcFlagSetup :: DynFlags -> IO DynFlags -- ^ Sets up the ghc environment for compiling the modules of this collection + , _mcLoadFlagSetup :: DynFlags -> IO DynFlags -- ^ Sets up the ghc environment for dependency analysis + , _mcDependencies :: [ModuleCollectionId] + } + +-- | The state of a module. +data ModuleRecord + = ModuleNotLoaded { _recModuleWillNeedCode :: Bool + , _recModuleExposed :: Bool + } + | ModuleParsed { _parsedRecModule :: UnnamedModule (Dom RdrName) + , _modRecMS :: ModSummary + } + | ModuleRenamed { _renamedRecModule :: UnnamedModule (Dom GHC.Name) + , _modRecMS :: ModSummary + } + | ModuleTypeChecked { _typedRecModule :: UnnamedModule IdDom + , _modRecMS :: ModSummary + } + | ModuleCodeGenerated { _typedRecModule :: UnnamedModule IdDom + , _modRecMS :: ModSummary + } + +-- | This data structure identifies a module collection. +data ModuleCollectionId = DirectoryMC FilePath + | LibraryMC String + | ExecutableMC String String + | TestSuiteMC String String + | BenchmarkMC String String + deriving (Eq, Ord, Show) + +-- | A common class for the state of refactoring tools +class IsRefactSessionState st where + refSessMCs :: Simple Lens st [ModuleCollection] + initSession :: st + instance Show ErrorMessages where show = show . bagToList @@ -397,3 +446,11 @@ isOperatorChar c = (isPunctuation c || isSymbol c) && isAscii c makeReferences ''SourceFileKey +makeReferences ''ModuleCollection +makeReferences ''ModuleRecord + + +findModule :: (IsRefactSessionState st, Monad m) => String -> StateT st m [FilePath] +findModule m = do + mods <- gets (^? refSessMCs & traversal & mcModules) + return $ concatMap @[] (map (^. sfkFileName) . filter ((== m) . (^. sfkModuleName)) . Map.keys) mods
Language/Haskell/Tools/Refactor/Session.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE TemplateHaskell , TupleSections + , TypeApplications #-} -- | Common operations for managing refactoring sessions, for example loading packages, re-loading modules. module Language.Haskell.Tools.Refactor.Session where @@ -11,6 +12,7 @@ import qualified Data.Map as Map import Data.Maybe import System.FilePath +import System.IO import Data.IntSet (member) import Digraph as GHC @@ -18,6 +20,7 @@ import Exception (ExceptionMonad) import FastString as GHC import GHC +import DynFlags import HscTypes as GHC import Language.Haskell.TH.LanguageExtensions import Outputable @@ -34,17 +37,12 @@ makeReferences ''RefactorSessionState --- | A common class for the state of refactoring tools -class IsRefactSessionState st where - refSessMCs :: Simple Lens st [ModuleCollection] - initSession :: st - instance IsRefactSessionState RefactorSessionState where refSessMCs = _refSessMCs initSession = RefactorSessionState [] -- | Load packages from the given directories. Loads modules, performs the given callback action, warns for duplicate modules. -loadPackagesFrom :: IsRefactSessionState st => (ModSummary -> IO a) -> ([ModSummary] -> IO ()) -> (st -> FilePath -> IO [FilePath]) -> [FilePath] -> StateT st Ghc (Either RefactorException ([a], [String])) +loadPackagesFrom :: IsRefactSessionState st => (ModSummary -> IO a) -> ([ModSummary] -> IO ()) -> (st -> FilePath -> IO [FilePath]) -> [FilePath] -> StateT st Ghc (Either RefactorException [a]) loadPackagesFrom report loadCallback additionalSrcDirs packages = do modColls <- liftIO $ getAllModules packages modify $ refSessMCs .- (++ modColls) @@ -52,27 +50,28 @@ st <- get moreSrcDirs <- liftIO $ mapM (additionalSrcDirs st) packages lift $ useDirs ((modColls ^? traversal & mcSourceDirs & traversal) ++ concat moreSrcDirs) - let (ignored, modNames) = extractDuplicates $ map (^. sfkModuleName) $ concat $ map Map.keys $ modColls ^? traversal & mcModules - alreadyExistingMods = concatMap (map (^. sfkModuleName) . Map.keys . (^. mcModules)) (allModColls List.\\ modColls) - lift $ mapM_ addTarget $ map (\mod -> (Target (TargetModule (GHC.mkModuleName mod)) True Nothing)) modNames + let fileNames = map (^. sfkFileName) $ concat + $ map (Map.keys . Map.filter (\v -> fromMaybe True (v ^? recModuleExposed))) + $ modColls ^? traversal & mcModules + alreadyLoadedFilesInOtherPackages + = concatMap (map (^. sfkFileName) . Map.keys . Map.filter (isJust . (^? typedRecModule)) . (^. mcModules)) + (filter (\mc -> (mc ^. mcRoot) `notElem` packages) allModColls) + targets <- map targetId <$> (lift getTargets) + lift $ mapM_ (\t -> when (targetId t `notElem` targets) (addTarget t)) + $ map (\f -> (Target (TargetFile f Nothing) True Nothing)) fileNames handleErrors $ withAlteredDynFlags (liftIO . setupLoadFlags allModColls) $ do modsForColls <- lift $ depanal [] True let modsToParse = flattenSCCs $ topSortModuleGraph False modsForColls Nothing - actuallyCompiled = filter (\ms -> modSumName ms `notElem` alreadyExistingMods) modsToParse - liftIO $ loadCallback actuallyCompiled - void $ checkEvaluatedMods (\_ -> return ()) modsToParse + actuallyCompiled = filter (\ms -> getModSumOrig ms `notElem` alreadyLoadedFilesInOtherPackages) modsToParse + liftIO $ loadCallback actuallyCompiled+ void $ checkEvaluatedMods (\_ -> return ()) actuallyCompiled mods <- mapM (loadModule report) actuallyCompiled - return (mods, ignored) - - where extractDuplicates :: Eq a => [a] -> ([a],[a]) - extractDuplicates (a:rest) - = case extractDuplicates rest of (repl, orig) -> if a `elem` orig then (a:repl, orig) else (repl, a:orig) - extractDuplicates [] = ([],[]) + return mods - loadModule :: IsRefactSessionState st => (ModSummary -> IO a) -> ModSummary -> StateT st Ghc a - loadModule report ms = do - needsCodeGen <- gets (needsGeneratedCode (keyFromMS ms) . (^. refSessMCs)) - reloadModule report (if needsCodeGen then forceCodeGen ms else ms) + where loadModule :: IsRefactSessionState st => (ModSummary -> IO a) -> ModSummary -> StateT st Ghc a + loadModule report ms+ = do needsCodeGen <- gets (needsGeneratedCode (keyFromMS ms) . (^. refSessMCs))+ reloadModule report (if needsCodeGen then forceCodeGen ms else ms) -- | Handle GHC exceptions and RefactorException. handleErrors :: ExceptionMonad m => m a -> m (Either RefactorException a) @@ -80,7 +79,7 @@ `gcatch` (return . Left) keyFromMS :: ModSummary -> SourceFileKey -keyFromMS ms = SourceFileKey (case ms_hsc_src ms of HsSrcFile -> NormalHs; _ -> IsHsBoot) (modSumName ms) +keyFromMS ms = SourceFileKey (normalise $ getModSumOrig ms) (modSumName ms) getMods :: (Monad m, IsRefactSessionState st) => Maybe SourceFileKey -> StateT st m ( Maybe (SourceFileKey, UnnamedModule IdDom) @@ -95,7 +94,7 @@ , [(SourceFileKey, UnnamedModule IdDom)] ) getFileMods fname = do mcs <- gets (^. refSessMCs) - let mods = map (\(k,m) -> (fromJust $ m ^? modRecMS, k)) + let mods = map (\(k,m) -> (fromMaybe (error $ "getFileMods: module not loaded: " ++ show m) $ m ^? modRecMS, k)) (concatMap Map.assocs $ (mcs ^? traversal & mcModules :: [Map.Map SourceFileKey ModuleRecord])) let sfs = catMaybes $ map (\(ms,k) -> if Just fname == fmap normalise (ml_hs_file (ms_location ms)) then Just k else Nothing) mods case sfs of sf:_ -> getMods (Just sf) @@ -133,17 +132,22 @@ let dfs = ms_hspp_opts ms dfs' <- liftIO $ compileInContext mc mcs dfs let ms' = ms { ms_hspp_opts = dfs' } - newm <- lift $ withAlteredDynFlags (liftIO . compileInContext mc mcs) $ - parseTyped (if codeGen then forceCodeGen ms' else ms') - modify $ refSessMCs & traversal & filtered (\mc' -> (mc' ^. mcRoot) == (mc ^. mcRoot)) & mcModules + newm <- lift $ withAlteredDynFlags (\_ -> return (ms_hspp_opts ms')) $ + parseTyped (mc ^. mcRoot) (if codeGen then forceCodeGen ms' else ms') + modify $ refSessMCs & traversal & filtered (== mc) & mcModules .- Map.insert (keyFromMS ms) ((if codeGen then ModuleCodeGenerated else ModuleTypeChecked) newm ms) liftIO $ report ms Nothing -> liftIO $ throwIO $ ModuleNotInPackage modName checkEvaluatedMods :: IsRefactSessionState st => (ModSummary -> IO a) -> [ModSummary] -> StateT st Ghc [a] checkEvaluatedMods report mods = do - modsNeedCode <- lift (getEvaluatedMods mods) mcs <- gets (^. refSessMCs) + let lookupFlags ms = maybe return (^. mcFlagSetup) mc + where modName = modSumName ms + mc = lookupModuleColl modName mcs + + modsNeedCode <- lift (getEvaluatedMods mods lookupFlags) + mcs <- gets (^. refSessMCs) res <- forM modsNeedCode $ \ms -> reloadIfNeeded ms mcs return $ catMaybes res where reloadIfNeeded ms mcs @@ -166,17 +170,20 @@ mc = fromMaybe (error $ "codeGenForModule: The following module is not found: " ++ modName) $ lookupModuleColl modName mcs in -- TODO: don't recompile, only load? do withAlteredDynFlags (liftIO . compileInContext mc mcs) - $ void $ parseTyped (forceCodeGen ms) + $ void $ parseTyped (mc ^. mcRoot) (forceCodeGen ms) liftIO $ report ms -- | Check which modules can be reached from the module, if it uses template haskell. -getEvaluatedMods :: [ModSummary] -> Ghc [GHC.ModSummary] +getEvaluatedMods :: [ModSummary] -> (ModSummary -> DynFlags -> IO DynFlags) -> Ghc [GHC.ModSummary] -- We cannot really get the modules that need to be linked, because we cannot rename splice content if the -- module is not type checked and that is impossible if the splice cannot be evaluated. -getEvaluatedMods mods +getEvaluatedMods mods additionalFlags = do allMods <- getModuleGraph + flags <- getSessionDynFlags let (allModsGraph, lookup) = moduleGraphNodes False allMods - modsWithTH = catMaybes $ map (\ms -> lookup (ms_hsc_src ms) (moduleName $ ms_mod ms)) $ filter isTH mods + -- some flags are stored only in the module collection and are not recorded in the summary + thmods <- liftIO $ filterM (\ms -> ((|| isTH ms) . xopt TemplateHaskell) <$> additionalFlags ms flags) mods + let modsWithTH = catMaybes $ map (\ms -> lookup (ms_hsc_src ms) (moduleName $ ms_mod ms)) thmods recompMods = map (moduleName . ms_mod . getModFromNode) $ reachablesG allModsGraph modsWithTH sortedMods = map getModFromNode $ reverse $ topologicalSortG allModsGraph sortedTHMods = filter ((`elem` recompMods) . moduleName . ms_mod) sortedMods @@ -189,7 +196,7 @@ -- * code copied from GHC because it is not public in GhcMake module -type NodeKey = (ModuleName, IsBoot) +type NodeKey = (ModuleName, HscSource) type NodeMap a = Map.Map NodeKey a type SummaryNode = (ModSummary, Int, [Int]) @@ -203,14 +210,13 @@ numbered_summaries = zip summaries [1..] lookup_node :: HscSource -> ModuleName -> Maybe SummaryNode - lookup_node hs_src mod = Map.lookup (mod, hscSourceToIsBoot hs_src) node_map + lookup_node hs_src mod = Map.lookup (mod, hs_src) node_map lookup_key :: HscSource -> ModuleName -> Maybe Int lookup_key hs_src mod = fmap summaryNodeKey (lookup_node hs_src mod) node_map :: NodeMap SummaryNode - node_map = Map.fromList [ ((moduleName (ms_mod s), - hscSourceToIsBoot (ms_hsc_src s)), node) + node_map = Map.fromList [ ((moduleName (ms_mod s), (ms_hsc_src s)), node) | node@(s, _, _) <- nodes ] nodes :: [SummaryNode] @@ -231,10 +237,6 @@ out_edge_keys :: HscSource -> [ModuleName] -> [Int] out_edge_keys hi_boot ms = mapMaybe (lookup_key hi_boot) ms - -hscSourceToIsBoot :: HscSource -> IsBoot -hscSourceToIsBoot HsBootFile = IsHsBoot -hscSourceToIsBoot _ = NormalHs summaryNodeKey :: SummaryNode -> Int summaryNodeKey (_, k, _) = k
+ examples/CPP/BetweenImports.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleContexts #-} +module CPP.BetweenImports where + +import Data.List +#if !(MIN_VERSION_text(1,2,1)) +#endif +import Data.Maybe + +x = Just
+ examples/CPP/BetweenImports_res.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleContexts #-} +module CPP.BetweenImports where + +import Data.Maybe (Maybe(..)) +#if !(MIN_VERSION_text(1,2,1)) +#endif + + +x = Just
+ examples/Decl/InstanceFamily.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE TypeOperators, TypeFamilies #-} +module Decl.InstanceFamily where + +import GHC.Generics + +class HasTrie a where + data (:->:) a :: * -> * + +instance (HasTrie (f x)) => HasTrie (M1 i t f x) where + data (M1 i t f x :->: b) = M1Trie (f x :->: b)
+ examples/Decl/ViewPatternSynonym.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE PatternSynonyms, ViewPatterns #-} +module Decl.ViewPatternSynonym where + +data Uncert a = Un a a + +pattern x :+/- dx <- Un x (sqrt->dx) + where + x :+/- dx = Un x (dx*dx)
+ examples/TH/CrossDef.hs view
@@ -0,0 +1,4 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.CrossDef where + +$([d| x = 3 |])
+ examples/TH/DoubleSplice.hs view
@@ -0,0 +1,4 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.DoubleSplice where + +$($(id [| return [] |]))
+ examples/TH/LocalDefinition.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.LocalDefinition where + +import Language.Haskell.TH + +decls :: Q [Dec] +decls = [d| w = 3 |] + +exp :: Q Exp +exp = [| 3 |] + +exp' :: Q Exp +exp' = [e| 3 |] + +pat :: Q Pat +pat = [p| x |] + +typ :: Q Type +typ = [t| Int |]
+ examples/TH/MultiImport.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.MultiImport where + +import Prelude (last,return) +import qualified Data.Text (last) + +$(let f = last in return [])
+ examples/TH/NestedSplices.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.NestedSplices where + +import Language.Haskell.TH + +f = [t| $(parensT [t| $(return ListT) |]) |]
+ examples/TH/Quoted.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE TemplateHaskell #-} +module TH.Quoted where + +import qualified Text.Read.Lex (Lexeme) + +$(let x = ''Text.Read.Lex.Lexeme in return [])
+ examples/TH/WithWildcards.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE TemplateHaskell, RecordWildCards #-} +module TH.WithWildcards where + +import Language.Haskell.TH.Syntax + +data A = A { x :: Q Exp } + +g A{..} = [| $(x) |]
haskell-tools-refactor.cabal view
@@ -1,5 +1,5 @@ name: haskell-tools-refactor -version: 0.7.0.0 +version: 0.8.0.0 synopsis: Refactoring Tool for Haskell description: Contains a set of refactorings based on the Haskell-Tools framework to easily transform a Haskell program. For the descriptions of the implemented refactorings, see the homepage. homepage: https://github.com/haskell-tools/haskell-tools @@ -91,10 +91,10 @@ , template-haskell >= 2.11 && < 2.12 , ghc >= 8.0 && < 8.1 , Cabal >= 1.24 && < 1.25 - , haskell-tools-ast >= 0.7 && < 0.8 - , haskell-tools-backend-ghc >= 0.7 && < 0.8 - , haskell-tools-rewrite >= 0.7 && < 0.8 - , haskell-tools-prettyprint >= 0.7 && < 0.8 + , haskell-tools-ast >= 0.8 && < 0.9 + , haskell-tools-backend-ghc >= 0.8 && < 0.9 + , haskell-tools-rewrite >= 0.8 && < 0.9 + , haskell-tools-prettyprint >= 0.8 && < 0.9 default-language: Haskell2010 test-suite haskell-tools-test @@ -119,11 +119,11 @@ , ghc >= 8.0 && < 8.1 , ghc-paths >= 0.1 && < 0.2 , Cabal >= 1.24 && < 1.25 - , haskell-tools-ast >= 0.7 && < 0.8 - , haskell-tools-backend-ghc >= 0.7 && < 0.8 - , haskell-tools-rewrite >= 0.7 && < 0.8 - , haskell-tools-prettyprint >= 0.7 && < 0.8 - , haskell-tools-refactor >= 0.7 && < 0.8 + , haskell-tools-ast >= 0.8 && < 0.9 + , haskell-tools-backend-ghc >= 0.8 && < 0.9 + , haskell-tools-rewrite >= 0.8 && < 0.9 + , haskell-tools-prettyprint >= 0.8 && < 0.9 + , haskell-tools-refactor >= 0.8 && < 0.9 -- libraries used by the examples , old-time >= 1.1 && < 1.2 , polyparse >= 1.12 && < 1.13
test/Main.hs view
@@ -110,6 +110,7 @@ , "Decl.InfixPatSyn" , "Decl.InjectiveTypeFamily" , "Decl.InlinePragma" + , "Decl.InstanceFamily" , "Decl.InstanceOverlaps" , "Decl.InstanceSpec" , "Decl.LocalBindings" @@ -135,6 +136,7 @@ , "Decl.TypeRole" , "Decl.TypeSynonym" , "Decl.ValBind" + , "Decl.ViewPatternSynonym" , "Expr.ArrowNotation" , "Expr.Case" , "Expr.DoNotation" @@ -189,8 +191,15 @@ , "TH.QuasiQuote.Use" , "TH.Splice.Define" , "TH.Splice.Use" + , "TH.CrossDef" , "TH.Splice.UseQual" , "TH.Splice.UseQualMulti" + , "TH.LocalDefinition" + , "TH.MultiImport" + , "TH.NestedSplices" + , "TH.Quoted" + , "TH.WithWildcards" + , "TH.DoubleSplice" , "Refactor.CommentHandling.CommentTypes" , "Refactor.CommentHandling.BlockComments" , "Refactor.CommentHandling.Crosslinking" @@ -252,6 +261,7 @@ , "Refactor.OrganizeImports.StandaloneDeriving" , "Refactor.OrganizeImports.TemplateHaskell" , "Refactor.OrganizeImports.NarrowType" + , "CPP.BetweenImports" , "CPP.ConditionalImport" , "CPP.ConditionalImportBegin" , "CPP.ConditionalImportEnd" @@ -527,8 +537,8 @@ = runGhc (Just libdir) $ do initGhcFlags useDirs [rootDir] - mod <- loadModule rootDir moduleName >>= parseTyped - res <- runRefactor (SourceFileKey NormalHs moduleName, mod) [] (localRefactoring $ refact mod) + mod <- loadModule rootDir moduleName >>= parseTyped rootDir + res <- runRefactor (SourceFileKey (rootDir </> moduleSourceFile moduleName) moduleName, mod) [] (localRefactoring $ refact mod) case res of Right r -> return $ Right $ prettyPrint $ snd $ fromContentChanged $ head r Left err -> return $ Left err @@ -563,7 +573,7 @@ parsed <- loadModule workingDir moduleName actual <- prettyPrint <$> parseAST parsed actual' <- prettyPrint <$> parseRenamed parsed - actual'' <- prettyPrint <$> parseTyped parsed + actual'' <- prettyPrint <$> parseTyped workingDir parsed return (actual, actual', actual'') assertEqual "Parsed: The original and the transformed source differ" expected actual assertEqual "Renamed: The original and the transformed source differ" expected actual' @@ -581,10 +591,10 @@ allMods <- getModuleGraph selectedMod <- getModSummary (GHC.mkModuleName target) let otherModules = filter (not . (\ms -> ms_mod ms == ms_mod selectedMod && ms_hsc_src ms == ms_hsc_src selectedMod)) allMods - targetMod <- parseTyped selectedMod - otherMods <- mapM parseTyped otherModules + targetMod <- parseTyped workingDir selectedMod + otherMods <- mapM (parseTyped workingDir) otherModules res <- performCommand (either error id $ readCommand command) - (SourceFileKey NormalHs target, targetMod) (zip (map keyFromMS otherModules) otherMods) + (SourceFileKey (workingDir </> moduleSourceFile target) target, targetMod) (zip (map keyFromMS otherModules) otherMods) return $ (\case Right r -> Right $ (map (\case ContentChanged (n,m) -> (n ^. sfkModuleName, Just $ prettyPrint m) ModuleCreated n m _ -> (n, Just $ prettyPrint m) ModuleRemoved m -> (m, Nothing) @@ -629,8 +639,8 @@ performRefactor command workingDir flags target = runGhc (Just libdir) $ do useFlags flags - ((\case Right r -> Right (newContent r); Left l -> Left l) <$> (refact =<< parseTyped =<< loadModule workingDir target)) - where refact m = performCommand (either error id $ readCommand command) (SourceFileKey NormalHs target,m) [] + ((\case Right r -> Right (newContent r); Left l -> Left l) <$> (refact =<< parseTyped workingDir =<< loadModule workingDir target)) + where refact m = performCommand (either error id $ readCommand command) (SourceFileKey (workingDir </> moduleSourceFile target) target,m) [] newContent (ContentChanged (_, newContent) : ress) = prettyPrint newContent newContent ((ModuleCreated _ newContent _) : ress) = prettyPrint newContent newContent (_ : ress) = newContent ress