fix(tools): ignore wrapped declarations in pr_overlap exports

exports() only checked whether the matching line ended with a semicolon, so a
prototype wrapped over several lines was counted as an implemented export and
two PRs adding the same forward declaration were flagged as overlapping. It now
joins the following added lines up to the first semicolon or brace and treats
the match as a declaration when the semicolon comes first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
This commit is contained in:
GalaxyGamingFR 2026-10-11 12:03:50 -07:00
parent a11c8f7f70
commit 08169eae25
3 changed files with 41 additions and 2 deletions

View File

@ -63,6 +63,8 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/hw-oracle/test_hw_oracle.py)
add_test(NAME pr_overlap_exports COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_exports.py)
add_test(NAME pr_overlap_wrapped_exports COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_wrapped_exports.py)
add_test(NAME nid_database_cache COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_nid_names.py)
endif()

View File

@ -70,9 +70,18 @@ def commit(tree):
def exports(diff):
found = set()
for line in diff.splitlines():
lines = diff.splitlines()
for i, line in enumerate(lines):
m = EXPORT.match(line)
if m and not m.group(1).endswith("_nid_no_patch") and not line.rstrip().endswith(";"):
if not m or m.group(1).endswith("_nid_no_patch"):
continue
text = line[1:]
for nxt in lines[i + 1:]:
if ";" in text or "{" in text or not nxt.startswith("+") or nxt.startswith("+++"):
break
text += nxt[1:]
semi, brace = text.find(";"), text.find("{")
if semi < 0 or 0 <= brace < semi:
found.add(m.group(1))
return found

View File

@ -0,0 +1,28 @@
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import pr_overlap
DECL = "+int APS5_VABI sceFooBar(int a,\n+ int b);\n"
class WrappedExportTests(unittest.TestCase):
def test_wrapped_declaration_is_not_export(self):
self.assertEqual(pr_overlap.exports(DECL), set())
def test_wrapped_definition_is_export(self):
diff = "+int APS5_VABI sceFooBar(int a,\n+ int b) {\n+ return a + b;\n+}\n"
self.assertEqual(pr_overlap.exports(diff), {"sceFooBar"})
def test_declaration_then_definition_returns_only_definition(self):
diff = DECL + "+int APS5_VABI sceBaz(int a) { return a; }\n"
self.assertEqual(pr_overlap.exports(diff), {"sceBaz"})
def test_declaration_at_end_of_diff(self):
self.assertEqual(pr_overlap.exports("+int APS5_VABI sceFooBar(int a, int b);"), set())
if __name__ == "__main__":
unittest.main()