Skip to content
This repository was archived by the owner on Aug 3, 2024. It is now read-only.

Commit 1722852

Browse files
alexbiehl-gcalexbiehl
authored andcommitted
Prepare Haddock for being a GHC Plugin
1 parent e90e798 commit 1722852

File tree

2 files changed

+222
-34
lines changed

2 files changed

+222
-34
lines changed

haddock-api/src/Haddock/Interface.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,15 @@ processModule verbosity modsum flags modMap instIfaceMap = do
165165
return Nothing
166166
NotBoot -> do
167167
out verbosity verbose "Creating interface..."
168+
169+
let
170+
mod_summary = pm_mod_summary (tm_parsed_module tm)
171+
tcg_gbl_env = fst (tm_internals_ tm)
172+
168173
(interface, msgs) <- {-# SCC createIterface #-}
169174
withTimingD "createInterface" (const ()) $ do
170-
runWriterGhc $ createInterface tm flags modMap instIfaceMap
175+
runWriterGhc $ createInterface1 flags mod_summary
176+
tcg_gbl_env modMap instIfaceMap
171177

172178
-- We need to keep track of which modules were somehow in scope so that when
173179
-- Haddock later looks for instances, it also looks in these modules too.

haddock-api/src/Haddock/Interface/Create.hs

Lines changed: 215 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE CPP, TupleSections, BangPatterns, LambdaCase #-}
1+
{-# LANGUAGE CPP, TupleSections, BangPatterns, LambdaCase, NamedFieldPuns #-}
22
{-# LANGUAGE TypeFamilies #-}
33
{-# LANGUAGE ViewPatterns #-}
44
{-# OPTIONS_GHC -Wwarn #-}
@@ -18,7 +18,7 @@
1818
-- which creates a Haddock 'Interface' from the typechecking
1919
-- results 'TypecheckedModule' from GHC.
2020
-----------------------------------------------------------------------------
21-
module Haddock.Interface.Create (createInterface) where
21+
module Haddock.Interface.Create (createInterface, createInterface1) where
2222

2323
import Documentation.Haddock.Doc (metaDocAppend)
2424
import Haddock.Types
@@ -28,6 +28,7 @@ import Haddock.Utils
2828
import Haddock.Convert
2929
import Haddock.Interface.LexParseRn
3030

31+
import Control.Monad.IO.Class
3132
import Data.Bifunctor
3233
import Data.Bitraversable
3334
import qualified Data.Map as M
@@ -39,6 +40,7 @@ import Control.Monad
3940
import Data.Traversable
4041
import GHC.Stack (HasCallStack)
4142

43+
import GHC.Tc.Utils.Monad (finalSafeMode)
4244
import GHC.Types.Avail hiding (avail)
4345
import qualified GHC.Types.Avail as Avail
4446
import qualified GHC.Unit.Module as Module
@@ -62,6 +64,190 @@ mkExceptionContext :: TypecheckedModule -> String
6264
mkExceptionContext =
6365
("creating Haddock interface for " ++) . moduleNameString . ms_mod_name . pm_mod_summary . tm_parsed_module
6466

67+
createInterface1
68+
:: [Flag]
69+
-> ModSummary
70+
-> TcGblEnv
71+
-> IfaceMap
72+
-> InstIfaceMap
73+
-> ErrMsgGhc Interface
74+
createInterface1 flags mod_sum tc_gbl_env ifaces inst_ifaces = do
75+
76+
let
77+
ModSummary
78+
{
79+
-- Cached flags from OPTIONS, INCLUDE and LANGUAGE
80+
-- pragmas in the modules source code. Used to infer
81+
-- safety of module.
82+
ms_hspp_opts
83+
, ms_location = ModLocation
84+
{
85+
ml_hie_file
86+
}
87+
} = mod_sum
88+
89+
TcGblEnv
90+
{
91+
tcg_mod
92+
, tcg_src
93+
, tcg_semantic_mod
94+
, tcg_rdr_env
95+
, tcg_exports
96+
, tcg_insts
97+
, tcg_fam_insts
98+
, tcg_warns
99+
100+
-- Renamed source
101+
, tcg_rn_imports
102+
, tcg_rn_exports
103+
, tcg_rn_decls
104+
105+
, tcg_doc_hdr
106+
} = tc_gbl_env
107+
108+
dflags = ms_hspp_opts
109+
110+
is_sig = tcg_src == HsigFile
111+
112+
(pkg_name_fs, _) =
113+
modulePackageInfo dflags flags (Just tcg_mod)
114+
115+
pkg_name :: Maybe Package
116+
pkg_name =
117+
let
118+
unpack (PackageName name) = unpackFS name
119+
in
120+
fmap unpack pkg_name_fs
121+
122+
fixities :: FixMap
123+
fixities = case tcg_rn_decls of
124+
Nothing -> mempty
125+
Just dx -> mkFixMap dx
126+
127+
-- Locations of all the TH splices
128+
loc_splices :: [SrcSpan]
129+
loc_splices = case tcg_rn_decls of
130+
Nothing -> []
131+
Just HsGroup { hs_splcds } -> [ loc | L loc _ <- hs_splcds ]
132+
133+
decls <- case tcg_rn_decls of
134+
Nothing -> do
135+
liftErrMsg $ tell [ "Warning: Renamed source is not available" ]
136+
pure []
137+
Just dx ->
138+
pure (topDecls dx)
139+
140+
-- Derive final options to use for haddocking this module
141+
doc_opts <- liftErrMsg $ mkDocOpts (haddockOptions ms_hspp_opts) flags tcg_mod
142+
143+
let
144+
-- All elements of an explicit export list, if present
145+
export_list :: Maybe [(IE GhcRn, Avails)]
146+
export_list
147+
| OptIgnoreExports `elem` doc_opts =
148+
Nothing
149+
| Just rn_exports <- tcg_rn_exports =
150+
Just [ (ie, avail) | (L _ ie, avail) <- rn_exports ]
151+
| otherwise =
152+
Nothing
153+
154+
-- All the exported Names of this module.
155+
exported_names :: [Name]
156+
exported_names =
157+
concatMap availNamesWithSelectors tcg_exports
158+
159+
-- Module imports of the form `import X`. Note that there is
160+
-- a) no qualification and
161+
-- b) no import list
162+
imported_modules :: Map ModuleName [ModuleName]
163+
imported_modules
164+
| Just{} <- export_list =
165+
unrestrictedModuleImports (map unLoc tcg_rn_imports)
166+
| otherwise =
167+
M.empty
168+
169+
-- TyThings that have instances defined in this module
170+
local_instances :: [Name]
171+
local_instances =
172+
[ name
173+
| name <- map getName tcg_insts ++ map getName tcg_fam_insts
174+
, nameIsLocalOrFrom tcg_semantic_mod name
175+
]
176+
177+
-- Infer module safety
178+
safety <- liftIO (finalSafeMode ms_hspp_opts tc_gbl_env)
179+
180+
-- Process the top-level module header documentation.
181+
(!info, header_doc) <- liftErrMsg $ processModuleHeader dflags pkg_name
182+
tcg_rdr_env safety tcg_doc_hdr
183+
184+
-- Warnings on declarations in this module
185+
decl_warnings <- liftErrMsg (mkWarningMap dflags tcg_warns tcg_rdr_env exported_names)
186+
187+
-- Warning on the module header
188+
mod_warning <- liftErrMsg (moduleWarning dflags tcg_rdr_env tcg_warns)
189+
190+
let
191+
-- Warnings in this module and transitive warnings from dependend modules
192+
warnings :: Map Name (Doc Name)
193+
warnings = M.unions (decl_warnings : map ifaceWarningMap (M.elems ifaces))
194+
195+
maps@(!docs, !arg_docs, !decl_map, _) <-
196+
liftErrMsg (mkMaps dflags pkg_name tcg_rdr_env local_instances decls)
197+
198+
export_items <- mkExportItems is_sig ifaces pkg_name tcg_mod tcg_semantic_mod
199+
warnings tcg_rdr_env exported_names (map fst decls) maps fixities
200+
imported_modules loc_splices export_list tcg_exports inst_ifaces dflags
201+
202+
let
203+
visible_names :: [Name]
204+
visible_names = mkVisibleNames maps export_items doc_opts
205+
206+
-- Measure haddock documentation coverage.
207+
pruned_export_items :: [ExportItem GhcRn]
208+
pruned_export_items = pruneExportItems export_items
209+
210+
!haddockable = 1 + length export_items -- module + exports
211+
!haddocked = (if isJust tcg_doc_hdr then 1 else 0) + length pruned_export_items
212+
213+
coverage :: (Int, Int)
214+
!coverage = (haddockable, haddocked)
215+
216+
aliases :: Map Module ModuleName
217+
aliases = mkAliasMap (unitState dflags) tcg_rn_imports
218+
219+
return $! Interface
220+
{
221+
ifaceMod = tcg_mod
222+
, ifaceIsSig = is_sig
223+
, ifaceOrigFilename = msHsFilePath mod_sum
224+
, ifaceHieFile = Just ml_hie_file
225+
, ifaceInfo = info
226+
, ifaceDoc = Documentation header_doc mod_warning
227+
, ifaceRnDoc = Documentation Nothing Nothing
228+
, ifaceOptions = doc_opts
229+
, ifaceDocMap = docs
230+
, ifaceArgMap = arg_docs
231+
, ifaceRnDocMap = M.empty
232+
, ifaceRnArgMap = M.empty
233+
, ifaceExportItems = if OptPrune `elem` doc_opts then
234+
pruned_export_items else export_items
235+
, ifaceRnExportItems = []
236+
, ifaceExports = exported_names
237+
, ifaceVisibleExports = visible_names
238+
, ifaceDeclMap = decl_map
239+
, ifaceFixMap = fixities
240+
, ifaceModuleAliases = aliases
241+
, ifaceInstances = tcg_insts
242+
, ifaceFamInstances = tcg_fam_insts
243+
, ifaceOrphanInstances = [] -- Filled in attachInstances
244+
, ifaceRnOrphanInstances = [] -- Filled in attachInstances
245+
, ifaceHaddockCoverage = coverage
246+
, ifaceWarningMap = warnings
247+
, ifaceDynFlags = dflags
248+
}
249+
250+
65251
-- | Use a 'TypecheckedModule' to produce an 'Interface'.
66252
-- To do this, we need access to already processed modules in the topological
67253
-- sort. That's what's in the 'IfaceMap'.
@@ -167,8 +353,7 @@ createInterface tm flags modMap instIfaceMap =
167353
!prunedExportItems = seqList prunedExportItems' `seq` prunedExportItems'
168354

169355
let !aliases =
170-
mkAliasMap (unitState dflags) $ tm_renamed_source tm
171-
356+
mkAliasMap (unitState dflags) imports
172357
modWarn <- liftErrMsg (moduleWarning dflags gre warnings)
173358

174359
-- Prune the docstring 'Map's to keep only docstrings that are not private.
@@ -217,35 +402,32 @@ createInterface tm flags modMap instIfaceMap =
217402
-- create a mapping from the module identity of M, to an alias N
218403
-- (if there are multiple aliases, we pick the last one.) This
219404
-- will go in 'ifaceModuleAliases'.
220-
mkAliasMap :: UnitState -> Maybe RenamedSource -> M.Map Module ModuleName
221-
mkAliasMap state mRenamedSource =
222-
case mRenamedSource of
223-
Nothing -> M.empty
224-
Just (_,impDecls,_,_) ->
225-
M.fromList $
226-
mapMaybe (\(SrcLoc.L _ impDecl) -> do
227-
SrcLoc.L _ alias <- ideclAs impDecl
228-
return $
229-
(lookupModuleDyn state
230-
-- TODO: This is supremely dodgy, because in general the
231-
-- UnitId isn't going to look anything like the package
232-
-- qualifier (even with old versions of GHC, the
233-
-- IPID would be p-0.1, but a package qualifier never
234-
-- has a version number it. (Is it possible that in
235-
-- Haddock-land, the UnitIds never have version numbers?
236-
-- I, ezyang, have not quite understand Haddock's package
237-
-- identifier model.)
238-
--
239-
-- Additionally, this is simulating some logic GHC already
240-
-- has for deciding how to qualify names when it outputs
241-
-- them to the user. We should reuse that information;
242-
-- or at least reuse the renamed imports, which know what
243-
-- they import!
244-
(fmap Module.fsToUnit $
245-
fmap sl_fs $ ideclPkgQual impDecl)
246-
(case ideclName impDecl of SrcLoc.L _ name -> name),
247-
alias))
248-
impDecls
405+
mkAliasMap :: UnitState -> [LImportDecl GhcRn] -> M.Map Module ModuleName
406+
mkAliasMap state impDecls =
407+
M.fromList $
408+
mapMaybe (\(SrcLoc.L _ impDecl) -> do
409+
SrcLoc.L _ alias <- ideclAs impDecl
410+
return $
411+
(lookupModuleDyn state
412+
-- TODO: This is supremely dodgy, because in general the
413+
-- UnitId isn't going to look anything like the package
414+
-- qualifier (even with old versions of GHC, the
415+
-- IPID would be p-0.1, but a package qualifier never
416+
-- has a version number it. (Is it possible that in
417+
-- Haddock-land, the UnitIds never have version numbers?
418+
-- I, ezyang, have not quite understand Haddock's package
419+
-- identifier model.)
420+
--
421+
-- Additionally, this is simulating some logic GHC already
422+
-- has for deciding how to qualify names when it outputs
423+
-- them to the user. We should reuse that information;
424+
-- or at least reuse the renamed imports, which know what
425+
-- they import!
426+
(fmap Module.fsToUnit $
427+
fmap sl_fs $ ideclPkgQual impDecl)
428+
(case ideclName impDecl of SrcLoc.L _ name -> name),
429+
alias))
430+
impDecls
249431

250432
-- We want to know which modules are imported without any qualification. This
251433
-- way we can display module reexports more compactly. This mapping also looks

0 commit comments

Comments
 (0)