Skip to content

Commit 1555040

Browse files
committed
Update the code to difflib instead of unidiff library
Signed-off-by: ziad hany <ziadhany2016@gmail.com>
1 parent 19d3425 commit 1555040

9 files changed

Lines changed: 146 additions & 920 deletions

File tree

scanpipe/pipes/reachability.py

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
2121
# Visit https://github.com/aboutcode-org/scancode.io for support and download.
2222
#
23-
23+
import difflib
2424
import os
2525
import shutil
2626
import tempfile
@@ -36,7 +36,6 @@
3636
from scanpipe.pipes.symbols import SymbolExtractor
3737
from scanpipe.pipes.symbols import create_sha256_fingerprint
3838
from scanpipe.pipes.symbols import is_supported_language
39-
from scanpipe.pipes.unidiff.patch import PatchSet
4039

4140

4241
class ReachabilityStatus(str, Enum):
@@ -149,6 +148,26 @@ def get_commit_diff_text(self):
149148
base = self.parent_commit.hexsha if self.parent_commit else NULL_TREE
150149
return self.repo.git.diff(base, self.commit.hexsha, unified=3)
151150

151+
@classmethod
152+
def compute_changed_lines(cls, vulnerable_text, fixed_text):
153+
"""Return the removed and added line numbers between two file contents."""
154+
matcher = difflib.SequenceMatcher(
155+
a=vulnerable_text.splitlines(),
156+
b=fixed_text.splitlines(),
157+
autojunk=False, # otherwise difflib ignores lines that repeat often
158+
)
159+
160+
removed_lines = []
161+
added_lines = []
162+
for tag, vuln_start, vuln_end, fixed_start, fixed_end in matcher.get_opcodes():
163+
if tag == "equal":
164+
continue
165+
# opcodes are 0-based and end-exclusive, line numbers are 1-based
166+
removed_lines.extend(range(vuln_start + 1, vuln_end + 1))
167+
added_lines.extend(range(fixed_start + 1, fixed_end + 1))
168+
169+
return removed_lines, added_lines
170+
152171
@classmethod
153172
def diff_changed_symbols(cls, vuln_meta, fixed_meta):
154173
vuln_only = {
@@ -163,50 +182,16 @@ def diff_changed_symbols(cls, vuln_meta, fixed_meta):
163182
}
164183
return vuln_only, fixed_only
165184

166-
@classmethod
167-
def parse_diff_lines(cls, diff_text):
168-
diff_map = {}
169-
if not diff_text:
170-
return diff_map
171-
172-
for patched_file in PatchSet.from_string(diff_text):
173-
removed = []
174-
added = []
175-
176-
for hunk in patched_file:
177-
removed.extend(
178-
line.source_line_no
179-
for line in hunk
180-
if line.is_removed and line.source_line_no
181-
)
182-
added.extend(
183-
line.target_line_no
184-
for line in hunk
185-
if line.is_added and line.target_line_no
186-
)
187-
188-
candidates = {
189-
patched_file.path,
190-
(patched_file.source_file or "").removeprefix("a/"),
191-
(patched_file.target_file or "").removeprefix("b/"),
192-
}
193-
194-
for candidate in candidates:
195-
if candidate:
196-
diff_map[candidate] = (removed, added)
197-
198-
return diff_map
199-
200185
def collect_patch_symbols(self):
201-
diff_text = self.get_commit_diff_text()
186+
by_language = {}
202187
changed_files = self.get_changed_files()
203-
diff_line_map = self.parse_diff_lines(diff_text=diff_text)
204188

205-
by_language = {}
206189
for file_path, texts in changed_files.items():
207190
vulnerable_text = texts["vulnerable_text"]
208191
fixed_text = texts["fixed_text"]
209-
removed_lines, added_lines = diff_line_map.get(file_path, ([], []))
192+
removed_lines, added_lines = self.compute_changed_lines(
193+
vulnerable_text, fixed_text
194+
)
210195

211196
vuln_meta, fixed_meta, language = self.analyze(
212197
vulnerable_text=vulnerable_text,
@@ -504,11 +489,9 @@ def build_index(self) -> dict | None:
504489
)
505490

506491
for node, _ in lang_query.get_constants(tree.root_node):
507-
# Skip constants defined inside functions, classes, or other blocks
508-
if node.parent == tree.root_node:
509-
self.process_node(
510-
node, extractor, definitions_index, definitions, fingerprints
511-
)
492+
self.process_node(
493+
node, extractor, definitions_index, definitions, fingerprints
494+
)
512495

513496
return {
514497
"definitions": definitions,

0 commit comments

Comments
 (0)