"""This module contains domain models regrading found issues."""
from typing import Any, Dict, List, Optional, Tuple, Union
from enum import Enum
from pydantic import BaseModel, Field
try:
from typing_extensions import Literal
except ImportError:
from typing import Literal
Severity = Union[
Literal["Unknown"],
Literal["None"],
Literal["Low"],
Literal["Medium"],
Literal["High"],
]
[docs]class SEVERITY(str, Enum):
"""An Enum holding the possible severities an issue can have."""
UNKNOWN = "Unknown"
NONE = "None"
LOW = "Low"
MEDIUM = "Medium"
HIGH = "High"
SourceType = Union[
Literal["raw-bytecode"],
Literal["ethereum-address"],
Literal["solidity-contract"],
Literal["solidity-file"],
]
SourceFormat = Union[
Literal["text"],
Literal["solc-ast-legacy-json"],
Literal["solc-ast-compact-json"],
Literal["evm-byzantium-bytecode"],
Literal["ewasm-raw"],
]
[docs]class SourceMapLocation(BaseModel):
offset: int = Field(ge=0)
length: int = Field(ge=0)
file_id: int = Field(ge=-1)
jump_type: Literal["o", "i", "-"]
[docs]class SourceMap(BaseModel):
raw: str
@property
def components(self):
return self.decompress(self.raw)
[docs] @staticmethod
def sourcemap_reducer(
accumulator: Tuple[int, int, int, str], component: str
) -> List[str]:
parts = component.split(":")
full = []
for i in range(4):
part_exists = i < len(parts) and parts[i]
part = parts[i] if part_exists else accumulator[i]
full.append(part)
return full
[docs] @staticmethod
def decompress(source_map: str) -> List[SourceMapLocation]:
components = source_map.split(";")
accumulator = (-1, -1, -2, "")
result = []
for val in components:
curr = SourceMap.sourcemap_reducer(accumulator, val)
accumulator = curr
result.append(curr)
return [
SourceMapLocation(
offset=c[0] if c[0] else 0,
length=c[1] if c[1] else 0,
file_id=c[2] if c[2] else -1,
jump_type=c[3] if c[3] else "-",
)
for c in result
]
[docs]class LineLocation(BaseModel):
line: int
column: int
[docs]class SourceLocation(BaseModel):
source_map: str = Field(alias="sourceMap")
source_type: Optional[str] = Field(alias="sourceType")
source_format: Optional[str] = Field(alias="sourceFormat")
source_list: Optional[List[str]] = Field(alias="sourceList")
[docs] class Config:
allow_population_by_field_name = True
[docs]class IssueDescription(BaseModel):
head: str
tail: str
[docs]class Issue(BaseModel):
uuid: Optional[str]
swc_id: str = Field(alias="swcID")
swc_title: str = Field(alias="swcTitle")
description: IssueDescription
severity: Severity
locations: List[SourceLocation]
extra: Dict[str, Any]
decoded_locations: Optional[List[Union[Tuple[LineLocation, LineLocation, bool], List]]] = Field(
alias="decodedLocations"
)
[docs] class Config:
allow_population_by_field_name = True
use_enum_values = True