Skip to content

Commit 6097a30

Browse files
authored
Add generic type bounds for ResultSet (#1039)
* Add generic type bounds for ResultSet * Make top-level SARIF run data available to location parser
1 parent 2c50d4d commit 6097a30

File tree

2 files changed

+29
-18
lines changed

2 files changed

+29
-18
lines changed

src/codemodder/codeql.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def detect(cls, run_data: Run) -> bool:
1717

1818
class CodeQLLocation(SarifLocation):
1919
@classmethod
20-
def from_sarif(cls, sarif_location: LocationModel) -> Self:
20+
def from_sarif(cls, run: Run, sarif_location: LocationModel) -> Self:
21+
del run
2122
if (physical_location := sarif_location.physical_location) is None:
2223
raise ValueError("Location does not contain a physicalLocation")
2324
if (artifact_location := physical_location.artifact_location) is None:

src/codemodder/result.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import itertools
44
from dataclasses import dataclass, field
55
from pathlib import Path
6-
from typing import TYPE_CHECKING, Any, ClassVar, Sequence, Type
6+
from typing import TYPE_CHECKING, Any, ClassVar, Sequence, Type, TypeVar
77

88
import libcst as cst
99
from boltons.setutils import IndexedSet
@@ -41,8 +41,13 @@ class SarifLocation(Location):
4141
def get_snippet(sarif_location: LocationModel) -> str | None:
4242
return sarif_location.message.text if sarif_location.message else None
4343

44+
@staticmethod
45+
def process_uri(run: Run, sarif_location: LocationModel, uri: str) -> Path:
46+
del sarif_location
47+
return Path(uri)
48+
4449
@classmethod
45-
def from_sarif(cls, sarif_location: LocationModel) -> Self:
50+
def from_sarif(cls, run: Run, sarif_location: LocationModel) -> Self:
4651
if not (physical_location := sarif_location.physical_location):
4752
raise ValueError("Sarif location does not have a physical location")
4853
if not (artifact_location := physical_location.artifact_location):
@@ -52,7 +57,7 @@ def from_sarif(cls, sarif_location: LocationModel) -> Self:
5257
if not (uri := artifact_location.uri):
5358
raise ValueError("Sarif location does not have a uri")
5459

55-
file = Path(uri)
60+
file = cls.process_uri(run, sarif_location, uri)
5661
snippet = cls.get_snippet(sarif_location)
5762
start = LineInfo(
5863
line=region.start_line or -1,
@@ -117,9 +122,9 @@ def from_sarif(
117122
finding_id = cls.extract_finding_id(sarif_result) or rule_id
118123
return cls(
119124
rule_id=rule_id,
120-
locations=cls.extract_locations(sarif_result),
121-
codeflows=cls.extract_code_flows(sarif_result),
122-
related_locations=cls.extract_related_locations(sarif_result),
125+
locations=cls.extract_locations(sarif_result, sarif_run),
126+
codeflows=cls.extract_code_flows(sarif_result, sarif_run),
127+
related_locations=cls.extract_related_locations(sarif_result, sarif_run),
123128
finding_id=finding_id,
124129
finding=Finding(
125130
id=finding_id,
@@ -147,23 +152,25 @@ def rule_url_from_id(
147152
return None
148153

149154
@classmethod
150-
def extract_locations(cls, sarif_result: ResultModel) -> Sequence[Location]:
155+
def extract_locations(
156+
cls, sarif_result: ResultModel, run: Run
157+
) -> Sequence[Location]:
151158
return tuple(
152159
[
153-
cls.location_type.from_sarif(location)
160+
cls.location_type.from_sarif(run, location)
154161
for location in sarif_result.locations or []
155162
]
156163
)
157164

158165
@classmethod
159166
def extract_related_locations(
160-
cls, sarif_result: ResultModel
167+
cls, sarif_result: ResultModel, run: Run
161168
) -> Sequence[LocationWithMessage]:
162169
return tuple(
163170
[
164171
LocationWithMessage(
165172
message=rel_location.message.text,
166-
location=cls.location_type.from_sarif(rel_location),
173+
location=cls.location_type.from_sarif(run, rel_location),
167174
)
168175
for rel_location in sarif_result.related_locations or []
169176
if rel_location.message
@@ -172,13 +179,13 @@ def extract_related_locations(
172179

173180
@classmethod
174181
def extract_code_flows(
175-
cls, sarif_result: ResultModel
182+
cls, sarif_result: ResultModel, run: Run
176183
) -> Sequence[Sequence[Location]]:
177184
return tuple(
178185
[
179186
tuple(
180187
[
181-
cls.location_type.from_sarif(locations.location)
188+
cls.location_type.from_sarif(run, locations.location)
182189
for locations in threadflow.locations or []
183190
if locations.location
184191
]
@@ -225,8 +232,11 @@ def fuzzy_column_match(pos: CodeRange, location: Location) -> bool:
225232
)
226233

227234

228-
class ResultSet(dict[str, dict[Path, list[Result]]]):
229-
results_for_rule: dict[str, list[Result]]
235+
ResultType = TypeVar("ResultType", bound=Result)
236+
237+
238+
class ResultSet(dict[str, dict[Path, list[ResultType]]]):
239+
results_for_rule: dict[str, list[ResultType]]
230240
# stores SARIF runs.tool data
231241
tools: list[dict[str, dict]]
232242

@@ -235,7 +245,7 @@ def __init__(self, *args, **kwargs):
235245
self.results_for_rule = {}
236246
self.tools = []
237247

238-
def add_result(self, result: Result):
248+
def add_result(self, result: ResultType):
239249
self.results_for_rule.setdefault(result.rule_id, []).append(result)
240250
for loc in result.locations:
241251
self.setdefault(result.rule_id, {}).setdefault(loc.file, []).append(result)
@@ -246,7 +256,7 @@ def store_tool_data(self, tool_data: dict):
246256

247257
def results_for_rule_and_file(
248258
self, context: CodemodExecutionContext, rule_id: str, file: Path
249-
) -> list[Result]:
259+
) -> list[ResultType]:
250260
"""
251261
Return list of results for a given rule and file.
252262
@@ -258,7 +268,7 @@ def results_for_rule_and_file(
258268
"""
259269
return self.get(rule_id, {}).get(file.relative_to(context.directory), [])
260270

261-
def results_for_rules(self, rule_ids: list[str]) -> list[Result]:
271+
def results_for_rules(self, rule_ids: list[str]) -> list[ResultType]:
262272
"""
263273
Returns flat list of all results that match any of the given rule IDs.
264274
"""

0 commit comments

Comments
 (0)