From d48c74161e1a17fd5c8464605f9eb1e45d6e359a Mon Sep 17 00:00:00 2001 From: shartte Date: Tue, 14 Sep 2021 23:40:47 +0200 Subject: [PATCH] Access Widener 2.0 with support for Transitive Access Wideners (#484) * Added global access widener support. * Adapt loom to changed API of latest AW PR. * Fix expected access widener to fix the test. Since the access widener is now streamed directly into the writer, the expanded rules (i.e. accessible field makes the owning class also accessible) are no longer found in the remapped file. * Add basic transitive accesswidener test * Extracted applying transitive access wideners into their own jar processor since they also need to be applied if there is no AW in the mod itself. * Misc assortment of fixes * Set up the processor lazily to allow for adding the intermediary MC jar, which is needed to correctly remap intermediary AWs to named. * Rework to setup the tiny remapper classpath with the mc jar Add an extension prop to disable * Add TransitiveDetectorVisitor * Minor refactoring. * Use release-version of access-widener. Co-authored-by: modmuss50 --- build.gradle | 2 +- .../loom/api/LoomGradleExtensionAPI.java | 7 + .../accesswidener/AccessWidenerFile.java | 66 ++++++ .../AccessWidenerJarProcessor.java | 156 ++++---------- .../AccessWidenerTransformer.java | 82 +++++++ .../TransitiveAccessWidenerJarProcessor.java | 200 ++++++++++++++++++ .../loom/configuration/mods/ModProcessor.java | 46 ++-- .../mappings/MappingsProviderImpl.java | 9 + .../minecraft/MinecraftMappedProvider.java | 28 +-- .../extension/LoomGradleExtensionApiImpl.java | 9 + .../extension/MinecraftGradleExtension.java | 6 + .../net/fabricmc/loom/task/RemapJarTask.java | 18 +- ...ngsHelper.java => TinyRemapperHelper.java} | 46 +++- .../test/integration/AccessWidenerTest.groovy | 17 ++ .../accesswidener/expected.accesswidener | 7 +- .../transitiveAccesswidener/build.gradle | 18 ++ .../dummyDependency/dummy.accesswidener | 3 + .../dummyDependency/fabric.mod.json | 7 + .../src/main/java/ExampleMod.java | 13 ++ 19 files changed, 553 insertions(+), 187 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java rename src/main/java/net/fabricmc/loom/util/{TinyRemapperMappingsHelper.java => TinyRemapperHelper.java} (63%) create mode 100644 src/test/resources/projects/transitiveAccesswidener/build.gradle create mode 100644 src/test/resources/projects/transitiveAccesswidener/dummyDependency/dummy.accesswidener create mode 100644 src/test/resources/projects/transitiveAccesswidener/dummyDependency/fabric.mod.json create mode 100644 src/test/resources/projects/transitiveAccesswidener/src/main/java/ExampleMod.java diff --git a/build.gradle b/build.gradle index 3a37ecd..305b659 100644 --- a/build.gradle +++ b/build.gradle @@ -81,7 +81,7 @@ dependencies { implementation ('net.fabricmc:tiny-remapper:0.5.0') implementation ('net.fabricmc:tiny-mappings-parser:0.3.0+build.17') - implementation 'net.fabricmc:access-widener:1.1.0' + implementation 'net.fabricmc:access-widener:2.0.0' implementation 'net.fabricmc:mapping-io:0.2.1' implementation ('net.fabricmc:lorenz-tiny:3.0.0') { diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 1a84efc..4020ecd 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -204,4 +204,11 @@ public interface LoomGradleExtensionAPI { * @return the version defined in the fabric.mod.json */ String getModVersion(); + + /** + * When true loom will apply transitive access wideners from compile dependencies. + * + * @return the property controlling the transitive access wideners + */ + Property getEnableTransitiveAccessWideners(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java new file mode 100644 index 0000000..680aae9 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java @@ -0,0 +1,66 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.accesswidener; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.zeroturnaround.zip.ZipUtil; + +public record AccessWidenerFile( + String name, + String modId, + byte[] content +) { + /** + * Reads the access-widener contained in a mod jar, or returns null if there is none. + */ + public static AccessWidenerFile fromModJar(Path modJarPath) { + byte[] modJsonBytes = ZipUtil.unpackEntry(modJarPath.toFile(), "fabric.mod.json"); + + if (modJsonBytes == null) { + return null; + } + + JsonObject jsonObject = new Gson().fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class); + + if (!jsonObject.has("accessWidener")) { + return null; + } + + String awPath = jsonObject.get("accessWidener").getAsString(); + String modId = jsonObject.get("id").getAsString(); + + byte[] content = ZipUtil.unpackEntry(modJarPath.toFile(), awPath); + + return new AccessWidenerFile( + awPath, + modId, + content + ); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java index 6ac63ac..0970717 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java @@ -24,46 +24,34 @@ package net.fabricmc.loom.configuration.accesswidener; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.zip.ZipEntry; -import com.google.gson.Gson; -import com.google.gson.JsonObject; +import com.google.common.hash.Hashing; import org.gradle.api.Project; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; import org.objectweb.asm.commons.Remapper; import org.zeroturnaround.zip.ZipUtil; -import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; -import org.zeroturnaround.zip.transform.ZipEntryTransformer; -import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; import net.fabricmc.accesswidener.AccessWidener; import net.fabricmc.accesswidener.AccessWidenerReader; import net.fabricmc.accesswidener.AccessWidenerRemapper; -import net.fabricmc.accesswidener.AccessWidenerVisitor; import net.fabricmc.accesswidener.AccessWidenerWriter; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.processors.JarProcessor; -import net.fabricmc.loom.util.Checksum; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.tinyremapper.TinyRemapper; public class AccessWidenerJarProcessor implements JarProcessor { - private AccessWidener accessWidener = new AccessWidener(); - private AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); + // Filename used to store hash of input access widener in processed jar file + private static final String HASH_FILENAME = "aw.sha256"; + // The mod's own access widener file + private byte[] modAccessWidener; + private final AccessWidener accessWidener = new AccessWidener(); private final Project project; + // This is a SHA256 hash across the mod's and all transitive AWs private byte[] inputHash; public AccessWidenerJarProcessor(Project project) { @@ -77,119 +65,53 @@ public class AccessWidenerJarProcessor implements JarProcessor { @Override public void setup() { - LoomGradleExtension loomGradleExtension = LoomGradleExtension.get(project); - File awPath = loomGradleExtension.getAccessWidenerPath().get().getAsFile(); + LoomGradleExtension extension = LoomGradleExtension.get(project); + Path awPath = extension.getAccessWidenerPath().get().getAsFile().toPath(); - if (!awPath.exists()) { - throw new RuntimeException("Could not find access widener file @ " + awPath.getAbsolutePath()); - } - - inputHash = Checksum.sha256(awPath); - - try (BufferedReader reader = new BufferedReader(new FileReader(awPath))) { - accessWidenerReader.read(reader); + // Read our own mod's access widener, used later for producing a version remapped to intermediary + try { + modAccessWidener = Files.readAllBytes(awPath); + } catch (NoSuchFileException e) { + throw new RuntimeException("Could not find access widener file @ " + awPath.toAbsolutePath()); } catch (IOException e) { - throw new RuntimeException("Failed to read project access widener file"); + throw new RuntimeException("Failed to read access widener: " + awPath); } - //Remap accessWidener if its not named, allows for AE's to be written in intermediary - if (!accessWidener.getNamespace().equals(MappingsNamespace.NAMED.toString())) { - try { - List validNamespaces = loomGradleExtension.getMappingsProvider().getMappings().getMetadata().getNamespaces(); + AccessWidenerReader reader = new AccessWidenerReader(accessWidener); + reader.read(modAccessWidener); - if (!validNamespaces.contains(accessWidener.getNamespace())) { - throw new UnsupportedOperationException(String.format("Access Widener namespace '%s' is not a valid namespace, it must be one of: '%s'", accessWidener.getNamespace(), String.join(", ", validNamespaces))); - } - - TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.NAMED.toString()); - tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath()); - - AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, tinyRemapper.getRemapper(), MappingsNamespace.NAMED.toString()); - accessWidener = remapper.remap(); - - tinyRemapper.finish(); - } catch (IOException e) { - throw new RuntimeException("Failed to remap access widener", e); - } - } + inputHash = Hashing.sha256().hashBytes(modAccessWidener).asBytes(); } @Override public void process(File file) { - project.getLogger().lifecycle("Processing file: " + file.getName()); - ZipUtil.transformEntries(file, getTransformers(accessWidener.getTargets())); - ZipUtil.addEntry(file, "aw.sha256", inputHash); + AccessWidenerTransformer applier = new AccessWidenerTransformer(project.getLogger(), accessWidener); + applier.apply(file); + ZipUtil.addEntry(file, HASH_FILENAME, inputHash); } - private ZipEntryTransformerEntry[] getTransformers(Set classes) { - return classes.stream() - .map(string -> new ZipEntryTransformerEntry(string.replaceAll("\\.", "/") + ".class", getTransformer(string))) - .toArray(ZipEntryTransformerEntry[]::new); - } + /** + * Get this mods access widener remapped to the intermediary namespace. + */ + public byte[] getRemappedAccessWidener(Remapper asmRemapper, String targetNamespace) throws IOException { + int version = AccessWidenerReader.readVersion(modAccessWidener); - private ZipEntryTransformer getTransformer(String className) { - return new ByteArrayZipEntryTransformer() { - @Override - protected byte[] transform(ZipEntry zipEntry, byte[] input) { - ClassReader reader = new ClassReader(input); - ClassWriter writer = new ClassWriter(0); - ClassVisitor classVisitor = AccessWidenerVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener); + AccessWidenerWriter writer = new AccessWidenerWriter(version); + AccessWidenerRemapper remapper = new AccessWidenerRemapper( + writer, + asmRemapper, + MappingsNamespace.NAMED.toString(), + targetNamespace + ); + AccessWidenerReader reader = new AccessWidenerReader(remapper); + reader.read(modAccessWidener); - project.getLogger().lifecycle("Applying access widener to " + className); - - reader.accept(classVisitor, 0); - return writer.toByteArray(); - } - }; - } - - //Called when remapping the mod - public void remapAccessWidener(Path modJarPath, Remapper asmRemapper) throws IOException { - byte[] bytes = getRemappedAccessWidener(asmRemapper); - - String path = getAccessWidenerPath(modJarPath); - - if (path == null) { - throw new RuntimeException("Failed to find accessWidener in fabric.mod.json"); - } - - boolean replaced = ZipUtil.replaceEntry(modJarPath.toFile(), path, bytes); - - if (!replaced) { - project.getLogger().warn("Failed to replace access widener file at " + path); - } - } - - public byte[] getRemappedAccessWidener(Remapper asmRemapper) throws IOException { - AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, MappingsNamespace.INTERMEDIARY.toString()); - AccessWidener remapped = remapper.remap(); - AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); - - try (StringWriter writer = new StringWriter()) { - accessWidenerWriter.write(writer); - return writer.toString().getBytes(); - } - } - - public String getAccessWidenerPath(Path modJarPath) { - byte[] modJsonBytes = ZipUtil.unpackEntry(modJarPath.toFile(), "fabric.mod.json"); - - if (modJsonBytes == null) { - return null; - } - - JsonObject jsonObject = new Gson().fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class); - - if (!jsonObject.has("accessWidener")) { - return null; - } - - return jsonObject.get("accessWidener").getAsString(); + return writer.write(); } @Override public boolean isInvalid(File file) { - byte[] hash = ZipUtil.unpackEntry(file, "aw.sha256"); + byte[] hash = ZipUtil.unpackEntry(file, HASH_FILENAME); if (hash == null) { return true; diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java new file mode 100644 index 0000000..bdde740 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java @@ -0,0 +1,82 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.accesswidener; + +import java.io.File; +import java.util.Set; +import java.util.zip.ZipEntry; + +import org.gradle.api.logging.Logger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.zeroturnaround.zip.ZipUtil; +import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; +import org.zeroturnaround.zip.transform.ZipEntryTransformer; +import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; + +import net.fabricmc.accesswidener.AccessWidener; +import net.fabricmc.accesswidener.AccessWidenerClassVisitor; +import net.fabricmc.loom.util.Constants; + +final class AccessWidenerTransformer { + private final Logger logger; + private final AccessWidener accessWidener; + + AccessWidenerTransformer(Logger logger, AccessWidener accessWidener) { + this.logger = logger; + this.accessWidener = accessWidener; + } + + /** + * Apply the rules from an access-widener to the given jar or zip file. + */ + void apply(File jarFile) { + logger.lifecycle("Processing file: " + jarFile.getName()); + ZipUtil.transformEntries(jarFile, getTransformers(accessWidener.getTargets())); + } + + private ZipEntryTransformerEntry[] getTransformers(Set classes) { + return classes.stream() + .map(string -> new ZipEntryTransformerEntry(string.replaceAll("\\.", "/") + ".class", getTransformer(string))) + .toArray(ZipEntryTransformerEntry[]::new); + } + + private ZipEntryTransformer getTransformer(String className) { + return new ByteArrayZipEntryTransformer() { + @Override + protected byte[] transform(ZipEntry zipEntry, byte[] input) { + ClassReader reader = new ClassReader(input); + ClassWriter writer = new ClassWriter(0); + ClassVisitor classVisitor = AccessWidenerClassVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener); + + logger.info("Applying access widener to " + className); + + reader.accept(classVisitor, 0); + return writer.toByteArray(); + } + }; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java new file mode 100644 index 0000000..5412975 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java @@ -0,0 +1,200 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2020-2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.accesswidener; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.google.common.base.Preconditions; +import org.gradle.api.Project; + +import net.fabricmc.accesswidener.AccessWidener; +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerRemapper; +import net.fabricmc.accesswidener.AccessWidenerVisitor; +import net.fabricmc.accesswidener.TransitiveOnlyFilter; +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.RemappedConfigurationEntry; +import net.fabricmc.loom.configuration.processors.JarProcessor; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.TinyRemapperHelper; +import net.fabricmc.tinyremapper.TinyRemapper; + +/** + * Applies transitive access wideners that are inherited from mod and api dependencies. + */ +public class TransitiveAccessWidenerJarProcessor implements JarProcessor { + private final Project project; + private final LoomGradleExtension extension; + + private final List transitiveAccessWideners; + + public TransitiveAccessWidenerJarProcessor(Project project) { + this.project = project; + this.extension = LoomGradleExtension.get(project); + + transitiveAccessWideners = getTransitiveAccessWideners(); + } + + @Override + public void setup() { + } + + public boolean isEmpty() { + return transitiveAccessWideners.isEmpty(); + } + + @Override + public String getId() { + Preconditions.checkArgument(!isEmpty()); + + return "loom:transitive_access_wideners:" + transitiveAccessWideners.hashCode(); + } + + private List getTransitiveAccessWideners() { + List accessWideners = new ArrayList<>(); + + for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { + // Only apply global AWs from mods that are part of the compile classpath + if (!entry.compileClasspath()) { + continue; + } + + Set artifacts = extension.getLazyConfigurationProvider(entry.sourceConfiguration()) + .get() + .resolve(); + + for (File artifact : artifacts) { + AccessWidenerFile accessWidener = AccessWidenerFile.fromModJar(artifact.toPath()); + + if (accessWidener == null) { + continue; + } + + if (!TransitiveDetectorVisitor.isTransitive(accessWidener.content())) { + // AW does not contain anything transitive, skip over it + continue; + } + + accessWideners.add(accessWidener); + } + } + + return accessWideners; + } + + @Override + public void process(File file) { + Preconditions.checkArgument(!isEmpty()); + + AccessWidener accessWidener = createAccessWidener(); + AccessWidenerTransformer transformer = new AccessWidenerTransformer(project.getLogger(), accessWidener); + transformer.apply(file); + } + + private AccessWidener createAccessWidener() { + AccessWidener accessWidener = new AccessWidener(); + // For other mods, only consider transitive AWs and remap from intermediary->named + TinyRemapper tinyRemapper = createTinyRemapper(); + + try { + AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper( + accessWidener, + tinyRemapper.getRemapper(), + MappingsNamespace.INTERMEDIARY.toString(), + MappingsNamespace.NAMED.toString() + ); + AccessWidenerReader transitiveReader = new AccessWidenerReader(new TransitiveOnlyFilter(remappingVisitor)); + + for (AccessWidenerFile accessWidenerFile : transitiveAccessWideners) { + project.getLogger().info("Reading transitive access widener from {}", accessWidenerFile.modId()); + transitiveReader.read(accessWidenerFile.content()); + } + } finally { + tinyRemapper.finish(); + } + + return accessWidener; + } + + private TinyRemapper createTinyRemapper() { + try { + TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named"); + + tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project)); + tinyRemapper.readClassPath(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath()); + + return tinyRemapper; + } catch (IOException e) { + throw new RuntimeException("Failed to create tiny remapper for intermediary->named", e); + } + } + + @Override + public boolean isInvalid(File file) { + // The hash is handled by getId() + return false; + } + + private static class TransitiveDetectorVisitor implements AccessWidenerVisitor { + private boolean transitive = false; + + @Override + public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) { + if (transitive) { + this.transitive = true; + } + } + + @Override + public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) { + if (transitive) { + this.transitive = true; + } + } + + @Override + public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) { + if (transitive) { + this.transitive = true; + } + } + + public static boolean isTransitive(byte[] content) { + if (AccessWidenerReader.readVersion(content) < 2) { + // Transitive AWs are only in v2 or higher, so we can save parsing the file to find out... + return false; + } + + TransitiveDetectorVisitor transitiveDetector = new TransitiveDetectorVisitor(); + new AccessWidenerReader(transitiveDetector).read(content); + return transitiveDetector.transitive; + } + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java index 7cdc667..2cd519f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java @@ -24,13 +24,9 @@ package net.fabricmc.loom.configuration.mods; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; @@ -48,7 +44,6 @@ import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.transform.StringZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; -import net.fabricmc.accesswidener.AccessWidener; import net.fabricmc.accesswidener.AccessWidenerReader; import net.fabricmc.accesswidener.AccessWidenerRemapper; import net.fabricmc.accesswidener.AccessWidenerWriter; @@ -60,7 +55,7 @@ import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.TinyRemapperMappingsHelper; +import net.fabricmc.loom.util.TinyRemapperHelper; import net.fabricmc.tinyremapper.InputTag; import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; @@ -98,7 +93,7 @@ public class ModProcessor { private static void stripNestedJars(File file) { // Strip out all contained jar info as we dont want loader to try and load the jars contained in dev. - ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[] {(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { + ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[]{(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { @Override protected String transform(ZipEntry zipEntry, String input) { JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class); @@ -108,23 +103,22 @@ public class ModProcessor { }))}); } + /** + * Remap another mod's access widener from intermediary to named, so that loader can apply it in our dev-env. + */ private static byte[] remapAccessWidener(byte[] input, Remapper remapper) { - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) { - AccessWidener accessWidener = new AccessWidener(); - AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); - accessWidenerReader.read(bufferedReader); + int version = AccessWidenerReader.readVersion(input); - AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, MappingsNamespace.NAMED.toString()); - AccessWidener remapped = accessWidenerRemapper.remap(); - AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); - - try (StringWriter writer = new StringWriter()) { - accessWidenerWriter.write(writer); - return writer.toString().getBytes(StandardCharsets.UTF_8); - } - } catch (IOException e) { - throw new RuntimeException(e); - } + AccessWidenerWriter writer = new AccessWidenerWriter(version); + AccessWidenerRemapper awRemapper = new AccessWidenerRemapper( + writer, + remapper, + MappingsNamespace.INTERMEDIARY.toString(), + MappingsNamespace.NAMED.toString() + ); + AccessWidenerReader reader = new AccessWidenerReader(awRemapper); + reader.read(input); + return writer.write(); } private static void remapJars(Project project, List processList) throws IOException { @@ -137,16 +131,16 @@ public class ModProcessor { Path mc = mappedProvider.getIntermediaryJar().toPath(); Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles() - .stream().map(File::toPath).toArray(Path[]::new); + .stream().map(File::toPath).toArray(Path[]::new); List remapList = processList.stream().filter(ModDependencyInfo::requiresRemapping).collect(Collectors.toList()); project.getLogger().lifecycle(":remapping " + remapList.size() + " mods (TinyRemapper, " + fromM + " -> " + toM + ")"); TinyRemapper remapper = TinyRemapper.newRemapper() - .withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)) - .renameInvalidLocals(false) - .build(); + .withMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false)) + .renameInvalidLocals(false) + .build(); remapper.readClassPathAsync(mc); remapper.readClassPathAsync(mcDeps); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java index 0456ada..603df94 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java @@ -51,6 +51,7 @@ import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.DependencyProvider; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; +import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor; import net.fabricmc.loom.configuration.processors.JarProcessorManager; import net.fabricmc.loom.configuration.processors.MinecraftProcessedProvider; import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; @@ -141,6 +142,14 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(getProject())); } + if (extension.getEnableTransitiveAccessWideners().get()) { + TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(getProject()); + + if (!transitiveAccessWidenerJarProcessor.isEmpty()) { + extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor); + } + } + extension.getAccessWidenerPath().finalizeValue(); extension.getGameJarProcessors().finalizeValue(); JarProcessorManager processorManager = new JarProcessorManager(extension.getGameJarProcessors().get()); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java index 7535e1a..b5f175f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java @@ -29,10 +29,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; -import java.util.Map; import java.util.function.Consumer; -import com.google.common.collect.ImmutableMap; import org.gradle.api.Project; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; @@ -40,17 +38,11 @@ import net.fabricmc.loom.configuration.DependencyProvider; import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.TinyRemapperMappingsHelper; +import net.fabricmc.loom.util.TinyRemapperHelper; import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; public class MinecraftMappedProvider extends DependencyProvider { - private static final Map JSR_TO_JETBRAINS = new ImmutableMap.Builder() - .put("javax/annotation/Nullable", "org/jetbrains/annotations/Nullable") - .put("javax/annotation/Nonnull", "org/jetbrains/annotations/NotNull") - .put("javax/annotation/concurrent/Immutable", "org/jetbrains/annotations/Unmodifiable") - .build(); - private File minecraftMappedJar; private File minecraftIntermediaryJar; @@ -115,11 +107,11 @@ public class MinecraftMappedProvider extends DependencyProvider { Files.deleteIfExists(output); - TinyRemapper remapper = getTinyRemapper(fromM, toM); + TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), fromM, toM); try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { outputConsumer.addNonClassFiles(input); - remapper.readClassPath(getRemapClasspath()); + remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(getProject())); remapper.readInputs(input); remapper.apply(outputConsumer); } catch (Exception e) { @@ -130,20 +122,6 @@ public class MinecraftMappedProvider extends DependencyProvider { } } - public TinyRemapper getTinyRemapper(String fromM, String toM) throws IOException { - return TinyRemapper.newRemapper() - .withMappings(TinyRemapperMappingsHelper.create(getExtension().getMappingsProvider().getMappings(), fromM, toM, true)) - .withMappings(out -> JSR_TO_JETBRAINS.forEach(out::acceptClass)) - .renameInvalidLocals(true) - .rebuildSourceFilenames(true) - .build(); - } - - public Path[] getRemapClasspath() { - return getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles() - .stream().map(File::toPath).toArray(Path[]::new); - } - protected void addDependencies(DependencyInfo dependency, Consumer postPopulationScheduler) { getProject().getDependencies().add(Constants.Configurations.MINECRAFT_NAMED, getProject().getDependencies().module("net.minecraft:minecraft-mapped:" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier())); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 93e8852..0a7b0ca 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -60,6 +60,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA protected final Property remapArchives; protected final Property customManifest; protected final Property setupRemappedVariants; + protected final Property transitiveAccessWideners; private final ModVersionParser versionParser; @@ -81,6 +82,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA this.customManifest = project.getObjects().property(String.class); this.setupRemappedVariants = project.getObjects().property(Boolean.class) .convention(true); + this.transitiveAccessWideners = project.getObjects().property(Boolean.class) + .convention(true); + this.transitiveAccessWideners.finalizeValueOnRead(); this.versionParser = new ModVersionParser(project); @@ -160,6 +164,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return versionParser.getModVersion(); } + @Override + public Property getEnableTransitiveAccessWideners() { + return transitiveAccessWideners; + } + protected abstract Project getProject(); protected abstract LoomFiles getFiles(); diff --git a/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java b/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java index 5b02a7d..4d1e395 100644 --- a/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java @@ -150,4 +150,10 @@ public class MinecraftGradleExtension implements LoomGradleExtensionAPI { reportDeprecation(); throw new UnsupportedOperationException("Use loom extension"); } + + @Override + public Property getEnableTransitiveAccessWideners() { + reportDeprecation(); + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index bd83c79..2fc6b3c 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -66,10 +66,11 @@ import net.fabricmc.loom.build.nesting.NestedDependencyProvider; import net.fabricmc.loom.build.nesting.NestedJarPathProvider; import net.fabricmc.loom.build.nesting.NestedJarProvider; import net.fabricmc.loom.configuration.JarManifestConfiguration; +import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.TinyRemapperMappingsHelper; +import net.fabricmc.loom.util.TinyRemapperHelper; import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.stitch.util.Pair; import net.fabricmc.tinyremapper.TinyRemapper; @@ -137,7 +138,7 @@ public class RemapJarTask extends Jar { if (isMainRemapTask) { jarRemapper.addToClasspath(getRemapClasspath()); - jarRemapper.addMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); + jarRemapper.addMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); } for (File mixinMapFile : extension.getAllMixinMappings()) { @@ -159,15 +160,15 @@ public class RemapJarTask extends Jar { byte[] data; try { - data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper); + data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper, toM); } catch (IOException e) { - throw new RuntimeException("Failed to remap access widener"); + throw new RuntimeException("Failed to remap access widener", e); } - String awPath = accessWidenerJarProcessor.getAccessWidenerPath(remapData.input); - Preconditions.checkNotNull(awPath, "Failed to find accessWidener in fabric.mod.json: " + remapData.input); + AccessWidenerFile awFile = AccessWidenerFile.fromModJar(remapData.input); + Preconditions.checkNotNull(awFile, "Failed to find accessWidener in fabric.mod.json: " + remapData.input); - return Pair.of(awPath, data); + return Pair.of(awFile.name(), data); } return null; @@ -285,7 +286,8 @@ public class RemapJarTask extends Jar { return this; } - @ApiStatus.Experimental // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task. + @ApiStatus.Experimental + // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task. public RemapJarTask include(Object... paths) { Collections.addAll(nestedPaths, paths); this.addNestedDependencies.set(true); diff --git a/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java similarity index 63% rename from src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java rename to src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java index 7470c0f..bec7756 100644 --- a/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java +++ b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2016-2019 FabricMC + * Copyright (c) 2021 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,15 @@ package net.fabricmc.loom.util; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.gradle.api.Project; + +import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.mapping.tree.ClassDef; import net.fabricmc.mapping.tree.FieldDef; import net.fabricmc.mapping.tree.LocalVariableDef; @@ -31,9 +40,36 @@ import net.fabricmc.mapping.tree.MethodDef; import net.fabricmc.mapping.tree.ParameterDef; import net.fabricmc.mapping.tree.TinyTree; import net.fabricmc.tinyremapper.IMappingProvider; +import net.fabricmc.tinyremapper.TinyRemapper; -public class TinyRemapperMappingsHelper { - private TinyRemapperMappingsHelper() { } +/** + * Contains shortcuts to create tiny remappers using the mappings accessibly to the project. + */ +public final class TinyRemapperHelper { + private static final Map JSR_TO_JETBRAINS = new ImmutableMap.Builder() + .put("javax/annotation/Nullable", "org/jetbrains/annotations/Nullable") + .put("javax/annotation/Nonnull", "org/jetbrains/annotations/NotNull") + .put("javax/annotation/concurrent/Immutable", "org/jetbrains/annotations/Unmodifiable") + .build(); + + private TinyRemapperHelper() { + } + + public static TinyRemapper getTinyRemapper(Project project, String fromM, String toM) throws IOException { + LoomGradleExtension extension = LoomGradleExtension.get(project); + + return TinyRemapper.newRemapper() + .withMappings(create(extension.getMappingsProvider().getMappings(), fromM, toM, true)) + .withMappings(out -> JSR_TO_JETBRAINS.forEach(out::acceptClass)) + .renameInvalidLocals(true) + .rebuildSourceFilenames(true) + .build(); + } + + public static Path[] getMinecraftDependencies(Project project) { + return project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles() + .stream().map(File::toPath).toArray(Path[]::new); + } private static IMappingProvider.Member memberOf(String className, String memberName, String descriptor) { return new IMappingProvider.Member(className, memberName, descriptor); @@ -60,8 +96,8 @@ public class TinyRemapperMappingsHelper { for (LocalVariableDef localVariable : method.getLocalVariables()) { acceptor.acceptMethodVar(methodIdentifier, localVariable.getLocalVariableIndex(), - localVariable.getLocalVariableStartOffset(), localVariable.getLocalVariableTableIndex(), - localVariable.getName(to)); + localVariable.getLocalVariableStartOffset(), localVariable.getLocalVariableTableIndex(), + localVariable.getName(to)); } } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/AccessWidenerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/AccessWidenerTest.groovy index 8fed624..43c793c 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/AccessWidenerTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/AccessWidenerTest.groovy @@ -25,6 +25,7 @@ package net.fabricmc.loom.test.integration import net.fabricmc.loom.test.util.GradleProjectTestTrait +import org.zeroturnaround.zip.ZipUtil import spock.lang.Specification import spock.lang.Unroll @@ -48,4 +49,20 @@ class AccessWidenerTest extends Specification implements GradleProjectTestTrait String expected() { new File("src/test/resources/accesswidener/expected.accesswidener").text } + + @Unroll + def "transitive accesswidener (gradle #version)"() { + setup: + def gradle = gradleProject(project: "transitiveAccesswidener", version: version) + ZipUtil.pack(new File(gradle.projectDir, "dummyDependency"), new File(gradle.projectDir, "dummy.jar")) + + when: + def result = gradle.run(task: "build") + + then: + result.task(":build").outcome == SUCCESS + + where: + version << STANDARD_TEST_VERSIONS + } } diff --git a/src/test/resources/accesswidener/expected.accesswidener b/src/test/resources/accesswidener/expected.accesswidener index 53bf68a..66f5542 100644 --- a/src/test/resources/accesswidener/expected.accesswidener +++ b/src/test/resources/accesswidener/expected.accesswidener @@ -1,9 +1,6 @@ accessWidener v1 intermediary -accessible class net/minecraft/class_1928$class_5199 -accessible class net/minecraft/class_1735 -accessible class net/minecraft/class_1928$class_4314 -extendable class net/minecraft/class_1928$class_4314 -accessible class net/minecraft/class_5235$class_5238 accessible method net/minecraft/class_1928$class_4314 (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/class_1928$class_5199;)V extendable method net/minecraft/class_1928$class_4314 (Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/class_1928$class_5199;)V +accessible class net/minecraft/class_1928$class_5199 +accessible class net/minecraft/class_5235$class_5238 accessible field net/minecraft/class_1735 field_7873 I diff --git a/src/test/resources/projects/transitiveAccesswidener/build.gradle b/src/test/resources/projects/transitiveAccesswidener/build.gradle new file mode 100644 index 0000000..52f1fc3 --- /dev/null +++ b/src/test/resources/projects/transitiveAccesswidener/build.gradle @@ -0,0 +1,18 @@ +// This is used by a range of tests that append to this file before running the gradle tasks. +// Can be used for tests that require minimal custom setup +plugins { + id 'fabric-loom' + id 'maven-publish' +} + +archivesBaseName = "fabric-example-mod" +version = "1.0.0" +group = "com.example" + +dependencies { + minecraft "com.mojang:minecraft:1.17.1" + mappings "net.fabricmc:yarn:1.17.1+build.59:v2" + modImplementation "net.fabricmc:fabric-loader:0.11.6" + + modImplementation files("dummy.jar") +} \ No newline at end of file diff --git a/src/test/resources/projects/transitiveAccesswidener/dummyDependency/dummy.accesswidener b/src/test/resources/projects/transitiveAccesswidener/dummyDependency/dummy.accesswidener new file mode 100644 index 0000000..05537ad --- /dev/null +++ b/src/test/resources/projects/transitiveAccesswidener/dummyDependency/dummy.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 intermediary + +transitive-accessible method net/minecraft/class_1972 method_8775 (Ljava/lang/String;)Lnet/minecraft/class_5321; \ No newline at end of file diff --git a/src/test/resources/projects/transitiveAccesswidener/dummyDependency/fabric.mod.json b/src/test/resources/projects/transitiveAccesswidener/dummyDependency/fabric.mod.json new file mode 100644 index 0000000..b89a826 --- /dev/null +++ b/src/test/resources/projects/transitiveAccesswidener/dummyDependency/fabric.mod.json @@ -0,0 +1,7 @@ +{ + "schemaVersion": 1, + "id": "dummy", + "version": "1", + "name": "Dummy Mod", + "accessWidener" : "dummy.accesswidener" +} diff --git a/src/test/resources/projects/transitiveAccesswidener/src/main/java/ExampleMod.java b/src/test/resources/projects/transitiveAccesswidener/src/main/java/ExampleMod.java new file mode 100644 index 0000000..e5442d2 --- /dev/null +++ b/src/test/resources/projects/transitiveAccesswidener/src/main/java/ExampleMod.java @@ -0,0 +1,13 @@ +import net.minecraft.world.biome.BiomeKeys; +import net.minecraft.world.biome.Biome; +import net.minecraft.util.registry.RegistryKey; + +import net.fabricmc.api.ModInitializer; + +public class ExampleMod implements ModInitializer { + @Override + public void onInitialize() { + // BiomeKeys.register has been made public by a transitive AW + RegistryKey biomeRegistryKey = BiomeKeys.register("dummy"); + } +}