packages feed

hsinspect 0.0.10 → 0.0.11

raw patch · 7 files changed

+103/−46 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ HsInspect.Util: homeSources :: GhcMonad m => m [FilePath]
+ HsInspect.Util: showGhc :: Outputable a => a -> String
+ HsInspect.Workarounds: parseHeader' :: GhcMonad m => FilePath -> m ([String], HsModule GhcPs)
+ HsInspect.Workarounds: parseModuleName' :: GhcMonad m => FilePath -> m (Maybe ModuleName)

Files

exe/Main.hs view
@@ -6,8 +6,8 @@ import qualified Config as GHC import Control.Monad import Control.Monad.IO.Class-import Data.Char (isUpper) import Data.List (find, isPrefixOf)+import Data.Maybe (catMaybes) import DynFlags (parseDynamicFlagsCmdLine, updOptLevel) import qualified EnumSet as EnumSet import qualified GHC as GHC@@ -16,6 +16,8 @@ import HsInspect.Json import HsInspect.Packages import HsInspect.Sexp as S+import HsInspect.Util+import HsInspect.Workarounds import System.Environment (getArgs) import System.Exit @@ -53,7 +55,7 @@       flags' = filter (not . ("-B" `isPrefixOf`)) flags   GHC.runGhc libdir $ do     dflags <- GHC.getSessionDynFlags-    (updOptLevel 0 -> dflags', (GHC.unLoc <$>) -> ghcargs, _) <-+    (updOptLevel 0 -> dflags', (GHC.unLoc <$>) -> _ghcargs, _) <-       liftIO $ parseDynamicFlagsCmdLine dflags (GHC.noLoc <$> flags')     void $ GHC.setSessionDynFlags dflags'            { GHC.hscTarget = GHC.HscInterpreted -- HscNothing compiles home modules, dunno why@@ -62,8 +64,14 @@            , GHC.warningFlags = EnumSet.empty            , GHC.fatalWarningFlags = EnumSet.empty            }-    let mkTarget m = GHC.Target (GHC.TargetModule $ GHC.mkModuleName m) True Nothing-    GHC.setTargets $ mkTarget <$> filter (isUpper . head) ghcargs++    -- The caller may have provided a list of home modules, but we do not trust+    -- them because the ghcflags plugin does not keep the flags up to date for+    -- incremental compiles.+    let mkTarget m = GHC.Target (GHC.TargetModule m) True Nothing+    homeModules <- inferHomeModules+    GHC.setTargets $ mkTarget <$> homeModules+     let respond rest (S.filterNil . S.toSexp -> a) = liftIO . putStrLn $           if (elem "--json" rest)           then case sexpToJson a of@@ -82,6 +90,13 @@         respond rest hits       _ ->         liftIO $ error "invalid parameters"++inferHomeModules :: GHC.GhcMonad m => m [GHC.ModuleName]+inferHomeModules = do+  files <- homeSources+  mmns <- traverse parseModuleName' files+  let main' = GHC.mkModuleName "Main"+  pure . filter (main' /=) $ catMaybes mmns  -- removes the "+RTS ... -RTS" sections filterFlags :: [String] -> [String]
hsinspect.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name:          hsinspect-version:       0.0.10+version:       0.0.11 synopsis:      Inspect Haskell source files. license:       GPL-3.0-or-later license-file:  LICENSE
library/HsInspect/Imports.hs view
@@ -9,12 +9,11 @@ where  import Data.Maybe (fromJust)-import DynFlags (unsafeGlobalDynFlags) import qualified GHC as GHC import HscTypes (TargetId(..)) import HsInspect.Sexp import HsInspect.Workarounds-import Outputable (Outputable, showPpr)+import HsInspect.Util import RdrName (GlobalRdrElt(..), ImpDeclSpec(..), ImportSpec(..),                 globalRdrEnvElts) @@ -33,9 +32,6 @@    rdr_env <- minf_rdr_env' m   pure $ describe =<< globalRdrEnvElts rdr_env--showGhc :: (Outputable a) => a -> String-showGhc = showPpr unsafeGlobalDynFlags  describe :: GlobalRdrElt -> [Qualified] describe GRE {gre_name, gre_imp} = describe' <$> gre_imp
library/HsInspect/Index.hs view
@@ -30,7 +30,6 @@ import HsInspect.Sexp import HsInspect.Util import qualified Id as GHC-import Module (Module(..), moduleNameString) import Module as GHC import qualified Name as GHC import Outputable (showPpr, showSDoc)@@ -129,6 +128,8 @@   -> m (Maybe (GHC.Module, [(Maybe GHC.Module, GHC.TcTyThing)])) hiToSymbols exposed hi = (join <$>) <$> withHi hi $ \iface -> do   let m = mi_module iface+  -- FIXME we should include all modules from inplace packages, otherwise the+  -- user is unable to jump-to-definition within the same multi-package project.   if not $ Set.member (GHC.moduleName m) exposed     then pure Nothing     else do@@ -185,6 +186,8 @@ -- srcid is Nothing if it matches the re-export location data Exported = Exported (Maybe SourcePackageId) GHC.ModuleName +-- FIXME Exported should follow re-exports until they reach the original symbol.+-- Otherwise editors have to do this. mkExported :: GHC.DynFlags -> UnitId -> Module -> Exported mkExported dflags unitid m =   let unitid' = moduleUnitId m
library/HsInspect/Packages.hs view
@@ -8,8 +8,9 @@ import Control.Monad (join, void) import Control.Monad.IO.Class (liftIO) import Data.Coerce-import Data.List (delete, nub, sort, (\\))+import Data.List (delete, nub, nubBy, sort, (\\)) import Data.Maybe (catMaybes, mapMaybe)+import Data.Set (Set) import qualified Data.Set as Set import qualified DynFlags as GHC import FastString@@ -28,19 +29,29 @@ -- separate -ddump-minimal-imports pass). packages :: GHC.GhcMonad m => m PkgSummary packages = do-  mods <- Set.toList <$> getTargetModules+  homes <- getTargetModules+  targetsImportsOnly homes    dflags <- GHC.getSessionDynFlags   void $ GHC.setSessionDynFlags dflags { GHC.ghcMode = GHC.CompManager }   _ <- GHC.load $ GHC.LoadAllTargets -  imps <- nub . join <$> traverse getImports mods+  imps <- nub . join <$> traverse getImports (Set.toList homes)   pkgs <- catMaybes <$> traverse (uncurry findPackage) imps   let home = GHC.thisPackage dflags       used = delete home . nub . sort $ pkgs       loaded = nub . sort . explicitPackages $ GHC.pkgState dflags       asNames unitids = GHC.packageName <$> mapMaybe (lookupPackage dflags) unitids   pure $ PkgSummary (asNames used) (asNames $ loaded \\ used)++targetsImportsOnly :: GHC.GhcMonad m => Set GHC.ModuleName -> m ()+targetsImportsOnly homes = do+  files <- homeSources+  trimmed <- traverse (importsOnly homes) files+  -- side effect: multiple modules with no name will be deduped+  let fstEq (n1, _) (n2, _) = n1 == n2+      targets = (snd <$>) . nubBy fstEq $ trimmed+  GHC.setTargets targets  findPackage :: GHC.GhcMonad m => ModuleName -> Maybe FastString -> m (Maybe GHC.UnitId) findPackage m mp = do
library/HsInspect/Util.hs view
@@ -1,14 +1,26 @@ {-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE ViewPatterns #-}  module HsInspect.Util where -import Data.List (isSuffixOf)+import Control.Monad.IO.Class+import Data.List (isSuffixOf, nub) import Data.Maybe (catMaybes) import Data.Set (Set) import qualified Data.Set as Set+import DynFlags (unsafeGlobalDynFlags) import qualified GHC as GHC-import System.Directory (doesDirectoryExist, listDirectory)+import Outputable (Outputable, showPpr)+import System.Directory (doesDirectoryExist, listDirectory, makeAbsolute)++homeSources :: GHC.GhcMonad m => m [FilePath]+homeSources = do+  dflags <- GHC.getSessionDynFlags+  paths <- liftIO . traverse makeAbsolute $ GHC.importPaths dflags+  let infer dir = liftIO $ walkSuffix ".hs" dir+  nub . concat <$> traverse infer paths++showGhc :: (Outputable a) => a -> String+showGhc = showPpr unsafeGlobalDynFlags  getTargetModules :: GHC.GhcMonad m => m (Set GHC.ModuleName) getTargetModules = do
library/HsInspect/Workarounds.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}  module HsInspect.Workarounds where @@ -9,7 +10,6 @@ import Data.List (delete, intercalate, isSuffixOf) import Data.Set (Set) import qualified Data.Set as Set-import DriverPhases (HscSource(..), Phase(..)) import DriverPipeline (preprocess) import DynFlags (parseDynamicFilePragma) import FastString@@ -24,16 +24,17 @@ import SrcLoc import StringBuffer import System.Directory (getModificationTime, removeFile)++#if MIN_VERSION_GLASGOW_HASKELL(8,8,2,0)+import Data.Maybe (fromJust, fromMaybe)+import OccName (emptyOccEnv)+#else import TcRnTypes (tcg_rdr_env)+#endif --- TODO avoid this codepath in 8.8.2+--- WORKAROUND https://gitlab.haskell.org/ghc/ghc/merge_requests/1541-importsOnly :: GHC.GhcMonad m => Set GHC.ModuleName -> FilePath -> m (Maybe GHC.ModuleName, Target)-importsOnly homes file = do+parseHeader' :: GHC.GhcMonad m => FilePath -> m ([String], GHC.HsModule GHC.GhcPs)+parseHeader' file = do   sess <- GHC.getSession-  -- NOTE: the behaviour of preprocess changed in 8.8.1 and it no longer reads-  -- and sets LANGUAGE pragamas from in header of the file. Since this function-  -- is no longer needed in 8.8.2 we don't bother fixing this. #if MIN_VERSION_GLASGOW_HASKELL(8,8,1,0)   pp <- liftIO $ preprocess sess file Nothing Nothing   let (dflags, tmp) = case pp of@@ -47,38 +48,57 @@     liftIO . removeFile $ tmp   let pragmas = getOptions dflags full file       loc  = mkRealSrcLoc (mkFastString file) 1 1-      allowed (L _ (ImportDecl{ideclName})) = Set.notMember (unLoc ideclName) homes+  (dflags', _, _) <- parseDynamicFilePragma dflags pragmas+  case unP parseHeader (mkPState dflags' full loc) of+    POk _ (L _ hsmod) -> pure (unLoc <$> pragmas, hsmod)+    _ -> error $ "parseHeader failed for " <> file++importsOnly :: GHC.GhcMonad m => Set GHC.ModuleName -> FilePath -> m (Maybe GHC.ModuleName, Target)+importsOnly homes file = do+  dflags <- GHC.getSessionDynFlags+  (pragmas, hsmod) <- parseHeader' file+  let allowed (L _ (ImportDecl{ideclName})) = Set.notMember (unLoc ideclName) homes #if MIN_VERSION_GLASGOW_HASKELL(8,6,0,0)       allowed (L _ (XImportDecl _)) = False #endif-  (dflags', _, _) <- parseDynamicFilePragma dflags pragmas-  (modname, trimmed) <- case unP parseHeader (mkPState dflags' full loc) of-    POk _ (L _ hsmod) -> do-      let modname = unLoc <$> GHC.hsmodName hsmod-          extra =-            if modname == Nothing || modname == (Just $ GHC.mkModuleName "Main")-            then "\nmain = return ()"-            else ""-          imps = filter allowed $ GHC.hsmodImports hsmod-          -- WORKAROUND https://gitlab.haskell.org/ghc/ghc/issues/17066-          --            cannot use CPP in combination with targetContents-          pragmas' = delete "-XCPP" (unLoc <$> pragmas)-          contents =-            "{-# OPTIONS_GHC " <> (intercalate " " pragmas') <> " #-}\n" <>-            showPpr dflags' (hsmod { GHC.hsmodExports = Nothing-                                   , GHC.hsmodImports = imps }) <>-            extra-      pure (modname, stringToStringBuffer contents)-    _ -> error  $ "parseHeader failed for " <> file+      modname = unLoc <$> GHC.hsmodName hsmod+      extra =+        if modname == Nothing || modname == (Just $ GHC.mkModuleName "Main")+        then "\nmain = return ()"+        else ""+      imps = filter allowed $ GHC.hsmodImports hsmod+      -- WORKAROUND https://gitlab.haskell.org/ghc/ghc/issues/17066+      --            cannot use CPP in combination with targetContents+      pragmas' = delete "-XCPP" pragmas+      contents =+        "{-# OPTIONS_GHC " <> (intercalate " " pragmas') <> " #-}\n" <>+        showPpr dflags (hsmod { GHC.hsmodExports = Nothing+                               , GHC.hsmodImports = imps }) <>+        extra+      trimmed = stringToStringBuffer contents    ts <- liftIO $ getModificationTime file-  pure $ (modname, Target (TargetFile file (Just $ Hsc HsSrcFile)) False (Just (trimmed, ts)))+  -- since 0f9ec9d1ff can't use Phase+  pure $ (modname, Target (TargetFile file Nothing) False (Just (trimmed, ts))) +parseModuleName' :: GHC.GhcMonad m => FilePath -> m (Maybe GHC.ModuleName)+parseModuleName' file = do+  (_, hsmod) <- parseHeader' file+  pure $ unLoc <$> GHC.hsmodName hsmod+ -- WORKAROUND https://gitlab.haskell.org/ghc/ghc/merge_requests/1541 minf_rdr_env' :: GHC.GhcMonad m => GHC.ModuleName -> m GlobalRdrEnv minf_rdr_env' m = do+#if MIN_VERSION_GLASGOW_HASKELL(8,8,2,0)+  mo <- GHC.findModule m Nothing+  (fromJust -> mi) <- GHC.getModuleInfo mo+  pure . fromMaybe emptyOccEnv $ GHC.modInfoRdrEnv mi+#else   modSum <- GHC.getModSummary m   pmod <- GHC.parseModule modSum   tmod <- GHC.typecheckModule pmod   let (tc_gbl_env, _) = GHC.tm_internals_ tmod   pure $ tcg_rdr_env tc_gbl_env+#endif++