33import itertools
44from dataclasses import dataclass , field
55from 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
88import libcst as cst
99from 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