Add ability to remap annotations data (#1366)

* Add ability to remap annotations data

* Fix unpick remap test
This commit is contained in:
Joseph Burton
2025-09-20 13:17:37 +01:00
committed by GitHub
parent 2e24e358ea
commit 213bbfcd18
13 changed files with 496 additions and 39 deletions

View File

@@ -134,13 +134,13 @@ public record LayeredMappingsFactory(LayeredMappingSpec spec) {
}
private void writeAnnotationData(LayeredMappingsProcessor processor, List<MappingLayer> layers, Path mappingsFile) throws IOException {
AnnotationsData annotationsData = processor.getAnnotationsData(layers);
List<AnnotationsData> annotationsData = processor.getAnnotationsData(layers);
if (annotationsData == null) {
if (annotationsData.isEmpty()) {
return;
}
byte[] data = AnnotationsData.GSON.toJson(annotationsData.toJson()).getBytes(StandardCharsets.UTF_8);
byte[] data = AnnotationsData.GSON.toJson(AnnotationsData.listToJson(annotationsData)).getBytes(StandardCharsets.UTF_8);
ZipUtils.add(mappingsFile, AnnotationsLayer.ANNOTATIONS_PATH, data);
}

View File

@@ -119,20 +119,15 @@ public class LayeredMappingsProcessor {
return mappingTree;
}
@Nullable
public AnnotationsData getAnnotationsData(List<MappingLayer> layers) throws IOException {
AnnotationsData result = null;
public List<AnnotationsData> getAnnotationsData(List<MappingLayer> layers) throws IOException {
List<AnnotationsData> result = new ArrayList<>();
for (MappingLayer layer : layers) {
if (layer instanceof AnnotationsLayer annotationsLayer) {
AnnotationsData annotationsData = annotationsLayer.getAnnotationsData();
if (annotationsData != null) {
if (result == null) {
result = annotationsData;
} else {
result = result.merge(annotationsData);
}
result.add(annotationsData);
}
}
}

View File

@@ -77,8 +77,7 @@ public class MappingConfiguration {
public final Path tinyMappingsJar;
private final Path unpickDefinitions;
@Nullable
private AnnotationsData annotationsData;
private List<AnnotationsData> annotationsData = List.of();
@Nullable
private UnpickMetadata unpickMetadata;
private Map<String, String> signatureFixes;
@@ -233,7 +232,7 @@ public class MappingConfiguration {
}
try (BufferedReader reader = Files.newBufferedReader(annotationsPath, StandardCharsets.UTF_8)) {
annotationsData = AnnotationsData.read(reader);
annotationsData = AnnotationsData.readList(reader);
}
}
@@ -312,8 +311,7 @@ public class MappingConfiguration {
return unpickMetadata != null;
}
@Nullable
public AnnotationsData getAnnotationsData() {
public List<AnnotationsData> getAnnotationsData() {
return annotationsData;
}

View File

@@ -24,19 +24,35 @@
package net.fabricmc.loom.configuration.providers.mappings.extras.annotations;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.commons.AnnotationRemapper;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.TypeAnnotationNode;
public record AnnotationsData(Map<String, ClassAnnotationData> classes) {
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.tinyremapper.TinyRemapper;
public record AnnotationsData(Map<String, ClassAnnotationData> classes, String namespace) {
public static final Gson GSON = new GsonBuilder()
.disableHtmlEscaping()
.setFieldNamingStrategy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
@@ -45,34 +61,139 @@ public record AnnotationsData(Map<String, ClassAnnotationData> classes) {
.registerTypeAdapter(AnnotationNode.class, new AnnotationNodeSerializer())
.registerTypeAdapterFactory(new SkipEmptyTypeAdapterFactory())
.create();
private static final Type LIST_TYPE = new TypeToken<List<AnnotationNode>>() { }.getType();
private static final int CURRENT_VERSION = 1;
public AnnotationsData {
if (namespace == null) {
namespace = MappingsNamespace.NAMED.toString();
}
}
public static AnnotationsData read(Reader reader) {
JsonObject json = GSON.fromJson(reader, JsonObject.class);
checkVersion(json);
return GSON.fromJson(json, AnnotationsData.class);
}
public static List<AnnotationsData> readList(Reader reader) {
JsonObject json = GSON.fromJson(reader, JsonObject.class);
checkVersion(json);
JsonElement values = json.get("values");
if (values == null || values.isJsonNull()) {
return List.of(GSON.fromJson(json, AnnotationsData.class));
}
return GSON.fromJson(values, LIST_TYPE);
}
private static void checkVersion(JsonObject json) {
if (!json.has("version")) {
throw new JsonSyntaxException("Missing annotations version");
}
int version = json.getAsJsonPrimitive("version").getAsInt();
if (version != 1) {
if (version != CURRENT_VERSION) {
throw new JsonSyntaxException("Invalid annotations version " + version + ". Try updating loom");
}
return GSON.fromJson(json, AnnotationsData.class);
}
public JsonObject toJson() {
JsonObject json = GSON.toJsonTree(this).getAsJsonObject();
JsonObject result = new JsonObject();
result.addProperty("version", 1);
result.addProperty("version", CURRENT_VERSION);
result.asMap().putAll(json.asMap());
return result;
}
public static JsonObject listToJson(List<AnnotationsData> annotationsData) {
if (annotationsData.size() == 1) {
return annotationsData.getFirst().toJson();
}
JsonObject result = new JsonObject();
result.addProperty("version", CURRENT_VERSION);
result.add("values", GSON.toJsonTree(annotationsData));
return result;
}
public AnnotationsData merge(AnnotationsData other) {
if (!namespace.equals(other.namespace)) {
throw new IllegalArgumentException("Cannot merge annotations from namespace " + other.namespace + " into annotations from namespace " + this.namespace);
}
Map<String, ClassAnnotationData> newClassData = new LinkedHashMap<>(classes);
other.classes.forEach((key, value) -> newClassData.merge(key, value, ClassAnnotationData::merge));
return new AnnotationsData(newClassData);
return new AnnotationsData(newClassData, namespace);
}
public AnnotationsData remap(TinyRemapper remapper, String newNamespace) {
return new AnnotationsData(
remapMap(
classes,
entry -> remapper.getEnvironment().getRemapper().map(entry.getKey()),
entry -> entry.getValue().remap(entry.getKey(), remapper)
),
newNamespace
);
}
static AnnotationNode remap(AnnotationNode node, TinyRemapper remapper) {
AnnotationNode remapped = new AnnotationNode(remapper.getEnvironment().getRemapper().mapDesc(node.desc));
node.accept(new AnnotationRemapper(node.desc, remapped, remapper.getEnvironment().getRemapper()));
return remapped;
}
static TypeAnnotationNode remap(TypeAnnotationNode node, TinyRemapper remapper) {
TypeAnnotationNode remapped = new TypeAnnotationNode(node.typeRef, node.typePath, remapper.getEnvironment().getRemapper().mapDesc(node.desc));
node.accept(new AnnotationRemapper(node.desc, remapped, remapper.getEnvironment().getRemapper()));
return remapped;
}
static <K, V> Map<K, V> remapMap(Map<K, V> map, Function<Map.Entry<K, V>, K> keyRemapper, Function<Map.Entry<K, V>, V> valueRemapper) {
Map<K, V> result = LinkedHashMap.newLinkedHashMap(map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
if (result.put(keyRemapper.apply(entry), valueRemapper.apply(entry)) != null) {
throw new IllegalStateException("Remapping annotations resulted in duplicate key: " + keyRemapper.apply(entry));
}
}
return result;
}
@Nullable
public static AnnotationsData getRemappedAnnotations(MappingsNamespace targetNamespace, MappingConfiguration mappingConfiguration, Project project, ServiceFactory serviceFactory, String newNamespace) throws IOException {
List<AnnotationsData> datas = mappingConfiguration.getAnnotationsData();
if (datas.isEmpty()) {
return null;
}
Map<String, TinyRemapper> existingRemappers = new HashMap<>();
AnnotationsData result = datas.getFirst().remap(targetNamespace, project, serviceFactory, newNamespace, existingRemappers);
for (int i = 1; i < datas.size(); i++) {
result = result.merge(datas.get(i).remap(targetNamespace, project, serviceFactory, newNamespace, existingRemappers));
}
return result;
}
private AnnotationsData remap(MappingsNamespace targetNamespace, Project project, ServiceFactory serviceFactory, String newNamespace, Map<String, TinyRemapper> existingRemappers) throws IOException {
if (namespace.equals(targetNamespace.toString())) {
return this;
}
TinyRemapper remapper = existingRemappers.get(namespace);
if (remapper == null) {
remapper = TinyRemapperHelper.getTinyRemapper(project, serviceFactory, namespace, newNamespace);
existingRemappers.put(namespace, remapper);
}
return remap(remapper, newNamespace);
}
}

View File

@@ -30,6 +30,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.gson.annotations.SerializedName;
import org.jetbrains.annotations.Nullable;
@@ -37,6 +38,9 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.TypeAnnotationNode;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.api.TrRemapper;
public record ClassAnnotationData(
@SerializedName("remove")
Set<String> annotationsToRemove,
@@ -90,6 +94,49 @@ public record ClassAnnotationData(
return new ClassAnnotationData(newAnnotationsToRemove, newAnnotationsToAdd, newTypeAnnotationsToRemove, newTypeAnnotationsToAdd, newFields, newMethods);
}
ClassAnnotationData remap(String className, TinyRemapper remapper) {
return new ClassAnnotationData(
annotationsToRemove.stream().map(remapper.getEnvironment().getRemapper()::map).collect(Collectors.toCollection(LinkedHashSet::new)),
annotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new)),
typeAnnotationsToRemove.stream().map(key -> key.remap(remapper)).collect(Collectors.toCollection(LinkedHashSet::new)),
typeAnnotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new)),
AnnotationsData.remapMap(
fields,
entry -> remapField(className, entry.getKey(), remapper),
entry -> entry.getValue().remap(remapper)
),
AnnotationsData.remapMap(
methods,
entry -> remapMethod(className, entry.getKey(), remapper),
entry -> entry.getValue().remap(remapper)
)
);
}
private static String remapField(String className, String field, TinyRemapper remapper) {
String[] nameDesc = field.split(":", 2);
if (nameDesc.length != 2) {
return field;
}
TrRemapper trRemapper = remapper.getEnvironment().getRemapper();
return trRemapper.mapFieldName(className, nameDesc[0], nameDesc[1]) + ":" + trRemapper.mapDesc(nameDesc[1]);
}
private static String remapMethod(String className, String method, TinyRemapper remapper) {
int parenIndex = method.indexOf('(');
if (parenIndex == -1) {
return method;
}
String name = method.substring(0, parenIndex);
String desc = method.substring(parenIndex);
TrRemapper trRemapper = remapper.getEnvironment().getRemapper();
return trRemapper.mapMethodName(className, name, desc) + trRemapper.mapMethodDesc(desc);
}
public int modifyAccessFlags(int access) {
if (annotationsToRemove.contains("java/lang/Deprecated")) {
access &= ~Opcodes.ACC_DEPRECATED;

View File

@@ -28,12 +28,15 @@ import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.gson.annotations.SerializedName;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.TypeAnnotationNode;
import net.fabricmc.tinyremapper.TinyRemapper;
public record GenericAnnotationData(
@SerializedName("remove")
Set<String> annotationsToRemove,
@@ -74,6 +77,15 @@ public record GenericAnnotationData(
return new GenericAnnotationData(newAnnotationToRemove, newAnnotationsToAdd, newTypeAnnotationsToRemove, newTypeAnnotationsToAdd);
}
GenericAnnotationData remap(TinyRemapper remapper) {
return new GenericAnnotationData(
annotationsToRemove.stream().map(remapper.getEnvironment().getRemapper()::map).collect(Collectors.toCollection(LinkedHashSet::new)),
annotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new)),
typeAnnotationsToRemove.stream().map(key -> key.remap(remapper)).collect(Collectors.toCollection(LinkedHashSet::new)),
typeAnnotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new))
);
}
public int modifyAccessFlags(int access) {
if (annotationsToRemove.contains("java/lang/Deprecated")) {
access &= ~Opcodes.ACC_DEPRECATED;

View File

@@ -30,12 +30,15 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.gson.annotations.SerializedName;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.TypeAnnotationNode;
import net.fabricmc.tinyremapper.TinyRemapper;
public record MethodAnnotationData(
@SerializedName("remove")
Set<String> annotationsToRemove,
@@ -83,6 +86,20 @@ public record MethodAnnotationData(
return new MethodAnnotationData(newAnnotationsToRemove, newAnnotationsToAdd, newTypeAnnotationsToRemove, newTypeAnnotationsToAdd, newParameters);
}
MethodAnnotationData remap(TinyRemapper remapper) {
return new MethodAnnotationData(
annotationsToRemove.stream().map(remapper.getEnvironment().getRemapper()::map).collect(Collectors.toCollection(LinkedHashSet::new)),
annotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new)),
typeAnnotationsToRemove.stream().map(key -> key.remap(remapper)).collect(Collectors.toCollection(LinkedHashSet::new)),
typeAnnotationsToAdd.stream().map(ann -> AnnotationsData.remap(ann, remapper)).collect(Collectors.toCollection(ArrayList::new)),
AnnotationsData.remapMap(
parameters,
Map.Entry::getKey,
entry -> entry.getValue().remap(remapper)
)
);
}
public int modifyAccessFlags(int access) {
if (annotationsToRemove.contains("java/lang/Deprecated")) {
access &= ~Opcodes.ACC_DEPRECATED;

View File

@@ -24,5 +24,10 @@
package net.fabricmc.loom.configuration.providers.mappings.extras.annotations;
import net.fabricmc.tinyremapper.TinyRemapper;
public record TypeAnnotationKey(int typeRef, String typePath, String name) {
TypeAnnotationKey remap(TinyRemapper remapper) {
return new TypeAnnotationKey(typeRef, typePath, remapper.getEnvironment().getRemapper().map(name));
}
}

View File

@@ -244,15 +244,14 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
Files.deleteIfExists(remappedJars.outputJarPath());
final AnnotationsData remappedAnnotations = AnnotationsData.getRemappedAnnotations(getTargetNamespace(), mappingConfiguration, getProject(), configContext.serviceFactory(), toM);
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingConfiguration, getProject(), configContext.serviceFactory(), toM);
final MinecraftVersionMeta.JavaVersion javaVersion = minecraftProvider.getVersionInfo().javaVersion();
final boolean fixRecords = javaVersion != null && javaVersion.majorVersion() >= 16;
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceFactory(), fromM, toM, fixRecords, (builder) -> {
AnnotationsData annotationsData = mappingConfiguration.getAnnotationsData();
if (annotationsData != null) {
builder.extraPostApplyVisitor(new AnnotationsApplyVisitor(annotationsData));
if (remappedAnnotations != null) {
builder.extraPostApplyVisitor(new AnnotationsApplyVisitor(remappedAnnotations));
}
builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures));

View File

@@ -0,0 +1,259 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2025 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.test.unit.layeredmappings
import org.intellij.lang.annotations.Language
import spock.lang.Specification
import net.fabricmc.loom.configuration.providers.mappings.extras.annotations.AnnotationsData
import net.fabricmc.loom.test.unit.service.mocks.MockTinyRemapper
import net.fabricmc.tinyremapper.api.TrClass
import net.fabricmc.tinyremapper.api.TrField
import net.fabricmc.tinyremapper.api.TrMethod
import static org.mockito.Mockito.*
class AnnotationsDataRemapTest extends Specification {
def "remap annotations data"() {
given:
def reader = new BufferedReader(new StringReader(ANNOTATIONS))
def annotationsData = AnnotationsData.read(reader)
def mockTr = new MockTinyRemapper()
when(mockTr.remapper.map("pkg/Foo")).thenReturn("mapped/pkg/FooMapped")
when(mockTr.remapper.map("pkg/Bar")).thenReturn("mapped/pkg/BarMapped")
when(mockTr.remapper.map("pkg/Annotation1")).thenReturn("mapped/pkg/Annotation1Mapped")
when(mockTr.remapper.map("pkg/Annotation2")).thenReturn("mapped/pkg/Annotation2Mapped")
when(mockTr.remapper.map("pkg/Annotation3")).thenReturn("mapped/pkg/Annotation3Mapped")
when(mockTr.remapper.map("pkg/Annotation4")).thenReturn("mapped/pkg/Annotation4Mapped")
when(mockTr.remapper.map("pkg/Annotation5")).thenReturn("mapped/pkg/Annotation5Mapped")
when(mockTr.remapper.map("pkg/Annotation6")).thenReturn("mapped/pkg/Annotation6Mapped")
when(mockTr.remapper.map("pkg/Annotation7")).thenReturn("mapped/pkg/Annotation7Mapped")
when(mockTr.remapper.map("pkg/Annotation8")).thenReturn("mapped/pkg/Annotation8Mapped")
when(mockTr.remapper.map("pkg/MyEnum")).thenReturn("mapped/pkg/MyEnumMapped")
when(mockTr.remapper.map("baz")).thenReturn("mapped/baz")
when(mockTr.remapper.mapFieldName("pkg/Foo", "bar", "Lbaz;")).thenReturn("barRenamed")
when(mockTr.remapper.mapMethodName("pkg/Foo", "bar", "()V")).thenReturn("barMethodRenamed")
def mockClass = mock(TrClass.class)
when(mockTr.trEnvironment.getClass("pkg/Foo")).thenReturn(mockClass)
def mockField = mock(TrField.class)
when(mockField.name).thenReturn("bar")
when(mockField.desc).thenReturn("Lbaz;")
when(mockClass.fields).thenReturn([mockField])
def mockMethod = mock(TrMethod.class)
when(mockMethod.name).thenReturn("bar")
when(mockMethod.desc).thenReturn("()V")
when(mockClass.methods).thenReturn([mockMethod])
when:
def remapped = annotationsData.remap(mockTr.tinyRemapper, "mapped")
then:
def json = AnnotationsData.GSON.newBuilder()
.setPrettyPrinting()
.create()
.toJson(remapped.toJson())
.replace(" ", "\t")
json == REMAPPED_ANNOTATIONS.trim()
}
@Language("JSON")
private static final String ANNOTATIONS = """
{
"version": 1,
"classes": {
"pkg/Foo": {
"remove": [
"pkg/Annotation1",
"pkg/Annotation2",
"pkg/Annotation3"
],
"add": [
{
"desc": "Lpkg/Annotation4;"
},
{
"desc": "Lpkg/Annotation5;",
"values": {
"foo": {
"type": "int",
"value": 42
},
"bar": {
"type": "class",
"value": "Ljava/lang/String;"
},
"baz": {
"type": "enum_constant",
"owner": "Lpkg/MyEnum;",
"name": "VALUE"
},
"ann": {
"type": "annotation",
"desc": "Lpkg/Annotation6;"
},
"arr": {
"type": "array",
"value": [
{
"type": "int",
"value": 1
},
{
"type": "int",
"value": 2
}
]
}
}
}
],
"type_add": [
{
"desc": "Lpkg/Annotation7;",
"type_ref": 22,
"type_path": "["
}
],
"fields": {
"bar:Lbaz;": {
"remove": [
"pkg/Annotation8"
]
}
},
"methods": {
"bar()V": {
"remove": [
"pkg/Annotation8"
]
}
}
},
"pkg/Bar": {
"add": [
{
"desc": "Lpkg/Annotation1;"
}
]
}
},
"namespace": "someNamespace"
}
"""
@Language("JSON")
private static final String REMAPPED_ANNOTATIONS = """
{
"version": 1,
"classes": {
"mapped/pkg/FooMapped": {
"remove": [
"mapped/pkg/Annotation1Mapped",
"mapped/pkg/Annotation2Mapped",
"mapped/pkg/Annotation3Mapped"
],
"add": [
{
"desc": "Lmapped/pkg/Annotation4Mapped;"
},
{
"desc": "Lmapped/pkg/Annotation5Mapped;",
"values": {
"foo": {
"type": "int",
"value": 42
},
"bar": {
"type": "class",
"value": "Ljava/lang/String;"
},
"baz": {
"type": "enum_constant",
"owner": "Lmapped/pkg/MyEnumMapped;",
"name": "VALUE"
},
"ann": {
"type": "annotation",
"desc": "Lmapped/pkg/Annotation6Mapped;"
},
"arr": {
"type": "array",
"value": [
{
"type": "int",
"value": 1
},
{
"type": "int",
"value": 2
}
]
}
}
}
],
"type_add": [
{
"desc": "Lmapped/pkg/Annotation7Mapped;",
"type_ref": 22,
"type_path": "["
}
],
"fields": {
"barRenamed:Lmapped/baz;": {
"remove": [
"mapped/pkg/Annotation8Mapped"
]
}
},
"methods": {
"barMethodRenamed()V": {
"remove": [
"mapped/pkg/Annotation8Mapped"
]
}
}
},
"mapped/pkg/BarMapped": {
"add": [
{
"desc": "Lmapped/pkg/Annotation1Mapped;"
}
]
}
},
"namespace": "mapped"
}
"""
}

View File

@@ -44,11 +44,11 @@ class AnnotationsLayerTest extends Specification {
"pkg/Annotation2",
"pkg/Annotation3"
] as Set
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[0].desc == "pkg/Annotation4"
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[0].desc == "Lpkg/Annotation4;"
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[1] == 42
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[3] == Type.getType("Ljava/lang/String;")
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[5] == ["pkg/MyEnum", "VALUE"] as String[]
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[7] instanceof AnnotationNode && annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[7].desc == "pkg/Annotation6"
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[5] == ["Lpkg/MyEnum;", "VALUE"] as String[]
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[7] instanceof AnnotationNode && annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[7].desc == "Lpkg/Annotation6;"
annotationsData.classes()["pkg/Foo"].annotationsToAdd()[1].values[9] == [1, 2]
annotationsData.classes()["pkg/Foo"].typeAnnotationsToAdd()[0].typePath.toString() == "["
annotationsData.classes()["pkg/Foo"].fields().keySet().first() == "bar:Lbaz;"
@@ -83,10 +83,10 @@ class AnnotationsLayerTest extends Specification {
],
"add": [
{
"desc": "pkg/Annotation4"
"desc": "Lpkg/Annotation4;"
},
{
"desc": "pkg/Annotation5",
"desc": "Lpkg/Annotation5;",
"values": {
"foo": {
"type": "int",
@@ -98,12 +98,12 @@ class AnnotationsLayerTest extends Specification {
},
"baz": {
"type": "enum_constant",
"owner": "pkg/MyEnum",
"owner": "Lpkg/MyEnum;",
"name": "VALUE"
},
"ann": {
"type": "annotation",
"desc": "pkg/Annotation6"
"desc": "Lpkg/Annotation6;"
},
"arr": {
"type": "array",
@@ -123,7 +123,7 @@ class AnnotationsLayerTest extends Specification {
],
"type_add": [
{
"desc": "pkg/Annotation7",
"desc": "Lpkg/Annotation7;",
"type_ref": 22,
"type_path": "["
}
@@ -146,11 +146,12 @@ class AnnotationsLayerTest extends Specification {
"pkg/Bar": {
"add": [
{
"desc": "pkg/Annotation1"
"desc": "Lpkg/Annotation1;"
}
]
}
}
},
"namespace": "someNamespace"
}
"""
}

View File

@@ -24,17 +24,20 @@
package net.fabricmc.loom.test.unit.service.mocks
import org.mockito.Answers
import net.fabricmc.tinyremapper.TinyRemapper
import net.fabricmc.tinyremapper.api.TrEnvironment
import net.fabricmc.tinyremapper.api.TrRemapper
import static org.mockito.Mockito.mock
import static org.mockito.Mockito.when
import static org.mockito.Mockito.withSettings
class MockTinyRemapper {
TinyRemapper tinyRemapper = mock(TinyRemapper.class)
TrEnvironment trEnvironment = mock(TrEnvironment.class)
TrRemapper remapper = mock(TrRemapper.class)
TrRemapper remapper = mock(TrRemapper.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS))
MockTinyRemapper() {
when(tinyRemapper.getEnvironment()).thenReturn(trEnvironment)

View File

@@ -2,7 +2,7 @@ unpick v3
target_field mapped.bar.Y quux I g
target_field mapped.bar.Z null Lmapped/foo/X; g
target_field mapped.bar.Z foo Lmapped/foo/X; g
target_method mapped.bar.Y bar2 (Lmapped/foo/X;)V
@@ -13,7 +13,7 @@ group float
mapped.bar.Y.quux:int
group float
mapped.bar.Y.*:float
mapped.bar.Y.baz:float
group int
@scope class mapped.bar.Y