Just some alpha renaming
[ghc-hetmet.git] / compiler / deSugar / Coverage.lhs
1 %
2 % (c) Galois, 2006
3 % (c) University of Glasgow, 2007
4 %
5 \section[Coverage]{@coverage@: the main function}
6
7 \begin{code}
8 module Coverage (addCoverageTicksToBinds) where
9
10 import HsSyn
11 import Module
12 import Outputable
13 import DynFlags
14 import Control.Monad
15 import SrcLoc
16 import ErrUtils
17 import Name
18 import Bag
19 import Id
20 import VarSet
21 import Data.List
22 import FastString
23 import HscTypes 
24 import StaticFlags
25 import TyCon
26 import MonadUtils
27 import Maybes
28
29 import Data.Array
30 import System.Directory ( createDirectoryIfMissing )
31
32 import Trace.Hpc.Mix
33 import Trace.Hpc.Util
34
35 import BreakArray 
36 import Data.HashTable   ( hashString )
37 import Data.Map (Map)
38 import qualified Data.Map as Map
39 \end{code}
40
41
42 %************************************************************************
43 %*                                                                      *
44 %*              The main function: addCoverageTicksToBinds
45 %*                                                                      *
46 %************************************************************************
47
48 \begin{code}
49 addCoverageTicksToBinds
50         :: DynFlags
51         -> Module
52         -> ModLocation          -- of the current module
53         -> [TyCon]              -- type constructor in this module
54         -> LHsBinds Id
55         -> IO (LHsBinds Id, HpcInfo, ModBreaks)
56
57 addCoverageTicksToBinds dflags mod mod_loc tyCons binds = 
58  case ml_hs_file mod_loc of
59  Nothing -> return (binds, emptyHpcInfo False, emptyModBreaks)
60  Just orig_file -> do
61
62   if "boot" `isSuffixOf` orig_file then return (binds, emptyHpcInfo False, emptyModBreaks) else do
63
64   -- Now, we try look for a file generated from a .hsc file to a .hs file, by peeking ahead.
65
66   let top_pos = catMaybes $ foldrBag (\ (L pos _) rest -> srcSpanFileName_maybe pos : rest) [] binds
67   let orig_file2 = case top_pos of
68                      (file_name:_) 
69                        | ".hsc" `isSuffixOf` unpackFS file_name -> unpackFS file_name
70                      _ -> orig_file
71
72   let mod_name = moduleNameString (moduleName mod)
73
74   let (binds1,_,st)
75                  = unTM (addTickLHsBinds binds) 
76                    (TTE
77                        { fileName    = mkFastString orig_file2
78                       , declPath     = []
79                       , inScope      = emptyVarSet
80                       , blackList    = Map.fromList [ (getSrcSpan (tyConName tyCon),()) 
81                                                     | tyCon <- tyCons ]
82                        })
83                    (TT 
84                       { tickBoxCount = 0
85                       , mixEntries   = []
86                       })
87
88   let entries = reverse $ mixEntries st
89
90   -- write the mix entries for this module
91   hashNo <- if opt_Hpc then do
92      let hpc_dir = hpcDir dflags
93
94      let hpc_mod_dir = if modulePackageId mod == mainPackageId 
95                        then hpc_dir
96                        else hpc_dir ++ "/" ++ packageIdString (modulePackageId mod)
97
98      let tabStop = 1 -- <tab> counts as a normal char in GHC's location ranges.
99      createDirectoryIfMissing True hpc_mod_dir
100      modTime <- getModificationTime orig_file2
101      let entries' = [ (hpcPos, box) 
102                     | (span,_,_,box) <- entries, hpcPos <- [mkHpcPos span] ]
103      when (length entries' /= tickBoxCount st) $ do
104        panic "the number of .mix entries are inconsistent"
105      let hashNo = mixHash orig_file2 modTime tabStop entries'
106      mixCreate hpc_mod_dir mod_name 
107                $ Mix orig_file2 modTime (toHash hashNo) tabStop entries'
108      return $ hashNo 
109    else do
110      return $ 0
111
112   -- Todo: use proper src span type
113   breakArray <- newBreakArray $ length entries
114
115   let locsTicks = listArray (0,tickBoxCount st-1) 
116                      [ span | (span,_,_,_) <- entries ]
117       varsTicks = listArray (0,tickBoxCount st-1) 
118                      [ vars | (_,_,vars,_) <- entries ]
119       declsTicks= listArray (0,tickBoxCount st-1) 
120                      [ decls | (_,decls,_,_) <- entries ]
121       modBreaks = emptyModBreaks 
122                   { modBreaks_flags = breakArray 
123                   , modBreaks_locs  = locsTicks 
124                   , modBreaks_vars  = varsTicks
125                   , modBreaks_decls = declsTicks
126                   } 
127
128   doIfSet_dyn dflags  Opt_D_dump_hpc $ do
129           printDump (pprLHsBinds binds1)
130
131   return (binds1, HpcInfo (tickBoxCount st) hashNo, modBreaks)
132 \end{code}
133
134
135 \begin{code}
136 liftL :: (Monad m) => (a -> m a) -> Located a -> m (Located a)
137 liftL f (L loc a) = do
138   a' <- f a
139   return $ L loc a'
140
141 addTickLHsBinds :: LHsBinds Id -> TM (LHsBinds Id)
142 addTickLHsBinds binds = mapBagM addTickLHsBind binds
143
144 addTickLHsBind :: LHsBind Id -> TM (LHsBind Id)
145 addTickLHsBind (L pos bind@(AbsBinds { abs_binds = binds })) = do
146   binds' <- addTickLHsBinds binds
147   return $ L pos $ bind { abs_binds = binds' }
148 addTickLHsBind (L pos (funBind@(FunBind { fun_id = (L _ id)  }))) = do 
149   let name = getOccString id
150   decl_path <- getPathEntry
151
152   (fvs, (MatchGroup matches' ty)) <- 
153         getFreeVars $
154         addPathEntry name $
155         addTickMatchGroup (fun_matches funBind)
156
157   blackListed <- isBlackListed pos
158
159   -- Todo: we don't want redundant ticks on simple pattern bindings
160   -- We don't want to generate code for blacklisted positions
161   if blackListed || (not opt_Hpc && isSimplePatBind funBind)
162      then 
163         return $ L pos $ funBind { fun_matches = MatchGroup matches' ty 
164                                  , fun_tick = Nothing 
165                                  }
166      else do
167         tick_no <- allocATickBox (if null decl_path
168                                      then TopLevelBox [name]
169                                      else LocalBox (decl_path ++ [name])) 
170                                 pos fvs
171
172         return $ L pos $ funBind { fun_matches = MatchGroup matches' ty 
173                                  , fun_tick = tick_no
174                                  }
175    where
176    -- a binding is a simple pattern binding if it is a funbind with zero patterns
177    isSimplePatBind :: HsBind a -> Bool
178    isSimplePatBind funBind = matchGroupArity (fun_matches funBind) == 0
179
180 -- TODO: Revisit this
181 addTickLHsBind (L pos (pat@(PatBind { pat_rhs = rhs }))) = do
182   let name = "(...)"
183   rhs' <- addPathEntry name $ addTickGRHSs False rhs
184 {-
185   decl_path <- getPathEntry
186   tick_me <- allocTickBox (if null decl_path
187                            then TopLevelBox [name]
188                            else LocalBox (name : decl_path))
189 -}                         
190   return $ L pos $ pat { pat_rhs = rhs' }
191
192 -- Only internal stuff, not from source, uses VarBind, so we ignore it.
193 addTickLHsBind var_bind@(L _ (VarBind {})) = return var_bind
194
195 -- Add a tick to the expression no matter what it is.  There is one exception:
196 -- for the debugger, if the expression is a 'let', then we don't want to add
197 -- a tick here because there will definititely be a tick on the body anyway.
198 addTickLHsExprAlways :: LHsExpr Id -> TM (LHsExpr Id)
199 addTickLHsExprAlways (L pos e0)
200   | not opt_Hpc, HsLet _ _ <- e0 = addTickLHsExprNever (L pos e0)
201   | otherwise = allocTickBox (ExpBox False) pos $ addTickHsExpr e0
202
203 addTickLHsExprNeverOrAlways :: LHsExpr Id -> TM (LHsExpr Id)
204 addTickLHsExprNeverOrAlways e
205     | opt_Hpc   = addTickLHsExprNever e
206     | otherwise = addTickLHsExprAlways e
207
208 addTickLHsExprNeverOrMaybe :: LHsExpr Id -> TM (LHsExpr Id)
209 addTickLHsExprNeverOrMaybe e
210     | opt_Hpc   = addTickLHsExprNever e
211     | otherwise = addTickLHsExpr e
212
213 -- version of addTick that does not actually add a tick,
214 -- because the scope of this tick is completely subsumed by 
215 -- another.
216 addTickLHsExprNever :: LHsExpr Id -> TM (LHsExpr Id)
217 addTickLHsExprNever (L pos e0) = do
218     e1 <- addTickHsExpr e0
219     return $ L pos e1
220
221 -- selectively add ticks to interesting expressions
222 addTickLHsExpr :: LHsExpr Id -> TM (LHsExpr Id)
223 addTickLHsExpr (L pos e0) = do
224     if opt_Hpc || isGoodBreakExpr e0
225        then do
226           allocTickBox (ExpBox False) pos $ addTickHsExpr e0
227        else do
228           e1 <- addTickHsExpr e0
229           return $ L pos e1 
230
231 -- general heuristic: expressions which do not denote values are good break points
232 isGoodBreakExpr :: HsExpr Id -> Bool
233 isGoodBreakExpr (HsApp {})     = True
234 isGoodBreakExpr (OpApp {})     = True
235 isGoodBreakExpr (NegApp {})    = True
236 isGoodBreakExpr (HsCase {})    = True
237 isGoodBreakExpr (HsIf {})      = True
238 isGoodBreakExpr (RecordCon {}) = True
239 isGoodBreakExpr (RecordUpd {}) = True
240 isGoodBreakExpr (ArithSeq {})  = True
241 isGoodBreakExpr (PArrSeq {})   = True
242 isGoodBreakExpr _other         = False 
243
244 addTickLHsExprOptAlt :: Bool -> LHsExpr Id -> TM (LHsExpr Id)
245 addTickLHsExprOptAlt oneOfMany (L pos e0)
246   | not opt_Hpc = addTickLHsExpr (L pos e0)
247   | otherwise =
248     allocTickBox (ExpBox oneOfMany) pos $ 
249         addTickHsExpr e0
250
251 addBinTickLHsExpr :: (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)
252 addBinTickLHsExpr boxLabel (L pos e0) =
253     allocBinTickBox boxLabel pos $
254         addTickHsExpr e0
255
256 addTickHsExpr :: HsExpr Id -> TM (HsExpr Id)
257 addTickHsExpr e@(HsVar id) = do freeVar id; return e
258 addTickHsExpr e@(HsIPVar _) = return e
259 addTickHsExpr e@(HsOverLit _) = return e
260 addTickHsExpr e@(HsLit _) = return e
261 addTickHsExpr (HsLam matchgroup) =
262         liftM HsLam (addTickMatchGroup matchgroup)
263 addTickHsExpr (HsApp e1 e2) = 
264         liftM2 HsApp (addTickLHsExprNever e1) (addTickLHsExpr e2)
265 addTickHsExpr (OpApp e1 e2 fix e3) = 
266         liftM4 OpApp 
267                 (addTickLHsExpr e1) 
268                 (addTickLHsExprNever e2)
269                 (return fix)
270                 (addTickLHsExpr e3)
271 addTickHsExpr (NegApp e neg) =
272         liftM2 NegApp
273                 (addTickLHsExpr e) 
274                 (addTickSyntaxExpr hpcSrcSpan neg)
275 addTickHsExpr (HsPar e) = liftM HsPar (addTickLHsExprNeverOrMaybe e)
276 addTickHsExpr (SectionL e1 e2) = 
277         liftM2 SectionL
278                 (addTickLHsExpr e1)
279                 (addTickLHsExpr e2)
280 addTickHsExpr (SectionR e1 e2) = 
281         liftM2 SectionR
282                 (addTickLHsExpr e1)
283                 (addTickLHsExpr e2)
284 addTickHsExpr (ExplicitTuple es boxity) =
285         liftM2 ExplicitTuple
286                 (mapM addTickTupArg es)
287                 (return boxity)
288 addTickHsExpr (HsCase e mgs) = 
289         liftM2 HsCase
290                 (addTickLHsExpr e) 
291                 (addTickMatchGroup mgs)
292 addTickHsExpr (HsIf cnd e1 e2 e3) = 
293         liftM3 (HsIf cnd)
294                 (addBinTickLHsExpr (BinBox CondBinBox) e1)
295                 (addTickLHsExprOptAlt True e2)
296                 (addTickLHsExprOptAlt True e3)
297 addTickHsExpr (HsLet binds e) =
298         bindLocals (collectLocalBinders binds) $
299         liftM2 HsLet
300                 (addTickHsLocalBinds binds) -- to think about: !patterns.
301                 (addTickLHsExprNeverOrAlways e)
302 addTickHsExpr (HsDo cxt stmts last_exp srcloc) = do
303         (stmts', last_exp') <- addTickLStmts' forQual stmts 
304                                      (addTickLHsExpr last_exp)
305         return (HsDo cxt stmts' last_exp' srcloc)
306   where
307         forQual = case cxt of
308                     ListComp -> Just $ BinBox QualBinBox
309                     _        -> Nothing
310 addTickHsExpr (ExplicitList ty es) = 
311         liftM2 ExplicitList
312                 (return ty)
313                 (mapM (addTickLHsExpr) es)
314 addTickHsExpr (ExplicitPArr ty es) =
315         liftM2 ExplicitPArr
316                 (return ty)
317                 (mapM (addTickLHsExpr) es)
318 addTickHsExpr (RecordCon id ty rec_binds) = 
319         liftM3 RecordCon
320                 (return id)
321                 (return ty)
322                 (addTickHsRecordBinds rec_binds)
323 addTickHsExpr (RecordUpd e rec_binds cons tys1 tys2) =
324         liftM5 RecordUpd
325                 (addTickLHsExpr e)
326                 (addTickHsRecordBinds rec_binds)
327                 (return cons) (return tys1) (return tys2)
328
329 addTickHsExpr (ExprWithTySigOut e ty) =
330         liftM2 ExprWithTySigOut
331                 (addTickLHsExprNever e) -- No need to tick the inner expression
332                                     -- for expressions with signatures
333                 (return ty)
334 addTickHsExpr (ArithSeq  ty arith_seq) =
335         liftM2 ArithSeq 
336                 (return ty)
337                 (addTickArithSeqInfo arith_seq)
338 addTickHsExpr (HsTickPragma _ (L pos e0)) = do
339     e2 <- allocTickBox (ExpBox False) pos $
340                 addTickHsExpr e0
341     return $ unLoc e2
342 addTickHsExpr (PArrSeq   ty arith_seq) =
343         liftM2 PArrSeq  
344                 (return ty)
345                 (addTickArithSeqInfo arith_seq)
346 addTickHsExpr (HsSCC nm e) =
347         liftM2 HsSCC 
348                 (return nm)
349                 (addTickLHsExpr e)
350 addTickHsExpr (HsCoreAnn nm e) = 
351         liftM2 HsCoreAnn 
352                 (return nm)
353                 (addTickLHsExpr e)
354 addTickHsExpr e@(HsBracket     {}) = return e
355 addTickHsExpr e@(HsBracketOut  {}) = return e
356 addTickHsExpr e@(HsSpliceE  {}) = return e
357 addTickHsExpr (HsProc pat cmdtop) =
358         liftM2 HsProc
359                 (addTickLPat pat)
360                 (liftL (addTickHsCmdTop) cmdtop)
361 addTickHsExpr (HsWrap w e) = 
362         liftM2 HsWrap
363                 (return w)
364                 (addTickHsExpr e)       -- explicitly no tick on inside
365 addTickHsExpr (HsArrApp  e1 e2 ty1 arr_ty lr) = 
366         liftM5 HsArrApp
367                (addTickLHsExpr e1)
368                (addTickLHsExpr e2)
369                (return ty1)
370                (return arr_ty)
371                (return lr)
372 addTickHsExpr (HsArrForm e fix cmdtop) = 
373         liftM3 HsArrForm
374                (addTickLHsExpr e)
375                (return fix)
376                (mapM (liftL (addTickHsCmdTop)) cmdtop)
377
378 addTickHsExpr e@(HsType _) = return e
379
380 -- Others dhould never happen in expression content.
381 addTickHsExpr e  = pprPanic "addTickHsExpr" (ppr e)
382
383 addTickTupArg :: HsTupArg Id -> TM (HsTupArg Id)
384 addTickTupArg (Present e)  = do { e' <- addTickLHsExpr e; return (Present e') }
385 addTickTupArg (Missing ty) = return (Missing ty)
386
387 addTickMatchGroup :: MatchGroup Id -> TM (MatchGroup Id)
388 addTickMatchGroup (MatchGroup matches ty) = do
389   let isOneOfMany = matchesOneOfMany matches
390   matches' <- mapM (liftL (addTickMatch isOneOfMany)) matches
391   return $ MatchGroup matches' ty
392
393 addTickMatch :: Bool -> Match Id -> TM (Match Id)
394 addTickMatch isOneOfMany (Match pats opSig gRHSs) =
395   bindLocals (collectPatsBinders pats) $ do
396     gRHSs' <- addTickGRHSs isOneOfMany gRHSs
397     return $ Match pats opSig gRHSs'
398
399 addTickGRHSs :: Bool -> GRHSs Id -> TM (GRHSs Id)
400 addTickGRHSs isOneOfMany (GRHSs guarded local_binds) = do
401   bindLocals binders $ do
402     local_binds' <- addTickHsLocalBinds local_binds
403     guarded' <- mapM (liftL (addTickGRHS isOneOfMany)) guarded
404     return $ GRHSs guarded' local_binds'
405   where
406     binders = collectLocalBinders local_binds
407
408 addTickGRHS :: Bool -> GRHS Id -> TM (GRHS Id)
409 addTickGRHS isOneOfMany (GRHS stmts expr) = do
410   (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox) stmts
411                         (if opt_Hpc then addTickLHsExprOptAlt isOneOfMany expr
412                                     else addTickLHsExprAlways expr)
413   return $ GRHS stmts' expr'
414
415 addTickLStmts :: (Maybe (Bool -> BoxLabel)) -> [LStmt Id] -> TM [LStmt Id]
416 addTickLStmts isGuard stmts = do
417   (stmts, _) <- addTickLStmts' isGuard stmts (return ())
418   return stmts
419
420 addTickLStmts' :: (Maybe (Bool -> BoxLabel)) -> [LStmt Id] -> TM a 
421                -> TM ([LStmt Id], a)
422 addTickLStmts' isGuard lstmts res
423   = bindLocals binders $ do
424         lstmts' <- mapM (liftL (addTickStmt isGuard)) lstmts
425         a <- res
426         return (lstmts', a)
427   where
428         binders = collectLStmtsBinders lstmts
429
430 addTickStmt :: (Maybe (Bool -> BoxLabel)) -> Stmt Id -> TM (Stmt Id)
431 addTickStmt _isGuard (BindStmt pat e bind fail) = do
432         liftM4 BindStmt
433                 (addTickLPat pat)
434                 (addTickLHsExprAlways e)
435                 (addTickSyntaxExpr hpcSrcSpan bind)
436                 (addTickSyntaxExpr hpcSrcSpan fail)
437 addTickStmt isGuard (ExprStmt e bind' ty) = do
438         liftM3 ExprStmt
439                 (addTick isGuard e)
440                 (addTickSyntaxExpr hpcSrcSpan bind')
441                 (return ty)
442 addTickStmt _isGuard (LetStmt binds) = do
443         liftM LetStmt
444                 (addTickHsLocalBinds binds)
445 addTickStmt isGuard (ParStmt pairs) = do
446     liftM ParStmt 
447         (mapM (addTickStmtAndBinders isGuard) pairs)
448
449 addTickStmt isGuard (TransformStmt stmts ids usingExpr maybeByExpr) = do
450     liftM4 TransformStmt 
451         (addTickLStmts isGuard stmts)
452         (return ids)
453         (addTickLHsExprAlways usingExpr)
454         (addTickMaybeByLHsExpr maybeByExpr)
455
456 addTickStmt isGuard (GroupStmt stmts binderMap by using) = do
457     liftM4 GroupStmt 
458         (addTickLStmts isGuard stmts)
459         (return binderMap)
460         (fmapMaybeM  addTickLHsExprAlways by)
461         (fmapEitherM addTickLHsExprAlways (addTickSyntaxExpr hpcSrcSpan) using)
462
463 addTickStmt isGuard stmt@(RecStmt {})
464   = do { stmts' <- addTickLStmts isGuard (recS_stmts stmt)
465        ; ret'   <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)
466        ; mfix'  <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)
467        ; bind'  <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)
468        ; dicts' <- addTickEvBinds (recS_dicts stmt)
469        ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'
470                       , recS_mfix_fn = mfix', recS_bind_fn = bind'
471                       , recS_dicts = dicts' }) }
472
473 addTick :: Maybe (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)
474 addTick isGuard e | Just fn <- isGuard = addBinTickLHsExpr fn e
475                   | otherwise          = addTickLHsExprAlways e
476
477 addTickStmtAndBinders :: Maybe (Bool -> BoxLabel) -> ([LStmt Id], a) 
478                       -> TM ([LStmt Id], a)
479 addTickStmtAndBinders isGuard (stmts, ids) = 
480     liftM2 (,) 
481         (addTickLStmts isGuard stmts)
482         (return ids)
483
484 addTickMaybeByLHsExpr :: Maybe (LHsExpr Id) -> TM (Maybe (LHsExpr Id))
485 addTickMaybeByLHsExpr maybeByExpr = 
486     case maybeByExpr of
487         Nothing -> return Nothing
488         Just byExpr -> addTickLHsExprAlways byExpr >>= (return . Just)
489
490 addTickHsLocalBinds :: HsLocalBinds Id -> TM (HsLocalBinds Id)
491 addTickHsLocalBinds (HsValBinds binds) = 
492         liftM HsValBinds 
493                 (addTickHsValBinds binds)
494 addTickHsLocalBinds (HsIPBinds binds)  = 
495         liftM HsIPBinds 
496                 (addTickHsIPBinds binds)
497 addTickHsLocalBinds (EmptyLocalBinds)  = return EmptyLocalBinds
498
499 addTickHsValBinds :: HsValBindsLR Id a -> TM (HsValBindsLR Id b)
500 addTickHsValBinds (ValBindsOut binds sigs) =
501         liftM2 ValBindsOut
502                 (mapM (\ (rec,binds') -> 
503                                 liftM2 (,)
504                                         (return rec)
505                                         (addTickLHsBinds binds'))
506                         binds)
507                 (return sigs)
508 addTickHsValBinds _ = panic "addTickHsValBinds"
509
510 addTickHsIPBinds :: HsIPBinds Id -> TM (HsIPBinds Id)
511 addTickHsIPBinds (IPBinds ipbinds dictbinds) =
512         liftM2 IPBinds
513                 (mapM (liftL (addTickIPBind)) ipbinds)
514                 (return dictbinds)
515
516 addTickIPBind :: IPBind Id -> TM (IPBind Id)
517 addTickIPBind (IPBind nm e) =
518         liftM2 IPBind
519                 (return nm)
520                 (addTickLHsExpr e)
521
522 -- There is no location here, so we might need to use a context location??
523 addTickSyntaxExpr :: SrcSpan -> SyntaxExpr Id -> TM (SyntaxExpr Id)
524 addTickSyntaxExpr pos x = do
525         L _ x' <- addTickLHsExpr (L pos x)
526         return $ x'
527 -- we do not walk into patterns.
528 addTickLPat :: LPat Id -> TM (LPat Id)
529 addTickLPat pat = return pat
530
531 addTickHsCmdTop :: HsCmdTop Id -> TM (HsCmdTop Id)
532 addTickHsCmdTop (HsCmdTop cmd tys ty syntaxtable) =
533         liftM4 HsCmdTop
534                 (addTickLHsCmd cmd)
535                 (return tys)
536                 (return ty)
537                 (return syntaxtable)
538
539 addTickLHsCmd ::  LHsCmd Id -> TM (LHsCmd Id)
540 addTickLHsCmd x = addTickLHsExpr x
541
542 addTickEvBinds :: TcEvBinds -> TM TcEvBinds
543 addTickEvBinds x = return x   -- No coverage testing for dictionary binding
544
545 addTickHsRecordBinds :: HsRecordBinds Id -> TM (HsRecordBinds Id)
546 addTickHsRecordBinds (HsRecFields fields dd) 
547   = do  { fields' <- mapM process fields
548         ; return (HsRecFields fields' dd) }
549   where
550     process (HsRecField ids expr doc)
551         = do { expr' <- addTickLHsExpr expr
552              ; return (HsRecField ids expr' doc) }
553
554 addTickArithSeqInfo :: ArithSeqInfo Id -> TM (ArithSeqInfo Id)
555 addTickArithSeqInfo (From e1) =
556         liftM From
557                 (addTickLHsExpr e1)
558 addTickArithSeqInfo (FromThen e1 e2) =
559         liftM2 FromThen
560                 (addTickLHsExpr e1)
561                 (addTickLHsExpr e2)
562 addTickArithSeqInfo (FromTo e1 e2) =
563         liftM2 FromTo
564                 (addTickLHsExpr e1)
565                 (addTickLHsExpr e2)
566 addTickArithSeqInfo (FromThenTo e1 e2 e3) =
567         liftM3 FromThenTo
568                 (addTickLHsExpr e1)
569                 (addTickLHsExpr e2)
570                 (addTickLHsExpr e3)
571 \end{code}
572
573 \begin{code}
574 data TickTransState = TT { tickBoxCount:: Int
575                          , mixEntries  :: [MixEntry_]
576                          }                        
577
578 data TickTransEnv = TTE { fileName      :: FastString
579                         , declPath     :: [String]
580                         , inScope      :: VarSet
581                         , blackList   :: Map SrcSpan ()
582                         }
583
584 --      deriving Show
585
586 type FreeVars = OccEnv Id
587 noFVs :: FreeVars
588 noFVs = emptyOccEnv
589
590 -- Note [freevars]
591 --   For breakpoints we want to collect the free variables of an
592 --   expression for pinning on the HsTick.  We don't want to collect
593 --   *all* free variables though: in particular there's no point pinning
594 --   on free variables that are will otherwise be in scope at the GHCi
595 --   prompt, which means all top-level bindings.  Unfortunately detecting
596 --   top-level bindings isn't easy (collectHsBindsBinders on the top-level
597 --   bindings doesn't do it), so we keep track of a set of "in-scope"
598 --   variables in addition to the free variables, and the former is used
599 --   to filter additions to the latter.  This gives us complete control
600 --   over what free variables we track.
601
602 data TM a = TM { unTM :: TickTransEnv -> TickTransState -> (a,FreeVars,TickTransState) }
603         -- a combination of a state monad (TickTransState) and a writer
604         -- monad (FreeVars).
605
606 instance Monad TM where
607   return a = TM $ \ _env st -> (a,noFVs,st)
608   (TM m) >>= k = TM $ \ env st -> 
609                                 case m env st of
610                                   (r1,fv1,st1) -> 
611                                      case unTM (k r1) env st1 of
612                                        (r2,fv2,st2) -> 
613                                           (r2, fv1 `plusOccEnv` fv2, st2)
614
615 -- getState :: TM TickTransState
616 -- getState = TM $ \ env st -> (st, noFVs, st)
617
618 -- setState :: (TickTransState -> TickTransState) -> TM ()
619 -- setState f = TM $ \ env st -> ((), noFVs, f st)
620
621 getEnv :: TM TickTransEnv
622 getEnv = TM $ \ env st -> (env, noFVs, st)
623
624 withEnv :: (TickTransEnv -> TickTransEnv) -> TM a -> TM a
625 withEnv f (TM m) = TM $ \ env st -> 
626                                  case m (f env) st of
627                                    (a, fvs, st') -> (a, fvs, st')
628
629 getFreeVars :: TM a -> TM (FreeVars, a)
630 getFreeVars (TM m) 
631   = TM $ \ env st -> case m env st of (a, fv, st') -> ((fv,a), fv, st')
632
633 freeVar :: Id -> TM ()
634 freeVar id = TM $ \ env st -> 
635                 if id `elemVarSet` inScope env
636                    then ((), unitOccEnv (nameOccName (idName id)) id, st)
637                    else ((), noFVs, st)
638
639 addPathEntry :: String -> TM a -> TM a
640 addPathEntry nm = withEnv (\ env -> env { declPath = declPath env ++ [nm] })
641
642 getPathEntry :: TM [String]
643 getPathEntry = declPath `liftM` getEnv
644
645 getFileName :: TM FastString
646 getFileName = fileName `liftM` getEnv
647
648 sameFileName :: SrcSpan -> TM a -> TM a -> TM a
649 sameFileName pos out_of_scope in_scope = do
650   file_name <- getFileName
651   case srcSpanFileName_maybe pos of 
652     Just file_name2 
653       | file_name == file_name2 -> in_scope
654     _ -> out_of_scope
655
656 bindLocals :: [Id] -> TM a -> TM a
657 bindLocals new_ids (TM m)
658   = TM $ \ env st -> 
659                  case m env{ inScope = inScope env `extendVarSetList` new_ids } st of
660                    (r, fv, st') -> (r, fv `delListFromOccEnv` occs, st')
661   where occs = [ nameOccName (idName id) | id <- new_ids ] 
662
663 isBlackListed :: SrcSpan -> TM Bool
664 isBlackListed pos = TM $ \ env st -> 
665               case Map.lookup pos (blackList env) of
666                 Nothing -> (False,noFVs,st)
667                 Just () -> (True,noFVs,st)
668
669 -- the tick application inherits the source position of its
670 -- expression argument to support nested box allocations 
671 allocTickBox :: BoxLabel -> SrcSpan -> TM (HsExpr Id) -> TM (LHsExpr Id)
672 allocTickBox boxLabel pos m | isGoodSrcSpan' pos = 
673   sameFileName pos 
674     (do e <- m; return (L pos e)) $ do
675   (fvs, e) <- getFreeVars m
676   TM $ \ env st ->
677     let c = tickBoxCount st
678         ids = occEnvElts fvs
679         mes = mixEntries st
680         me = (pos, declPath env, map (nameOccName.idName) ids, boxLabel)
681     in
682     ( L pos (HsTick c ids (L pos e))
683     , fvs
684     , st {tickBoxCount=c+1,mixEntries=me:mes}
685     )
686 allocTickBox _boxLabel pos m = do e <- m; return (L pos e)
687
688 -- the tick application inherits the source position of its
689 -- expression argument to support nested box allocations 
690 allocATickBox :: BoxLabel -> SrcSpan -> FreeVars -> TM (Maybe (Int,[Id]))
691 allocATickBox boxLabel pos fvs | isGoodSrcSpan' pos = 
692   sameFileName pos 
693     (return Nothing) $ TM $ \ env st ->
694   let me = (pos, declPath env, map (nameOccName.idName) ids, boxLabel)
695       c = tickBoxCount st
696       mes = mixEntries st
697       ids = occEnvElts fvs
698   in ( Just (c, ids)
699      , noFVs
700      , st {tickBoxCount=c+1, mixEntries=me:mes}
701      )
702 allocATickBox _boxLabel _pos _fvs = return Nothing
703
704 allocBinTickBox :: (Bool -> BoxLabel) -> SrcSpan -> TM (HsExpr Id)
705                 -> TM (LHsExpr Id)
706 allocBinTickBox boxLabel pos m
707  | not opt_Hpc = allocTickBox (ExpBox False) pos m
708  | isGoodSrcSpan' pos =
709  do
710  e <- m
711  TM $ \ env st ->
712   let meT = (pos,declPath env, [],boxLabel True)
713       meF = (pos,declPath env, [],boxLabel False)
714       meE = (pos,declPath env, [],ExpBox False)
715       c = tickBoxCount st
716       mes = mixEntries st
717   in 
718              ( L pos $ HsTick c [] $ L pos $ HsBinTick (c+1) (c+2) (L pos e)
719            -- notice that F and T are reversed,
720            -- because we are building the list in
721            -- reverse...
722              , noFVs
723              , st {tickBoxCount=c+3 , mixEntries=meF:meT:meE:mes}
724              )
725 allocBinTickBox _boxLabel pos m = do e <- m; return (L pos e)
726
727 isGoodSrcSpan' :: SrcSpan -> Bool
728 isGoodSrcSpan' pos
729    | not (isGoodSrcSpan pos) = False
730    | start == end            = False
731    | otherwise               = True
732   where
733    start = srcSpanStart pos
734    end   = srcSpanEnd pos
735
736 mkHpcPos :: SrcSpan -> HpcPos
737 mkHpcPos pos 
738    | not (isGoodSrcSpan' pos) = panic "bad source span; expected such spans to be filtered out"
739    | otherwise                = hpcPos
740   where
741    start = srcSpanStart pos
742    end   = srcSpanEnd pos
743    hpcPos = toHpcPos ( srcLocLine start
744                      , srcLocCol start
745                      , srcLocLine end
746                      , srcLocCol end - 1
747                      )
748
749 hpcSrcSpan :: SrcSpan
750 hpcSrcSpan = mkGeneralSrcSpan (fsLit "Haskell Program Coverage internals")
751 \end{code}
752
753
754 \begin{code}
755 matchesOneOfMany :: [LMatch Id] -> Bool
756 matchesOneOfMany lmatches = sum (map matchCount lmatches) > 1
757   where
758         matchCount (L _ (Match _pats _ty (GRHSs grhss _binds))) = length grhss
759 \end{code}
760
761
762 \begin{code}
763 type MixEntry_ = (SrcSpan, [String], [OccName], BoxLabel)
764
765 -- For the hash value, we hash everything: the file name, 
766 --  the timestamp of the original source file, the tab stop,
767 --  and the mix entries. We cheat, and hash the show'd string.
768 -- This hash only has to be hashed at Mix creation time,
769 -- and is for sanity checking only.
770
771 mixHash :: FilePath -> Integer -> Int -> [MixEntry] -> Int
772 mixHash file tm tabstop entries = fromIntegral $ hashString
773         (show $ Mix file tm 0 tabstop entries)
774 \end{code}