@@ -9,24 +9,21 @@
99-- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values.
1010module Development.IDE.Core.Compile
1111 ( TcModuleResult(..)
12− , getGhcDynFlags
1312 , compileModule
14− , getSrcSpanInfos
1513 , parseModule
16− , parseFileContents
1714 , typecheckModule
1815 , computePackageDeps
16+ , addRelativeImport
1917 ) where
2018
2119import Development.IDE.GHC.Warnings
2220import Development.IDE.GHC.CPP
2321import Development.IDE.Types.Diagnostics
24−import qualified Development.IDE.Import.FindImports as FindImports
2522import Development.IDE.GHC.Error
26−import Development.IDE.Spans.Calculate
2723import Development.IDE.GHC.Orphans()
2824import Development.IDE.GHC.Util
2925import Development.IDE.GHC.Compat
26+import qualified GHC.LanguageExtensions.Type as GHC
3027import Development.IDE.Types.Options
3128import Development.IDE.Types.Location
3229
@@ -47,6 +44,7 @@ import qualified GHC.LanguageExtensions as LangExt
4744
4845import Control.DeepSeq
4946import Control.Monad.Extra
47+import Control.Monad.Except
5048import Control.Monad.Trans.Except
5149import qualified Data.Text as T
5250import Data.IORef
@@ -54,7 +52,6 @@ import Data.List.Extra
5452import Data.Maybe
5553import Data.Tuple.Extra
5654import qualified Data.Map.Strict as Map
57−import Development.IDE.Spans.Type
5855import System.FilePath
5956import System.Directory
6057import System.IO.Extra
@@ -74,19 +71,6 @@ instance NFData TcModuleResult where
7471 rnf = rwhnf
7572
7673
77−-- | Get source span info, used for e.g. AtPoint and Goto Definition.
78−getSrcSpanInfos
79− :: ParsedModule
80− -> HscEnv
81− -> [(Located ModuleName, Maybe NormalizedFilePath)]
82− -> TcModuleResult
83− -> IO [SpanInfo]
84−getSrcSpanInfos mod env imports tc =
85− runGhcSession (Just mod) env
86− . getSpanInfo imports
87− $ tmrModule tc
88−
89−
9074-- | Given a string buffer, return a pre-processed @ParsedModule@.
9175parseModule
9276 :: IdeOptions
@@ -97,7 +81,7 @@ parseModule
9781parseModule IdeOptions{..} env file =
9882 fmap (either (, Nothing) (second Just)) .
9983 -- We need packages since imports fail to resolve otherwise.
100− runGhcSession Nothing env . runExceptT . parseFileContents optPreprocessor file
84+ runGhcEnv env . runExceptT . parseFileContents optPreprocessor file
10185
10286
10387-- | Given a package identifier, what packages does it depend on
@@ -122,7 +106,7 @@ typecheckModule
122106 -> IO ([FileDiagnostic], Maybe TcModuleResult)
123107typecheckModule opt packageState deps pm =
124108 fmap (either (, Nothing) (second Just)) $
125− runGhcSession (Just pm) packageState $
109+ runGhcEnv packageState $
126110 catchSrcErrors $ do
127111 setupEnv deps
128112 (warnings, tcm) <- withWarnings $ \tweak ->
@@ -133,14 +117,13 @@ typecheckModule opt packageState deps pm =
133117-- | Compile a single type-checked module to a 'CoreModule' value, or
134118-- provide errors.
135119compileModule
136− :: ParsedModule
137− -> HscEnv
120+ :: HscEnv
138121 -> [TcModuleResult]
139122 -> TcModuleResult
140123 -> IO ([FileDiagnostic], Maybe CoreModule)
141−compileModule mod packageState deps tmr =
124+compileModule packageState deps tmr =
142125 fmap (either (, Nothing) (second Just)) $
143− runGhcSession (Just mod) packageState $
126+ runGhcEnv packageState $
144127 catchSrcErrors $ do
145128 setupEnv (deps ++ [tmr])
146129
@@ -164,21 +147,9 @@ compileModule mod packageState deps tmr =
164147 return (warnings, core)
165148
166149
167−getGhcDynFlags :: ParsedModule -> HscEnv -> IO DynFlags
168−getGhcDynFlags mod pkg = runGhcSession (Just mod) pkg getSessionDynFlags
169−
170−-- | Evaluate a GHC session using a new environment constructed with
171−-- the supplied options.
172−runGhcSession
173− :: Maybe ParsedModule
174− -> HscEnv
175− -> Ghc a
176− -> IO a
177−runGhcSession modu env act = runGhcEnv env $ do
178− modifyDynFlags $ \x -> x
179− {importPaths = nubOrd $ maybeToList (moduleImportPaths =<< modu) ++ importPaths x}
180− act
181−
150+addRelativeImport :: ParsedModule -> DynFlags -> DynFlags
151+addRelativeImport modu dflags = dflags
152+ {importPaths = nubOrd $ maybeToList (moduleImportPaths modu) ++ importPaths dflags}
182153
183154moduleImportPaths :: GHC.ParsedModule -> Maybe FilePath
184155moduleImportPaths pm
@@ -258,6 +229,35 @@ loadModuleHome tmr = modifySession $ \e ->
258229 mod_info = tmrModInfo tmr
259230 mod = ms_mod_name ms
260231
232+
233+
234+-- | GhcMonad function to chase imports of a module given as a StringBuffer. Returns given module's
235+-- name and its imports.
236+getImportsParsed :: DynFlags ->
237+ GHC.ParsedSource ->
238+ Either [FileDiagnostic] (GHC.ModuleName, [(Maybe FastString, Located GHC.ModuleName)])
239+getImportsParsed dflags (L loc parsed) = do
240+ let modName = maybe (GHC.mkModuleName "Main") GHC.unLoc $ GHC.hsmodName parsed
241+
242+ -- refuse source imports
243+ let srcImports = filter (ideclSource . GHC.unLoc) $ GHC.hsmodImports parsed
244+ when (not $ null srcImports) $ Left $
245+ concat
246+ [ diagFromString mloc ("Illegal source import of " <> GHC.moduleNameString (GHC.unLoc $ GHC.ideclName i))
247+ | L mloc i <- srcImports ]
248+
249+ -- most of these corner cases are also present in https://hackage.haskell.org/package/ghc-8.6.1/docs/src/HeaderInfo.html#getImports
250+ -- but we want to avoid parsing the module twice
251+ let implicit_prelude = xopt GHC.ImplicitPrelude dflags
252+ implicit_imports = Hdr.mkPrelImports modName loc implicit_prelude $ GHC.hsmodImports parsed
253+
254+ -- filter out imports that come from packages
255+ return (modName, [(fmap sl_fs $ ideclPkgQual i, ideclName i)
256+ | i <- map GHC.unLoc $ implicit_imports ++ GHC.hsmodImports parsed
257+ , GHC.moduleNameString (GHC.unLoc $ ideclName i) /= "GHC.Prim"
258+ ])
259+
260+
261261-- | Produce a module summary from a StringBuffer.
262262getModSummaryFromBuffer
263263 :: GhcMonad m
@@ -267,7 +267,7 @@ getModSummaryFromBuffer
267267 -> GHC.ParsedSource
268268 -> ExceptT [FileDiagnostic] m ModSummary
269269getModSummaryFromBuffer fp contents dflags parsed = do
270− (modName, imports) <- FindImports.getImportsParsed dflags parsed
270+ (modName, imports) <- liftEither $ getImportsParsed dflags parsed
271271
272272 let modLoc = ModLocation
273273 { ml_hs_file = Just fp