|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import itertools |
4 | | -from abc import abstractmethod |
5 | 4 | from dataclasses import dataclass, field |
6 | 5 | from pathlib import Path |
7 | 6 | from typing import TYPE_CHECKING, Any, ClassVar, Sequence, Type |
@@ -39,23 +38,30 @@ class Location(ABCDataclass): |
39 | 38 | @dataclass(frozen=True) |
40 | 39 | class SarifLocation(Location): |
41 | 40 | @staticmethod |
42 | | - @abstractmethod |
43 | | - def get_snippet(sarif_location) -> str: |
44 | | - pass |
| 41 | + def get_snippet(sarif_location: LocationModel) -> str | None: |
| 42 | + return sarif_location.message.text if sarif_location.message else None |
45 | 43 |
|
46 | 44 | @classmethod |
47 | 45 | def from_sarif(cls, sarif_location: LocationModel) -> Self: |
48 | | - artifact_location = sarif_location["physicalLocation"]["artifactLocation"] |
49 | | - file = Path(artifact_location["uri"]) |
| 46 | + if not (physical_location := sarif_location.physical_location): |
| 47 | + raise ValueError("Sarif location does not have a physical location") |
| 48 | + if not (artifact_location := physical_location.artifact_location): |
| 49 | + raise ValueError("Sarif location does not have an artifact location") |
| 50 | + if not (region := physical_location.region): |
| 51 | + raise ValueError("Sarif location does not have a region") |
| 52 | + if not (uri := artifact_location.uri): |
| 53 | + raise ValueError("Sarif location does not have a uri") |
| 54 | + |
| 55 | + file = Path(uri) |
50 | 56 | snippet = cls.get_snippet(sarif_location) |
51 | 57 | start = LineInfo( |
52 | | - line=sarif_location["physicalLocation"]["region"]["startLine"], |
53 | | - column=sarif_location["physicalLocation"]["region"]["startColumn"], |
| 58 | + line=region.start_line or -1, |
| 59 | + column=region.start_column or -1, |
54 | 60 | snippet=snippet, |
55 | 61 | ) |
56 | 62 | end = LineInfo( |
57 | | - line=sarif_location["physicalLocation"]["region"]["endLine"], |
58 | | - column=sarif_location["physicalLocation"]["region"]["endColumn"], |
| 63 | + line=region.end_line or -1, |
| 64 | + column=region.end_column or -1, |
59 | 65 | snippet=snippet, |
60 | 66 | ) |
61 | 67 | return cls(file=file, start=start, end=end) |
@@ -150,14 +156,17 @@ def extract_locations(cls, sarif_result: ResultModel) -> Sequence[Location]: |
150 | 156 | ) |
151 | 157 |
|
152 | 158 | @classmethod |
153 | | - def extract_related_locations(cls, sarif_result) -> Sequence[LocationWithMessage]: |
| 159 | + def extract_related_locations( |
| 160 | + cls, sarif_result: ResultModel |
| 161 | + ) -> Sequence[LocationWithMessage]: |
154 | 162 | return tuple( |
155 | 163 | [ |
156 | 164 | LocationWithMessage( |
157 | | - message=rel_location.get("message", {}).get("text", ""), |
| 165 | + message=rel_location.message.text, |
158 | 166 | location=cls.location_type.from_sarif(rel_location), |
159 | 167 | ) |
160 | | - for rel_location in sarif_result.get("relatedLocations", []) |
| 168 | + for rel_location in sarif_result.related_locations or [] |
| 169 | + if rel_location.message |
161 | 170 | ] |
162 | 171 | ) |
163 | 172 |
|
@@ -187,7 +196,12 @@ def extract_rule_id( |
187 | 196 | return rule_id.split(".")[-1] if truncate_rule_id else rule_id |
188 | 197 |
|
189 | 198 | # it may be contained in the 'rule' field through the tool component in the sarif file |
190 | | - if (rule := result.rule) and sarif_run.tool.extensions and rule.tool_component: |
| 199 | + if ( |
| 200 | + (rule := result.rule) |
| 201 | + and sarif_run.tool.extensions |
| 202 | + and rule.tool_component |
| 203 | + and rule.tool_component.index is not None |
| 204 | + ): |
191 | 205 | tool_index = rule.tool_component.index |
192 | 206 | rule_index = rule.index |
193 | 207 | return sarif_run.tool.extensions[tool_index].rules[rule_index].id |
|
0 commit comments