sflkit 0.5.0__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sflkit-0.5.0/src/sflkit.egg-info → sflkit-0.5.2}/PKG-INFO +2 -2
- {sflkit-0.5.0 → sflkit-0.5.2}/pyproject.toml +1 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/__init__.py +1 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/analysis_type.py +13 -13
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/analyzer.py +14 -4
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/factory.py +180 -95
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/predicate.py +86 -63
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/similarity.py +1 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/spectra.py +100 -49
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/events/event_file.py +8 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/features/handler.py +67 -33
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/features/value.py +26 -5
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/features/vector.py +27 -14
- sflkit-0.5.2/src/sflkit/model/model.py +150 -0
- sflkit-0.5.2/src/sflkit/model/parallel.py +97 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/runners/run.py +49 -50
- sflkit-0.5.2/src/sflkit/weights/models.py +329 -0
- {sflkit-0.5.0 → sflkit-0.5.2/src/sflkit.egg-info}/PKG-INFO +2 -2
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit.egg-info/SOURCES.txt +1 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit.egg-info/requires.txt +1 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_cli.py +2 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_config.py +2 -2
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_dependency_weights.py +4 -2
- sflkit-0.5.2/tests/test_features.py +451 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_runner.py +1 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_runner_parallel.py +3 -1
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_suggestions.py +2 -0
- sflkit-0.5.0/src/sflkit/model/model.py +0 -114
- sflkit-0.5.0/src/sflkit/model/parallel.py +0 -127
- sflkit-0.5.0/src/sflkit/weights/models.py +0 -300
- {sflkit-0.5.0 → sflkit-0.5.2}/LICENSE +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/README.md +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/setup.cfg +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/mapping.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/analysis/suggestion.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/cli.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/color.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/config.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/evaluation.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/events/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/events/mapping.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/features/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/instrumentation/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/instrumentation/dir_instrumentation.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/instrumentation/file_instrumentation.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/extract.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/finder.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/java/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/java/extract.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/java/factory.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/java/finder.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/java/visitor.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/language.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/meta.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/python/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/python/extract.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/python/factory.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/python/finder.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/python/visitor.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/language/visitor.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/logger.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/model/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/model/scope.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/runners/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/weights/__init__.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit/weights/analyzer.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit.egg-info/dependency_links.txt +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit.egg-info/entry_points.txt +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/src/sflkit.egg-info/top_level.txt +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_analysis_objects.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_analyzer.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_color.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_coverage.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_evaluation.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_events.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_execution.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_instrumentation.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_language.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_parallelization.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_predicates.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_runner_pytest_versions.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_scope.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_spectra.py +0 -0
- {sflkit-0.5.0 → sflkit-0.5.2}/tests/test_visitors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sflkit
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: SFLKit: : A Workbench for Statistical Fault Localization
|
|
5
5
|
Author-email: Marius Smytzek <marius.smytzek@cispa.de>
|
|
6
6
|
Project-URL: Homepage, https://github.com/smythi93/sflkit/
|
|
@@ -15,7 +15,7 @@ Classifier: Topic :: Software Development :: Testing
|
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: sflkitlib>=0.2.
|
|
18
|
+
Requires-Dist: sflkitlib>=0.2.2
|
|
19
19
|
Requires-Dist: numpy>=2.1.3
|
|
20
20
|
Requires-Dist: matplotlib>=3.10.0
|
|
21
21
|
Requires-Dist: pandas>=2.2.3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import abc
|
|
1
2
|
import enum
|
|
2
|
-
from
|
|
3
|
-
from typing import List, Type, Optional
|
|
3
|
+
from typing import List, Type, Optional, Any
|
|
4
4
|
|
|
5
5
|
from sflkit.events.event_file import EventFile
|
|
6
6
|
from sflkit.model.scope import Scope
|
|
@@ -43,7 +43,7 @@ If you want to add new spectra or predicates, please register them here and in s
|
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class AnalysisObject:
|
|
46
|
+
class AnalysisObject(abc.ABC):
|
|
47
47
|
function_finder = None
|
|
48
48
|
loop_finder = None
|
|
49
49
|
branch_finder = None
|
|
@@ -58,17 +58,17 @@ class AnalysisObject:
|
|
|
58
58
|
def __init__(self):
|
|
59
59
|
self.suspiciousness: float = 0
|
|
60
60
|
self.last_evaluation: EvaluationResult = EvaluationResult.UNOBSERVED
|
|
61
|
-
self.hits = dict()
|
|
61
|
+
self.hits: dict[EventFile, dict[Optional[int], Any]] = dict()
|
|
62
62
|
|
|
63
63
|
def adjust_weight(self, event_file: EventFile, weight: float):
|
|
64
64
|
pass
|
|
65
65
|
|
|
66
|
-
@abstractmethod
|
|
66
|
+
@abc.abstractmethod
|
|
67
67
|
def serialize(self) -> dict:
|
|
68
68
|
pass
|
|
69
69
|
|
|
70
70
|
@staticmethod
|
|
71
|
-
@abstractmethod
|
|
71
|
+
@abc.abstractmethod
|
|
72
72
|
def deserialize(s: dict) -> "AnalysisObject":
|
|
73
73
|
pass
|
|
74
74
|
|
|
@@ -82,7 +82,7 @@ class AnalysisObject:
|
|
|
82
82
|
return f"{self.analysis_type()}"
|
|
83
83
|
|
|
84
84
|
@staticmethod
|
|
85
|
-
@abstractmethod
|
|
85
|
+
@abc.abstractmethod
|
|
86
86
|
def analysis_type() -> AnalysisType:
|
|
87
87
|
raise NotImplementedError()
|
|
88
88
|
|
|
@@ -93,19 +93,19 @@ class AnalysisObject:
|
|
|
93
93
|
def calculate(self):
|
|
94
94
|
pass
|
|
95
95
|
|
|
96
|
-
@abstractmethod
|
|
96
|
+
@abc.abstractmethod
|
|
97
97
|
def finalize(self, passed: List, failed: List):
|
|
98
98
|
raise NotImplementedError()
|
|
99
99
|
|
|
100
|
-
@abstractmethod
|
|
101
|
-
def hit(self, id_, event,
|
|
100
|
+
@abc.abstractmethod
|
|
101
|
+
def hit(self, id_: EventFile, event, scope: Scope = None):
|
|
102
102
|
raise NotImplementedError()
|
|
103
103
|
|
|
104
|
-
@abstractmethod
|
|
104
|
+
@abc.abstractmethod
|
|
105
105
|
def get_suggestion(self):
|
|
106
106
|
raise NotImplementedError()
|
|
107
107
|
|
|
108
|
-
@abstractmethod
|
|
108
|
+
@abc.abstractmethod
|
|
109
109
|
def assign_suspiciousness(self):
|
|
110
110
|
raise NotImplementedError()
|
|
111
111
|
|
|
@@ -114,7 +114,7 @@ class AnalysisObject:
|
|
|
114
114
|
return any(map(lambda e: isinstance(event, e), events))
|
|
115
115
|
|
|
116
116
|
@staticmethod
|
|
117
|
-
@abstractmethod
|
|
117
|
+
@abc.abstractmethod
|
|
118
118
|
def events() -> List[Type]:
|
|
119
119
|
raise NotImplementedError()
|
|
120
120
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
4
|
from typing import List, Callable, Set, Dict, Optional, Any, Type
|
|
4
5
|
|
|
5
6
|
from sflkit.analysis.analysis_type import AnalysisType, AnalysisObject
|
|
@@ -42,6 +43,7 @@ class Analyzer:
|
|
|
42
43
|
meta_model: Optional[MetaModel] = None,
|
|
43
44
|
model_class: Type[Model] = None,
|
|
44
45
|
parallel: bool = False,
|
|
46
|
+
workers: int = 4,
|
|
45
47
|
):
|
|
46
48
|
if (
|
|
47
49
|
relevant_event_files is None
|
|
@@ -64,6 +66,7 @@ class Analyzer:
|
|
|
64
66
|
else:
|
|
65
67
|
model_class = Model
|
|
66
68
|
self.model = model_class(factory)
|
|
69
|
+
self.workers = workers
|
|
67
70
|
self.paths: Dict[int, os.PathLike] = dict()
|
|
68
71
|
self.max_suspiciousness = 0
|
|
69
72
|
self.min_suspiciousness = 0
|
|
@@ -76,7 +79,7 @@ class Analyzer:
|
|
|
76
79
|
self.model.prepare(event_file)
|
|
77
80
|
with event_file:
|
|
78
81
|
for event in event_file.load():
|
|
79
|
-
event.handle(self.model)
|
|
82
|
+
event.handle(self.model, event_file)
|
|
80
83
|
self.model.follow_up(event_file)
|
|
81
84
|
|
|
82
85
|
def _finalize(self):
|
|
@@ -87,9 +90,16 @@ class Analyzer:
|
|
|
87
90
|
def analyze(self):
|
|
88
91
|
if self.meta:
|
|
89
92
|
raise NotImplementedError("Not implemented for meta/loaded analyzer")
|
|
90
|
-
|
|
91
|
-
self.
|
|
92
|
-
|
|
93
|
+
if self.workers > 1:
|
|
94
|
+
event_files = self.relevant_event_files + self.irrelevant_event_files
|
|
95
|
+
for event_file in event_files:
|
|
96
|
+
self.paths[event_file.run_id] = event_file.path
|
|
97
|
+
with ThreadPoolExecutor(max_workers=self.workers) as executor:
|
|
98
|
+
list(executor.map(self._analyze, event_files))
|
|
99
|
+
else:
|
|
100
|
+
for event_file in self.relevant_event_files + self.irrelevant_event_files:
|
|
101
|
+
self.paths[event_file.run_id] = event_file.path
|
|
102
|
+
self._analyze(event_file)
|
|
93
103
|
self._finalize()
|
|
94
104
|
|
|
95
105
|
def dump(self, path: os.PathLike, indent: Optional[int] = None):
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import abc
|
|
2
|
-
from
|
|
2
|
+
from threading import Lock
|
|
3
3
|
from typing import List, Type, Set
|
|
4
4
|
|
|
5
5
|
from sflkitlib.events import EventType
|
|
6
|
+
from sflkitlib.events.event import DefEvent
|
|
6
7
|
|
|
7
8
|
from sflkit.analysis.analysis_type import AnalysisObject, AnalysisType
|
|
8
9
|
from sflkit.analysis.predicate import (
|
|
@@ -21,25 +22,29 @@ from sflkit.analysis.predicate import (
|
|
|
21
22
|
FunctionErrorPredicate,
|
|
22
23
|
)
|
|
23
24
|
from sflkit.analysis.spectra import Line, Function, Loop, DefUse, Length
|
|
25
|
+
from sflkit.events.event_file import EventFile
|
|
24
26
|
from sflkit.model.scope import Scope
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
class AnalysisFactory:
|
|
29
|
+
class AnalysisFactory(abc.ABC):
|
|
28
30
|
def __init__(self):
|
|
29
31
|
self.objects = dict()
|
|
32
|
+
self._lock = Lock()
|
|
30
33
|
|
|
31
|
-
@abstractmethod
|
|
32
|
-
def get_analysis(
|
|
34
|
+
@abc.abstractmethod
|
|
35
|
+
def get_analysis(
|
|
36
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
37
|
+
) -> List[AnalysisObject]:
|
|
33
38
|
raise NotImplementedError()
|
|
34
39
|
|
|
35
|
-
def handle(self, event, scope: Scope = None):
|
|
36
|
-
analysis = self.get_analysis(event, scope=scope)
|
|
40
|
+
def handle(self, event, event_file: EventFile, scope: Scope = None):
|
|
41
|
+
analysis = self.get_analysis(event, event_file, scope=scope)
|
|
37
42
|
if analysis:
|
|
38
43
|
return analysis
|
|
39
44
|
else:
|
|
40
45
|
return self.default()
|
|
41
46
|
|
|
42
|
-
def reset(self):
|
|
47
|
+
def reset(self, event_file: EventFile):
|
|
43
48
|
pass
|
|
44
49
|
|
|
45
50
|
@staticmethod
|
|
@@ -55,25 +60,32 @@ class CombinationFactory(AnalysisFactory):
|
|
|
55
60
|
super().__init__()
|
|
56
61
|
self.factories = factories
|
|
57
62
|
|
|
58
|
-
def get_analysis(
|
|
63
|
+
def get_analysis(
|
|
64
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
65
|
+
) -> List[AnalysisObject]:
|
|
59
66
|
return sum(
|
|
60
|
-
[factory.handle(event, scope) for factory in self.factories],
|
|
67
|
+
[factory.handle(event, event_file, scope) for factory in self.factories],
|
|
68
|
+
start=list(),
|
|
61
69
|
)
|
|
62
70
|
|
|
63
|
-
def reset(self):
|
|
64
|
-
[f.reset() for f in self.factories]
|
|
71
|
+
def reset(self, event_file: EventFile):
|
|
72
|
+
[f.reset(event_file) for f in self.factories]
|
|
65
73
|
|
|
66
74
|
def get_all(self) -> Set[AnalysisObject]:
|
|
67
75
|
return set().union(*map(lambda f: f.get_all(), self.factories))
|
|
68
76
|
|
|
69
77
|
|
|
70
78
|
class LineFactory(AnalysisFactory):
|
|
71
|
-
def get_analysis(
|
|
79
|
+
def get_analysis(
|
|
80
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
81
|
+
) -> List[AnalysisObject]:
|
|
72
82
|
if event.event_type == EventType.LINE:
|
|
73
83
|
key = (Line.analysis_type(), event.file, event.line)
|
|
74
|
-
|
|
75
|
-
self.objects
|
|
84
|
+
with self._lock:
|
|
85
|
+
if key not in self.objects:
|
|
86
|
+
self.objects[key] = Line(event)
|
|
76
87
|
return [self.objects[key]]
|
|
88
|
+
return None
|
|
77
89
|
|
|
78
90
|
|
|
79
91
|
class BranchFactory(AnalysisFactory):
|
|
@@ -81,12 +93,15 @@ class BranchFactory(AnalysisFactory):
|
|
|
81
93
|
super().__init__()
|
|
82
94
|
self.else_ = else_
|
|
83
95
|
|
|
84
|
-
def get_analysis(
|
|
96
|
+
def get_analysis(
|
|
97
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
98
|
+
) -> List[AnalysisObject]:
|
|
85
99
|
if event.event_type == EventType.BRANCH:
|
|
86
100
|
key = (Branch.analysis_type(), event.file, event.line, event.then_id)
|
|
87
101
|
then = event.then_id < event.else_id
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
with self._lock:
|
|
103
|
+
if key not in self.objects:
|
|
104
|
+
self.objects[key] = Branch(event, then=then, then_id=event.then_id)
|
|
90
105
|
if self.else_ and event.else_id >= 0:
|
|
91
106
|
else_key = (
|
|
92
107
|
Branch.analysis_type(),
|
|
@@ -94,19 +109,28 @@ class BranchFactory(AnalysisFactory):
|
|
|
94
109
|
event.line,
|
|
95
110
|
event.else_id,
|
|
96
111
|
)
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
with self._lock:
|
|
113
|
+
if else_key not in self.objects:
|
|
114
|
+
self.objects[else_key] = Branch(
|
|
115
|
+
event, then=not then, then_id=event.else_id
|
|
116
|
+
)
|
|
99
117
|
return [self.objects[key], self.objects[else_key]]
|
|
100
118
|
return [self.objects[key]]
|
|
101
119
|
|
|
120
|
+
return None
|
|
121
|
+
|
|
102
122
|
|
|
103
123
|
class FunctionFactory(AnalysisFactory):
|
|
104
|
-
def get_analysis(
|
|
124
|
+
def get_analysis(
|
|
125
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
126
|
+
) -> List[AnalysisObject]:
|
|
105
127
|
if event.event_type == EventType.FUNCTION_ENTER:
|
|
106
128
|
key = (Function.analysis_type(), event.file, event.line, event.function_id)
|
|
107
|
-
|
|
108
|
-
self.objects
|
|
129
|
+
with self._lock:
|
|
130
|
+
if key not in self.objects:
|
|
131
|
+
self.objects[key] = Function(event)
|
|
109
132
|
return [self.objects[key]]
|
|
133
|
+
return None
|
|
110
134
|
|
|
111
135
|
|
|
112
136
|
class LoopFactory(AnalysisFactory):
|
|
@@ -119,60 +143,74 @@ class LoopFactory(AnalysisFactory):
|
|
|
119
143
|
def get_all(self) -> Set[AnalysisObject]:
|
|
120
144
|
return set(obj for value in self.objects.values() for obj in value)
|
|
121
145
|
|
|
122
|
-
def get_analysis(
|
|
146
|
+
def get_analysis(
|
|
147
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
148
|
+
) -> List[AnalysisObject]:
|
|
123
149
|
if event.event_type in (
|
|
124
150
|
EventType.LOOP_BEGIN,
|
|
125
151
|
EventType.LOOP_HIT,
|
|
126
152
|
EventType.LOOP_END,
|
|
127
153
|
):
|
|
128
154
|
key = (Loop.analysis_type(), event.file, event.line, event.loop_id)
|
|
129
|
-
|
|
130
|
-
self.objects
|
|
131
|
-
|
|
132
|
-
self.
|
|
133
|
-
|
|
134
|
-
self.
|
|
135
|
-
|
|
136
|
-
self.
|
|
155
|
+
with self._lock:
|
|
156
|
+
if key not in self.objects:
|
|
157
|
+
self.objects[key] = []
|
|
158
|
+
if self.hit_0:
|
|
159
|
+
self.objects[key].append(Loop(event, Loop.evaluate_hit_0)),
|
|
160
|
+
if self.hit_1:
|
|
161
|
+
self.objects[key].append(Loop(event, Loop.evaluate_hit_1)),
|
|
162
|
+
if self.hit_more:
|
|
163
|
+
self.objects[key].append(Loop(event, Loop.evaluate_hit_more)),
|
|
137
164
|
if event.event_type == EventType.LOOP_BEGIN:
|
|
138
|
-
|
|
165
|
+
for obj in self.objects[key]:
|
|
166
|
+
obj.start_loop(thread_id=event.thread_id)
|
|
139
167
|
elif event.event_type == EventType.LOOP_HIT:
|
|
140
|
-
|
|
168
|
+
for obj in self.objects[key]:
|
|
169
|
+
obj.hit_loop(thread_id=event.thread_id)
|
|
141
170
|
elif event.event_type == EventType.LOOP_END:
|
|
142
171
|
return self.objects[key][:]
|
|
143
172
|
return list()
|
|
173
|
+
return None
|
|
144
174
|
|
|
145
175
|
|
|
146
176
|
class DefUseFactory(AnalysisFactory):
|
|
147
177
|
def __init__(self):
|
|
148
178
|
super().__init__()
|
|
149
|
-
self.id_to_def = dict()
|
|
179
|
+
self.id_to_def: dict[EventFile, dict[tuple[str, int], DefEvent]] = dict()
|
|
150
180
|
|
|
151
|
-
def reset(self):
|
|
152
|
-
self.
|
|
181
|
+
def reset(self, event_file: EventFile):
|
|
182
|
+
with self._lock:
|
|
183
|
+
self.id_to_def[event_file] = dict()
|
|
153
184
|
|
|
154
|
-
def get_analysis(
|
|
185
|
+
def get_analysis(
|
|
186
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
187
|
+
) -> List[AnalysisObject]:
|
|
155
188
|
if event.event_type == EventType.DEF:
|
|
156
|
-
self.
|
|
189
|
+
with self._lock:
|
|
190
|
+
self.id_to_def[event_file][(event.var, event.var_id)] = event
|
|
157
191
|
elif event.event_type == EventType.USE:
|
|
158
|
-
|
|
192
|
+
with self._lock:
|
|
193
|
+
def_event = self.id_to_def[event_file].get((event.var, event.var_id))
|
|
194
|
+
if def_event:
|
|
159
195
|
key = (
|
|
160
196
|
DefUse.analysis_type(),
|
|
161
|
-
|
|
162
|
-
|
|
197
|
+
def_event.file,
|
|
198
|
+
def_event.line,
|
|
163
199
|
event.file,
|
|
164
200
|
event.line,
|
|
165
201
|
event.var,
|
|
166
202
|
)
|
|
167
|
-
|
|
168
|
-
self.objects
|
|
169
|
-
self.
|
|
170
|
-
)
|
|
203
|
+
with self._lock:
|
|
204
|
+
if key not in self.objects:
|
|
205
|
+
self.objects[key] = DefUse(def_event, event)
|
|
171
206
|
return [self.objects[key]]
|
|
207
|
+
return None
|
|
172
208
|
|
|
173
209
|
|
|
174
210
|
class ConditionFactory(AnalysisFactory):
|
|
175
|
-
def get_analysis(
|
|
211
|
+
def get_analysis(
|
|
212
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
213
|
+
) -> List[AnalysisObject]:
|
|
176
214
|
objects = list()
|
|
177
215
|
if event.event_type == EventType.CONDITION:
|
|
178
216
|
for negate in (True, False):
|
|
@@ -183,10 +221,11 @@ class ConditionFactory(AnalysisFactory):
|
|
|
183
221
|
event.condition,
|
|
184
222
|
negate,
|
|
185
223
|
)
|
|
186
|
-
|
|
187
|
-
self.objects
|
|
188
|
-
|
|
189
|
-
|
|
224
|
+
with self._lock:
|
|
225
|
+
if key not in self.objects:
|
|
226
|
+
self.objects[key] = Condition(
|
|
227
|
+
event.file, event.line, event.condition, negate=negate
|
|
228
|
+
)
|
|
190
229
|
objects.append(self.objects[key])
|
|
191
230
|
return objects
|
|
192
231
|
|
|
@@ -218,7 +257,9 @@ class ComparisonFactory(AnalysisFactory, abc.ABC):
|
|
|
218
257
|
|
|
219
258
|
|
|
220
259
|
class ScalarPairFactory(ComparisonFactory):
|
|
221
|
-
def get_analysis(
|
|
260
|
+
def get_analysis(
|
|
261
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
262
|
+
) -> List[AnalysisObject]:
|
|
222
263
|
if event.event_type == EventType.DEF:
|
|
223
264
|
variables = scope.get_all_vars()
|
|
224
265
|
objects = list()
|
|
@@ -238,10 +279,11 @@ class ScalarPairFactory(ComparisonFactory):
|
|
|
238
279
|
comp,
|
|
239
280
|
types[0],
|
|
240
281
|
)
|
|
241
|
-
|
|
242
|
-
self.objects
|
|
243
|
-
|
|
244
|
-
|
|
282
|
+
with self._lock:
|
|
283
|
+
if key not in self.objects:
|
|
284
|
+
self.objects[key] = ScalarPair(
|
|
285
|
+
event, comp, variable.var
|
|
286
|
+
)
|
|
245
287
|
objects.append(self.objects[key])
|
|
246
288
|
else:
|
|
247
289
|
for variable in variables:
|
|
@@ -257,16 +299,20 @@ class ScalarPairFactory(ComparisonFactory):
|
|
|
257
299
|
comp,
|
|
258
300
|
event.type_,
|
|
259
301
|
)
|
|
260
|
-
|
|
261
|
-
self.objects
|
|
262
|
-
|
|
263
|
-
|
|
302
|
+
with self._lock:
|
|
303
|
+
if key not in self.objects:
|
|
304
|
+
self.objects[key] = ScalarPair(
|
|
305
|
+
event, comp, variable.var
|
|
306
|
+
)
|
|
264
307
|
objects.append(self.objects[key])
|
|
265
308
|
return objects
|
|
309
|
+
return None
|
|
266
310
|
|
|
267
311
|
|
|
268
312
|
class VariableFactory(ComparisonFactory):
|
|
269
|
-
def get_analysis(
|
|
313
|
+
def get_analysis(
|
|
314
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
315
|
+
) -> List[AnalysisObject]:
|
|
270
316
|
if event.event_type == EventType.DEF and event.type_ in [
|
|
271
317
|
"int",
|
|
272
318
|
"float",
|
|
@@ -282,14 +328,18 @@ class VariableFactory(ComparisonFactory):
|
|
|
282
328
|
comp,
|
|
283
329
|
"int",
|
|
284
330
|
)
|
|
285
|
-
|
|
286
|
-
|
|
331
|
+
with self._lock:
|
|
332
|
+
if key not in self.objects:
|
|
333
|
+
self.objects[key] = VariablePredicate(event, comp)
|
|
287
334
|
objects.append(self.objects[key])
|
|
288
335
|
return objects
|
|
336
|
+
return None
|
|
289
337
|
|
|
290
338
|
|
|
291
339
|
class ReturnFactory(ComparisonFactory):
|
|
292
|
-
def get_analysis(
|
|
340
|
+
def get_analysis(
|
|
341
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
342
|
+
) -> List[AnalysisObject]:
|
|
293
343
|
if event.event_type == EventType.FUNCTION_EXIT:
|
|
294
344
|
objects = list()
|
|
295
345
|
if event.type_ in ("int", "float", "bool", "str", "bytes"):
|
|
@@ -312,10 +362,13 @@ class ReturnFactory(ComparisonFactory):
|
|
|
312
362
|
comp,
|
|
313
363
|
type_,
|
|
314
364
|
)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
365
|
+
with self._lock:
|
|
366
|
+
if key not in self.objects:
|
|
367
|
+
self.objects[key] = ReturnPredicate(
|
|
368
|
+
event, comp, value=tr
|
|
369
|
+
)
|
|
370
|
+
objects.append(self.objects[key])
|
|
371
|
+
elif event.type_ == "NoneType":
|
|
319
372
|
for comp in Comp.EQ, Comp.NE:
|
|
320
373
|
if comp in self.comparators:
|
|
321
374
|
key = (
|
|
@@ -326,8 +379,11 @@ class ReturnFactory(ComparisonFactory):
|
|
|
326
379
|
comp,
|
|
327
380
|
event.type_,
|
|
328
381
|
)
|
|
329
|
-
|
|
330
|
-
|
|
382
|
+
with self._lock:
|
|
383
|
+
if key not in self.objects:
|
|
384
|
+
self.objects[key] = ReturnPredicate(
|
|
385
|
+
event, comp, value=None
|
|
386
|
+
)
|
|
331
387
|
objects.append(self.objects[key])
|
|
332
388
|
else:
|
|
333
389
|
for comp in Comp.EQ, Comp.NE:
|
|
@@ -340,9 +396,14 @@ class ReturnFactory(ComparisonFactory):
|
|
|
340
396
|
comp,
|
|
341
397
|
"NoneType",
|
|
342
398
|
)
|
|
343
|
-
|
|
344
|
-
|
|
399
|
+
with self._lock:
|
|
400
|
+
if key not in self.objects:
|
|
401
|
+
self.objects[key] = ReturnPredicate(
|
|
402
|
+
event, comp, value=None
|
|
403
|
+
)
|
|
404
|
+
objects.append(self.objects[key])
|
|
345
405
|
return objects
|
|
406
|
+
return None
|
|
346
407
|
|
|
347
408
|
|
|
348
409
|
class ConstantCompFactory(AnalysisFactory):
|
|
@@ -350,7 +411,9 @@ class ConstantCompFactory(AnalysisFactory):
|
|
|
350
411
|
super().__init__()
|
|
351
412
|
self.class_ = class_
|
|
352
413
|
|
|
353
|
-
def get_analysis(
|
|
414
|
+
def get_analysis(
|
|
415
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
416
|
+
) -> List[AnalysisObject]:
|
|
354
417
|
if event.event_type == EventType.DEF:
|
|
355
418
|
objects = list()
|
|
356
419
|
for comp in Comp.EQ, Comp.NE:
|
|
@@ -361,10 +424,13 @@ class ConstantCompFactory(AnalysisFactory):
|
|
|
361
424
|
event.var,
|
|
362
425
|
comp,
|
|
363
426
|
)
|
|
364
|
-
|
|
365
|
-
|
|
427
|
+
with self._lock:
|
|
428
|
+
if key not in self.objects:
|
|
429
|
+
# noinspection PyArgumentList
|
|
430
|
+
self.objects[key] = self.class_(event)
|
|
366
431
|
objects.append(self.objects[key])
|
|
367
432
|
return objects
|
|
433
|
+
return None
|
|
368
434
|
|
|
369
435
|
|
|
370
436
|
class NoneFactory(ConstantCompFactory):
|
|
@@ -387,7 +453,9 @@ class PredicateFunctionFactory(AnalysisFactory):
|
|
|
387
453
|
super().__init__()
|
|
388
454
|
self.class_ = class_
|
|
389
455
|
|
|
390
|
-
def get_analysis(
|
|
456
|
+
def get_analysis(
|
|
457
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
458
|
+
) -> List[AnalysisObject]:
|
|
391
459
|
if event.event_type == EventType.DEF:
|
|
392
460
|
key = (
|
|
393
461
|
self.class_.analysis_type(),
|
|
@@ -395,9 +463,12 @@ class PredicateFunctionFactory(AnalysisFactory):
|
|
|
395
463
|
event.line,
|
|
396
464
|
event.var,
|
|
397
465
|
)
|
|
398
|
-
|
|
399
|
-
|
|
466
|
+
with self._lock:
|
|
467
|
+
if key not in self.objects:
|
|
468
|
+
# noinspection PyArgumentList
|
|
469
|
+
self.objects[key] = self.class_(event)
|
|
400
470
|
return [self.objects[key]]
|
|
471
|
+
return None
|
|
401
472
|
|
|
402
473
|
|
|
403
474
|
class IsAsciiFactory(PredicateFunctionFactory):
|
|
@@ -427,20 +498,28 @@ class LengthFactory(AnalysisFactory):
|
|
|
427
498
|
def get_all(self) -> Set[AnalysisObject]:
|
|
428
499
|
return set(obj for value in self.objects.values() for obj in value)
|
|
429
500
|
|
|
430
|
-
def get_analysis(
|
|
501
|
+
def get_analysis(
|
|
502
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
503
|
+
) -> List[AnalysisObject]:
|
|
431
504
|
if event.event_type == EventType.LEN:
|
|
432
505
|
key = (Length.analysis_type(), event.file, event.line, event.var)
|
|
433
|
-
|
|
434
|
-
self.objects
|
|
435
|
-
|
|
436
|
-
self.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
self.
|
|
441
|
-
|
|
442
|
-
|
|
506
|
+
with self._lock:
|
|
507
|
+
if key not in self.objects:
|
|
508
|
+
self.objects[key] = []
|
|
509
|
+
if self.length_0:
|
|
510
|
+
self.objects[key].append(
|
|
511
|
+
Length(event, Length.evaluate_length_0)
|
|
512
|
+
),
|
|
513
|
+
if self.length_1:
|
|
514
|
+
self.objects[key].append(
|
|
515
|
+
Length(event, Length.evaluate_length_1)
|
|
516
|
+
),
|
|
517
|
+
if self.length_more:
|
|
518
|
+
self.objects[key].append(
|
|
519
|
+
Length(event, Length.evaluate_length_more)
|
|
520
|
+
)
|
|
443
521
|
return self.objects[key][:]
|
|
522
|
+
return None
|
|
444
523
|
|
|
445
524
|
|
|
446
525
|
class FunctionErrorFactory(AnalysisFactory):
|
|
@@ -448,22 +527,28 @@ class FunctionErrorFactory(AnalysisFactory):
|
|
|
448
527
|
super().__init__()
|
|
449
528
|
self.function_mapping = dict()
|
|
450
529
|
|
|
451
|
-
def get_analysis(
|
|
530
|
+
def get_analysis(
|
|
531
|
+
self, event, event_file: EventFile, scope: Scope = None
|
|
532
|
+
) -> List[AnalysisObject]:
|
|
452
533
|
if event.event_type == EventType.FUNCTION_ENTER:
|
|
453
|
-
self.
|
|
534
|
+
with self._lock:
|
|
535
|
+
self.function_mapping[event.function_id] = event.line
|
|
454
536
|
if event.event_type in (EventType.FUNCTION_ERROR, EventType.FUNCTION_EXIT):
|
|
455
|
-
|
|
537
|
+
with self._lock:
|
|
538
|
+
line = self.function_mapping.get(event.function_id, event.line)
|
|
456
539
|
key = (
|
|
457
540
|
FunctionErrorPredicate.analysis_type(),
|
|
458
541
|
event.file,
|
|
459
542
|
line,
|
|
460
543
|
event.function_id,
|
|
461
544
|
)
|
|
462
|
-
|
|
463
|
-
self.objects
|
|
464
|
-
|
|
465
|
-
|
|
545
|
+
with self._lock:
|
|
546
|
+
if key not in self.objects:
|
|
547
|
+
self.objects[key] = FunctionErrorPredicate(
|
|
548
|
+
event.file, line, event.function
|
|
549
|
+
)
|
|
466
550
|
return [self.objects[key]]
|
|
551
|
+
return None
|
|
467
552
|
|
|
468
553
|
|
|
469
554
|
analysis_factory_mapping = {
|