aboutsummaryrefslogtreecommitdiff
path: root/src/Haddock
diff options
context:
space:
mode:
authorDavid Waern <david.waern@gmail.com>2009-11-24 20:55:49 +0000
committerDavid Waern <david.waern@gmail.com>2009-11-24 20:55:49 +0000
commitdc3a42156eeb0fd1457a395e69f5778c0446caa5 (patch)
tree480019738b5aa5060ac43e133949f7fb1e09eab9 /src/Haddock
parent53f11cbd4af38e88ef547fec54cc42f976b1d048 (diff)
Comments on instances
Implementing this was a little trickier than I thought, since we need to match up instances from the renamed syntax with instances represented by InstEnv.Instance. This is due to the current design of Haddock, which matches comments with declarations from the renamed syntax, while getting the list of instances of a class/family directly using the GHC API. - Works for class instances only (Haddock has no support for type family instances yet) - The comments are rendered to the right of the instance head in the HTML output - No change to the .haddock file format - Works for normal user-written instances only. No comments are added on derived or TH-generated instances
Diffstat (limited to 'src/Haddock')
-rw-r--r--src/Haddock/Backends/Html.hs47
-rw-r--r--src/Haddock/Interface.hs2
-rw-r--r--src/Haddock/Interface/AttachInstances.hs43
-rw-r--r--src/Haddock/Interface/Create.hs34
-rw-r--r--src/Haddock/Interface/Rename.hs15
-rw-r--r--src/Haddock/Types.hs15
6 files changed, 110 insertions, 46 deletions
diff --git a/src/Haddock/Backends/Html.hs b/src/Haddock/Backends/Html.hs
index fead8470..93c2a491 100644
--- a/src/Haddock/Backends/Html.hs
+++ b/src/Haddock/Backends/Html.hs
@@ -809,7 +809,7 @@ declWithDoc False links loc nm (Just doc) html_decl =
-- TODO: use DeclInfo DocName or something
ppDecl :: Bool -> LinksInfo -> LHsDecl DocName ->
- DocForDecl DocName -> [InstHead DocName] -> [(DocName, DocForDecl DocName)] -> Bool -> HtmlTable
+ DocForDecl DocName -> [DocInstance DocName] -> [(DocName, DocForDecl DocName)] -> Bool -> HtmlTable
ppDecl summ links (L loc decl) (mbDoc, fnArgsDoc) instances subdocs unicode = case decl of
TyClD d@(TyFamily {}) -> ppTyFam summ False links loc mbDoc d unicode
TyClD d@(TyData {})
@@ -955,7 +955,7 @@ ppTyFam summary associated links loc mbDoc decl unicode
tda [theclass "body"] <<
collapsed thediv instId (
spacedTable1 << (
- aboves (map (declBox . ppInstHead unicode) instances)
+ aboves (map (ppDocInstance unicode) instances)
)
)
@@ -1150,7 +1150,7 @@ ppShortClassDecl _ _ _ _ _ _ = error "declaration type not supported by ppShortC
-ppClassDecl :: Bool -> LinksInfo -> [InstHead DocName] -> SrcSpan
+ppClassDecl :: Bool -> LinksInfo -> [DocInstance DocName] -> SrcSpan
-> Maybe (HsDoc DocName) -> [(DocName, DocForDecl DocName)]
-> TyClDecl DocName -> Bool -> HtmlTable
ppClassDecl summary links instances loc mbDoc subdocs
@@ -1191,12 +1191,19 @@ ppClassDecl summary links instances loc mbDoc subdocs
= s8 </> instHdr instId </>
tda [theclass "body"] <<
collapsed thediv instId (
- spacedTable1 << (
- aboves (map (declBox . ppInstHead unicode) instances)
- ))
+ spacedTable1 << aboves (map (ppDocInstance unicode) instances)
+ )
ppClassDecl _ _ _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl"
+-- | Print a possibly commented instance. The instance header is printed inside
+-- an 'argBox'. The comment is printed to the right of the box in normal comment
+-- style.
+ppDocInstance :: Bool -> DocInstance DocName -> HtmlTable
+ppDocInstance unicode (_, instHead, maybeDoc) =
+ argBox (ppInstHead unicode instHead) <-> maybeRDocBox maybeDoc
+
+
ppInstHead :: Bool -> InstHead DocName -> Html
ppInstHead unicode ([], n, ts) = ppAppNameTypes n ts unicode
ppInstHead unicode (ctxt, n, ts) = ppContextNoLocs ctxt unicode <+> ppAppNameTypes n ts unicode
@@ -1249,7 +1256,7 @@ ppShortDataDecl summary links loc dataDecl unicode
cons = tcdCons dataDecl
resTy = (con_res . unLoc . head) cons
-ppDataDecl :: Bool -> LinksInfo -> [InstHead DocName] ->
+ppDataDecl :: Bool -> LinksInfo -> [DocInstance DocName] ->
[(DocName, DocForDecl DocName)] ->
SrcSpan -> Maybe (HsDoc DocName) -> TyClDecl DocName -> Bool -> HtmlTable
ppDataDecl summary links instances subdocs loc mbDoc dataDecl unicode
@@ -1303,8 +1310,7 @@ ppDataDecl summary links instances subdocs loc mbDoc dataDecl unicode
= instHdr instId </>
tda [theclass "body"] <<
collapsed thediv instId (
- spacedTable1 << (
- aboves (map (declBox . ppInstHead unicode) instances)
+ spacedTable1 << aboves (map (ppDocInstance unicode) instances
)
)
@@ -1374,17 +1380,17 @@ ppSideBySideConstr subdocs unicode (L _ con) = case con_res con of
PrefixCon args ->
argBox (hsep ((header_ unicode +++ ppBinder False occ) : map (ppLParendType unicode) args))
- <-> maybeRDocBox mbLDoc
+ <-> maybeRDocBox mbDoc
RecCon fields ->
argBox (header_ unicode +++ ppBinder False occ) <->
- maybeRDocBox mbLDoc
+ maybeRDocBox mbDoc
</>
doRecordFields fields
InfixCon arg1 arg2 ->
argBox (hsep [header_ unicode+++ppLParendType unicode arg1, ppBinder False occ, ppLParendType unicode arg2])
- <-> maybeRDocBox mbLDoc
+ <-> maybeRDocBox mbDoc
ResTyGADT resTy -> case con_details con of
-- prefix & infix could also use hsConDeclArgTys if it seemed to
@@ -1401,7 +1407,7 @@ ppSideBySideConstr subdocs unicode (L _ con) = case con_res con of
doGADTCon args resTy = argBox (ppBinder False occ <+> dcolon unicode <+> hsep [
ppForAll forall ltvs (con_cxt con) unicode,
ppLType unicode (foldr mkFunTy resTy args) ]
- ) <-> maybeRDocBox mbLDoc
+ ) <-> maybeRDocBox mbDoc
header_ = ppConstrHdr forall tyVars context
@@ -1412,19 +1418,17 @@ ppSideBySideConstr subdocs unicode (L _ con) = case con_res con of
forall = con_explicit con
-- don't use "con_doc con", in case it's reconstructed from a .hi file,
-- or also because we want Haddock to do the doc-parsing, not GHC.
- -- The 'fmap' and 'join' are in Maybe
- mbLDoc = fmap noLoc $ join $ fmap fst $
- lookup (unLoc $ con_name con) subdocs
+ -- 'join' is in Maybe.
+ mbDoc = join $ fmap fst $ lookup (unLoc $ con_name con) subdocs
mkFunTy a b = noLoc (HsFunTy a b)
ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocName -> HtmlTable
ppSideBySideField subdocs unicode (ConDeclField (L _ name) ltype _) =
argBox (ppBinder False (docNameOcc name)
- <+> dcolon unicode <+> ppLType unicode ltype) <->
- maybeRDocBox mbLDoc
+ <+> dcolon unicode <+> ppLType unicode ltype) <-> maybeRDocBox mbDoc
where
-- don't use cd_fld_doc for same reason we don't use con_doc above
- mbLDoc = fmap noLoc $ join $ fmap fst $ lookup name subdocs
+ mbDoc = join $ fmap fst $ lookup name subdocs
{-
ppHsFullConstr :: HsConDecl -> Html
@@ -1764,6 +1768,7 @@ htmlCleanup = idMarkup {
-- -----------------------------------------------------------------------------
-- * Misc
+
hsep :: [Html] -> Html
hsep [] = noHtml
hsep htmls = foldr1 (\a b -> a+++" "+++b) htmls
@@ -1890,9 +1895,9 @@ ndocBox html = tda [theclass "ndoc"] << html
rdocBox :: Html -> HtmlTable
rdocBox html = tda [theclass "rdoc"] << html
-maybeRDocBox :: Maybe (LHsDoc DocName) -> HtmlTable
+maybeRDocBox :: Maybe (HsDoc DocName) -> HtmlTable
maybeRDocBox Nothing = rdocBox (noHtml)
-maybeRDocBox (Just ldoc) = rdocBox (docToHtml (unLoc ldoc))
+maybeRDocBox (Just doc) = rdocBox (docToHtml doc)
-- a box for the buttons at the top of the page
topButBox :: Html -> HtmlTable
diff --git a/src/Haddock/Interface.hs b/src/Haddock/Interface.hs
index 6cbd4c9a..cc53efdf 100644
--- a/src/Haddock/Interface.hs
+++ b/src/Haddock/Interface.hs
@@ -61,7 +61,7 @@ createInterfaces verbosity modules flags extIfaces = do
-- part 3, attach instances
out verbosity verbose "Attaching instances..."
- interfaces' <- attachInstances interfaces
+ interfaces' <- attachInstances interfaces instIfaceMap
-- part 4, rename interfaces
out verbosity verbose "Renaming interfaces..."
diff --git a/src/Haddock/Interface/AttachInstances.hs b/src/Haddock/Interface/AttachInstances.hs
index b996f278..a10cb36a 100644
--- a/src/Haddock/Interface/AttachInstances.hs
+++ b/src/Haddock/Interface/AttachInstances.hs
@@ -18,7 +18,9 @@ module Haddock.Interface.AttachInstances (attachInstances) where
import Haddock.Types
import Haddock.Convert
+import Control.Arrow
import Data.List
+import qualified Data.Map as Map
import GHC
import Name
@@ -40,22 +42,38 @@ import FastString
#define FSLIT(x) (mkFastString# (x#))
-attachInstances :: [Interface] -> Ghc [Interface]
-attachInstances = mapM attach
+attachInstances :: [Interface] -> InstIfaceMap -> Ghc [Interface]
+attachInstances ifaces instIfaceMap = mapM attach ifaces
where
attach iface = do
newItems <- mapM attachExport $ ifaceExportItems iface
return $ iface { ifaceExportItems = newItems }
-
- attachExport export@ExportDecl{expItemDecl = L _ (TyClD d)} = do
- mb_info <- getAllInfo (unLoc (tcdLName d))
- return $ export { expItemInstances = case mb_info of
- Just (_, _, instances) ->
- map synifyInstHead . sortImage instHead . map instanceHead $ instances
- Nothing ->
- []
- }
- attachExport export = return export
+ where
+ attachExport export@ExportDecl{expItemDecl = L _ (TyClD d)} = do
+ mb_info <- getAllInfo (unLoc (tcdLName d))
+ return $ export { expItemInstances = case mb_info of
+ Just (_, _, instances) ->
+ let insts = map (first synifyInstHead) $ sortImage (first instHead)
+ [ (instanceHead i, getName i) | i <- instances ]
+ in [ (name, inst, lookupInstDoc name iface instIfaceMap)
+ | (inst, name) <- insts ]
+ Nothing -> []
+ }
+ attachExport export = return export
+
+
+lookupInstDoc :: Name -> Interface -> InstIfaceMap -> Maybe (HsDoc Name)
+-- TODO: capture this pattern in a function (when we have streamlined the
+-- handling of instances)
+lookupInstDoc name iface ifaceMap =
+ case Map.lookup name (ifaceInstanceDocMap iface) of
+ Just doc -> Just doc
+ Nothing -> do -- in Maybe
+ instIface <- Map.lookup modName ifaceMap
+ (Just doc, _) <- Map.lookup name (instDocMap instIface)
+ return doc
+ where
+ modName = nameModule name
-- | Like GHC's getInfo but doesn't cut things out depending on the
@@ -63,6 +81,7 @@ attachInstances = mapM attach
getAllInfo :: GhcMonad m => Name -> m (Maybe (TyThing,Fixity,[Instance]))
getAllInfo name = withSession $ \hsc_env -> ioMsg $ tcRnGetInfo hsc_env name
+
--------------------------------------------------------------------------------
-- Collecting and sorting instances
--------------------------------------------------------------------------------
diff --git a/src/Haddock/Interface/Create.hs b/src/Haddock/Interface/Create.hs
index f1023825..874037d7 100644
--- a/src/Haddock/Interface/Create.hs
+++ b/src/Haddock/Interface/Create.hs
@@ -56,13 +56,18 @@ createInterface ghcMod flags modMap instIfaceMap = do
(info, mbDoc) <- liftErrMsg $ lexParseRnHaddockModHeader
gre (ghcMbDocHdr ghcMod)
decls0 <- liftErrMsg $ declInfos gre (topDecls (ghcGroup ghcMod))
- let decls = filterOutInstances decls0
+
+ let instances = ghcInstances ghcMod
+ localInsts = filter (nameIsLocalOrFrom mdl . getName) instances
+ declDocs = [ (decl, doc) | (L _ decl, (Just doc, _), _) <- decls0 ]
+ instanceDocMap = mkInstanceDocMap localInsts declDocs
+
+ decls = filterOutInstances decls0
declMap = mkDeclMap decls
exports = fmap (reverse . map unLoc) (ghcMbExports ghcMod)
localNames = ghcDefinedNames ghcMod
ignoreExps = Flag_IgnoreAllExports `elem` flags
exportedNames = ghcExportedNames ghcMod
- instances = ghcInstances ghcMod
liftErrMsg $ warnAboutFilteredDecls mdl decls0
@@ -93,7 +98,8 @@ createInterface ghcMod flags modMap instIfaceMap = do
ifaceVisibleExports = visibleNames,
ifaceDeclMap = declMap,
ifaceSubMap = mkSubMap declMap exportedNames,
- ifaceInstances = ghcInstances ghcMod
+ ifaceInstances = instances,
+ ifaceInstanceDocMap = instanceDocMap
}
@@ -128,6 +134,22 @@ parseOption other = tell ["Unrecognised option: " ++ other] >> return Nothing
-- Declarations
--------------------------------------------------------------------------------
+
+mkInstanceDocMap :: [Instance] -> [(HsDecl name, doc)] -> Map Name doc
+mkInstanceDocMap instances decls =
+ -- We relate Instances to InstDecls using the SrcSpans buried inside them.
+ -- That should work for normal user-written instances (from looking at GHC
+ -- sources). We can assume that commented instances are user-written.
+ -- This lets us relate Names (from Instances) to comments (associated
+ -- with InstDecls).
+ let docMap = Map.fromList [ (loc, doc)
+ | (InstD (InstDecl (L loc _) _ _ _), doc) <- decls ]
+
+ in Map.fromList [ (name, doc) | inst <- instances
+ , let name = getName inst
+ , Just doc <- [ Map.lookup (getSrcSpan name) docMap ] ]
+
+
-- | Make a sub map from a declaration map. Make sure we only include exported
-- names.
mkSubMap :: Map Name DeclInfo -> [Name] -> Map Name [Name]
@@ -137,13 +159,13 @@ mkSubMap declMap exports =
filterSubs (_, _, subs) = [ sub | (sub, _) <- subs, sub `elem` exports ]
--- Make a map from names to 'DeclInfo's. Exclude declarations that don't
--- have names (instances and stand-alone documentation comments). Include
+-- Make a map from names to 'DeclInfo's. Exclude declarations that don't have
+-- names (e.g. instances and stand-alone documentation comments). Include
-- subordinate names, but map them to their parent declarations.
mkDeclMap :: [DeclInfo] -> Map Name DeclInfo
mkDeclMap decls = Map.fromList . concat $
[ (declName d, (parent, doc, subs)) : subDecls
- | (parent@(L _ d), doc, subs) <- decls
+ | (parent@(L _ d), doc, subs) <- decls
, let subDecls = [ (n, (parent, doc', [])) | (n, doc') <- subs ]
, not (isDocD d), not (isInstD d) ]
diff --git a/src/Haddock/Interface/Rename.hs b/src/Haddock/Interface/Rename.hs
index 5eac9e67..308c86c5 100644
--- a/src/Haddock/Interface/Rename.hs
+++ b/src/Haddock/Interface/Rename.hs
@@ -37,8 +37,13 @@ renameInterface renamingEnv warnings iface =
let localEnv = foldl fn renamingEnv (ifaceVisibleExports iface)
where fn env name = Map.insert name (ifaceMod iface) env
- docMap = Map.map (\(_,x,_) -> x) (ifaceDeclMap iface)
- docs = Map.toList docMap
+ docMap = Map.map (\(_,x,_) -> x) (ifaceDeclMap iface)
+
+ -- make instance docs into 'docForDecls'
+ instDocs = [ (name, (Just doc, Map.empty))
+ | (name, doc) <- Map.toList (ifaceInstanceDocMap iface) ]
+
+ docs = Map.toList docMap ++ instDocs
renameMapElem (k,d) = do d' <- renameDocForDecl d; return (k, d')
-- rename names in the exported declarations to point to things that
@@ -448,7 +453,11 @@ renameExportItem item = case item of
decl' <- renameLDecl decl
doc' <- renameDocForDecl doc
subs' <- mapM renameSub subs
- instances' <- mapM renameInstHead instances
+ instances' <- forM instances $ \(name, inst, idoc) -> do
+ name' <- rename name
+ inst' <- renameInstHead inst
+ idoc' <- mapM renameDoc idoc
+ return (name', inst', idoc')
return (ExportDecl decl' doc' subs' instances')
ExportNoDecl x subs -> do
x' <- lookupRn id x
diff --git a/src/Haddock/Types.hs b/src/Haddock/Types.hs
index 4c8c3656..d7d5e7bd 100644
--- a/src/Haddock/Types.hs
+++ b/src/Haddock/Types.hs
@@ -40,6 +40,8 @@ import Name
type Decl = LHsDecl Name
type Doc = HsDoc Name
+type DocInstance name = (name, InstHead name, Maybe (HsDoc name))
+
#if __GLASGOW_HASKELL__ <= 610
type HsDocString = HsDoc Name
type LHsDocString = Located HsDocString
@@ -98,8 +100,8 @@ data ExportItem name
-- | Subordinate names, possibly with documentation
expItemSubDocs :: [(name, DocForDecl name)],
- -- | Instances relevant to this declaration
- expItemInstances :: [InstHead name]
+ -- | Instances relevant to this declaration, possibly with documentation
+ expItemInstances :: [DocInstance name]
} -- ^ An exported declaration
@@ -131,7 +133,11 @@ data ExportItem name
| ExportModule Module -- ^ A cross-reference to another module
+-- | The head of an instance. Consists of a context, a class name and a list of
+-- instance types.
type InstHead name = ([HsPred name], name, [HsType name])
+
+
type ModuleMap = Map Module Interface
type InstIfaceMap = Map Module InstalledInterface
type DocMap = Map Name (HsDoc DocName)
@@ -215,7 +221,10 @@ data Interface = Interface {
ifaceVisibleExports :: ![Name],
-- | The instances exported by this module
- ifaceInstances :: ![Instance]
+ ifaceInstances :: ![Instance],
+
+ -- | Docs for instances defined in this module
+ ifaceInstanceDocMap :: Map Name (HsDoc Name)
}