diff options
author | David Waern <david.waern@gmail.com> | 2011-12-27 13:33:41 +0100 |
---|---|---|
committer | David Waern <david.waern@gmail.com> | 2011-12-27 13:33:41 +0100 |
commit | 12e619d5b00d205443768c224da2bfb045569590 (patch) | |
tree | 4c50f7e3a3d8e34b70b6d6b80dd42d191284ba50 /src | |
parent | 505df72e9e0962e01cf031f799d8d8940ced73b1 (diff) | |
parent | 60a043541e062ff6ceb52b0ab9e4f67d79dd3754 (diff) |
Merge ../../../haddock
Conflicts:
src/Haddock/InterfaceFile.hs
Diffstat (limited to 'src')
-rw-r--r-- | src/Documentation/Haddock.hs | 1 | ||||
-rw-r--r-- | src/Haddock/GhcUtils.hs | 14 | ||||
-rw-r--r-- | src/Haddock/Interface/AttachInstances.hs | 9 | ||||
-rw-r--r-- | src/Haddock/Interface/Create.hs | 456 | ||||
-rw-r--r-- | src/Haddock/Interface/ExtractFnArgDocs.hs | 49 | ||||
-rw-r--r-- | src/Haddock/Interface/Rename.hs | 19 | ||||
-rw-r--r-- | src/Haddock/InterfaceFile.hs | 14 | ||||
-rw-r--r-- | src/Haddock/Types.hs | 40 |
8 files changed, 252 insertions, 350 deletions
diff --git a/src/Documentation/Haddock.hs b/src/Documentation/Haddock.hs index 96198494..052f1044 100644 --- a/src/Documentation/Haddock.hs +++ b/src/Documentation/Haddock.hs @@ -22,7 +22,6 @@ module Documentation.Haddock ( -- * Export items & declarations ExportItem(..), Decl, - DeclInfo, DocForDecl, FnArgsDoc, diff --git a/src/Haddock/GhcUtils.hs b/src/Haddock/GhcUtils.hs index 2fb8c8a3..fc04351b 100644 --- a/src/Haddock/GhcUtils.hs +++ b/src/Haddock/GhcUtils.hs @@ -20,6 +20,7 @@ import Data.Version import Control.Applicative ( (<$>) ) import Control.Arrow import Data.Foldable hiding (concatMap) +import Data.Function import Data.Traversable import Distribution.Compat.ReadP import Distribution.Text @@ -77,7 +78,7 @@ isVarSym = isLexVarSym . occNameFS getMainDeclBinder :: HsDecl name -> [name] -getMainDeclBinder (TyClD d) = [tcdName d] +getMainDeclBinder (TyClD d) | not (isFamInstDecl d) = [tcdName d] getMainDeclBinder (ValD d) = case collectHsBindBinders d of [] -> [] @@ -141,6 +142,11 @@ isInstD (TyClD d) = isFamInstDecl d isInstD _ = False +isValD :: HsDecl a -> Bool +isValD (ValD _) = True +isValD _ = False + + declATs :: HsDecl a -> [a] declATs (TyClD d) | isClassDecl d = map (tcdName . unL) $ tcdATs d declATs _ = [] @@ -167,6 +173,10 @@ reL :: a -> Located a reL = L undefined +before :: Located a -> Located a -> Bool +before = (<) `on` getLoc + + instance Foldable (GenLocated l) where foldMap f (L _ x) = f x @@ -253,7 +263,7 @@ modifySessionDynFlags f = do -- | A variant of 'gbracket' where the return value from the first computation -- is not required. gbracket_ :: ExceptionMonad m => m a -> m b -> m c -> m c -gbracket_ before after thing = gbracket before (const after) (const thing) +gbracket_ before_ after thing = gbracket before_ (const after) (const thing) ------------------------------------------------------------------------------- diff --git a/src/Haddock/Interface/AttachInstances.hs b/src/Haddock/Interface/AttachInstances.hs index 5b7771ec..c012f2e0 100644 --- a/src/Haddock/Interface/AttachInstances.hs +++ b/src/Haddock/Interface/AttachInstances.hs @@ -73,20 +73,17 @@ lookupInstDoc :: Name -> Interface -> IfaceMap -> InstIfaceMap -> Maybe (Doc Nam -- TODO: capture this pattern in a function (when we have streamlined the -- handling of instances) lookupInstDoc name iface ifaceMap instIfaceMap = - case Map.lookup name (ifaceInstanceDocMap iface) of + case Map.lookup name (ifaceDocMap iface) of Just doc -> Just doc Nothing -> case Map.lookup modName ifaceMap of Just iface2 -> - case Map.lookup name (ifaceInstanceDocMap iface2) of + case Map.lookup name (ifaceDocMap iface2) of Just doc -> Just doc Nothing -> Nothing Nothing -> case Map.lookup modName instIfaceMap of - Just instIface -> - case Map.lookup name (instDocMap instIface) of - Just (doc, _) -> doc - Nothing -> Nothing + Just instIface -> Map.lookup name (instDocMap instIface) Nothing -> Nothing where modName = nameModule name diff --git a/src/Haddock/Interface/Create.hs b/src/Haddock/Interface/Create.hs index 155cd938..a9f6c2ed 100644 --- a/src/Haddock/Interface/Create.hs +++ b/src/Haddock/Interface/Create.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Interface.Create @@ -18,13 +19,15 @@ import Haddock.GhcUtils import Haddock.Utils import Haddock.Convert import Haddock.Interface.LexParseRn -import Haddock.Interface.ExtractFnArgDocs import qualified Data.Map as Map +import qualified Data.Map as M import Data.Map (Map) import Data.List import Data.Maybe +import Data.Monoid import Data.Ord +import Control.Applicative import Control.Monad import qualified Data.Traversable as Traversable @@ -61,22 +64,20 @@ createInterface tm flags modMap instIfaceMap = do | otherwise = opts0 (info, mbDoc) <- liftErrMsg $ lexParseRnHaddockModHeader dflags gre optDocHeader - decls0 <- liftErrMsg $ declInfos dflags gre (topDecls group_) - let localInsts = filter (nameIsLocalOrFrom mdl . getName) instances - declDocs = [ (decl, doc) | (L _ decl, (Just doc, _), _) <- decls0 ] - instanceDocMap = mkInstanceDocMap localInsts declDocs + let declsWithDocs = topDecls group_ + (decls, _) = unzip declsWithDocs + localInsts = filter (nameIsLocalOrFrom mdl . getName) instances + (docMap, argMap, subMap, declMap) <- liftErrMsg $ maps dflags gre localInsts exportedNames declsWithDocs - decls = filterOutInstances decls0 - declMap = mkDeclMap decls - exports0 = fmap (reverse . map unLoc) optExports - exports + let exports0 = fmap (reverse . map unLoc) optExports + exports | OptIgnoreExports `elem` opts = Nothing | otherwise = exports0 - liftErrMsg $ warnAboutFilteredDecls mdl decls0 + liftErrMsg $ warnAboutFilteredDecls mdl decls - exportItems <- mkExportItems modMap mdl gre exportedNames decls declMap + exportItems <- mkExportItems modMap mdl gre exportedNames decls docMap argMap subMap declMap exports instances instIfaceMap dflags let visibleNames = mkVisibleNames exportItems opts @@ -102,15 +103,17 @@ createInterface tm flags modMap instIfaceMap = do ifaceDoc = mbDoc, ifaceRnDoc = Nothing, ifaceOptions = opts, + ifaceDocMap = docMap, + ifaceArgMap = argMap, ifaceRnDocMap = Map.empty, + ifaceRnArgMap = Map.empty, ifaceExportItems = prunedExportItems, ifaceRnExportItems = [], ifaceExports = exportedNames, ifaceVisibleExports = visibleNames, ifaceDeclMap = declMap, - ifaceSubMap = mkSubMap declMap exportedNames, + ifaceSubMap = subMap, ifaceInstances = instances, - ifaceInstanceDocMap = instanceDocMap, ifaceHaddockCoverage = coverage } @@ -147,94 +150,68 @@ parseOption other = tell ["Unrecognised option: " ++ other] >> return Nothing -------------------------------------------------------------------------------- -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 ] +type Maps = (DocMap Name, ArgMap Name, SubMap, DeclMap) - 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] -mkSubMap declMap exports = - Map.filterWithKey (\k _ -> k `elem` exports) (Map.map filterSubs declMap) - where - filterSubs (_, _, subs) = [ sub | (sub, _) <- subs, sub `elem` exports ] - - --- 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 $ - [ decls_ ++ subDecls - | (parent@(L _ d), doc, subs) <- decls - , let decls_ = [ (name, (parent, doc, subs)) | name <- getMainDeclBinder d ] - subDecls = [ (n, (parent, doc', [])) | (n, doc') <- subs ] - , not (isDocD d), not (isInstD d) ] - - -declInfos :: DynFlags -> GlobalRdrEnv -> [(Decl, MaybeDocStrings)] -> ErrMsgM [DeclInfo] -declInfos dflags gre decls = - forM decls $ \(parent@(L _ d), mbDocString) -> do - mbDoc <- lexParseRnHaddockCommentList dflags NormalHaddockComment - gre mbDocString - fnArgsDoc <- fmap (Map.mapMaybe id) $ - Traversable.forM (getDeclFnArgDocs d) $ - \doc -> lexParseRnHaddockComment dflags NormalHaddockComment gre doc - - let subs_ = subordinates d - subs <- forM subs_ $ \(subName, mbSubDocStr, subFnArgsDocStr) -> do - mbSubDoc <- lexParseRnHaddockCommentList dflags NormalHaddockComment - gre mbSubDocStr - subFnArgsDoc <- fmap (Map.mapMaybe id) $ - Traversable.forM subFnArgsDocStr $ - \doc -> lexParseRnHaddockComment dflags NormalHaddockComment gre doc - return (subName, (mbSubDoc, subFnArgsDoc)) - - return (parent, (mbDoc, fnArgsDoc), subs) - - --- | If you know the HsDecl can't contain any docs --- (e.g., it was loaded from a .hi file and you don't have a .haddock file --- to help you find out about the subs or docs) --- then you can use this to get its subs. -subordinatesWithNoDocs :: HsDecl Name -> [(Name, DocForDecl Name)] -subordinatesWithNoDocs decl = map noDocs (subordinates decl) +maps :: DynFlags -> GlobalRdrEnv -> [Instance] -> [Name] -> [(Decl, MaybeDocStrings)] -> ErrMsgM Maps +maps dflags gre instances exports decls = do + maps_ <- mapM f decls + let mergeMaps (a,b,c,d) (x,y,z,w) = + (M.unionWith mappend a x, M.unionWith mappend b y, + M.unionWith mappend c z, M.unionWith mappend d w) + let emptyMaps = (M.empty, M.empty, M.empty, M.empty) + return (foldl' mergeMaps emptyMaps maps_) where - -- check the condition... or shouldn't we be checking? - noDocs (n, doc1, doc2) | null doc1, Map.null doc2 - = (n, noDocForDecl) - noDocs _ = error ("no-docs thing has docs! " ++ pretty decl) + instanceMap = M.fromList [ (getSrcSpan n, n) | i <- instances, let n = getName i ] + f :: (Decl, MaybeDocStrings) -> ErrMsgM Maps + f (decl@(L _ d), docs) = do + mayDoc <- lexParseRnHaddockCommentList dflags NormalHaddockComment gre docs + argDocs <- fmap (Map.mapMaybe id) $ Traversable.forM (typeDocs d) $ + \doc -> lexParseRnHaddockComment dflags NormalHaddockComment gre doc -subordinates :: HsDecl Name -> [(Name, MaybeDocStrings, Map Int HsDocString)] -subordinates (TyClD d) = classDataSubs d -subordinates _ = [] + let subs_ = subordinates d + let subs_' = filter (\(name, _, _) -> name `elem` exports) subs_ + + (subDocs, subArgMap) <- unzip <$> (forM subs_' $ \(name, mbSubDocStr, subFnArgsDocStr) -> do + mbSubDoc <- lexParseRnHaddockCommentList dflags NormalHaddockComment gre mbSubDocStr + subFnArgsDoc <- fmap (Map.mapMaybe id) $ Traversable.forM subFnArgsDocStr $ + \doc -> lexParseRnHaddockComment dflags NormalHaddockComment gre doc + return ((name, mbSubDoc), (name, subFnArgsDoc))) + + let subNames = map fst subDocs + + let names = case d of + InstD (InstDecl (L l _) _ _ _) -> maybeToList (M.lookup l instanceMap) -- See note [2]. + _ -> filter (`elem` exports) (getMainDeclBinder d) + + let docMap' = M.fromList (mapMaybe (\(n,doc) -> fmap (n,) doc) ([ (n, mayDoc) | n <- names ] ++ subDocs)) + let argMap' = M.fromList [ (n, argDocs) | n <- names ] `mappend` M.fromList subArgMap + let subMap' = M.fromList [ (n, subNames) | n <- names ] + let dclMap' = M.fromList [ (n, [decl]) | n <- names ++ subNames ] + return (docMap', argMap', subMap', dclMap') -classDataSubs :: TyClDecl Name -> [(Name, MaybeDocStrings, Map Int HsDocString)] -classDataSubs decl +-- Note [2]: +------------ +-- 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). + + +subordinates :: HsDecl Name -> [(Name, MaybeDocStrings, Map Int HsDocString)] +subordinates (TyClD decl) | isClassDecl decl = classSubs | isDataDecl decl = dataSubs - | otherwise = [] where - classSubs = [ (name, doc, fnArgsDoc) - | (L _ d, doc) <- classDecls decl - , name <- getMainDeclBinder d - , let fnArgsDoc = getDeclFnArgDocs d ] - dataSubs = constrs ++ fields + classSubs = [ (name, doc, typeDocs d) | (L _ d, doc) <- classDecls decl + , name <- getMainDeclBinder d, not (isValD d) + ] + dataSubs = constrs ++ fields where - cons = map unL $ tcdCons decl + cons = map unL $ tcdCons decl -- should we use the type-signature of the constructor -- and the docs of the fields to produce fnArgsDoc for the constr, -- just in case someone exports it without exporting the type @@ -244,48 +221,62 @@ classDataSubs decl fields = [ (unL n, maybeToList $ fmap unL doc, Map.empty) | RecCon flds <- map con_details cons , ConDeclField n _ doc <- flds ] +subordinates _ = [] --- All the sub declarations of a class (that we handle), ordered by --- source location, with documentation attached if it exists. -classDecls :: TyClDecl Name -> [(Decl, MaybeDocStrings)] -classDecls = filterDecls . collectDocs . sortByLoc . declsFromClass +-- | Extract function argument docs from inside types. +typeDocs :: HsDecl Name -> Map Int HsDocString +typeDocs d = + let docs = go 0 in + case d of + SigD (TypeSig _ ty) -> docs (unLoc ty) + ForD (ForeignImport _ ty _ _) -> docs (unLoc ty) + TyClD (TySynonym {tcdSynRhs = ty}) -> docs (unLoc ty) + _ -> Map.empty + where + go n (HsForAllTy _ _ _ ty) = go n (unLoc ty) + go n (HsFunTy (L _ (HsDocTy _ (L _ x))) (L _ ty)) = Map.insert n x $ go (n+1) ty + go n (HsFunTy _ ty) = go (n+1) (unLoc ty) + go n (HsDocTy _ (L _ doc)) = Map.singleton n doc + go _ _ = Map.empty -declsFromClass :: TyClDecl a -> [Located (HsDecl a)] -declsFromClass class_ = docs ++ defs ++ sigs ++ ats +-- | All the sub declarations of a class (that we handle), ordered by +-- source location, with documentation attached if it exists. +classDecls :: TyClDecl Name -> [(Decl, MaybeDocStrings)] +classDecls class_ = filterDecls . collectDocs . sortByLoc $ decls where - docs = mkDecls tcdDocs DocD class_ - defs = mkDecls (bagToList . tcdMeths) ValD class_ - sigs = mkDecls tcdSigs SigD class_ - ats = mkDecls tcdATs TyClD class_ + decls = docs ++ defs ++ sigs ++ ats + docs = mkDecls tcdDocs DocD class_ + defs = mkDecls (bagToList . tcdMeths) ValD class_ + sigs = mkDecls tcdSigs SigD class_ + ats = mkDecls tcdATs TyClD class_ -- | The top-level declarations of a module that we care about, -- ordered by source location, with documentation attached if it exists. topDecls :: HsGroup Name -> [(Decl, MaybeDocStrings)] -topDecls = filterClasses . filterDecls . collectDocs . sortByLoc . declsFromGroup - - -filterOutInstances :: [(Located (HsDecl a), b, c)] -> [(Located (HsDecl a), b, c)] -filterOutInstances = filter (\(L _ d, _, _) -> not (isInstD d)) - - --- | Take all declarations except pragmas, infix decls, rules and value --- bindings from an 'HsGroup'. -declsFromGroup :: HsGroup Name -> [Decl] -declsFromGroup group_ = - mkDecls (concat . hs_tyclds) TyClD group_ ++ - mkDecls hs_derivds DerivD group_ ++ - mkDecls hs_defds DefD group_ ++ - mkDecls hs_fords ForD group_ ++ - mkDecls hs_docs DocD group_ ++ - mkDecls hs_instds InstD group_ ++ - mkDecls (typesigs . hs_valds) SigD group_ +topDecls = filterClasses . filterDecls . collectDocs . sortByLoc . ungroup + + +-- | Take all declarations except pragmas, infix decls, rules from an 'HsGroup'. +ungroup :: HsGroup Name -> [Decl] +ungroup group_ = + mkDecls (concat . hs_tyclds) TyClD group_ ++ + mkDecls hs_derivds DerivD group_ ++ + mkDecls hs_defds DefD group_ ++ + mkDecls hs_fords ForD group_ ++ + mkDecls hs_docs DocD group_ ++ + mkDecls hs_instds InstD group_ ++ + mkDecls (typesigs . hs_valds) SigD group_ ++ + mkDecls (valbinds . hs_valds) ValD group_ where typesigs (ValBindsOut _ sigs) = filter isVanillaLSig sigs typesigs _ = error "expected ValBindsOut" + valbinds (ValBindsOut binds _) = concatMap bagToList . snd . unzip $ binds + valbinds _ = error "expected ValBindsOut" + -- | Take a field of declarations from a data structure and create HsDecls -- using the given constructor @@ -298,11 +289,11 @@ sortByLoc :: [Located a] -> [Located a] sortByLoc = sortBy (comparing getLoc) -warnAboutFilteredDecls :: Module -> [(LHsDecl Name, b, c)] -> ErrMsgM () +warnAboutFilteredDecls :: Module -> [LHsDecl Name] -> ErrMsgM () warnAboutFilteredDecls mdl decls = do let modStr = moduleString mdl let typeInstances = - nub [ tcdName d | (L _ (TyClD d), _, _) <- decls, isFamInstDecl d ] + nub [ tcdName d | L _ (TyClD d) <- decls, isFamInstDecl d ] unless (null typeInstances) $ tell [ @@ -311,7 +302,7 @@ warnAboutFilteredDecls mdl decls = do ++ "will be filtered out:\n " ++ concat (intersperse ", " $ map (occNameString . nameOccName) typeInstances) ] - let instances = nub [ pretty i | (L _ (InstD (InstDecl i _ _ ats)), _, _) <- decls + let instances = nub [ pretty i | L _ (InstD (InstDecl i _ _ ats)) <- decls , not (null ats) ] unless (null instances) $ @@ -335,6 +326,7 @@ filterDecls decls = filter (isHandled . unL . fst) decls isHandled (TyClD {}) = True isHandled (InstD {}) = True isHandled (SigD d) = isVanillaLSig (reL d) + isHandled (ValD _) = True -- we keep doc declarations to be able to get at named docs isHandled (DocD _) = True isHandled _ = False @@ -432,19 +424,24 @@ mkExportItems -> Module -- this module -> GlobalRdrEnv -> [Name] -- exported names (orig) - -> [DeclInfo] - -> Map Name DeclInfo -- maps local names to declarations + -> [LHsDecl Name] + -> DocMap Name + -> ArgMap Name + -> SubMap + -> DeclMap -- maps local names to declarations -> Maybe [IE Name] -> [Instance] -> InstIfaceMap -> DynFlags -> ErrMsgGhc [ExportItem Name] -mkExportItems modMap thisMod gre exportedNames decls declMap +mkExportItems modMap thisMod gre exportedNames decls0 docMap argMap subMap declMap optExports _ instIfaceMap dflags = case optExports of - Nothing -> liftErrMsg $ fullContentsOfThisModule dflags gre decls + Nothing -> liftErrMsg $ fullContentsOfThisModule dflags gre docMap argMap subMap decls Just exports -> liftM (nubBy commaDeclared . concat) $ mapM lookupExport exports where + decls = filter (\(L _ d) -> not (isInstD d || isValD d)) decls0 + -- A type signature can have multiple names, like: -- foo, bar :: Types.. -- When going throug the exported names we have to take care to detect such @@ -459,7 +456,7 @@ mkExportItems modMap thisMod gre exportedNames decls declMap lookupExport (IEThingAll t) = declWith t lookupExport (IEThingWith t _) = declWith t lookupExport (IEModuleContents m) = - moduleExports thisMod m dflags gre exportedNames decls modMap instIfaceMap + moduleExports thisMod m dflags gre exportedNames decls modMap instIfaceMap docMap argMap subMap lookupExport (IEGroup lev docStr) = liftErrMsg $ ifDoc (lexParseRnHaddockComment dflags DocSectionComment gre docStr) (\doc -> return [ ExportGroup lev "" doc ]) @@ -467,7 +464,7 @@ mkExportItems modMap thisMod gre exportedNames decls declMap ifDoc (lexParseRnHaddockComment dflags NormalHaddockComment gre docStr) (\doc -> return [ ExportDoc doc ]) lookupExport (IEDocNamed str) = liftErrMsg $ - ifDoc (findNamedDoc str [ unL d | (d,_,_) <- decls ]) + ifDoc (findNamedDoc str [ unL d | d <- decls ]) (\docStr -> ifDoc (lexParseRnHaddockComment dflags NormalHaddockComment gre docStr) (\doc -> return [ ExportDoc doc ])) @@ -481,8 +478,16 @@ mkExportItems modMap thisMod gre exportedNames decls declMap declWith :: Name -> ErrMsgGhc [ ExportItem Name ] declWith t = + let doc = (Map.lookup t docMap, maybe Map.empty id (Map.lookup t argMap)) in case findDecl t of - Just (decl, doc, subs) -> + [L _ (ValD _)] -> do + -- Top-level binding without type signature + mayDecl <- ifaceDecl t + case mayDecl of + Nothing -> return [ ExportNoDecl t [] ] + Just decl -> return [ ExportDecl decl doc [] [] ] + + ds | decl : _ <- filter (not . isValD . unLoc) ds -> let declNames = getMainDeclBinder (unL decl) in case () of _ @@ -504,7 +509,7 @@ mkExportItems modMap thisMod gre exportedNames decls declMap return [] -- normal case - | otherwise -> return [ mkExportDecl t (newDecl, doc, subs) ] + | otherwise -> return [ mkExportDecl t newDecl (exportDecl t newDecl docMap argMap subMap) ] where -- Since a single signature might refer to many names, we -- need to filter the ones that are actually exported. This @@ -516,118 +521,29 @@ mkExportItems modMap thisMod gre exportedNames decls declMap -- fromJust is safe since we already checked in guards -- that 't' is a name declared in this declaration. _ -> decl - Nothing -> do - -- If we can't find the declaration, it must belong to - -- another package - mbTyThing <- liftGhcToErrMsgGhc $ lookupName t - -- show the name as exported as well as the name's - -- defining module (because the latter is where we - -- looked for the .hi/.haddock). It's to help people - -- debugging after all, so good to show more info. - let exportInfoString = - moduleString thisMod ++ "." ++ getOccString t - ++ ": " - ++ pretty (nameModule t) ++ "." ++ getOccString t - - case mbTyThing of - Nothing -> do - liftErrMsg $ tell - ["Warning: Couldn't find TyThing for exported " - ++ exportInfoString ++ "; not documenting."] - -- Is getting to here a bug in Haddock? - -- Aren't the .hi files always present? - return [ ExportNoDecl t [] ] - Just tyThing -> do - let hsdecl = tyThingToLHsDecl tyThing - -- This is not the ideal way to implement haddockumentation - -- for functions/values without explicit type signatures. - -- - -- However I didn't find an easy way to implement it properly, - -- and as long as we're using lookupName it is going to find - -- the types of local inferenced binds. If we don't check for - -- this at all, then we'll get the "warning: couldn't find - -- .haddock" which is wrong. - -- - -- The reason this is not an ideal implementation - -- (besides that we take a trip to desugared syntax and back - -- unnecessarily) - -- is that Haddock won't be able to detect doc-strings being - -- attached to such a function, such as, - -- - -- > -- | this is an identity function - -- > id a = a - -- - -- . It's more difficult to say what it ought to mean in cases - -- where multiple exports are bound at once, like - -- - -- > -- | comment... - -- > (a, b) = ... - -- - -- especially since in the export-list they might not even - -- be next to each other. But a proper implementation would - -- really need to find the type of *all* exports as well as - -- addressing all these issues. This implementation works - -- adequately. Do you see a way to improve the situation? - -- Please go ahead! I got stuck trying to figure out how to - -- get the 'PostTcType's that we want for all the bindings - -- of an HsBind (you get 'LHsBinds' from 'GHC.typecheckedSource' - -- for example). - -- - -- But I might be missing something obvious. What's important - -- /here/ is that we behave reasonably when we run into one of - -- those exported type-inferenced values. - isLocalAndTypeInferenced <- liftGhcToErrMsgGhc $ do - let mdl = nameModule t - if modulePackageId mdl == thisPackage dflags then - isLoaded (moduleName mdl) - else return False - - if isLocalAndTypeInferenced then do - -- I don't think there can be any subs in this case, - -- currently? But better not to rely on it. - let subs = subordinatesWithNoDocs (unLoc hsdecl) - return [ mkExportDecl t (hsdecl, noDocForDecl, subs) ] - else - -- We try to get the subs and docs - -- from the installed interface of that package. - case Map.lookup (nameModule t) instIfaceMap of - -- It's Nothing in the cases where I thought - -- Haddock has already warned the user: "Warning: The - -- documentation for the following packages are not - -- installed. No links will be generated to these packages: - -- ..." - -- But I guess it was Cabal creating that warning. Anyway, - -- this is more serious than links: it's exported decls where - -- we don't have the docs that they deserve! - - -- We could use 'subordinates' to find the Names of the subs - -- (with no docs). Is that necessary? Yes it is, otherwise - -- e.g. classes will be shown without their exported subs. - Nothing -> do - liftErrMsg $ tell - ["Warning: Couldn't find .haddock for exported " - ++ exportInfoString] - let subs = subordinatesWithNoDocs (unLoc hsdecl) - return [ mkExportDecl t (hsdecl, noDocForDecl, subs) ] - Just iface -> do - let subs = case Map.lookup t (instSubMap iface) of - Nothing -> [] - Just x -> x - return [ mkExportDecl t - ( hsdecl - , fromMaybe noDocForDecl $ - Map.lookup t (instDocMap iface) - , map (\subt -> - ( subt , - fromMaybe noDocForDecl $ - Map.lookup subt (instDocMap iface) - ) - ) subs - )] - - - mkExportDecl :: Name -> DeclInfo -> ExportItem Name - mkExportDecl n (decl, doc, subs) = decl' + + -- Declaration from another package + [] -> do + mayDecl <- ifaceDecl t + case mayDecl of + Nothing -> return [ ExportNoDecl t [] ] + Just decl -> do + -- We try to get the subs and docs + -- from the installed .haddock file for that package. + case Map.lookup (nameModule t) instIfaceMap of + Nothing -> do + liftErrMsg $ tell + ["Warning: Couldn't find .haddock for export " ++ pretty t] + let subs = [ (n, noDocForDecl) | (n, _, _) <- subordinates (unLoc decl) ] + return [ mkExportDecl t decl (noDocForDecl, subs) ] + Just iface -> do + return [ mkExportDecl t decl (exportDecl t decl (instDocMap iface) (instArgMap iface) (instSubMap iface)) ] + + _ -> return [] + + + mkExportDecl :: Name -> Decl -> (DocForDecl Name, [(Name, DocForDecl Name)]) -> ExportItem Name + mkExportDecl n decl (doc, subs) = decl' where decl' = ExportDecl (restrictTo sub_names (extractDecl n mdl decl)) doc subs' [] mdl = nameModule n @@ -638,16 +554,34 @@ mkExportItems modMap thisMod gre exportedNames decls declMap isExported = (`elem` exportedNames) - findDecl :: Name -> Maybe DeclInfo + findDecl :: Name -> [Decl] findDecl n - | m == thisMod = Map.lookup n declMap + | m == thisMod = maybe [] id (Map.lookup n declMap) | otherwise = case Map.lookup m modMap of - Just iface -> Map.lookup n (ifaceDeclMap iface) - Nothing -> Nothing + Just iface -> maybe [] id (Map.lookup n (ifaceDeclMap iface)) + Nothing -> [] where m = nameModule n +ifaceDecl :: Name -> ErrMsgGhc (Maybe (LHsDecl Name)) +ifaceDecl t = do + mayTyThing <- liftGhcToErrMsgGhc $ lookupName t + case mayTyThing of + Nothing -> do + liftErrMsg $ tell ["Warning: Not found in environment: " ++ pretty t] + return Nothing + Just x -> return (Just (tyThingToLHsDecl x)) + + +exportDecl :: Name -> Decl -> DocMap Name -> ArgMap Name -> SubMap -> (DocForDecl Name, [(Name, DocForDecl Name)]) +exportDecl name _ docMap argMap subMap = + let lookupArgMap x = maybe M.empty id (M.lookup x argMap) in + let doc = (M.lookup name docMap, lookupArgMap name) in + let subs = [ (sub, (M.lookup sub docMap, lookupArgMap sub)) | sub <- maybe [] id (M.lookup name subMap) ] in + (doc, subs) + + -- | Return all export items produced by an exported module. That is, we're -- interested in the exports produced by \"module B\" in such a scenario: -- @@ -666,12 +600,15 @@ moduleExports :: Module -- ^ Module A -> DynFlags -- ^ The flag used when typechecking A -> GlobalRdrEnv -- ^ The renaming environment used for A -> [Name] -- ^ All the exports of A - -> [DeclInfo] -- ^ All the declarations in A + -> [Decl] -- ^ All the declarations in A -> IfaceMap -- ^ Already created interfaces -> InstIfaceMap -- ^ Interfaces in other packages + -> DocMap Name + -> ArgMap Name + -> SubMap -> ErrMsgGhc [ExportItem Name] -- ^ Resulting export items -moduleExports thisMod expMod dflags gre _exports decls ifaceMap instIfaceMap - | m == thisMod = liftErrMsg $ fullContentsOfThisModule dflags gre decls +moduleExports thisMod expMod dflags gre _exports decls ifaceMap instIfaceMap docMap argMap subMap + | m == thisMod = liftErrMsg $ fullContentsOfThisModule dflags gre docMap argMap subMap decls | otherwise = case Map.lookup m ifaceMap of Just iface @@ -709,17 +646,20 @@ moduleExports thisMod expMod dflags gre _exports decls ifaceMap instIfaceMap -- (For more information, see Trac #69) -fullContentsOfThisModule :: DynFlags -> GlobalRdrEnv -> [DeclInfo] -> ErrMsgM [ExportItem Name] -fullContentsOfThisModule dflags gre decls = liftM catMaybes $ mapM mkExportItem decls +fullContentsOfThisModule :: DynFlags -> GlobalRdrEnv -> DocMap Name -> ArgMap Name -> SubMap -> [Decl] -> ErrMsgM [ExportItem Name] +fullContentsOfThisModule dflags gre docMap argMap subMap decls = liftM catMaybes $ mapM mkExportItem decls where - mkExportItem (L _ (DocD (DocGroup lev docStr)), _, _) = do - mbDoc <- lexParseRnHaddockComment dflags DocSectionComment gre docStr - return $ fmap (ExportGroup lev "") mbDoc - mkExportItem (L _ (DocD (DocCommentNamed _ docStr)), _, _) = do - mbDoc <- lexParseRnHaddockComment dflags NormalHaddockComment gre docStr - return $ fmap ExportDoc mbDoc - mkExportItem (decl, doc, subs) = return $ Just $ ExportDecl decl doc subs [] - + mkExportItem (L _ (DocD (DocGroup lev docStr))) = do + mbDoc <- lexParseRnHaddockComment dflags DocSectionComment gre docStr + return $ fmap (ExportGroup lev "") mbDoc + mkExportItem (L _ (DocD (DocCommentNamed _ docStr))) = do + mbDoc <- lexParseRnHaddockComment dflags NormalHaddockComment gre docStr + return $ fmap ExportDoc mbDoc + mkExportItem decl + | name : _ <- getMainDeclBinder (unLoc decl) = + let (doc, subs) = exportDecl name decl docMap argMap subMap in + return $ Just (ExportDecl decl doc subs []) + | otherwise = return Nothing -- | Sometimes the declaration we want to export is not the "main" declaration: -- it might be an individual record selector or a class method. In these diff --git a/src/Haddock/Interface/ExtractFnArgDocs.hs b/src/Haddock/Interface/ExtractFnArgDocs.hs deleted file mode 100644 index a9f8a807..00000000 --- a/src/Haddock/Interface/ExtractFnArgDocs.hs +++ /dev/null @@ -1,49 +0,0 @@ ------------------------------------------------------------------------------ --- | --- Module : Haddock.Interface.ExtractFnArgDocs --- Copyright : (c) Isaac Dupree 2009, --- License : BSD-like --- --- Maintainer : haddock@projects.haskell.org --- Stability : experimental --- Portability : portable ------------------------------------------------------------------------------ -module Haddock.Interface.ExtractFnArgDocs ( - getDeclFnArgDocs, getSigFnArgDocs, getTypeFnArgDocs -) where - -import Haddock.Types - -import qualified Data.Map as Map -import Data.Map (Map) - -import GHC - --- the type of Name doesn't matter, except in 6.10 where --- HsDocString = HsDoc Name, so we can't just say "HsDecl name" yet. - -getDeclFnArgDocs :: HsDecl Name -> Map Int HsDocString -getDeclFnArgDocs (SigD (TypeSig _ ty)) = getTypeFnArgDocs ty -getDeclFnArgDocs (ForD (ForeignImport _ ty _ _)) = getTypeFnArgDocs ty -getDeclFnArgDocs (TyClD (TySynonym {tcdSynRhs = ty})) = getTypeFnArgDocs ty -getDeclFnArgDocs _ = Map.empty - -getSigFnArgDocs :: Sig Name -> Map Int HsDocString -getSigFnArgDocs (TypeSig _ ty) = getTypeFnArgDocs ty -getSigFnArgDocs _ = Map.empty - -getTypeFnArgDocs :: LHsType Name -> Map Int HsDocString -getTypeFnArgDocs ty = getLTypeDocs 0 ty - - -getLTypeDocs :: Int -> LHsType Name -> Map Int HsDocString -getLTypeDocs n (L _ ty) = getTypeDocs n ty - -getTypeDocs :: Int -> HsType Name -> Map Int HsDocString -getTypeDocs n (HsForAllTy _ _ _ ty) = getLTypeDocs n ty -getTypeDocs n (HsFunTy (L _ (HsDocTy _arg_type (L _ doc))) res_type) = - Map.insert n doc $ getLTypeDocs (n+1) res_type -getTypeDocs n (HsFunTy _ res_type) = getLTypeDocs (n+1) res_type -getTypeDocs n (HsDocTy _res_type (L _ doc)) = Map.singleton n doc -getTypeDocs _ _res_type = Map.empty - diff --git a/src/Haddock/Interface/Rename.hs b/src/Haddock/Interface/Rename.hs index 35ff8542..691dafbc 100644 --- a/src/Haddock/Interface/Rename.hs +++ b/src/Haddock/Interface/Rename.hs @@ -36,30 +36,22 @@ 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) - - -- 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 -- are closer to, or maybe even exported by, the current module. (renamedExportItems, missingNames1) = runRnFM localEnv (renameExportItems (ifaceExportItems iface)) - (rnDocMap, missingNames2) - = runRnFM localEnv (liftM Map.fromList (mapM renameMapElem docs)) + (rnDocMap, missingNames2) = runRnFM localEnv (mapM renameDoc (ifaceDocMap iface)) + + (rnArgMap, missingNames3) = runRnFM localEnv (mapM (mapM renameDoc) (ifaceArgMap iface)) - (finalModuleDoc, missingNames3) + (finalModuleDoc, missingNames4) = runRnFM localEnv (renameMaybeDoc (ifaceDoc iface)) -- combine the missing names and filter out the built-ins, which would -- otherwise allways be missing. missingNames = nub $ filter isExternalName -- XXX: isExternalName filters out too much - (missingNames1 ++ missingNames2 ++ missingNames3) + (missingNames1 ++ missingNames2 ++ missingNames3 ++ missingNames4) -- filter out certain built in type constructors using their string -- representation. TODO: use the Name constants from the GHC API. @@ -77,6 +69,7 @@ renameInterface renamingEnv warnings iface = return $ iface { ifaceRnDoc = finalModuleDoc, ifaceRnDocMap = rnDocMap, + ifaceRnArgMap = rnArgMap, ifaceRnExportItems = renamedExportItems } diff --git a/src/Haddock/InterfaceFile.hs b/src/Haddock/InterfaceFile.hs index 52f04f1a..fcf7fe65 100644 --- a/src/Haddock/InterfaceFile.hs +++ b/src/Haddock/InterfaceFile.hs @@ -65,13 +65,13 @@ binaryInterfaceMagic = 0xD0Cface -- we version our interface files accordingly. binaryInterfaceVersion :: Word16 #if __GLASGOW_HASKELL__ == 702 -binaryInterfaceVersion = 18 +binaryInterfaceVersion = 19 #elif __GLASGOW_HASKELL__ == 703 -binaryInterfaceVersion = 18 +binaryInterfaceVersion = 19 #elif __GLASGOW_HASKELL__ == 704 -binaryInterfaceVersion = 18 +binaryInterfaceVersion = 19 #elif __GLASGOW_HASKELL__ == 705 -binaryInterfaceVersion = 18 +binaryInterfaceVersion = 19 #else #error Unknown GHC version #endif @@ -359,10 +359,11 @@ instance Binary InterfaceFile where instance Binary InstalledInterface where - put_ bh (InstalledInterface modu info docMap exps visExps opts subMap) = do + put_ bh (InstalledInterface modu info docMap argMap exps visExps opts subMap) = do put_ bh modu put_ bh info put_ bh docMap + put_ bh argMap put_ bh exps put_ bh visExps put_ bh opts @@ -372,12 +373,13 @@ instance Binary InstalledInterface where modu <- get bh info <- get bh docMap <- get bh + argMap <- get bh exps <- get bh visExps <- get bh opts <- get bh subMap <- get bh - return (InstalledInterface modu info docMap + return (InstalledInterface modu info docMap argMap exps visExps opts subMap) diff --git a/src/Haddock/Types.hs b/src/Haddock/Types.hs index fbaf89c5..3baa4a94 100644 --- a/src/Haddock/Types.hs +++ b/src/Haddock/Types.hs @@ -25,6 +25,7 @@ import Control.Arrow import Data.Typeable import Data.Map (Map) import qualified Data.Map as Map +import Data.Monoid import GHC hiding (NoLink) import OccName @@ -35,8 +36,11 @@ import OccName type IfaceMap = Map Module Interface -type InstIfaceMap = Map Module InstalledInterface -type DocMap = Map Name (Doc DocName) +type InstIfaceMap = Map Module InstalledInterface -- TODO: rename +type DocMap a = Map Name (Doc a) +type ArgMap a = Map Name (Map Int (Doc a)) +type SubMap = Map Name [Name] +type DeclMap = Map Name [Decl] type SrcMap = Map PackageId FilePath type Decl = LHsDecl Name type GhcDocHdr = Maybe LHsDocString @@ -76,11 +80,17 @@ data Interface = Interface -- | Declarations originating from the module. Excludes declarations without -- names (instances and stand-alone documentation comments). Includes -- names of subordinate declarations mapped to their parent declarations. - , ifaceDeclMap :: Map Name DeclInfo + , ifaceDeclMap :: Map Name [Decl] -- | Documentation of declarations originating from the module (including -- subordinates). - , ifaceRnDocMap :: Map Name (DocForDecl DocName) + , ifaceDocMap :: DocMap Name + , ifaceArgMap :: ArgMap Name + + -- | Documentation of declarations originating from the module (including + -- subordinates). + , ifaceRnDocMap :: DocMap DocName + , ifaceRnArgMap :: ArgMap DocName , ifaceSubMap :: Map Name [Name] @@ -98,9 +108,6 @@ data Interface = Interface -- | Instances exported by the module. , ifaceInstances :: ![Instance] - -- | Documentation of instances defined in the module. - , ifaceInstanceDocMap :: Map Name (Doc Name) - -- | The number of haddockable and haddocked items in the module, as a -- tuple. Haddockable items are the exports and the module itself. , ifaceHaddockCoverage :: (Int,Int) @@ -119,7 +126,9 @@ data InstalledInterface = InstalledInterface -- | Documentation of declarations originating from the module (including -- subordinates). - , instDocMap :: Map Name (DocForDecl Name) + , instDocMap :: DocMap Name + + , instArgMap :: ArgMap Name -- | All names exported by this module. , instExports :: [Name] @@ -141,7 +150,8 @@ toInstalledIface :: Interface -> InstalledInterface toInstalledIface interface = InstalledInterface { instMod = ifaceMod interface , instInfo = ifaceInfo interface - , instDocMap = fmap unrenameDocForDecl $ ifaceRnDocMap interface + , instDocMap = ifaceDocMap interface + , instArgMap = ifaceArgMap interface , instExports = ifaceExports interface , instVisibleExports = ifaceVisibleExports interface , instOptions = ifaceOptions interface @@ -203,11 +213,6 @@ data ExportItem name | ExportModule Module --- | A declaration that may have documentation, including its subordinates, --- which may also have documentation. -type DeclInfo = (Decl, DocForDecl Name, [(Name, DocForDecl Name)]) - - -- | Arguments and result are indexed by Int, zero-based from the left, -- because that's the easiest to use when recursing over types. type FnArgsDoc name = Map Int (Doc name) @@ -289,7 +294,12 @@ data Doc id | DocPic String | DocAName String | DocExamples [Example] - deriving (Eq, Functor) + deriving (Functor) + + +instance Monoid (Doc id) where + mempty = DocEmpty + mappend = DocAppend unrenameDoc :: Doc DocName -> Doc Name |