diff --git a/build.gradle b/build.gradle index 317a831..f7b07d1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,12 @@ plugins { id 'java' + id 'eclipse' id 'maven-publish' id 'com.diffplug.spotless' version '5.8.2' } group 'net.fabricmc' -version '0.4.1' +version '0.4.2' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") @@ -19,7 +20,7 @@ repositories { } dependencies { - implementation 'net.fabricmc:javapoet:0.1.0' + implementation 'net.fabricmc:javapoet:0.1.1' implementation 'net.fabricmc:mapping-io:0.4.0' implementation 'org.ow2.asm:asm:9.7' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..20db9ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java index 0aa9bf3..3677191 100644 --- a/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java +++ b/src/main/java/net/fabricmc/mappingpoet/ClassBuilder.java @@ -15,16 +15,17 @@ */ package net.fabricmc.mappingpoet; +import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; 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.TypeAnnotationMapping; -import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import org.objectweb.asm.TypeReference; @@ -36,11 +37,11 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; +import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.mappingpoet.signature.ClassSignature; +import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; public class ClassBuilder { static final Handle OBJ_MTH_BOOTSTRAP = new Handle( @@ -48,8 +49,7 @@ public class ClassBuilder { "java/lang/runtime/ObjectMethods", "bootstrap", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", - false - ); + false); private final MappingsStore mappings; private final ClassNode classNode; @@ -131,14 +131,17 @@ public void addMembers() { } private ClassSignature setupSignature() { - return classNode.signature == null ? - AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment) : - AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment); + if (classNode.signature == null) { + return AnnotationAwareDescriptors.parse(classNode.superName, classNode.interfaces, typeAnnotations, environment); + } else { + return AnnotationAwareSignatures.parseClassSignature(classNode.signature, typeAnnotations, environment); + } } private TypeSpec.Builder setupBuilder() { TypeSpec.Builder builder; ClassName name = parseInternalName(classNode.name); // no type anno here + if (Modifier.isInterface(classNode.access)) { if (classNode.interfaces.size() == 1 && classNode.interfaces.get(0).equals("java/lang/annotation/Annotation")) { builder = TypeSpec.annotationBuilder(name); @@ -172,18 +175,19 @@ private TypeSpec.Builder setupBuilder() { return builder .addModifiers(new ModifierBuilder(classNode.access) .checkUnseal(classNode, environment) - .getModifiers(ModifierBuilder.getType(enumClass, recordClass)) - ); + .getModifiers(ModifierBuilder.getType(enumClass, recordClass))); } private void addInterfaces() { if (annotationClass) { return; } + if (signature != null) { builder.addSuperinterfaces(signature.superinterfaces()); return; } + if (classNode.interfaces.isEmpty()) return; for (String iFace : classNode.interfaces) { @@ -201,6 +205,7 @@ private void addDirectAnnotations(List regularAnnotations) { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -208,27 +213,33 @@ private void addDirectAnnotations(List regularAnnotations) { private void addMethods() { if (classNode.methods == null) return; - methodsLoop: - for (MethodNode method : classNode.methods) { + + methodsLoop: for (MethodNode method : classNode.methods) { if ((method.access & Opcodes.ACC_SYNTHETIC) != 0 || (method.access & Opcodes.ACC_MANDATED) != 0) { continue; } + if (method.name.equals("")) { continue; } + int formalParamStartIndex = 0; + if (enumClass) { // Skip enum sugar methods if (method.name.equals("values") && method.desc.equals("()[L" + classNode.name + ";")) { continue; } + if (method.name.equals("valueOf") && method.desc.equals("(Ljava/lang/String;)L" + classNode.name + ";")) { continue; } + if (method.name.equals("")) { formalParamStartIndex = 2; // 0 String 1 int } } + if (recordClass) { // skip record sugars if (method.name.equals("equals") && method.desc.equals("(Ljava/lang/Object;)Z") @@ -244,17 +255,20 @@ private void addMethods() { // todo test component getters } + if (instanceInner) { if (method.name.equals("")) { formalParamStartIndex = 1; // 0 this$0 } } + builder.addMethod(new MethodBuilder(mappings, classNode, method, environment, receiverSignature, formalParamStartIndex).build()); } } private void addFields() { if (classNode.fields == null) return; + for (FieldNode field : classNode.fields) { if (recordClass && !Modifier.isStatic(field.access)) { // proguard elevates record field access for direct record field gets @@ -270,9 +284,11 @@ private void addFields() { continue; } + if ((field.access & Opcodes.ACC_SYNTHETIC) != 0 || (field.access & Opcodes.ACC_MANDATED) != 0) { continue; // hide synthetic stuff } + if ((field.access & Opcodes.ACC_ENUM) == 0) { builder.addField(new FieldBuilder(mappings, classNode, field, environment).build()); } else { @@ -288,6 +304,7 @@ private void addFields() { .add(field.visibleTypeAnnotations) .build().getBank(TypeReference.newTypeReference(TypeReference.FIELD)) .getCurrentAnnotations(); + if (!annotations.isEmpty()) { enumBuilder.addAnnotations(annotations); // no custom paths for annotations rip } @@ -301,6 +318,7 @@ private void addDirectAnnotations(TypeSpec.Builder builder, List if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -312,6 +330,7 @@ private void addJavaDoc() { public void addInnerClass(ClassBuilder classBuilder) { InnerClassNode innerClassNode = null; + if (classNode.innerClasses != null) { for (InnerClassNode node : classNode.innerClasses) { if (node.name.equals(classBuilder.classNode.name)) { @@ -339,8 +358,8 @@ public void addInnerClass(ClassBuilder 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, environment) - .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass)) - ); + .getModifiers(ModifierBuilder.getType(classBuilder.enumClass, classBuilder.recordClass))); + if (!Modifier.isStatic(innerClassNode.access)) { classBuilder.instanceInner = true; } @@ -352,6 +371,7 @@ public void addInnerClass(ClassBuilder classBuilder) { sb.append(innerClassNode.innerName); // append simple name List innerClassGenerics = classBuilder.signature.generics(); + if (!innerClassGenerics.isEmpty()) { sb.append("<"); for (TypeVariableName each : innerClassGenerics) { @@ -359,9 +379,11 @@ public void addInnerClass(ClassBuilder classBuilder) { } sb.append(">"); } + classBuilder.receiverSignature = sb.toString(); } } + innerClasses.add(classBuilder); } @@ -370,9 +392,10 @@ public String getClassName() { } public TypeSpec build() { - innerClasses.stream() - .map(ClassBuilder::build) - .forEach(builder::addType); + for (ClassBuilder innerCb : innerClasses) { + builder.addType(innerCb.build()); + } + return builder.build(); } } diff --git a/src/main/java/net/fabricmc/mappingpoet/Main.java b/src/main/java/net/fabricmc/mappingpoet/Main.java index 62c9e12..9ff8ae2 100644 --- a/src/main/java/net/fabricmc/mappingpoet/Main.java +++ b/src/main/java/net/fabricmc/mappingpoet/Main.java @@ -15,17 +15,6 @@ */ 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; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InnerClassNode; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -50,6 +39,16 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; +import com.squareup.javapoet.JavaFile; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InnerClassNode; + +import net.fabricmc.mappingpoet.Environment.ClassNamePointer; +import net.fabricmc.mappingpoet.Environment.NestedClassInfo; + public class Main { public static void main(String[] args) { @@ -66,8 +65,8 @@ public static void main(String[] args) { if (Files.exists(outputDirectory)) { try (var stream = Files.walk(outputDirectory)) { stream.sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); + .map(Path::toFile) + .forEach(File::delete); } } @@ -94,20 +93,20 @@ public static void generate(Path mappings, Path inputJar, Path outputDirectory, Map classes = new HashMap<>(); forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), librariesDir); - classes.values().stream() - .filter(classBuilder -> !classBuilder.getClassName().contains("$")) - .forEach(classBuilder -> { - int packageEnd = classBuilder.getClassName().lastIndexOf("/"); - JavaFile javaFile = JavaFile.builder(packageEnd == -1 ? "" : classBuilder.getClassName().substring(0, packageEnd).replaceAll("/", "."), classBuilder.build()) - .build(); - try { - javaFile.writeTo(outputDirectory); - } catch (IOException e) { - throw new RuntimeException("Failed to write class", e); - } - }); + for (ClassBuilder classBuilder : classes.values()) { + String name = classBuilder.getClassName(); + if (name.contains("$")) continue; + try { + int packageEnd = classBuilder.getClassName().lastIndexOf("/"); + String pkgName = packageEnd < 0 ? "" : classBuilder.getClassName().substring(0, packageEnd).replaceAll("/", "."); + JavaFile javaFile = JavaFile.builder(pkgName, classBuilder.build()).build(); + javaFile.writeTo(outputDirectory); + } catch (Throwable t) { + throw new RuntimeException("Failed to process class "+name, t); + } + } } private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Path librariesDir) { @@ -170,7 +169,9 @@ private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, //Sort all the classes making sure that inner classes come after the parent classes classes.sort(Comparator.comparing(o -> o.name)); - classes.forEach(node -> classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses))); + for (ClassNode node : classes) { + classNodeConsumer.accept(node, new Environment(supers, sealedClasses, nestedClasses)); + } } private static void scanNestedClasses(Map classNames, Map instanceInnerClasses, Path librariesDir) { diff --git a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java index 01f589d..bb4cccf 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestAnno.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestAnno.java @@ -23,7 +23,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE_USE) +@Target({ElementType.TYPE_USE, ElementType.FIELD}) public @interface TestAnno { String value() default ""; } diff --git a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java index ad86065..213c331 100644 --- a/src/test/java/net/fabricmc/mappingpoet/TestOuter.java +++ b/src/test/java/net/fabricmc/mappingpoet/TestOuter.java @@ -72,7 +72,7 @@ class InnerThree { class OuterTwo { static class InnerOne { class InnerTwo { - InnerTwo(InnerOnenet.fabricmc.mappingpoet.OuterTwo.InnerOne.this) { + InnerTwo(InnerOneInnerOne.this) { }