From 4dd7ce65b50c60867a1510720665847d5592489e Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Sun, 2 Nov 2025 09:44:29 +0100 Subject: [PATCH] Add `RedundantDstDataFilter` --- CHANGELOG.md | 3 +- .../adapter/RedundantDstDataFilter.java | 105 +++++++++++++++++ .../filtering/RedundantDstDataFilterTest.java | 107 ++++++++++++++++++ 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/fabricmc/mappingio/adapter/RedundantDstDataFilter.java create mode 100644 src/test/java/net/fabricmc/mappingio/test/tests/filtering/RedundantDstDataFilterTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ca232d43..ef16420d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -- Added `EmptyElementFilter`, an adapter which filters out out elements that effectively don't contain any data +- Added `EmptyElementFilter`, an adapter which filters out elements that effectively don't contain any data +- Added `RedundantDstDataFilter`, an adapter which nulls out destination names and descriptors that are equal to their source counterparts - Added a simplified `MappingNsCompleter` constructor for completing all destination names with the source names - Added `MappingTree#propagateOuterClassNames` as a more efficient tree-API alternative to `OuterClassNamePropagator` - Promoted previously internal `NopMappingVisitor`, `VisitOrderVerifier` and `SubsetChecker` to experimental API diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RedundantDstDataFilter.java b/src/main/java/net/fabricmc/mappingio/adapter/RedundantDstDataFilter.java new file mode 100644 index 00000000..562cffe7 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/adapter/RedundantDstDataFilter.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio.adapter; + +import java.io.IOException; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingVisitor; + +/** + * A mapping visitor that nulls out destination names and descriptors that are equal to their source counterparts. + * + * @apiNote Extending this class is allowed, but no guarantees are made regarding the stability of its protected members. + */ +public class RedundantDstDataFilter extends ForwardingMappingVisitor { + public RedundantDstDataFilter(MappingVisitor next) { + super(next); + } + + protected void init() { + srcName = null; + srcDesc = null; + } + + @Override + public void reset() { + init(); + super.reset(); + } + + @Override + public boolean visitClass(String srcName) throws IOException { + this.srcName = srcName; + return super.visitClass(srcName); + } + + @Override + public boolean visitField(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + return super.visitField(srcName, srcDesc); + } + + @Override + public boolean visitMethod(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + return super.visitMethod(srcName, srcDesc); + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, @Nullable String srcName) throws IOException { + this.srcName = srcName; + return super.visitMethodArg(argPosition, lvIndex, srcName); + } + + @Override + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName) throws IOException { + this.srcName = srcName; + return super.visitMethodVar(lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcName); + } + + @Override + public void visitDstName(MappedElementKind targetKind, int namespace, String name) throws IOException { + if (name != null && name.equals(srcName)) { + name = null; + } + + super.visitDstName(targetKind, namespace, name); + } + + @Override + public void visitDstDesc(MappedElementKind targetKind, int namespace, String desc) throws IOException { + if (desc != null && desc.equals(srcDesc)) { + desc = null; + } + + super.visitDstDesc(targetKind, namespace, desc); + } + + @Override + public boolean visitEnd() throws IOException { + init(); + return super.visitEnd(); + } + + protected String srcName; + protected String srcDesc; +} diff --git a/src/test/java/net/fabricmc/mappingio/test/tests/filtering/RedundantDstDataFilterTest.java b/src/test/java/net/fabricmc/mappingio/test/tests/filtering/RedundantDstDataFilterTest.java new file mode 100644 index 00000000..326b7b65 --- /dev/null +++ b/src/test/java/net/fabricmc/mappingio/test/tests/filtering/RedundantDstDataFilterTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio.test.tests.filtering; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.io.IOException; +import java.nio.file.Files; + +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.Test; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.adapter.NopMappingVisitor; +import net.fabricmc.mappingio.adapter.RedundantDstDataFilter; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.test.TestMappings; +import net.fabricmc.mappingio.test.TestMappings.MappingDir; + +public class RedundantDstDataFilterTest { + @Test + public void run() { + for (MappingDir dir : TestMappings.values()) { + for (MappingFormat format : MappingFormat.values()) { + assertDoesNotThrow(() -> check(dir, format), "Failed for " + dir + " with " + format); + } + } + } + + private void check(MappingDir dir, MappingFormat format) throws Exception { + if (!Files.exists(dir.pathFor(format))) { + return; + } + + dir.read(format, new RedundantDstDataFilter(new NoRedundantDstDataAsserter())); + } + + private static class NoRedundantDstDataAsserter extends NopMappingVisitor { + private NoRedundantDstDataAsserter() { + super(true); + } + + @Override + public boolean visitClass(String srcName) throws IOException { + this.srcName = srcName; + return super.visitClass(srcName); + } + + @Override + public boolean visitField(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + return super.visitField(srcName, srcDesc); + } + + @Override + public boolean visitMethod(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + return super.visitMethod(srcName, srcDesc); + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, @Nullable String srcName) throws IOException { + this.srcName = srcName; + return super.visitMethodArg(argPosition, lvIndex, srcName); + } + + @Override + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName) throws IOException { + this.srcName = srcName; + return super.visitMethodVar(lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcName); + } + + @Override + public void visitDstName(MappedElementKind targetKind, int namespace, String name) { + assertNotEquals(srcName, name, "Redundant destination name for " + targetKind + " in destination namespace " + namespace + " (" + srcName + " -> " + name + ")"); + } + + @Override + public void visitDstDesc(MappedElementKind targetKind, int namespace, String desc) { + if (srcDesc == null) { + return; + } + + assertNotEquals(srcDesc, desc, "Redundant destination descriptor for " + targetKind + " in destination namespace " + namespace + " (" + srcDesc + " -> " + desc + ")"); + } + + private String srcName; + private String srcDesc; + } +}