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