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