@@ -23,6 +23,7 @@ import Desugar
2323import GHC
2424import GhcMonad
2525import FastString (mkFastString)
26+import OccName
2627import Development.IDE.Types.Location
2728import Development.IDE.Spans.Type
2829import Development.IDE.GHC.Error (zeroSpan)
@@ -30,6 +31,7 @@ import Prelude hiding (mod)
3031import TcHsSyn
3132import Var
3233import Development.IDE.Core.Compile
34+import qualified Development.IDE.GHC.Compat as Compat
3335import Development.IDE.GHC.Util
3436
3537
@@ -63,7 +65,8 @@ getSpanInfo mods tcm =
6365 es = listifyAllSpans tcs :: [LHsExpr GhcTc]
6466 ps = listifyAllSpans' tcs :: [Pat GhcTc]
6567 ts = listifyAllSpans $ tm_renamed_source tcm :: [LHsType GhcRn]
66− bts <- mapM (getTypeLHsBind tcm) bs -- binds
68+ let funBinds = funBindMap $ tm_parsed_module tcm
69+ bts <- mapM (getTypeLHsBind funBinds) bs -- binds
6770 ets <- mapM (getTypeLHsExpr tcm) es -- expressions
6871 pts <- mapM (getTypeLPat tcm) ps -- patterns
6972 tts <- mapM (getLHsType tcm) ts -- types
@@ -76,6 +79,15 @@ getSpanInfo mods tcm =
7679 | b `isSubspanOf` a = GT
7780 | otherwise = compare (srcSpanStart a) (srcSpanStart b)
7881
82+-- | The locations in the typechecked module are slightly messed up in some cases (e.g. HsMatchContext always
83+-- points to the first match) whereas the parsed module has the correct locations.
84+-- Therefore we build up a map from OccName to the corresponding definition in the parsed module
85+-- to lookup precise locations for things like multi-clause function definitions.
86+--
87+-- For now this only contains FunBinds.
88+funBindMap :: ParsedModule -> OccEnv (HsBind GhcPs)
89+funBindMap pm = mkOccEnv $ [ (occName $ unLoc f, bnd) | L _ (Compat.ValD bnd@FunBind{fun_id = f}) <- hsmodDecls $ unLoc $ pm_parsed_source pm ]
90+
7991getExports :: TypecheckedModule -> [(SpanSource, SrcSpan, Maybe Type)]
8092getExports m
8193 | Just (_, _, Just exports, _) <- renamedSource m =
@@ -95,12 +107,15 @@ ieLNames _ = []
95107
96108-- | Get the name and type of a binding.
97109getTypeLHsBind :: (GhcMonad m)
98− => TypecheckedModule
110+ => OccEnv (HsBind GhcPs)
99111 -> LHsBind GhcTc
100112 -> m [(SpanSource, SrcSpan, Maybe Type)]
101−getTypeLHsBind _ (L _spn FunBind{ fun_id = pid
102− , fun_matches = MG{mg_alts=(L _ matches)}}) =
103− return [(Named (getName (unLoc pid)), getLoc match, Just (varType (unLoc pid))) | match <- matches ]
113+getTypeLHsBind funBinds (L _spn FunBind{fun_id = pid})
114+ | Just FunBind {fun_matches = MG{mg_alts=L _ matches}} <- lookupOccEnv funBinds (occName $ unLoc pid) =
115+ return [(Named (getName (unLoc pid)), getLoc mc_fun, Just (varType (unLoc pid))) | match <- matches, FunRhs{mc_fun = mc_fun} <- [m_ctxt $ unLoc match] ]
116+-- In theory this shouldn’t ever fail but if it does, we can at least show the first clause.
117+getTypeLHsBind _ (L _spn FunBind{fun_id = pid,fun_matches = MG{}}) =
118+ return [(Named $ getName (unLoc pid), getLoc pid, Just (varType (unLoc pid)))]
104119getTypeLHsBind _ _ = return []
105120
106121-- | Get the name and type of an expression.