Direct port to class tweaker (#1398)

* Direct port to class tweaker

* Debugging help

* Checkstyle

* Update CT
This commit is contained in:
modmuss
2025-10-24 18:06:26 +01:00
committed by GitHub
parent c08bfbe5be
commit e076ac7bcf
13 changed files with 159 additions and 156 deletions

View File

@@ -103,7 +103,7 @@ dependencies {
// tinyfile management
implementation libs.fabric.tiny.remapper
implementation libs.fabric.access.widener
implementation libs.fabric.clazz.tweaker
implementation libs.fabric.mapping.io
implementation (libs.fabric.lorenz.tiny) {
transitive = false

View File

@@ -5,7 +5,7 @@ gson = "2.10.1"
stitch = "0.6.2"
tiny-remapper = "0.12.0"
access-widener = "2.1.0"
clazz-tweaker = "0.1.1"
mapping-io = "0.7.1"
lorenz-tiny = "4.0.2"
mercury = "0.4.2"
@@ -30,7 +30,7 @@ gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
fabric-stitch = { module = "net.fabricmc:stitch", version.ref = "stitch" }
fabric-tiny-remapper = { module = "net.fabricmc:tiny-remapper", version.ref = "tiny-remapper" }
fabric-access-widener = { module = "net.fabricmc:access-widener", version.ref = "access-widener" }
fabric-clazz-tweaker = { module = "net.fabricmc:class-tweaker", version.ref = "clazz-tweaker" }
fabric-mapping-io = { module = "net.fabricmc:mapping-io", version.ref = "mapping-io" }
fabric-lorenz-tiny = { module = "net.fabricmc:lorenz-tiny", version.ref = "lorenz-tiny" }
fabric-mercury = { module = "net.fabricmc:mercury", version.ref = "mercury" }

View File

@@ -28,7 +28,7 @@ import java.io.IOException;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.classtweaker.api.visitor.ClassTweakerVisitor;
import net.fabricmc.loom.util.LazyCloseable;
import net.fabricmc.loom.util.fmj.ModEnvironment;
import net.fabricmc.tinyremapper.TinyRemapper;
@@ -44,5 +44,5 @@ public interface AccessWidenerEntry {
String getSortKey();
void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException;
void read(ClassTweakerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException;
}

View File

@@ -38,7 +38,7 @@ import javax.inject.Inject;
import org.gradle.api.file.RegularFileProperty;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.classtweaker.api.ClassTweaker;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
import net.fabricmc.loom.api.processor.ProcessorContext;
@@ -131,7 +131,7 @@ public class AccessWidenerJarProcessor implements MinecraftJarProcessor<AccessWi
public void processJar(Path jar, AccessWidenerJarProcessor.Spec spec, ProcessorContext context) throws IOException {
final List<AccessWidenerEntry> accessWideners = spec.accessWidenersForContext(context);
final var accessWidener = new AccessWidener();
final var accessWidener = ClassTweaker.newInstance();
try (LazyCloseable<TinyRemapper> remapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) {
for (AccessWidenerEntry widener : accessWideners) {

View File

@@ -37,8 +37,7 @@ import org.objectweb.asm.ClassWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerClassVisitor;
import net.fabricmc.classtweaker.api.ClassTweaker;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.Pair;
import net.fabricmc.loom.util.ZipUtils;
@@ -46,9 +45,9 @@ import net.fabricmc.loom.util.ZipUtils;
final class AccessWidenerTransformer {
private static final Logger LOGGER = LoggerFactory.getLogger(AccessWidenerTransformer.class);
private final AccessWidener accessWidener;
private final ClassTweaker accessWidener;
AccessWidenerTransformer(AccessWidener accessWidener) {
AccessWidenerTransformer(ClassTweaker accessWidener) {
this.accessWidener = accessWidener;
}
@@ -57,7 +56,14 @@ final class AccessWidenerTransformer {
*/
void apply(Path jarFile) {
try {
ZipUtils.transform(jarFile, getTransformers(accessWidener.getTargets()));
Set<String> targets = accessWidener.getTargets();
int transformed = ZipUtils.transform(jarFile, getTransformers(targets));
LOGGER.debug("Applied access wideners to {} classes in {}", transformed, jarFile);
if (targets.size() != transformed) {
LOGGER.debug("Access widener target count ({}) does not match transformed class count ({}).", targets.size(), transformed);
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to apply access wideners to %s".formatted(jarFile), e);
}
@@ -65,17 +71,22 @@ final class AccessWidenerTransformer {
private List<Pair<String, ZipUtils.UnsafeUnaryOperator<byte[]>>> getTransformers(Set<String> classes) {
return classes.stream()
.map(string -> new Pair<>(string.replaceAll("\\.", "/") + ".class", getTransformer(string)))
.map(string -> new Pair<>(string + ".class", getTransformer(string)))
.collect(Collectors.toList());
}
private ZipUtils.UnsafeUnaryOperator<byte[]> getTransformer(String className) {
return input -> {
ClassReader reader = new ClassReader(input);
ClassWriter writer = new ClassWriter(0);
ClassVisitor classVisitor = AccessWidenerClassVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener);
LOGGER.debug("Applying access widener to " + className);
if (!reader.getClassName().equals(className)) {
throw new IllegalStateException("Class name mismatch: expected %s but transforming %s".formatted(className, reader.getClassName()));
}
ClassWriter writer = new ClassWriter(0);
ClassVisitor classVisitor = accessWidener.createClassVisitor(Constants.ASM_VERSION, writer, null);
LOGGER.debug("Applying access widener to {}", className);
reader.accept(classVisitor, 0);
return writer.toByteArray();

View File

@@ -30,8 +30,8 @@ import java.nio.file.Path;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.classtweaker.api.visitor.ClassTweakerVisitor;
import net.fabricmc.loom.util.Checksum;
import net.fabricmc.loom.util.LazyCloseable;
import net.fabricmc.loom.util.fmj.ModEnvironment;
@@ -43,9 +43,9 @@ public record LocalAccessWidenerEntry(Path path, String hash) implements AccessW
}
@Override
public void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
var reader = new AccessWidenerReader(visitor);
reader.read(Files.readAllBytes(path));
public void read(ClassTweakerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
var reader = ClassTweakerReader.create(visitor);
reader.read(Files.readAllBytes(path), null);
}
@Override

View File

@@ -32,10 +32,10 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.accesswidener.TransitiveOnlyFilter;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.classtweaker.api.visitor.ClassTweakerVisitor;
import net.fabricmc.classtweaker.visitors.ClassTweakerRemapperVisitor;
import net.fabricmc.classtweaker.visitors.TransitiveOnlyFilter;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.util.LazyCloseable;
import net.fabricmc.loom.util.fmj.FabricModJson;
@@ -67,26 +67,26 @@ public record ModAccessWidenerEntry(FabricModJson mod, String path, ModEnvironme
}
@Override
public void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
public void read(ClassTweakerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
if (transitiveOnly) {
// Filter for only transitive rules
visitor = new TransitiveOnlyFilter(visitor);
}
final byte[] data = readRaw();
final AccessWidenerReader.Header header = AccessWidenerReader.readHeader(data);
final ClassTweakerReader.Header header = ClassTweakerReader.readHeader(data);
if (!header.getNamespace().equals(MappingsNamespace.NAMED.toString())) {
// Remap the AW if needed
visitor = getRemapper(visitor, remapper.get());
}
var reader = new AccessWidenerReader(visitor);
reader.read(data);
var reader = ClassTweakerReader.create(visitor);
reader.read(data, mod.getId());
}
private static AccessWidenerRemapper getRemapper(AccessWidenerVisitor visitor, TinyRemapper tinyRemapper) {
return new AccessWidenerRemapper(
private static ClassTweakerRemapperVisitor getRemapper(ClassTweakerVisitor visitor, TinyRemapper tinyRemapper) {
return new ClassTweakerRemapperVisitor(
visitor,
tinyRemapper.getEnvironment().getRemapper(),
MappingsNamespace.INTERMEDIARY.toString(),

View File

@@ -31,8 +31,8 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.classtweaker.api.visitor.AccessWidenerVisitor;
import net.fabricmc.classtweaker.api.visitor.ClassTweakerVisitor;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.processor.MappingProcessorContext;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
@@ -44,6 +44,8 @@ import net.fabricmc.tinyremapper.TinyRemapper;
public final class TransitiveAccessWidenerMappingsProcessor implements MinecraftJarProcessor.MappingsProcessor<AccessWidenerJarProcessor.Spec> {
public static final TransitiveAccessWidenerMappingsProcessor INSTANCE = new TransitiveAccessWidenerMappingsProcessor();
private static final Logger LOGGER = LoggerFactory.getLogger(TransitiveAccessWidenerMappingsProcessor.class);
private TransitiveAccessWidenerMappingsProcessor() {
}
@@ -63,7 +65,7 @@ public final class TransitiveAccessWidenerMappingsProcessor implements Minecraft
try (LazyCloseable<TinyRemapper> remapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) {
for (AccessWidenerEntry accessWidener : accessWideners) {
var visitor = new MappingCommentVisitor(accessWidener.mappingId(), mappings);
var visitor = new MappingCommentClassTweakerVisitor(accessWidener.mappingId(), mappings);
accessWidener.read(visitor, remapper);
}
} catch (IOException e) {
@@ -73,80 +75,91 @@ public final class TransitiveAccessWidenerMappingsProcessor implements Minecraft
return true;
}
private record MappingCommentVisitor(String modId, MemoryMappingTree mappingTree) implements AccessWidenerVisitor {
private static final Logger LOGGER = LoggerFactory.getLogger(MappingCommentVisitor.class);
private record MappingCommentClassTweakerVisitor(String modId, MemoryMappingTree mappingTree) implements ClassTweakerVisitor {
@Override
public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) {
MappingTree.ClassMapping classMapping = mappingTree.getClass(name);
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId());
return;
}
classMapping.setComment(appendComment(classMapping.getComment(), access));
public AccessWidenerVisitor visitAccessWidener(String owner) {
return new MappingCommentAccessWidenerVisitor(owner);
}
@Override
public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(owner, access, transitive);
private class MappingCommentAccessWidenerVisitor implements AccessWidenerVisitor {
private final String className;
MappingTree.ClassMapping classMapping = mappingTree.getClass(owner);
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", owner, modId());
return;
private MappingCommentAccessWidenerVisitor(String className) {
this.className = className;
}
MappingTree.MethodMapping methodMapping = classMapping.getMethod(name, descriptor);
@Override
public void visitClass(AccessType access, boolean transitive) {
MappingTree.ClassMapping classMapping = mappingTree.getClass(className);
if (methodMapping == null) {
LOGGER.info("Failed to find method ({}) in ({}) to mark access widened by mod ({})", name, owner, modId());
return;
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", className, modId());
return;
}
classMapping.setComment(appendComment(classMapping.getComment(), access));
}
methodMapping.setComment(appendComment(methodMapping.getComment(), access));
}
@Override
public void visitMethod(String name, String descriptor, AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(access, transitive);
@Override
public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(owner, access, transitive);
MappingTree.ClassMapping classMapping = mappingTree.getClass(className);
MappingTree.ClassMapping classMapping = mappingTree.getClass(owner);
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", className, modId());
return;
}
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId());
return;
MappingTree.MethodMapping methodMapping = classMapping.getMethod(name, descriptor);
if (methodMapping == null) {
LOGGER.info("Failed to find method ({}) in ({}) to mark access widened by mod ({})", name, className, modId());
return;
}
methodMapping.setComment(appendComment(methodMapping.getComment(), access));
}
MappingTree.FieldMapping fieldMapping = classMapping.getField(name, descriptor);
@Override
public void visitField(String name, String descriptor, AccessType access, boolean transitive) {
// Access is also applied to the class, so also add the comment to the class
visitClass(access, transitive);
if (fieldMapping == null) {
LOGGER.info("Failed to find field ({}) in ({}) to mark access widened by mod ({})", name, owner, modId());
return;
MappingTree.ClassMapping classMapping = mappingTree.getClass(className);
if (classMapping == null) {
LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId());
return;
}
MappingTree.FieldMapping fieldMapping = classMapping.getField(name, descriptor);
if (fieldMapping == null) {
LOGGER.info("Failed to find field ({}) in ({}) to mark access widened by mod ({})", name, className, modId());
return;
}
fieldMapping.setComment(appendComment(fieldMapping.getComment(), access));
}
fieldMapping.setComment(appendComment(fieldMapping.getComment(), access));
}
private String appendComment(String comment, AccessType access) {
if (comment == null) {
comment = "";
} else {
comment += "\n";
}
private String appendComment(String comment, AccessWidenerReader.AccessType access) {
if (comment == null) {
comment = "";
} else {
comment += "\n";
String awComment = "Access widened by %s to %s".formatted(modId(), access);
if (!comment.contains(awComment)) {
// Ensure we don't comment the same thing twice. A bit of a cheap way to do this, but should work ok.
comment += awComment;
}
return comment;
}
String awComment = "Access widened by %s to %s".formatted(modId(), access);
if (!comment.contains(awComment)) {
// Ensure we don't comment the same thing twice. A bit of a cheap way to do this, but should work ok.
comment += awComment;
}
return comment;
}
}
}

View File

@@ -29,16 +29,15 @@ import java.util.List;
import org.objectweb.asm.ClassVisitor;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerClassVisitor;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.classtweaker.api.ClassTweaker;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.loom.configuration.mods.dependency.ModDependency;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.tinyremapper.TinyRemapper;
public record AccessWidenerAnalyzeVisitorProvider(AccessWidener accessWidener) implements TinyRemapper.AnalyzeVisitorProvider {
public record AccessWidenerAnalyzeVisitorProvider(ClassTweaker accessWidener) implements TinyRemapper.AnalyzeVisitorProvider {
static AccessWidenerAnalyzeVisitorProvider createFromMods(String namespace, List<ModDependency> mods) throws IOException {
AccessWidener accessWidener = new AccessWidener();
ClassTweaker accessWidener = ClassTweaker.newInstance();
accessWidener.visitHeader(namespace);
for (ModDependency mod : mods) {
@@ -48,8 +47,8 @@ public record AccessWidenerAnalyzeVisitorProvider(AccessWidener accessWidener) i
continue;
}
final var reader = new AccessWidenerReader(accessWidener);
reader.read(accessWidenerData.content());
final var reader = ClassTweakerReader.create(accessWidener);
reader.read(accessWidenerData.content(), null); // TODO pass mod id
}
return new AccessWidenerAnalyzeVisitorProvider(accessWidener);
@@ -57,6 +56,6 @@ public record AccessWidenerAnalyzeVisitorProvider(AccessWidener accessWidener) i
@Override
public ClassVisitor insertAnalyzeVisitor(int mrjVersion, String className, ClassVisitor next) {
return AccessWidenerClassVisitor.createClassVisitor(Constants.ASM_VERSION, next, accessWidener);
return accessWidener.createClassVisitor(Constants.ASM_VERSION, next, null);
}
}

View File

@@ -30,9 +30,9 @@ import java.util.List;
import org.objectweb.asm.commons.Remapper;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerWriter;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.classtweaker.api.ClassTweakerWriter;
import net.fabricmc.classtweaker.visitors.ClassTweakerRemapperVisitor;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
@@ -42,18 +42,18 @@ public class AccessWidenerUtils {
* Remap a mods access widener from intermediary to named, so that loader can apply it in our dev-env.
*/
public static byte[] remapAccessWidener(byte[] input, Remapper remapper) {
int version = AccessWidenerReader.readVersion(input);
int version = ClassTweakerReader.readVersion(input);
AccessWidenerWriter writer = new AccessWidenerWriter(version);
AccessWidenerRemapper awRemapper = new AccessWidenerRemapper(
ClassTweakerWriter writer = ClassTweakerWriter.create(version);
ClassTweakerRemapperVisitor awRemapper = new ClassTweakerRemapperVisitor(
writer,
remapper,
MappingsNamespace.INTERMEDIARY.toString(),
MappingsNamespace.NAMED.toString()
);
AccessWidenerReader reader = new AccessWidenerReader(awRemapper);
reader.read(input);
return writer.write();
ClassTweakerReader reader = ClassTweakerReader.create(awRemapper);
reader.read(input, null); // TODO pass modid
return writer.getOutput();
}
public static AccessWidenerData readAccessWidenerData(Path inputJar) throws IOException {
@@ -74,11 +74,11 @@ public class AccessWidenerUtils {
final String accessWidenerPath = classTweakers.get(0);
final byte[] accessWidener = fabricModJson.getSource().read(accessWidenerPath);
final AccessWidenerReader.Header header = AccessWidenerReader.readHeader(accessWidener);
final ClassTweakerReader.Header header = ClassTweakerReader.readHeader(accessWidener);
return new AccessWidenerData(accessWidenerPath, header, accessWidener);
}
public record AccessWidenerData(String path, AccessWidenerReader.Header header, byte[] content) {
public record AccessWidenerData(String path, ClassTweakerReader.Header header, byte[] content) {
}
}

View File

@@ -52,9 +52,9 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerWriter;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.classtweaker.api.ClassTweakerWriter;
import net.fabricmc.classtweaker.visitors.ClassTweakerRemapperVisitor;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.nesting.JarNester;
import net.fabricmc.loom.build.nesting.NestableJarGenerationTask;
@@ -268,19 +268,19 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
private byte[] remapAccessWidener(byte[] input) {
Objects.requireNonNull(tinyRemapper, "tinyRemapper");
int version = AccessWidenerReader.readVersion(input);
int version = ClassTweakerReader.readVersion(input);
AccessWidenerWriter writer = new AccessWidenerWriter(version);
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
ClassTweakerWriter writer = ClassTweakerWriter.create(version);
ClassTweakerRemapperVisitor remapper = new ClassTweakerRemapperVisitor(
writer,
tinyRemapper.getEnvironment().getRemapper(),
getParameters().getSourceNamespace().get(),
getParameters().getTargetNamespace().get()
);
AccessWidenerReader reader = new AccessWidenerReader(remapper);
reader.read(input);
ClassTweakerReader reader = ClassTweakerReader.create(remapper);
reader.read(input, null); // TODO pass mod id
return writer.write();
return writer.getOutput();
}
private void addNestedJars() {

View File

@@ -30,6 +30,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -41,14 +42,12 @@ import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import net.fabricmc.accesswidener.AccessWidenerFormatException;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.classtweaker.api.ClassTweakerReader;
import net.fabricmc.classtweaker.validator.ClassTweakerValidatingVisitor;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.util.TinyRemapperLoggerAdapter;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.api.TrEnvironment;
public abstract class ValidateAccessWidenerTask extends DefaultTask {
@SkipWhenEmpty
@@ -77,44 +76,26 @@ public abstract class ValidateAccessWidenerTask extends DefaultTask {
tinyRemapper.readClassPath(file.toPath());
}
final AccessWidenerValidator validator = new AccessWidenerValidator(tinyRemapper.getEnvironment());
final AccessWidenerReader accessWidenerReader = new AccessWidenerReader(validator);
AtomicBoolean hasProblem = new AtomicBoolean(false);
final ClassTweakerValidatingVisitor validator = new ClassTweakerValidatingVisitor(tinyRemapper.getEnvironment(), (lineNumber, message) -> {
hasProblem.set(true);
getLogger().error("{} on line {}", message, lineNumber);
});
final ClassTweakerReader accessWidenerReader = ClassTweakerReader.create(validator);
try (BufferedReader reader = Files.newBufferedReader(getAccessWidener().get().getAsFile().toPath(), StandardCharsets.UTF_8)) {
accessWidenerReader.read(reader, "named");
} catch (AccessWidenerFormatException e) {
getLogger().error("Failed to validate access-widener file {} on line {}: {}", getAccessWidener().get().getAsFile().getName(), e.getLineNumber(), e.getMessage());
throw e;
} catch (IOException e) {
throw new UncheckedIOException("Failed to read access widener", e);
} finally {
tinyRemapper.finish();
}
}
/**
* Validates that all entries in an access-widner file relate to a class/method/field in the mc jar.
*/
private record AccessWidenerValidator(TrEnvironment environment) implements AccessWidenerVisitor {
@Override
public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) {
if (environment().getClass(name) == null) {
throw new RuntimeException("Could not find class (%s)".formatted(name));
}
}
@Override
public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
if (environment().getMethod(owner, name, descriptor) == null) {
throw new RuntimeException("Could not find method (%s%s) in class (%s)".formatted(name, descriptor, owner));
}
}
@Override
public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) {
if (environment().getField(owner, name, descriptor) == null) {
throw new RuntimeException("Could not find field (%s%s) in class (%s)".formatted(name, descriptor, owner));
}
if (hasProblem.get()) {
getLogger().error("access-widener validation failed for {}", getAccessWidener().get().getAsFile().getName());
throw new RuntimeException("access-widener validation failed for %s".formatted(getAccessWidener().get().getAsFile().getName()));
}
}
}

View File

@@ -72,18 +72,17 @@ class AccessWidenerTest extends Specification implements GradleProjectTestTrait
setup:
def gradle = gradleProject(project: "accesswidener", version: version)
new File(gradle.projectDir, "src/main/resources/modid.accesswidener").append(awLine)
def errorPrefix = "Failed to validate access-widener file modid.accesswidener on line 10: java.lang.RuntimeException: "
when:
def result = gradle.run(task: "check", expectFailure: true)
then:
result.output.contains(errorPrefix + error)
result.output.contains(error)
where:
awLine | error | version
'accessible\tclass\tnet/minecraft/DoesntExists' | "Could not find class (net/minecraft/DoesntExists)" | DEFAULT_GRADLE
'accessible\tfield\tnet/minecraft/screen/slot/Slot\tabc\tI' | "Could not find field (abcI) in class (net/minecraft/screen/slot/Slot)" | DEFAULT_GRADLE
'accessible\tmethod\tnet/minecraft/client/main/Main\tmain\t([Ljava/lang/NotAString;)V' | "Could not find method (main([Ljava/lang/NotAString;)V) in class (net/minecraft/client/main/Main)" | DEFAULT_GRADLE
awLine | error | version
'accessible\tclass\tnet/minecraft/DoesntExists' | "Could not find class (net/minecraft/DoesntExists) on line 10" | DEFAULT_GRADLE
'accessible\tfield\tnet/minecraft/screen/slot/Slot\tabc\tI' | "Could not find field (abc:I) in class (net/minecraft/screen/slot/Slot) on line 10" | DEFAULT_GRADLE
'accessible\tmethod\tnet/minecraft/client/main/Main\tmain\t([Ljava/lang/NotAString;)V' | "Could not find method (main([Ljava/lang/NotAString;)V) in class (net/minecraft/client/main/Main) on line 10" | DEFAULT_GRADLE
}
}