Skip to content

Commit

Permalink
Update result location matching; enable customizable logic
Browse files Browse the repository at this point in the history
  • Loading branch information
drdavella committed Feb 29, 2024
1 parent 2b03399 commit 421cfbe
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 12 deletions.
4 changes: 3 additions & 1 deletion src/codemodder/codemods/base_codemod.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def _process_file(
findings_for_rule = []
for rule in rules:
findings_for_rule.extend(
results.results_for_rule_and_file(rule, filename)
results.results_for_rule_and_file(context, rule, filename)
)

file_context = FileContext(
Expand All @@ -199,6 +199,8 @@ def _process_file(
findings_for_rule,
)

# TODO: for SAST tools we should preemtively filter out files that are not part of the result set

if change_set := self.transformer.apply(
context, file_context, findings_for_rule
):
Expand Down
45 changes: 34 additions & 11 deletions src/codemodder/result.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from typing import Any, TYPE_CHECKING

import libcst as cst
from libcst._position import CodeRange

from .utils.abc_dataclass import ABCDataclass

if TYPE_CHECKING:
from codemodder.context import CodemodExecutionContext


@dataclass
class LineInfo:
Expand All @@ -24,24 +31,40 @@ class Result(ABCDataclass):
rule_id: str
locations: list[Location]

def match_location(self, pos, node):
for location in self.locations:
start_column = location.start.column
end_column = location.end.column
return (
pos.start.line == location.start.line
and (pos.start.column in (start_column - 1, start_column))
and pos.end.line == location.end.line
and (pos.end.column in (end_column - 1, end_column))
def match_location(self, pos: CodeRange, node: cst.CSTNode) -> bool:
del node
return any(
pos.start.line == location.start.line
and (
pos.start.column
in ((start_column := location.start.column) - 1, start_column)
)
and pos.end.line == location.end.line
and (
pos.end.column in ((end_column := location.end.column) - 1, end_column)
)
for location in self.locations
)


class ResultSet(dict[str, dict[Path, list[Result]]]):
def add_result(self, result: Result):
for loc in result.locations:
self.setdefault(result.rule_id, {}).setdefault(loc.file, []).append(result)

def results_for_rule_and_file(self, rule_id: str, file: Path) -> list[Result]:
def results_for_rule_and_file(
self, context: CodemodExecutionContext, rule_id: str, file: Path
) -> list[Result]:
"""
Return list of results for a given rule and file.
:param context: The codemod execution context
:param rule_id: The rule ID
:param file: The filename
Some implementers may need to use the context to compute paths that are relative to the target directory.
"""
del context
return self.get(rule_id, {}).get(file, [])

def files_for_rule(self, rule_id: str) -> list[Path]:
Expand Down

0 comments on commit 421cfbe

Please sign in to comment.