@@ -5,23 +5,22 @@
55{-# LANGUAGE CPP #-}
66#include "ghc-api-version.h"
77
8−-- | GHC utility functions. Importantly, code using our GHC should never:
9−--
10−-- * Call runGhc, use runGhcFast instead. It's faster and doesn't require config we don't have.
11−--
12−-- * Call setSessionDynFlags, use modifyDynFlags instead. It's faster and avoids loading packages.
8+-- | General utility functions, mostly focused around GHC operations.
139module Development.IDE.GHC.Util(
14− lookupPackageConfig,
10+ -- * HcsEnv and environment
11+ HscEnvEq, hscEnv, newHscEnvEq,
1512 modifyDynFlags,
1613 fakeDynFlags,
17− prettyPrint,
1814 runGhcEnv,
19− textToStringBuffer,
15+ -- * GHC wrappers
16+ prettyPrint,
17+ lookupPackageConfig,
2018 moduleImportPath,
21− HscEnvEq, hscEnv, newHscEnvEq,
19+ cgGutsToCoreModule,
20+ -- * General utilities
21+ textToStringBuffer,
2222 readFileUtf8,
2323 hDuplicateTo',
24− cgGutsToCoreModule
2524 ) where
2625
2726import Config
@@ -60,6 +59,8 @@ import Development.IDE.Types.Location
6059----------------------------------------------------------------------
6160-- GHC setup
6261
62+-- | Used to modify dyn flags in preference to calling 'setSessionDynFlags',
63+-- since that function also reloads packages (which is very slow).
6364modifyDynFlags :: GhcMonad m => (DynFlags -> DynFlags) -> m ()
6465modifyDynFlags f = do
6566 newFlags <- f <$> getSessionDynFlags
@@ -68,6 +69,7 @@ modifyDynFlags f = do
6869 modifySession $ \h ->
6970 h { hsc_dflags = newFlags, hsc_IC = (hsc_IC h) {ic_dflags = newFlags} }
7071
72+-- | Given a 'UnitId' try and find the associated 'PackageConfig' in the environment.
7173lookupPackageConfig :: UnitId -> HscEnv -> Maybe PackageConfig
7274lookupPackageConfig unitId env =
7375 lookupPackage' False pkgConfigMap unitId
@@ -78,14 +80,18 @@ lookupPackageConfig unitId env =
7880 getPackageConfigMap $ hsc_dflags env
7981
8082
81−-- would be nice to do this more efficiently...
83+-- | Convert from the @text@ package to the @GHC@ 'StringBuffer'.
84+-- Currently implemented somewhat inefficiently (if it ever comes up in a profile).
8285textToStringBuffer :: T.Text -> StringBuffer
8386textToStringBuffer = stringToStringBuffer . T.unpack
8487
8588
89+-- | Pretty print a GHC value using 'fakeDynFlags'.
8690prettyPrint :: Outputable a => a -> String
8791prettyPrint = showSDoc fakeDynFlags . ppr
8892
93+-- | Run a 'Ghc' monad value using an existing 'HscEnv'. Sets up and tears down all the required
94+-- pieces, but designed to be more efficient than a standard 'runGhc'.
8995runGhcEnv :: HscEnv -> Ghc a -> IO a
9096runGhcEnv env act = do
9197 filesToClean <- newIORef emptyFilesToClean
@@ -96,8 +102,8 @@ runGhcEnv env act = do
96102 cleanTempFiles dflags
97103 cleanTempDirs dflags
98104
99−-- Fake DynFlags which are mostly undefined, but define enough to do a
100−-- little bit.
105+-- | A 'DynFlags' value where most things are undefined. It's sufficient to call pretty printing,
106+-- but not much else.
101107fakeDynFlags :: DynFlags
102108fakeDynFlags = defaultDynFlags settings mempty
103109 where
@@ -120,6 +126,9 @@ fakeDynFlags = defaultDynFlags settings mempty
120126 , pc_WORD_SIZE=8
121127 }
122128
129+-- | Given a module location, and its parse tree, figure out what is the include directory implied by it.
130+-- For example, given the file @\/usr\/\Test\/Foo\/Bar.hs@ with the module name @Foo.Bar@ the directory
131+-- @\/usr\/Test@ should be on the include path to find sibling modules.
123132moduleImportPath :: NormalizedFilePath -> GHC.ParsedModule -> Maybe FilePath
124133-- The call to takeDirectory is required since DAML does not require that
125134-- the file name matches the module name in the last component.
@@ -137,12 +146,15 @@ moduleImportPath (takeDirectory . fromNormalizedFilePath -> pathDir) pm
137146 fromNormalizedFilePath $ toNormalizedFilePath $
138147 moduleNameSlashes $ GHC.moduleName mod'
139148
140−-- | An HscEnv with equality.
149+-- | An 'HscEnv' with equality. Two values are considered equal
150+-- if they are created with the same call to 'newHscEnvEq'.
141151data HscEnvEq = HscEnvEq Unique HscEnv
142152
153+-- | Unwrap an 'HsEnvEq'.
143154hscEnv :: HscEnvEq -> HscEnv
144155hscEnv (HscEnvEq _ x) = x
145156
157+-- | Wrap an 'HscEnv' into an 'HscEnvEq'.
146158newHscEnvEq :: HscEnv -> IO HscEnvEq
147159newHscEnvEq e = do u <- newUnique; return $ HscEnvEq u e
148160
@@ -155,9 +167,11 @@ instance Eq HscEnvEq where
155167instance NFData HscEnvEq where
156168 rnf (HscEnvEq a b) = rnf (hashUnique a) `seq` b `seq` ()
157169
170+-- | Read a UTF8 file, with lenient decoding, so it will never raise a decoding error.
158171readFileUtf8 :: FilePath -> IO T.Text
159172readFileUtf8 f = T.decodeUtf8With T.lenientDecode <$> BS.readFile f
160173
174+-- | Convert from a 'CgGuts' to a 'CoreModule'.
161175cgGutsToCoreModule :: SafeHaskellMode -> CgGuts -> ModDetails -> CoreModule
162176cgGutsToCoreModule safeMode guts modDetails = CoreModule
163177 (cg_module guts)
@@ -165,8 +179,8 @@ cgGutsToCoreModule safeMode guts modDetails = CoreModule
165179 (cg_binds guts)
166180 safeMode
167181
168−-- This is a slightly modified version of hDuplicateTo in GHC.
169−-- See the inline comment for more details.
182+-- | A slightly modified version of 'hDuplicateTo' from GHC.
183+-- Importantly, it avoids the bug listed in https://gitlab.haskell.org/ghc/ghc/merge_requests/2318.
170184hDuplicateTo' :: Handle -> Handle -> IO ()
171185hDuplicateTo' h1@(FileHandle path m1) h2@(FileHandle _ m2) = do
172186 withHandle__' "hDuplicateTo" h2 m2 $ \h2_ -> do