Migrate to mapping io, use spotless
still need to work on inner class handling, need named jar inspection first
This commit is contained in:
liach 2023-05-05 17:04:07 -05:00
parent f07ce4727a
commit 40a0d19ade
19 changed files with 203 additions and 232 deletions

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import com.squareup.javapoet.AnnotationSpec;
@ -24,7 +23,6 @@ import com.squareup.javapoet.TypeVariableName;
import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors;
import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures;
import net.fabricmc.mappingpoet.signature.ClassSignature;
import net.fabricmc.mappingpoet.signature.ClassStaticContext;
import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping;
import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage;
import org.objectweb.asm.Handle;
@ -40,10 +38,7 @@ import org.objectweb.asm.tree.MethodNode;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation;
@ -61,9 +56,7 @@ public class ClassBuilder {
private final TypeSpec.Builder builder;
private final List<ClassBuilder> innerClasses = new ArrayList<>();
private final Function<String, Collection<String>> superGetter;
private final Predicate<String> sealChecker;
private final ClassStaticContext context;
private final Environment environment;
private final ClassSignature signature; // not really signature
private final TypeAnnotationMapping typeAnnotations;
@ -75,12 +68,10 @@ public class ClassBuilder {
// omits L and ;
private String receiverSignature;
public ClassBuilder(MappingsStore mappings, ClassNode classNode, Function<String, Collection<String>> superGetter, Predicate<String> sealChecker, ClassStaticContext context) {
public ClassBuilder(MappingsStore mappings, ClassNode classNode, Environment environment) {
this.mappings = mappings;
this.classNode = classNode;
this.superGetter = superGetter;
this.sealChecker = sealChecker;
this.context = context;
this.environment = environment;
this.typeAnnotations = setupAnnotations();
this.signature = setupSignature();
this.builder = setupBuilder();
@ -141,8 +132,8 @@ public class ClassBuilder {
private ClassSignature setupSignature() {
return classNode.signature == null ?
AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, context) :
AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, context);
AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment) :
AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment);
}
private TypeSpec.Builder setupBuilder() {
@ -180,7 +171,7 @@ public class ClassBuilder {
return builder
.addModifiers(new ModifierBuilder(classNode.access)
.checkUnseal(classNode, sealChecker)
.checkUnseal(classNode, environment)
.getModifiers(ModifierBuilder.getType(enumClass, recordClass))
);
}
@ -258,7 +249,7 @@ public class ClassBuilder {
formalParamStartIndex = 1; // 0 this$0
}
}
builder.addMethod(new MethodBuilder(mappings, classNode, method, superGetter, context, receiverSignature, formalParamStartIndex).build());
builder.addMethod(new MethodBuilder(mappings, classNode, method, environment, receiverSignature, formalParamStartIndex).build());
}
}
@ -270,7 +261,7 @@ public class ClassBuilder {
if (!Modifier.isFinal(field.access) || Modifier.isProtected(field.access) || Modifier.isPublic(field.access)) {
System.out.println("abnormal instance field " + field.name + " in record " + getClassName() + ", skipping");
} else {
var fieldBuilder = new FieldBuilder(mappings, classNode, field, context);
var fieldBuilder = new FieldBuilder(mappings, classNode, field, environment);
var paramBuilder = ParameterSpec.builder(fieldBuilder.calculateType(), field.name);
fieldBuilder.addJavaDoc(paramBuilder);
fieldBuilder.addDirectAnnotations(paramBuilder);
@ -283,7 +274,7 @@ public class ClassBuilder {
continue; // hide synthetic stuff
}
if ((field.access & Opcodes.ACC_ENUM) == 0) {
builder.addField(new FieldBuilder(mappings, classNode, field, context).build());
builder.addField(new FieldBuilder(mappings, classNode, field, environment).build());
} else {
TypeSpec.Builder enumBuilder = TypeSpec.anonymousClassBuilder("");
// jd
@ -347,7 +338,7 @@ public class ClassBuilder {
classBuilder.builder.modifiers.remove(javax.lang.model.element.Modifier.PUBLIC); // this modifier may come from class access
classBuilder.builder.addModifiers(new ModifierBuilder(innerClassNode.access)
.checkUnseal(classBuilder.classNode, sealChecker)
.checkUnseal(classBuilder.classNode, environment)
.getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass))
);
if (!Modifier.isStatic(innerClassNode.access)) {

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import com.squareup.javapoet.ClassName;
import net.fabricmc.mappingpoet.signature.ClassStaticContext;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Represents an overall runtime environment, knows all inner class,
* super class, etc. information.
*/
public record Environment(
Map<String, Collection<String>> superTypes,
Set<String> sealedClasses,
// declaring classes keep track of namable inner classes
// and local/anon classes in whole codebase
Map<String, NestedClassInfo> declaringClasses
) implements ClassStaticContext {
public record NestedClassInfo(String declaringClass, boolean instanceInner, String simpleName) {
// two strings are nullable
}
public record ClassNamePointer(String simple, String outerClass) {
public ClassName toClassName(ClassName outerClassName) {
if (simple == null)
return null;
return outerClassName.nestedClass(simple);
}
}
@Override
public boolean isInstanceInner(String internalName) {
var info = declaringClasses.get(internalName);
return info != null && info.declaringClass != null && info.instanceInner;
}
}

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import com.squareup.javapoet.AnnotationSpec;
@ -24,7 +23,6 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import net.fabricmc.mapping.util.EntryTriple;
import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors;
import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures;
import net.fabricmc.mappingpoet.signature.ClassStaticContext;
@ -69,7 +67,7 @@ public class FieldBuilder {
}
static void addFieldJavaDoc(TypeSpec.Builder enumBuilder, MappingsStore mappings, ClassNode classNode, FieldNode fieldNode) {
mappings.addFieldDoc(enumBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc));
mappings.addFieldDoc(enumBuilder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc);
}
public static AnnotationSpec parseAnnotation(AnnotationNode annotation) {
@ -468,11 +466,11 @@ public class FieldBuilder {
}
private void addJavaDoc() {
mappings.addFieldDoc(builder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc));
mappings.addFieldDoc(builder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc);
}
void addJavaDoc(ParameterSpec.Builder paramBuilder) {
mappings.addFieldDoc(paramBuilder::addJavadoc, new EntryTriple(classNode.name, fieldNode.name, fieldNode.desc));
mappings.addFieldDoc(paramBuilder::addJavadoc, classNode.name, fieldNode.name, fieldNode.desc);
}
private void addDirectAnnotations() {

View File

@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import net.fabricmc.mappingpoet.Environment.ClassNamePointer;
import net.fabricmc.mappingpoet.Environment.NestedClassInfo;
import net.fabricmc.mappingpoet.signature.ClassStaticContext;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
@ -37,7 +39,6 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
@ -46,8 +47,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -65,15 +64,16 @@ public class Main {
try {
if (Files.exists(outputDirectory)) {
Files.walk(outputDirectory)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
try (var stream = Files.walk(outputDirectory)) {
stream.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
Files.createDirectories(outputDirectory);
} catch (IOException e) {
e.printStackTrace();
throw new UncheckedIOException(e);
}
if (!Files.exists(mappings)) {
@ -92,7 +92,7 @@ public class Main {
public static void generate(Path mappings, Path inputJar, Path outputDirectory, Path librariesDir) {
final MappingsStore mapping = new MappingsStore(mappings);
Map<String, ClassBuilder> classes = new HashMap<>();
forEachClass(inputJar, (superGetter, classNode, context, sealChecker) -> writeClass(mapping, classNode, classes, superGetter, sealChecker, context), librariesDir);
forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), librariesDir);
classes.values().stream()
.filter(classBuilder -> !classBuilder.getClassName().contains("$"))
@ -115,10 +115,11 @@ public class Main {
Map<String, Collection<String>> supers = new HashMap<>();
Set<String> sealedClasses = new HashSet<>(); // their subclsses/impls need non-sealed modifier
Map<String, Boolean> instanceInnerClasses = new ConcurrentHashMap<>();
Map<String, Environment.NestedClassInfo> nestedClasses = new ConcurrentHashMap<>();
Map<String, ClassNamePointer> classNames = new ConcurrentHashMap<>();
if (librariesDir != null) {
scanInnerClasses(instanceInnerClasses, librariesDir);
scanNestedClasses(classNames, nestedClasses, librariesDir);
}
try (final JarFile jarFile = new JarFile(jar.toFile())) {
@ -148,7 +149,10 @@ public class Main {
if (classNode.innerClasses != null) {
for (InnerClassNode e : classNode.innerClasses) {
instanceInnerClasses.put(e.name, !Modifier.isStatic(e.access));
if (e.outerName != null) {
// null -> declared in method/initializer
nestedClasses.put(e.name, new NestedClassInfo(e.outerName, !Modifier.isStatic(e.access), e.innerName));
}
}
}
@ -166,12 +170,10 @@ public class Main {
//Sort all the classes making sure that inner classes come after the parent classes
classes.sort(Comparator.comparing(o -> o.name));
ClassStaticContext innerClassContext = new InnerClassStats(instanceInnerClasses);
Function<String, Collection<String>> superGetter = k -> supers.getOrDefault(k, Collections.emptyList());
classes.forEach(node -> classNodeConsumer.accept(superGetter, node, innerClassContext, sealedClasses::contains));
classes.forEach(node -> classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses)));
}
private static void scanInnerClasses(Map<String, Boolean> instanceInnerClasses, Path librariesDir) {
private static void scanNestedClasses(Map<String, ClassNamePointer> classNames, Map<String, Environment.NestedClassInfo> instanceInnerClasses, Path librariesDir) {
try {
Files.walkFileTree(librariesDir, new SimpleFileVisitor<>() {
@Override
@ -194,8 +196,11 @@ public class Main {
ClassReader reader = new ClassReader(is);
reader.accept(new ClassVisitor(Opcodes.ASM8) {
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
instanceInnerClasses.put(name, !Modifier.isStatic(access));
public void visitInnerClass(String name, String outerName, String simpleName, int access) {
instanceInnerClasses.put(name, new Environment.NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName));
if (outerName != null) {
classNames.put(name, new ClassNamePointer(simpleName, outerName));
}
}
}, ClassReader.SKIP_CODE);
}
@ -225,7 +230,8 @@ public class Main {
return ch >= '0' && ch <= '9';
}
private static void writeClass(MappingsStore mappings, ClassNode classNode, Map<String, ClassBuilder> existingClasses, Function<String, Collection<String>> superGetter, Predicate<String> sealChecker, ClassStaticContext context) {
private static void writeClass(MappingsStore mappings, ClassNode classNode, Map<String, ClassBuilder> existingClasses, Environment environment) {
// TODO make sure named jar has valid InnerClasses, use that info instead
String name = classNode.name;
{
//Block anonymous class and their nested classes
@ -239,7 +245,8 @@ public class Main {
}
}
ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, superGetter, sealChecker, context);
// TODO: ensure InnerClasses is remapped, and create ClassName from parent class name
ClassBuilder classBuilder = new ClassBuilder(mappings, classNode, environment);
if (name.contains("$")) {
String parentClass = name.substring(0, name.lastIndexOf("$"));
@ -256,23 +263,6 @@ public class Main {
@FunctionalInterface
private interface ClassNodeConsumer {
void accept(Function<String, Collection<String>> superGetter, ClassNode node, ClassStaticContext staticContext, Predicate<String> sealedChecker);
}
private static final class InnerClassStats implements ClassStaticContext {
final Map<String, Boolean> instanceInnerClasses;
InnerClassStats(Map<String, Boolean> instanceInnerClasses) {
this.instanceInnerClasses = instanceInnerClasses;
}
@Override
public boolean isInstanceInner(String internalName) {
if (internalName.indexOf('$') == -1) {
return false; // heuristics
}
return instanceInnerClasses.computeIfAbsent(internalName, Main::isInstanceInnerOnClasspath);
}
void accept(ClassNode node, Environment environment);
}
}

View File

@ -13,71 +13,46 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import java.io.BufferedReader;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.tree.MappingTreeView;
import net.fabricmc.mappingio.tree.MappingTreeView.ClassMappingView;
import net.fabricmc.mappingio.tree.MappingTreeView.ElementMappingView;
import net.fabricmc.mappingio.tree.MappingTreeView.MethodMappingView;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mapping.tree.Mapped;
import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mapping.tree.TinyMappingFactory;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mapping.util.EntryTriple;
import static net.fabricmc.mappingio.tree.MappingTreeView.SRC_NAMESPACE_ID;
//Taken from loom
public class MappingsStore {
private final Map<String, ClassDef> classes = new HashMap<>();
private final Map<EntryTriple, FieldDef> fields = new HashMap<>();
private final Map<EntryTriple, Map.Entry<String, MethodDef>> methods = new HashMap<>();
private final String namespace = "named";
private final List<String> namespaces;
private final MappingTreeView tree;
private final int maxNamespace;
public MappingsStore(Path tinyFile) {
final TinyTree mappings = readMappings(tinyFile);
namespaces = mappings.getMetadata().getNamespaces();
for (ClassDef classDef : mappings.getClasses()) {
final String className = classDef.getName(namespace);
classes.put(className, classDef);
for (FieldDef fieldDef : classDef.getFields()) {
fields.put(new EntryTriple(className, fieldDef.getName(namespace), fieldDef.getDescriptor(namespace)), fieldDef);
}
for (MethodDef methodDef : classDef.getMethods()) {
methods.put(new EntryTriple(className, methodDef.getName(namespace), methodDef.getDescriptor(namespace)), new AbstractMap.SimpleImmutableEntry<>(className, methodDef));
}
}
this.tree = readMappings(tinyFile);
this.maxNamespace = tree.getMaxNamespaceId();
}
private static TinyTree readMappings(Path input) {
try (BufferedReader reader = Files.newBufferedReader(input)) {
return TinyMappingFactory.loadWithDetection(reader);
private static MappingTreeView readMappings(Path input) {
var tree = new MemoryMappingTree();
try {
MappingReader.read(input, MappingFormat.TINY_2, new MappingSourceNsSwitch(tree, "named"));
} catch (IOException e) {
throw new RuntimeException("Failed to read mappings", e);
}
return tree;
}
@Deprecated
public String getClassDoc(String className) {
ClassDef classDef = classes.get(className);
return classDef != null ? classDef.getComment() : null;
}
private void addDoc(Mapped element, DocAdder adder) {
private void addDoc(ElementMappingView element, DocAdder adder) {
String doc = element.getComment();
if (doc != null) {
adder.addJavadoc("$L", doc);
@ -85,109 +60,95 @@ public class MappingsStore {
}
public void addClassDoc(DocAdder adder, String className) {
ClassDef classDef = classes.get(className);
var classDef = tree.getClass(className);
if (classDef == null) {
return;
}
addDoc(classDef, adder);
adder.addJavadoc("\n");
for (String namespace : namespaces) {
String transformedName = classDef.getName(namespace);
adder.addJavadoc("@mapping {@literal $L:$L}\n", namespace, transformedName);
for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) {
String transformedName = classDef.getName(id);
adder.addJavadoc("@mapping {@literal $L:$L}\n", tree.getNamespaceName(id), transformedName);
}
}
@Deprecated
public String getFieldDoc(EntryTriple fieldEntry) {
FieldDef fieldDef = fields.get(fieldEntry);
return fieldDef != null ? fieldDef.getComment() : null;
}
public void addFieldDoc(DocAdder addJavadoc, String owner, String name, String desc) {
var classDef = tree.getClass(owner);
if (classDef == null) {
return;
}
public void addFieldDoc(DocAdder addJavadoc, EntryTriple fieldEntry) {
FieldDef fieldDef = fields.get(fieldEntry);
var fieldDef = classDef.getField(name, desc);
if (fieldDef == null) {
return;
}
addDoc(fieldDef, addJavadoc);
ClassDef owner = classes.get(fieldEntry.getOwner());
addJavadoc.addJavadoc("\n");
for (String namespace : namespaces) {
String transformedName = fieldDef.getName(namespace);
String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + ":" + fieldDef.getDescriptor(namespace);
addJavadoc.addJavadoc("@mapping {@literal $L:$L:$L}\n", namespace, transformedName, mixinForm);
for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) {
String transformedName = fieldDef.getName(id);
String mixinForm = "L" + classDef.getName(id) + ";" + transformedName + ":" + fieldDef.getDesc(id);
addJavadoc.addJavadoc("@mapping {@literal $L:$L:$L}\n", tree.getNamespaceName(id), transformedName, mixinForm);
}
}
public Map.Entry<String, String> getParamNameAndDoc(Function<String, Collection<String>> superGetters, EntryTriple methodEntry, int index) {
Map.Entry<String, MethodDef> found = searchMethod(superGetters, methodEntry);
public Map.Entry<String, String> getParamNameAndDoc(Environment environment, String owner, String name, String desc, int index) {
var found = searchMethod(environment, owner, name, desc);
if (found != null) {
MethodDef methodDef = found.getValue();
if (methodDef.getParameters().isEmpty()) {
var methodDef = found.getValue();
if (methodDef.getArgs().isEmpty()) {
return null;
}
return methodDef.getParameters().stream()
.filter(param -> param.getLocalVariableIndex() == index)
.map(param -> new AbstractMap.SimpleImmutableEntry<>(param.getName(namespace), param.getComment()))
return methodDef.getArgs().stream()
.filter(param -> param.getLvIndex() == index)
// Map.entry() is null-hostile
.map(param -> new SimpleImmutableEntry<>(param.getSrcName(), param.getComment()))
.findFirst()
.orElse(null);
}
return null;
}
@Deprecated
public String getMethodDoc(Function<String, Collection<String>> superGetters, EntryTriple methodEntry) {
Map.Entry<String, MethodDef> methodDef = searchMethod(superGetters, methodEntry);
if (methodDef != null) {
return methodDef.getValue().getComment(); // comment doc handled separately by javapoet
}
return null;
}
public void addMethodDoc(DocAdder adder, Function<String, Collection<String>> superGetters, EntryTriple methodEntry) {
Map.Entry<String, MethodDef> found = searchMethod(superGetters, methodEntry);
public void addMethodDoc(DocAdder adder, Environment environment, String owner, String name, String desc) {
var found = searchMethod(environment, owner, name, desc);
if (found == null) {
return;
}
MethodDef methodDef = found.getValue();
ClassDef owner = classes.get(found.getKey());
if (!owner.getName(namespace).equals(methodEntry.getOwner())) {
var methodDef = found.getValue();
var ownerDef = found.getKey();
if (!ownerDef.equals(methodDef.getOwner())) {
adder.addJavadoc("{@inheritDoc}");
} else {
addDoc(methodDef, adder);
}
adder.addJavadoc("\n");
for (String namespace : namespaces) {
String transformedName = methodDef.getName(namespace);
String mixinForm = "L" + owner.getName(namespace) + ";" + transformedName + methodDef.getDescriptor(namespace);
adder.addJavadoc("@mapping {@literal $L:$L:$L}\n", namespace, transformedName, mixinForm);
for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) {
String transformedName = methodDef.getName(id);
String mixinForm = "L" + ownerDef.getName(id) + ";" + transformedName + methodDef.getDesc(id);
adder.addJavadoc("@mapping {@literal $L:$L:$L}\n", tree.getNamespaceName(id), transformedName, mixinForm);
}
}
private Map.Entry<String, MethodDef> searchMethod(Function<String, Collection<String>> superGetters, EntryTriple methodEntry) {
String className = methodEntry.getOwner();
if (!classes.containsKey(className)) {
private Map.Entry<ClassMappingView, MethodMappingView> searchMethod(Environment environment, String owner, String name, String desc) {
var classDef = tree.getClass(owner);
if (classDef == null)
return null;
}
if (methods.containsKey(methodEntry)) {
return methods.get(methodEntry); // Nullable!
}
var methodDef = classDef.getMethod(name, desc);
if (methodDef != null)
return Map.entry(methodDef.getOwner(), methodDef);
for (String superName : superGetters.apply(className)) {
EntryTriple triple = new EntryTriple(superName, methodEntry.getName(), methodEntry.getDescriptor());
Map.Entry<String, MethodDef> ret = searchMethod(superGetters, triple);
for (String superName : environment.superTypes().getOrDefault(owner, List.of())) {
var ret = searchMethod(environment, superName, name, desc);
if (ret != null) {
methods.put(triple, ret);
return ret;
}
}
methods.put(methodEntry, null);
return null;
}

View File

@ -13,38 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors;
import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures;
import net.fabricmc.mappingpoet.signature.MethodSignature;
import net.fabricmc.mappingpoet.signature.TypeAnnotationBank;
import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping;
import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage;
import org.objectweb.asm.TypeReference;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import javax.lang.model.element.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import org.objectweb.asm.TypeReference;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import net.fabricmc.mapping.util.EntryTriple;
import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors;
import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures;
import net.fabricmc.mappingpoet.signature.ClassStaticContext;
import net.fabricmc.mappingpoet.signature.MethodSignature;
import net.fabricmc.mappingpoet.signature.TypeAnnotationBank;
import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping;
import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage;
public class MethodBuilder {
private static final Set<String> RESERVED_KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
@ -58,20 +51,18 @@ public class MethodBuilder {
private final ClassNode classNode;
private final MethodNode methodNode;
private final MethodSpec.Builder builder;
private final Function<String, Collection<String>> superGetter;
private final Environment environment;
private final int formalParamStartIndex;
private final ClassStaticContext context;
private final String receiverSignature;
private final TypeAnnotationMapping typeAnnotations;
private MethodSignature signature;
public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Function<String, Collection<String>> superGetter, ClassStaticContext context, String receiverSignature, int formalParamStartIndex) {
public MethodBuilder(MappingsStore mappings, ClassNode classNode, MethodNode methodNode, Environment environment, String receiverSignature, int formalParamStartIndex) {
this.mappings = mappings;
this.classNode = classNode;
this.methodNode = methodNode;
this.superGetter = superGetter;
this.context = context;
this.environment = environment;
this.receiverSignature = receiverSignature;
this.formalParamStartIndex = formalParamStartIndex;
@ -158,7 +149,7 @@ public class MethodBuilder {
}
if (methodNode.signature != null) {
signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, context);
signature = AnnotationAwareSignatures.parseMethodSignature(methodNode.signature, typeAnnotations, environment);
builder.addTypeVariables(signature.generics());
}
@ -190,7 +181,7 @@ public class MethodBuilder {
typeName = signature.result();
} else {
String returnDesc = methodNode.desc.substring(methodNode.desc.lastIndexOf(")") + 1);
typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), context);
typeName = AnnotationAwareDescriptors.parseDesc(returnDesc, typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RETURN)), environment);
}
builder.returns(typeName);
@ -215,7 +206,7 @@ public class MethodBuilder {
ParameterSpec.Builder receiverBuilder;
// only instance inner class ctor can have receivers
if (methodNode.name.equals("<init>")) {
TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, context);
TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, environment);
// vulnerable heuristics
String simpleNameChain = classNode.name.substring(classNode.name.lastIndexOf('/') + 1);
int part1 = simpleNameChain.lastIndexOf('$'); // def exists
@ -223,7 +214,7 @@ public class MethodBuilder {
String usedName = simpleNameChain.substring(part2 + 1, part1);
receiverBuilder = ParameterSpec.builder(annotatedReceiver, usedName + ".this");
} else {
TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature + ";", receiverAnnos, context);
TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature + ";", receiverAnnos, environment);
receiverBuilder = ParameterSpec.builder(annotatedReceiver, "this");
}
// receiver param cannot have its jd/param anno except type use anno
@ -269,9 +260,9 @@ public class MethodBuilder {
if (signatureParamIterator.hasNext()) {
parsedType = signatureParamIterator.next();
} else {
parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), context);
parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), environment);
}
paramTypes.add(new ParamType(mappings.getParamNameAndDoc(superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc), slot), parsedType, usedParamNames, slot));
paramTypes.add(new ParamType(mappings.getParamNameAndDoc(environment, classNode.name, methodNode.name, methodNode.desc, slot), parsedType, usedParamNames, slot));
}
slot++;
if (nonAnnotatedParsedType.equals(TypeName.DOUBLE) || nonAnnotatedParsedType.equals(TypeName.LONG)) {
@ -298,14 +289,14 @@ public class MethodBuilder {
if (exceptions != null) {
int index = 0;
for (String internalName : exceptions) {
builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), context));
builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), environment));
index++;
}
}
}
private void addJavaDoc() {
mappings.addMethodDoc(builder::addJavadoc, superGetter, new EntryTriple(classNode.name, methodNode.name, methodNode.desc));
mappings.addMethodDoc(builder::addJavadoc, environment, classNode.name, methodNode.name, methodNode.desc);
}
public MethodSpec build() {

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import org.objectweb.asm.tree.ClassNode;
@ -21,7 +20,6 @@ import org.objectweb.asm.tree.ClassNode;
import javax.lang.model.element.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class ModifierBuilder {
@ -32,21 +30,21 @@ public class ModifierBuilder {
this.access = access;
}
public ModifierBuilder checkUnseal(ClassNode node, Predicate<String> sealChecker) {
public ModifierBuilder checkUnseal(ClassNode node, Environment env) {
if (java.lang.reflect.Modifier.isFinal(node.access)) {
return this;
}
if (node.interfaces != null) {
for (String itf : node.interfaces) {
if (sealChecker.test(itf)) {
if (env.sealedClasses().contains(itf)) {
needsUnseal = true;
return this;
}
}
}
if (node.superName != null && sealChecker.test(node.superName)) {
if (node.superName != null && env.sealedClasses().contains(node.superName)) {
needsUnseal = true;
}
@ -98,7 +96,7 @@ public class ModifierBuilder {
modifiers.add(Modifier.NATIVE);
}
if (java.lang.reflect.Modifier.isStrict(access)) {
modifiers.add(Modifier.STRICTFP);
modifiers.add(Modifier.STRICTFP); // obsolete as of Java 17
}
if (needsUnseal && type == Type.CLASS) {

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet;
import java.util.AbstractMap;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.jd;
import java.util.EnumSet;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.AbstractMap;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import com.squareup.javapoet.TypeName;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.List;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
/**

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.List;

View File

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.LinkedList;
import java.util.ArrayList;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
@ -29,20 +28,20 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
private final TypeAnnotationMapping mapping;
private final ClassStaticContext context;
private final boolean forClass;
LinkedList<TypeVariableName> generics = new LinkedList<>();
ArrayList<TypeVariableName> generics = new ArrayList<>();
// collecting generic
String currentGenericName;
LinkedList<TypeName> currentGenericBounds = new LinkedList<>();
ArrayList<TypeName> currentGenericBounds = new ArrayList<>();
// bound for each generic
PoetTypeSignatureWriter pendingLowerBound;
// classes usage
LinkedList<TypeName> superTypes = new LinkedList<>();
ArrayList<TypeName> superTypes = new ArrayList<>();
PoetTypeSignatureWriter pendingSupertype;
// methods usage
LinkedList<TypeName> params = new LinkedList<>();
LinkedList<TypeName> throwables = new LinkedList<>();
ArrayList<TypeName> params = new ArrayList<>();
ArrayList<TypeName> throwables = new ArrayList<>();
PoetTypeSignatureWriter pendingSlot;
TypeName returnType;
@ -84,7 +83,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
private void collectLowerBound() {
if (pendingLowerBound != null) {
currentGenericBounds.addLast(pendingLowerBound.compute());
currentGenericBounds.add(pendingLowerBound.compute());
pendingLowerBound = null;
}
}
@ -113,7 +112,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
private void collectSupertype() {
if (pendingSupertype != null) {
TypeName simple = pendingSupertype.compute();
superTypes.addLast(simple);
superTypes.add(simple);
pendingSupertype = null;
}
@ -139,7 +138,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
public ClassSignature collectClass() {
collectSupertype();
TypeName superclass = superTypes.removeFirst();
TypeName superclass = superTypes.remove(0);
return new ClassSignature(generics, superclass, superTypes);
}
@ -148,7 +147,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
private void collectParam() {
if (pendingSlot != null) {
TypeName slot = pendingSlot.compute();
params.addLast(slot);
params.add(slot);
pendingSlot = null;
}
@ -159,7 +158,7 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor {
if (returnType == null) {
returnType = pendingSlot.compute();
} else {
throwables.addLast(pendingSlot.compute());
throwables.add(pendingSlot.compute());
}
pendingSlot = null;

View File

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
@ -42,7 +41,7 @@ import net.fabricmc.mappingpoet.Signatures;
public final class PoetTypeSignatureWriter extends SignatureVisitor {
private final ClassStaticContext context;
private final LinkedList<TypeName> params = new LinkedList<>();
private final ArrayList<TypeName> params = new ArrayList<>();
private /* NonNull */ TypeAnnotationBank storage; // mutable
private TypeName result;
// array
@ -158,7 +157,7 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor {
};
used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size()));
params.addLast(used);
params.add(used);
activeTypeArgument = null;
activeTypeArgumentKind = 0;
@ -172,7 +171,7 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor {
TypeName used = WildcardTypeName.subtypeOf(TypeName.OBJECT);
used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size()));
params.addLast(used);
params.add(used);
}
// (? extends/ ? super)? ClassType like in Consumer<? super Integer>,

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.Collections;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import org.objectweb.asm.TypeReference;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.mappingpoet.signature;
import java.util.ArrayList;