attachToExportItem :: ExportInfo -> Interface -> IfaceMap -> InstIfaceMap
                   -> ExportItem Name
                   -> Ghc (ExportItem Name)
attachToExportItem expInfo iface ifaceMap instIfaceMap export =
  case attachFixities export of
    e@ExportDecl { expItemDecl = L eSpan (TyClD d) } -> do
      mb_info <- getAllInfo (tcdName d)
      insts <- case mb_info of
        Just (_, _, cls_instances, fam_instances) ->
          let fam_insts = [ (synifyFamInst i opaque, doc,spanNameE n (synifyFamInst i opaque) (L eSpan (tcdName d)) )
                          | i <- sortBy (comparing instFam) fam_instances
                          , let n = getName i
                          , let doc = instLookup instDocMap n iface ifaceMap instIfaceMap
                          , not $ isNameHidden expInfo (fi_fam i)
                          , not $ any (isTypeHidden expInfo) (fi_tys i)
                          , let opaque = isTypeHidden expInfo (fi_rhs i)
                          ]
              cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, spanName n (synifyInstHead i) (L eSpan (tcdName d)))
                          | let is = [ (instanceSig i, getName i) | i <- cls_instances ]
                          , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is
                          , not $ isInstanceHidden expInfo cls tys
                          ]
              -- fam_insts but with failing type fams filtered out
              cleanFamInsts = [ (fi, n, L l r) | (Right fi, n, L l (Right r)) <- fam_insts ]
              famInstErrs = [ errm | (Left errm, _, _) <- fam_insts ]
          in do
            dfs <- getDynFlags
            let mkBug = (text "haddock-bug:" <+>) . text
            liftIO $ putMsg dfs (sep $ map mkBug famInstErrs)
            return $ cls_insts ++ cleanFamInsts
        Nothing -> return []
      return $ e { expItemInstances = insts }
    e -> return e
  where
    attachFixities e@ExportDecl{ expItemDecl = L _ d } = e { expItemFixities =
      nubBy ((==) `on` fst) $ expItemFixities e ++
      [ (n',f) | n <- getMainDeclBinder d
              , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap]
              , n' <- n : subs
              , Just f <- [instLookup instFixMap n' iface ifaceMap instIfaceMap]
      ] }

    attachFixities e = e
    -- spanName: attach the location to the name that is the same file as the instance location
    spanName s (InstHead { ihdClsName = clsn }) (L instL instn) =
        let s1 = getSrcSpan s
            sn = if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL
                    then instn
                    else clsn
        in L (getSrcSpan s) sn
    -- spanName on Either
    spanNameE s (Left e) _ =  L (getSrcSpan s) (Left e)
    spanNameE s (Right ok) linst =
      let L l r = spanName s ok linst
      in L l (Right r)
attachToExportItem :: ExportInfo -> Interface -> IfaceMap -> InstIfaceMap
                   -> ExportItem Name
                   -> Ghc (ExportItem Name)
attachToExportItem expInfo iface ifaceMap instIfaceMap export =
  case attachFixities export of
    e@ExportDecl { expItemDecl = L eSpan (TyClD d) } -> do
      mb_info <- getAllInfo (tcdName d)
      insts <- case mb_info of
        Just (_, _, cls_instances, fam_instances) ->
          let fam_insts = [ (synifyFamInst i opaque, doc,spanNameE n (synifyFamInst i opaque) (L eSpan (tcdName d)) )
                          | i <- sortBy (comparing instFam) fam_instances
                          , let n = getName i
                          , let doc = instLookup instDocMap n iface ifaceMap instIfaceMap
                          , not $ isNameHidden expInfo (fi_fam i)
                          , not $ any (isTypeHidden expInfo) (fi_tys i)
                          , let opaque = isTypeHidden expInfo (fi_rhs i)
                          ]
              cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, spanName n (synifyInstHead i) (L eSpan (tcdName d)))
                          | let is = [ (instanceSig i, getName i) | i <- cls_instances ]
                          , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is
                          , not $ isInstanceHidden expInfo cls tys
                          ]
              -- fam_insts but with failing type fams filtered out
              cleanFamInsts = [ (fi, n, L l r) | (Right fi, n, L l (Right r)) <- fam_insts ]
              famInstErrs = [ errm | (Left errm, _, _) <- fam_insts ]
          in do
            dfs <- getDynFlags
            let mkBug = (text "haddock-bug:" <+>) . text
            liftIO $ putMsg dfs (sep $ map mkBug famInstErrs)
            return $ cls_insts ++ cleanFamInsts
        Nothing -> return []
      return $ e { expItemInstances = insts }
    e -> return e
  where
    attachFixities e@ExportDecl{ expItemDecl = L _ d } = e { expItemFixities =
      nubBy ((==) `on` fst) $ expItemFixities e ++
      [ (n',f) | n <- getMainDeclBinder d
              , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap]
              , n' <- n : subs
              , Just f <- [instLookup instFixMap n' iface ifaceMap instIfaceMap]
      ] }

    attachFixities e = e
    -- spanName: attach the location to the name that is the same file as the instance location
    spanName s (InstHead { ihdClsName = clsn }) (L instL instn) =
        let s1 = getSrcSpan s
            sn = if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL
                    then instn
                    else clsn
        in L (getSrcSpan s) sn
    -- spanName on Either
    spanNameE s (Left e) _ =  L (getSrcSpan s) (Left e)
    spanNameE s (Right ok) linst =
      let L l r = spanName s ok linst
      in L l (Right r)
attachToExportItem expInfo iface ifaceMap instIfaceMap export =
  case attachFixities export of
    e@ExportDecl { expItemDecl = L eSpan (TyClD d) } -> do
      mb_info <- getAllInfo (tcdName d)
      insts <- case mb_info of
        Just (_, _, cls_instances, fam_instances) ->
          let fam_insts = [ (synifyFamInst i opaque, doc,spanNameE n (synifyFamInst i opaque) (L eSpan (tcdName d)) )
                          | i <- sortBy (comparing instFam) fam_instances
                          , let n = getName i
                          , let doc = instLookup instDocMap n iface ifaceMap instIfaceMap
                          , not $ isNameHidden expInfo (fi_fam i)
                          , not $ any (isTypeHidden expInfo) (fi_tys i)
                          , let opaque = isTypeHidden expInfo (fi_rhs i)
                          ]
              cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, spanName n (synifyInstHead i) (L eSpan (tcdName d)))
                          | let is = [ (instanceSig i, getName i) | i <- cls_instances ]
                          , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is
                          , not $ isInstanceHidden expInfo cls tys
                          ]
              -- fam_insts but with failing type fams filtered out
              cleanFamInsts = [ (fi, n, L l r) | (Right fi, n, L l (Right r)) <- fam_insts ]
              famInstErrs = [ errm | (Left errm, _, _) <- fam_insts ]
          in do
            dfs <- getDynFlags
            let mkBug = (text "haddock-bug:" <+>) . text
            liftIO $ putMsg dfs (sep $ map mkBug famInstErrs)
            return $ cls_insts ++ cleanFamInsts
        Nothing -> return []
      return $ e { expItemInstances = insts }
    e -> return e
  where
    attachFixities e@ExportDecl{ expItemDecl = L _ d } = e { expItemFixities =
      nubBy ((==) `on` fst) $ expItemFixities e ++
      [ (n',f) | n <- getMainDeclBinder d
              , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap]
              , n' <- n : subs
              , Just f <- [instLookup instFixMap n' iface ifaceMap instIfaceMap]
      ] }

    attachFixities e = e
    -- spanName: attach the location to the name that is the same file as the instance location
    spanName s (InstHead { ihdClsName = clsn }) (L instL instn) =
        let s1 = getSrcSpan s
            sn = if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL
                    then instn
                    else clsn
        in L (getSrcSpan s) sn
    -- spanName on Either
    spanNameE s (Left e) _ =  L (getSrcSpan s) (Left e)
    spanNameE s (Right ok) linst =
      let L l r = spanName s ok linst
      in L l (Right r)