11import enum
22from abc import ABC
3- from typing import Tuple , Callable , Optional
3+ from typing import Tuple , Callable , Optional , List , Type
44
55from sflkitlib .events import EventType
6- from sflkitlib .events .event import BranchEvent , FunctionExitEvent , DefEvent
6+ from sflkitlib .events .event import (
7+ BranchEvent ,
8+ FunctionExitEvent ,
9+ DefEvent ,
10+ Event ,
11+ ConditionEvent ,
12+ )
713
814from sflkit .analysis .analysis_type import AnalysisType , EvaluationResult
915from sflkit .analysis .spectra import Spectrum
@@ -51,12 +57,14 @@ def finalize(self, passed: list, failed: list):
5157 else :
5258 self .false_relevant_observed ()
5359
54- def hit (self , id_ , event , scope_ : scope .Scope = None ):
55- super (Predicate , self ).hit (id_ , event , scope_ )
60+ def hit (self , id_ , event : Event , scope_ : scope .Scope = None ):
5661 if id_ not in self .true_hits :
5762 self .true_hits [id_ ] = 0
58- if self ._evaluate_predicate (scope_ ):
63+ if id_ not in self .hits :
64+ self .hits [id_ ] = 0
65+ if self ._evaluate_predicate (event , scope_ ):
5966 self .true_hits [id_ ] += 1
67+ self .hits [id_ ] += 1
6068 self .last_evaluation = EvaluationResult .TRUE
6169 else :
6270 self .last_evaluation = EvaluationResult .FALSE
@@ -66,7 +74,7 @@ def get_metric(self, metric: Callable = None):
6674 metric = Predicate .IncreaseTrue
6775 return super ().get_metric (metric )
6876
69- def _evaluate_predicate (self , scope_ : scope .Scope ):
77+ def _evaluate_predicate (self , event : Event , scope_ : scope .Scope ):
7078 return False
7179
7280 def true_relevant_observed (self ):
@@ -139,7 +147,7 @@ def analysis_type() -> AnalysisType:
139147 def events ():
140148 return [EventType .BRANCH ]
141149
142- def hit (self , id_ , event , scope_ : scope .Scope = None ):
150+ def hit (self , id_ , event : BranchEvent , scope_ : scope .Scope = None ):
143151 if id_ not in self .true_hits :
144152 self .true_hits [id_ ] = 0
145153 if event .then_id == self .then_id :
@@ -206,7 +214,7 @@ def events():
206214 EventType .FUNCTION_ERROR ,
207215 ]
208216
209- def _evaluate_predicate (self , scope_ : scope .Scope ) -> bool :
217+ def _evaluate_predicate (self , event : Event , scope_ : scope .Scope ) -> bool :
210218 return self ._compare (self ._get_first (scope_ ), self ._get_second (scope_ ))
211219
212220 def _compare (self , first , second ) -> bool :
@@ -220,7 +228,7 @@ def _get_second(self, scope_: scope.Scope):
220228
221229
222230class ScalarPair (Comparison ):
223- def __init__ (self , event , op : Comp , var : str ):
231+ def __init__ (self , event : DefEvent , op : Comp , var : str ):
224232 super ().__init__ (event .file , event .line , op )
225233 self .var1 = event .var
226234 self .var2 = var
@@ -240,7 +248,7 @@ def __str__(self):
240248
241249
242250class VariablePredicate (Comparison ):
243- def __init__ (self , event , op : Comp ):
251+ def __init__ (self , event : DefEvent , op : Comp ):
244252 super ().__init__ (event .file , event .line , op )
245253 self .var = event .var
246254
@@ -376,7 +384,7 @@ def events():
376384 EventType .DEF ,
377385 ]
378386
379- def _evaluate_predicate (self , scope_ : scope .Scope ):
387+ def _evaluate_predicate (self , event : Event , scope_ : scope .Scope ):
380388 value = scope_ .value (self .var )
381389 return isinstance (value , str ) and self .predicate (scope_ .value (self .var ))
382390
@@ -438,7 +446,7 @@ def analysis_type():
438446 def events ():
439447 return [EventType .CONDITION ]
440448
441- def hit (self , id_ , event , scope_ : scope .Scope = None ):
449+ def hit (self , id_ , event : ConditionEvent , scope_ : scope .Scope = None ):
442450 super (Predicate , self ).hit (id_ , event , scope_ )
443451 if id_ not in self .true_hits :
444452 self .true_hits [id_ ] = 0
@@ -450,3 +458,34 @@ def hit(self, id_, event, scope_: scope.Scope = None):
450458
451459 def __str__ (self ):
452460 return f"{ self .analysis_type ()} :{ self .file } :{ self .line } :{ self .condition } "
461+
462+
463+ class FunctionErrorPredicate (Predicate ):
464+ def __init__ (self , file , line , function ):
465+ super ().__init__ (file , line )
466+ self .function = function
467+
468+ @staticmethod
469+ def analysis_type () -> AnalysisType :
470+ return AnalysisType .FUNCTION_ERROR
471+
472+ @staticmethod
473+ def events () -> List [Type ]:
474+ return [
475+ EventType .FUNCTION_ENTER ,
476+ EventType .FUNCTION_ERROR ,
477+ EventType .FUNCTION_EXIT ,
478+ ]
479+
480+ def _evaluate_predicate (self , event : Event , scope_ : scope .Scope ):
481+ return event .event_type == EventType .FUNCTION_ERROR
482+
483+ def get_suggestion (self , metric : Callable = None , base_dir : str = "" ):
484+ finder = self .function_finder (self .file , self .line , self .function )
485+ return Suggestion (
486+ [Location (self .file , line ) for line in finder .get_locations (base_dir )],
487+ self .get_metric (metric ),
488+ )
489+
490+ def __str__ (self ):
491+ return f"{ self .analysis_type ()} :{ self .file } :{ self .function } :{ self .line } "
0 commit comments