Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ dependencies {
implementation "net.fabricmc:mapping-io:0.7.1"

testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2'
testCompileOnly ('net.fabricmc:sponge-mixin:0.16.2+mixin.0.8.7') {
transitive = false
}
}

java {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ private Optional<TrMember> resolvePartial(TrClass owner, String name, String des

@Override
public MemberInfo result() {
// Special case to remap the desc of wildcards without a name, such as `*()Lcom/example/ClassName;`
if (info.getOwner().isEmpty()
&& info.getName().isEmpty()
&& info.getQuantifier().equals("*")
&& !info.getDesc().isEmpty()) {
return new MemberInfo(info.getOwner(), info.getName(), info.getQuantifier(), data.mapper.asTrRemapper().mapDesc(info.getDesc()));
}

if (targets.isEmpty() || info.getName().isEmpty()) {
return info;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,6 @@ private String formattedDesc() {
return ":" + desc;
}

// Wildcards match regardless of descriptor
if (getQuantifier().equals("*")) {
return "";
}

return desc;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2016, 2018, Player, asie
* Copyright (c) 2025, FabricMC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package net.fabricmc.tinyremapper.extension.mixin.integration;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;

import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.extension.mixin.MixinExtension;
import net.fabricmc.tinyremapper.extension.mixin.integration.mixins.TargetMixin;
import net.fabricmc.tinyremapper.extension.mixin.integration.targets.Target;

public class MixinIntegrationTest {
@TempDir
static Path folder;

@Test
public void remapWildcardName() throws IOException {
Path classpath = createJar(Target.class);
Path input = createJar(TargetMixin.class);
Path output = folder.resolve("output.jar");

TinyRemapper tinyRemapper = TinyRemapper.newRemapper()
.extension(new MixinExtension())
.withMappings(out -> out.acceptClass("java/lang/String", "com/example/NotString"))
.build();

try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) {
tinyRemapper.readClassPath(classpath);
tinyRemapper.readInputs(input);

tinyRemapper.apply(outputConsumer);
}

String remapped = textify(output, TargetMixin.class);
// Check constructor inject did not gain a desc
assertTrue(remapped.contains("@Lorg/spongepowered/asm/mixin/injection/Inject;(method={\"<init>*\"}"));
// Check that wildcard desc is remapped without a name
assertTrue(remapped.contains("@Lorg/spongepowered/asm/mixin/injection/Inject;(method={\"*()Lcom/example/NotString;\"}"));
}

// Create a zip file in the temp dir containing only the passed class file.
private Path createJar(Class<?> clazz) throws IOException {
String classFileName = clazz.getName().replace('.', '/') + ".class";
Path jarFile = folder.resolve(clazz.getSimpleName() + ".jar");

try (JarOutputStream jarOut = new JarOutputStream(Files.newOutputStream(jarFile))) {
jarOut.putNextEntry(new JarEntry(classFileName));

try (InputStream classIn = clazz.getResourceAsStream('/' + classFileName)) {
byte[] buffer = new byte[8192];
int bytesRead;

while ((bytesRead = classIn.read(buffer)) != -1) {
jarOut.write(buffer, 0, bytesRead);
}
}

jarOut.closeEntry();
}

return jarFile;
}

public static String textify(Path zipPath, Class<?> clazz) throws IOException {
String classFileName = clazz.getName().replace('.', '/') + ".class";

try (ZipFile zipFile = new ZipFile(zipPath.toFile())) {
ZipEntry entry = zipFile.getEntry(classFileName);

try (InputStream inputStream = zipFile.getInputStream(entry)) {
ClassReader classReader = new ClassReader(inputStream);
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, new Textifier(), printWriter);

classReader.accept(traceClassVisitor, 0);
return stringWriter.toString();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2016, 2018, Player, asie
* Copyright (c) 2025, FabricMC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package net.fabricmc.tinyremapper.extension.mixin.integration.mixins;

import java.lang.annotation.Target;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(Target.class)
public abstract class TargetMixin {
@Inject(method = "<init>*", at = @At(value = "RETURN"))
private void constructorHook(final CallbackInfo ci) {
}

@Inject(method = "*()Ljava/lang/String;", at = @At("HEAD"), cancellable = true)
private void injectName(CallbackInfoReturnable<String> ci) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 2018, Player, asie
* Copyright (c) 2025, FabricMC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package net.fabricmc.tinyremapper.extension.mixin.integration.targets;

public class Target {
public Target(String name) {
}

public String getName() {
return "";
}

public String getRealName() {
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ void parse() {
assertEquals(info.getName(), "<init>");
assertEquals(info.getQuantifier(), "*");
assertEquals(info.getDesc(), "()V");
assertEquals(info.toString(), "<init>*()V");

// https://github.com/FabricMC/tiny-remapper/issues/137
info = MemberInfo.parse("<init>*");
assertNotNull(info);
assertNull(info.getType());
assertEquals(info.getOwner(), "");
assertEquals(info.getName(), "<init>");
assertEquals(info.getQuantifier(), "*");
assertEquals(info.getDesc(), "");
assertEquals(info.toString(), "<init>*");

info = MemberInfo.parse("*()Lcom/example/ExampleClass;");
assertNotNull(info);
assertEquals(info.getType(), MemberType.METHOD);
assertEquals(info.getOwner(), "");
assertEquals(info.getName(), "");
assertEquals(info.getQuantifier(), "*");
assertEquals(info.getDesc(), "()Lcom/example/ExampleClass;");
assertEquals(info.toString(), "*()Lcom/example/ExampleClass;");
}
}