From db7666b22c14e8fc140f3e00340411d600075304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C5=A0l=C3=A9gl?= Date: Thu, 8 Oct 2026 19:59:25 +0200 Subject: [PATCH] fix(tools): count only definitions as exports in the overlap report pr_overlap.py took every added line with APS5_VABI before a name and a parenthesis as an export, so a declaration such as extern "C" int* APS5_VABI __error_nid_postfix(); made each pull request that adds it "implement the same function" as all the others. A line that ends in a semicolon is a declaration and is skipped; every definition's first line in the tree ends in a brace, a parenthesis or a comma. Registers pr_overlap_exports. Co-Authored-By: Claude Fable 5.1 --- CMakeLists.txt | 2 ++ tools/pr_overlap.py | 12 +++++-- tools/tests/test_pr_overlap_exports.py | 44 ++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tools/tests/test_pr_overlap_exports.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c6923e7e..30d3dc8f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,8 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_import_audit.py) add_test(NAME hardware_oracle COMMAND ${Python3_EXECUTABLE} ${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) endif() endif() diff --git a/tools/pr_overlap.py b/tools/pr_overlap.py index db2bbaa90..fd87ccb25 100644 --- a/tools/pr_overlap.py +++ b/tools/pr_overlap.py @@ -58,6 +58,15 @@ def commit(tree): "-p", "refs/pr/base", "-m", "pr_overlap").strip() +def exports(diff): + found = set() + for line in diff.splitlines(): + m = EXPORT.match(line) + if m and not m.group(1).endswith("_nid_no_patch") and not line.rstrip().endswith(";"): + found.add(m.group(1)) + return found + + def scan(pr): tree, conflicted = merge("refs/pr/base", pr["ref"]) pr["tree"] = None if conflicted else commit(tree) @@ -69,8 +78,7 @@ def scan(pr): if status == "A": pr["added"].add(path) diff = git("diff", "-U0", "--no-color", old, new, "--", "core/libs/prx/*.cpp") - pr["exports"] = {m.group(1) for m in map(EXPORT.match, diff.splitlines()) - if m and not m.group(1).endswith("_nid_no_patch")} + pr["exports"] = exports(diff) def hunks(pr, path): diff --git a/tools/tests/test_pr_overlap_exports.py b/tools/tests/test_pr_overlap_exports.py new file mode 100644 index 000000000..eb2e18db2 --- /dev/null +++ b/tools/tests/test_pr_overlap_exports.py @@ -0,0 +1,44 @@ +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) +import pr_overlap + +TRAILING = "+extern \"C\" std::int64_t APS5_VABI recv_nid_postfix(int, void*, std::uint64_t, int) noexcept; \n" +DIFF = """diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp +@@ -96,0 +97,2 @@ ++extern "C" int* APS5_VABI __error_nid_postfix(); +""" + TRAILING + """@@ -135,0 +136,5 @@ ++int APS5_VABI mlock_nid_postfix(const void* address, std::size_t length) { ++std::int64_t APS5_VABI sceKernelRead(int d, void* buf, std::size_t nbytes) noexcept { ++int APS5_VABI getpid_nid_postfix() { return 1; } ++int APS5_VABI sceNpUniversalDataSystemCreateEvent( ++void APS5_VABI Helper_nid_no_patch(int value) { +@@ -200 +205,0 @@ +-int APS5_VABI removed_nid_postfix(int) { +diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp +@@ -10,2 +10,2 @@ + int APS5_VABI context_nid_postfix(int) { +""" + + +class ExportTests(unittest.TestCase): + def test_added_definitions_are_exports(self): + self.assertEqual(pr_overlap.exports(DIFF), {"mlock_nid_postfix", "sceKernelRead", "getpid_nid_postfix", "sceNpUniversalDataSystemCreateEvent"}) + + def test_declarations_are_not_exports(self): + self.assertTrue(TRAILING.endswith("; \n")) + found = pr_overlap.exports(DIFF) + self.assertNotIn("__error_nid_postfix", found) + self.assertNotIn("recv_nid_postfix", found) + + def test_removed_context_and_helper_lines_are_not_exports(self): + found = pr_overlap.exports(DIFF) + self.assertNotIn("removed_nid_postfix", found) + self.assertNotIn("context_nid_postfix", found) + self.assertNotIn("Helper_nid_no_patch", found) + + +if __name__ == "__main__": + unittest.main()