diff --git a/filament/build.gradle b/filament/build.gradle index 9b4714b455..6003f6e2c0 100644 --- a/filament/build.gradle +++ b/filament/build.gradle @@ -39,6 +39,7 @@ dependencies { implementation "net.fabricmc:mappingpoet:$properties.mappingpoet_version" implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4.2' implementation 'net.fabricmc:mapping-io:0.5.1' + implementation 'net.fabricmc:javapoet:0.1.1' // Contains a number of useful utilities we can re-use. implementation ("net.fabricmc:fabric-loom:1.5.7") { diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/ClassBuilder.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/ClassBuilder.java index 36771913e7..1648183f90 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/ClassBuilder.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/ClassBuilder.java @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; -import static net.fabricmc.mappingpoet.FieldBuilder.parseAnnotation; +package net.fabricmc.filament.mappingpoet; + +import static net.fabricmc.filament.mappingpoet.FieldBuilder.parseAnnotation; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -37,11 +38,11 @@ import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -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 net.fabricmc.filament.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.filament.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.filament.mappingpoet.signature.ClassSignature; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationStorage; public class ClassBuilder { static final Handle OBJ_MTH_BOOTSTRAP = new Handle( @@ -88,6 +89,7 @@ public class ClassBuilder { ClassName currentClassName = null; char ch; + do { ch = index == internalName.length() ? ';' : internalName.charAt(index); @@ -165,9 +167,11 @@ public class ClassBuilder { StringBuilder sb = new StringBuilder(); sb.append(classNode.name); sb.append("<"); + for (TypeVariableName each : signature.generics()) { sb.append("T").append(each.name).append(";"); } + sb.append(">"); receiverSignature = sb.toString(); } @@ -248,8 +252,9 @@ public class ClassBuilder { for (AbstractInsnNode insn : method.instructions) { if (insn instanceof InvokeDynamicInsnNode indy && indy.bsm.equals(OBJ_MTH_BOOTSTRAP) - && indy.name.equals(method.name)) + && indy.name.equals(method.name)) { continue methodsLoop; + } } } @@ -318,7 +323,7 @@ public class ClassBuilder { if (regularAnnotations == null) { return; } - + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -363,6 +368,7 @@ public class ClassBuilder { if (!Modifier.isStatic(innerClassNode.access)) { classBuilder.instanceInner = true; } + // consider emit warning if this.instanceInner is true when classBuilder.instanceInner is false if (this.receiverSignature != null && classBuilder.instanceInner) { @@ -374,9 +380,11 @@ public class ClassBuilder { if (!innerClassGenerics.isEmpty()) { sb.append("<"); + for (TypeVariableName each : innerClassGenerics) { sb.append("T").append(each.name).append(";"); } + sb.append(">"); } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Environment.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Environment.java index 5355634b2f..9f51d13c8c 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Environment.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Environment.java @@ -13,15 +13,17 @@ * 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; +package net.fabricmc.filament.mappingpoet; import java.util.Collection; import java.util.Map; import java.util.Set; +import com.squareup.javapoet.ClassName; + +import net.fabricmc.filament.mappingpoet.signature.ClassStaticContext; + /** * Represents an overall runtime environment, knows all inner class, * super class, etc. information. @@ -39,8 +41,9 @@ public record Environment( public record ClassNamePointer(String simple, String outerClass) { public ClassName toClassName(ClassName outerClassName) { - if (simple == null) + if (simple == null) { return null; + } return outerClassName.nestedClass(simple); } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/FieldBuilder.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/FieldBuilder.java index 1bf98c93a6..b4eee04c1d 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/FieldBuilder.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/FieldBuilder.java @@ -13,7 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; + +package net.fabricmc.filament.mappingpoet; + +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ArrayTypeName; @@ -23,12 +31,6 @@ import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import net.fabricmc.mappingpoet.signature.AnnotationAwareDescriptors; -import net.fabricmc.mappingpoet.signature.AnnotationAwareSignatures; -import net.fabricmc.mappingpoet.signature.ClassStaticContext; -import net.fabricmc.mappingpoet.signature.TypeAnnotationBank; -import net.fabricmc.mappingpoet.signature.TypeAnnotationMapping; -import net.fabricmc.mappingpoet.signature.TypeAnnotationStorage; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.TypePath; @@ -37,12 +39,12 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; -import java.util.AbstractMap; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import net.fabricmc.filament.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.filament.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.filament.mappingpoet.signature.ClassStaticContext; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationStorage; public class FieldBuilder { private final MappingsStore mappings; @@ -74,8 +76,10 @@ public class FieldBuilder { ClassName annoClassName = (ClassName) typeFromDesc(annotation.desc); AnnotationSpec.Builder builder = AnnotationSpec.builder(annoClassName); List values = annotation.values; + if (values != null) { Iterator itr = values.iterator(); + while (itr.hasNext()) { String key = (String) itr.next(); Object value = itr.next(); @@ -92,24 +96,30 @@ public class FieldBuilder { if (value instanceof List) { return ((List) value).stream().map(FieldBuilder::codeFromAnnoValue).collect(CodeBlock.joining(",", "{", "}")); } + if (value instanceof Character || value instanceof Number || value instanceof Boolean) { return CodeBlock.builder().add("$L", value).build(); } + if (value instanceof String) { return CodeBlock.builder().add("$S", value).build(); } + if (value instanceof String[]) { String[] arr = (String[]) value; ClassName enumClassName = (ClassName) typeFromDesc(arr[0]); String valueName = arr[1]; return CodeBlock.builder().add("$T.$L", enumClassName, valueName).build(); } + if (value instanceof Type) { return CodeBlock.builder().add("$T.class", typeFromDesc(((Type) value).getDescriptor())).build(); } + if (value instanceof AnnotationNode) { return CodeBlock.builder().add(parseAnnotation((AnnotationNode) value).toString()).build(); } + throw new IllegalArgumentException(String.format("Don't know how to convert \"%s\" into annotation value", value)); } @@ -120,6 +130,7 @@ public class FieldBuilder { public static Map.Entry parseType(final String desc, final int start) { int index = start; int arrayLevel = 0; + while (desc.charAt(index) == '[') { arrayLevel++; index++; @@ -127,90 +138,91 @@ public class FieldBuilder { TypeName current; switch (desc.charAt(index)) { - case 'B': { - current = TypeName.BYTE; - index++; - break; - } - case 'C': { - current = TypeName.CHAR; - index++; - break; - } - case 'D': { - current = TypeName.DOUBLE; - index++; - break; - } - case 'F': { - current = TypeName.FLOAT; - index++; - break; - } - case 'I': { - current = TypeName.INT; - index++; - break; - } - case 'J': { - current = TypeName.LONG; - index++; - break; - } - case 'S': { - current = TypeName.SHORT; - index++; - break; - } - case 'Z': { - current = TypeName.BOOLEAN; - index++; - break; - } - case 'V': { - current = TypeName.VOID; - index++; - break; - } - case 'L': { - int classNameSeparator = index; - index++; - int nameStart = index; - ClassName currentClassName = null; + case 'B': { + current = TypeName.BYTE; + index++; + break; + } + case 'C': { + current = TypeName.CHAR; + index++; + break; + } + case 'D': { + current = TypeName.DOUBLE; + index++; + break; + } + case 'F': { + current = TypeName.FLOAT; + index++; + break; + } + case 'I': { + current = TypeName.INT; + index++; + break; + } + case 'J': { + current = TypeName.LONG; + index++; + break; + } + case 'S': { + current = TypeName.SHORT; + index++; + break; + } + case 'Z': { + current = TypeName.BOOLEAN; + index++; + break; + } + case 'V': { + current = TypeName.VOID; + index++; + break; + } + case 'L': { + int classNameSeparator = index; + index++; + int nameStart = index; + ClassName currentClassName = null; - char ch; - do { - ch = desc.charAt(index); + char ch; - if (ch == '$' || ch == ';') { - // collect class name - if (currentClassName == null) { - String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = ClassName.get(packageName, simpleName); - } else { - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = currentClassName.nestedClass(simpleName); - } + do { + ch = desc.charAt(index); + + if (ch == '$' || ch == ';') { + // collect class name + if (currentClassName == null) { + String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = ClassName.get(packageName, simpleName); + } else { + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = currentClassName.nestedClass(simpleName); } - - if (ch == '/' || ch == '$') { - // Start of simple name - classNameSeparator = index; - } - - index++; - } while (ch != ';'); - - if (currentClassName == null) { - throw invalidDesc(desc, index); } - current = currentClassName; - break; - } - default: + if (ch == '/' || ch == '$') { + // Start of simple name + classNameSeparator = index; + } + + index++; + } while (ch != ';'); + + if (currentClassName == null) { throw invalidDesc(desc, index); + } + + current = currentClassName; + break; + } + default: + throw invalidDesc(desc, index); } for (int i = 0; i < arrayLevel; i++) { @@ -223,6 +235,7 @@ public class FieldBuilder { public static Map.Entry parseAnnotatedType(final String desc, final int start, TypeAnnotationBank annotations, ClassStaticContext context) { int index = start; Deque> arrayAnnos = new ArrayDeque<>(); + while (desc.charAt(index) == '[') { arrayAnnos.push(annotations.getCurrentAnnotations()); annotations = annotations.advance(TypePath.ARRAY_ELEMENT, 0); @@ -231,106 +244,108 @@ public class FieldBuilder { TypeName current; switch (desc.charAt(index)) { - case 'B': { - current = TypeName.BYTE; - index++; - break; - } - case 'C': { - current = TypeName.CHAR; - index++; - break; - } - case 'D': { - current = TypeName.DOUBLE; - index++; - break; - } - case 'F': { - current = TypeName.FLOAT; - index++; - break; - } - case 'I': { - current = TypeName.INT; - index++; - break; - } - case 'J': { - current = TypeName.LONG; - index++; - break; - } - case 'S': { - current = TypeName.SHORT; - index++; - break; - } - case 'Z': { - current = TypeName.BOOLEAN; - index++; - break; - } - case 'V': { - current = TypeName.VOID; - index++; - break; - } - case 'L': { - int classNameSeparator = index; - index++; - int nameStart = index; - ClassName currentClassName = null; - boolean instanceInner = false; + case 'B': { + current = TypeName.BYTE; + index++; + break; + } + case 'C': { + current = TypeName.CHAR; + index++; + break; + } + case 'D': { + current = TypeName.DOUBLE; + index++; + break; + } + case 'F': { + current = TypeName.FLOAT; + index++; + break; + } + case 'I': { + current = TypeName.INT; + index++; + break; + } + case 'J': { + current = TypeName.LONG; + index++; + break; + } + case 'S': { + current = TypeName.SHORT; + index++; + break; + } + case 'Z': { + current = TypeName.BOOLEAN; + index++; + break; + } + case 'V': { + current = TypeName.VOID; + index++; + break; + } + case 'L': { + int classNameSeparator = index; + index++; + int nameStart = index; + ClassName currentClassName = null; + boolean instanceInner = false; - char ch; - do { - ch = desc.charAt(index); + char ch; - if (ch == '$' || ch == ';') { - // collect class name - if (currentClassName == null) { - String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; - String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = ClassName.get(packageName, simpleName); - } else { - String simpleName = desc.substring(classNameSeparator + 1, index); + do { + ch = desc.charAt(index); - if (!instanceInner && context.isInstanceInner(desc.substring(nameStart, index))) { - instanceInner = true; - } + if (ch == '$' || ch == ';') { + // collect class name + if (currentClassName == null) { + String packageName = nameStart < classNameSeparator ? desc.substring(nameStart, classNameSeparator).replace('/', '.') : ""; + String simpleName = desc.substring(classNameSeparator + 1, index); + currentClassName = ClassName.get(packageName, simpleName); + } else { + String simpleName = desc.substring(classNameSeparator + 1, index); - currentClassName = currentClassName.nestedClass(simpleName); + if (!instanceInner && context.isInstanceInner(desc.substring(nameStart, index))) { + instanceInner = true; + } - if (instanceInner) { - currentClassName = AnnotationAwareDescriptors.annotate(currentClassName, annotations); - annotations = annotations.advance(TypePath.INNER_TYPE, 0); - } + currentClassName = currentClassName.nestedClass(simpleName); + + if (instanceInner) { + currentClassName = AnnotationAwareDescriptors.annotate(currentClassName, annotations); + annotations = annotations.advance(TypePath.INNER_TYPE, 0); } } - - if (ch == '/' || ch == '$') { - // Start of simple name - classNameSeparator = index; - } - - index++; - } while (ch != ';'); - - if (currentClassName == null) { - throw invalidDesc(desc, index); } - current = currentClassName; - break; - } - default: + if (ch == '/' || ch == '$') { + // Start of simple name + classNameSeparator = index; + } + + index++; + } while (ch != ';'); + + if (currentClassName == null) { throw invalidDesc(desc, index); + } + + current = currentClassName; + break; + } + default: + throw invalidDesc(desc, index); } while (!arrayAnnos.isEmpty()) { current = ArrayTypeName.of(current); List currentAnnos = arrayAnnos.pop(); + if (!currentAnnos.isEmpty()) { current = current.annotated(currentAnnos); } @@ -346,31 +361,34 @@ public class FieldBuilder { @Deprecated // use typeFromDesc, non-recursive public static TypeName getFieldType(String desc) { switch (desc) { - case "B": - return TypeName.BYTE; - case "C": - return TypeName.CHAR; - case "S": - return TypeName.SHORT; - case "Z": - return TypeName.BOOLEAN; - case "I": - return TypeName.INT; - case "J": - return TypeName.LONG; - case "F": - return TypeName.FLOAT; - case "D": - return TypeName.DOUBLE; - case "V": - return TypeName.VOID; + case "B": + return TypeName.BYTE; + case "C": + return TypeName.CHAR; + case "S": + return TypeName.SHORT; + case "Z": + return TypeName.BOOLEAN; + case "I": + return TypeName.INT; + case "J": + return TypeName.LONG; + case "F": + return TypeName.FLOAT; + case "D": + return TypeName.DOUBLE; + case "V": + return TypeName.VOID; } + if (desc.startsWith("[")) { return ArrayTypeName.of(getFieldType(desc.substring(1))); } + if (desc.startsWith("L")) { return ClassBuilder.parseInternalName(desc.substring(1).substring(0, desc.length() - 2)); } + throw new UnsupportedOperationException("Unknown field type" + desc); } @@ -388,56 +406,65 @@ public class FieldBuilder { private CodeBlock makeInitializer(String desc) { // fake initializers exclude fields from constant values switch (desc.charAt(0)) { - case 'B': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("(byte) $L", fieldNode.value).build(); - } - // fake initializer falls through - case 'C': - if (fieldNode.value instanceof Integer) { - int value = (int) fieldNode.value; - char c = (char) value; - return printChar(CodeBlock.builder(), c, value).build(); - } - // fake initializer falls through - case 'D': - if (fieldNode.value instanceof Double) { - return CodeBlock.builder().add("$LD", fieldNode.value).build(); - } - // fake initializer falls through - case 'I': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("$L", fieldNode.value).build(); - } - // fake initializer falls through - case 'J': - if (fieldNode.value instanceof Long) { - return CodeBlock.builder().add("$LL", fieldNode.value).build(); - } - // fake initializer falls through - case 'S': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("(short) $L", fieldNode.value).build(); - } - return CodeBlock.builder().add("java.lang.Byte.parseByte(\"dummy\")").build(); - case 'F': - if (fieldNode.value instanceof Float) { - return CodeBlock.builder().add("$LF", fieldNode.value).build(); - } - return CodeBlock.builder().add("java.lang.Float.parseFloat(\"dummy\")").build(); - case 'Z': - if (fieldNode.value instanceof Integer) { - return CodeBlock.builder().add("$L", ((int) fieldNode.value) != 0).build(); - } - return CodeBlock.builder().add("java.lang.Boolean.parseBoolean(\"dummy\")").build(); + case 'B': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(byte) $L", fieldNode.value).build(); + } + + // fake initializer falls through + case 'C': + if (fieldNode.value instanceof Integer) { + int value = (int) fieldNode.value; + char c = (char) value; + return printChar(CodeBlock.builder(), c, value).build(); + } + + // fake initializer falls through + case 'D': + if (fieldNode.value instanceof Double) { + return CodeBlock.builder().add("$LD", fieldNode.value).build(); + } + + // fake initializer falls through + case 'I': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", fieldNode.value).build(); + } + + // fake initializer falls through + case 'J': + if (fieldNode.value instanceof Long) { + return CodeBlock.builder().add("$LL", fieldNode.value).build(); + } + + // fake initializer falls through + case 'S': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("(short) $L", fieldNode.value).build(); + } + + return CodeBlock.builder().add("java.lang.Byte.parseByte(\"dummy\")").build(); + case 'F': + if (fieldNode.value instanceof Float) { + return CodeBlock.builder().add("$LF", fieldNode.value).build(); + } + + return CodeBlock.builder().add("java.lang.Float.parseFloat(\"dummy\")").build(); + case 'Z': + if (fieldNode.value instanceof Integer) { + return CodeBlock.builder().add("$L", ((int) fieldNode.value) != 0).build(); + } + + return CodeBlock.builder().add("java.lang.Boolean.parseBoolean(\"dummy\")").build(); } + if (desc.equals("Ljava/lang/String;") && fieldNode.value instanceof String) { return CodeBlock.builder().add("$S", fieldNode.value).build(); } + return CodeBlock.builder().add(desc.equals("Ljava/lang/String;") ? "java.lang.String.valueOf(\"dummy\")" : "null").build(); } - private static CodeBlock.Builder printChar(CodeBlock.Builder builder, char c, int value) { if (!Character.isValidCodePoint(value) || !Character.isDefined(value)) { return builder.add("(char) $L", value); @@ -446,20 +473,20 @@ public class FieldBuilder { // See https://docs.oracle.com/javase/specs/jls/se16/html/jls-3.html#jls-EscapeSequence // ignore space or ", just use direct in those cases switch (c) { - case '\b': - return builder.add("'\\b'"); - case '\t': - return builder.add("'\\t'"); - case '\n': - return builder.add("'\\n'"); - case '\f': - return builder.add("'\\f'"); - case '\r': - return builder.add("'\\r'"); - case '\'': - return builder.add("'\\''"); - case '\\': - return builder.add("'\\\\'"); + case '\b': + return builder.add("'\\b'"); + case '\t': + return builder.add("'\\t'"); + case '\n': + return builder.add("'\\n'"); + case '\f': + return builder.add("'\\f'"); + case '\r': + return builder.add("'\\r'"); + case '\'': + return builder.add("'\\''"); + case '\\': + return builder.add("'\\\\'"); } return builder.add("'$L'", c); @@ -482,6 +509,7 @@ public class FieldBuilder { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(parseAnnotation(annotation)); } @@ -496,6 +524,7 @@ public class FieldBuilder { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { paramBuilder.addAnnotation(parseAnnotation(annotation)); } @@ -505,6 +534,7 @@ public class FieldBuilder { if (fieldNode.signature != null) { return AnnotationAwareSignatures.parseFieldSignature(fieldNode.signature, annotations, context); } + return parseAnnotatedType(fieldNode.desc, 0, annotations.getBank(TypeReference.newTypeReference(TypeReference.FIELD)), context).getValue(); } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Main.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Main.java index 9ff8ae2755..557a02d87b 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Main.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Main.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; + +package net.fabricmc.filament.mappingpoet; import java.io.File; import java.io.IOException; @@ -46,16 +47,16 @@ 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; +import net.fabricmc.filament.mappingpoet.Environment.ClassNamePointer; +import net.fabricmc.filament.mappingpoet.Environment.NestedClassInfo; public class Main { - public static void main(String[] args) { if (args.length != 3 && args.length != 4) { System.out.println(" []"); return; } + Path mappings = Paths.get(args[0]); Path inputJar = Paths.get(args[1]); Path outputDirectory = Paths.get(args[2]); @@ -65,8 +66,8 @@ public class Main { 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); } } @@ -121,7 +122,7 @@ public class Main { scanNestedClasses(classNames, nestedClasses, librariesDir); } - try (final JarFile jarFile = new JarFile(jar.toFile())) { + try (JarFile jarFile = new JarFile(jar.toFile())) { Enumeration entryEnumerator = jarFile.entries(); while (entryEnumerator.hasMoreElements()) { @@ -136,12 +137,15 @@ public class Main { ClassNode classNode = new ClassNode(); reader.accept(classNode, ClassReader.SKIP_CODE); List superNames = new ArrayList<>(); + if (classNode.superName != null && !classNode.superName.equals("java/lang/Object")) { superNames.add(classNode.superName); } + if (classNode.interfaces != null) { superNames.addAll(classNode.interfaces); } + if (!superNames.isEmpty()) { supers.put(classNode.name, superNames); } @@ -183,7 +187,7 @@ public class Main { return FileVisitResult.CONTINUE; } - try (final JarFile jarFile = new JarFile(file.toFile())) { + try (JarFile jarFile = new JarFile(file.toFile())) { Enumeration entryEnumerator = jarFile.entries(); while (entryEnumerator.hasMoreElements()) { @@ -198,7 +202,8 @@ public class Main { reader.accept(new ClassVisitor(Opcodes.ASM9) { @Override public void visitInnerClass(String name, String outerName, String simpleName, int access) { - instanceInnerClasses.put(name, new Environment.NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName)); + instanceInnerClasses.put(name, new NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName)); + if (outerName != null) { classNames.put(name, new ClassNamePointer(simpleName, outerName)); } @@ -234,11 +239,14 @@ public class Main { private static void writeClass(MappingsStore mappings, ClassNode classNode, Map 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 int lastSearch = name.length(); + while (lastSearch != -1) { lastSearch = name.lastIndexOf('$', lastSearch - 1); + // names starting with digit is illegal java if (isDigit(name.charAt(lastSearch + 1))) { return; @@ -251,15 +259,16 @@ public class Main { if (name.contains("$")) { String parentClass = name.substring(0, name.lastIndexOf("$")); + if (!existingClasses.containsKey(parentClass)) { throw new RuntimeException("Could not find parent class: " + parentClass + " for " + classNode.name); } + existingClasses.get(parentClass).addInnerClass(classBuilder); } classBuilder.addMembers(); existingClasses.put(name, classBuilder); - } @FunctionalInterface diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/MappingsStore.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/MappingsStore.java index 84abd70f96..8786e72d27 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/MappingsStore.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/MappingsStore.java @@ -13,7 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; + +package net.fabricmc.filament.mappingpoet; + +import static net.fabricmc.mappingio.tree.MappingTreeView.SRC_NAMESPACE_ID; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.List; +import java.util.Map; import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; @@ -24,14 +33,6 @@ 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.Path; -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.List; -import java.util.Map; - -import static net.fabricmc.mappingio.tree.MappingTreeView.SRC_NAMESPACE_ID; - //Taken from loom public class MappingsStore { private final MappingTreeView tree; @@ -44,16 +45,19 @@ public class MappingsStore { private static MappingTreeView readMappings(Path input) { var tree = new MemoryMappingTree(); + try { - MappingReader.read(input, MappingFormat.TINY_2, new MappingSourceNsSwitch(tree, "named")); + MappingReader.read(input, MappingFormat.TINY_2_FILE, new MappingSourceNsSwitch(tree, "named")); } catch (IOException e) { throw new RuntimeException("Failed to read mappings", e); } + return tree; } private void addDoc(ElementMappingView element, DocAdder adder) { String doc = element.getComment(); + if (doc != null) { adder.addJavadoc("$L", doc); } @@ -61,11 +65,14 @@ public class MappingsStore { public void addClassDoc(DocAdder adder, String className) { var classDef = tree.getClass(className); + if (classDef == null) { return; } + addDoc(classDef, adder); adder.addJavadoc("\n"); + 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); @@ -74,17 +81,20 @@ public class MappingsStore { public void addFieldDoc(DocAdder addJavadoc, String owner, String name, String desc) { var classDef = tree.getClass(owner); + if (classDef == null) { return; } var fieldDef = classDef.getField(name, desc); + if (fieldDef == null) { return; } addDoc(fieldDef, addJavadoc); addJavadoc.addJavadoc("\n"); + for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) { String transformedName = fieldDef.getName(id); String mixinForm = "L" + classDef.getName(id) + ";" + transformedName + ":" + fieldDef.getDesc(id); @@ -94,11 +104,14 @@ public class MappingsStore { public Map.Entry getParamNameAndDoc(Environment environment, String owner, String name, String desc, int index) { var found = searchMethod(environment, owner, name, desc); + if (found != null) { var methodDef = found.getValue(); + if (methodDef.getArgs().isEmpty()) { return null; } + return methodDef.getArgs().stream() .filter(param -> param.getLvIndex() == index) // Map.entry() is null-hostile @@ -106,17 +119,20 @@ public class MappingsStore { .findFirst() .orElse(null); } + return null; } public void addMethodDoc(DocAdder adder, Environment environment, String owner, String name, String desc) { var found = searchMethod(environment, owner, name, desc); + if (found == null) { return; } var methodDef = found.getValue(); var ownerDef = found.getKey(); + if (!ownerDef.equals(methodDef.getOwner())) { adder.addJavadoc("{@inheritDoc}"); } else { @@ -124,6 +140,7 @@ public class MappingsStore { } adder.addJavadoc("\n"); + for (int id = SRC_NAMESPACE_ID; id < maxNamespace; id++) { String transformedName = methodDef.getName(id); String mixinForm = "L" + ownerDef.getName(id) + ";" + transformedName + methodDef.getDesc(id); @@ -134,16 +151,19 @@ public class MappingsStore { private Map.Entry searchMethod(Environment environment, String owner, String name, String desc) { var classDef = tree.getClass(owner); - if (classDef == null) + if (classDef == null) { return null; + } var methodDef = classDef.getMethod(name, desc); - if (methodDef != null) - return Map.entry(methodDef.getOwner(), methodDef); + if (methodDef != null) { + return Map.entry(methodDef.getOwner(), methodDef); + } for (String superName : environment.superTypes().getOrDefault(owner, List.of())) { var ret = searchMethod(environment, superName, name, desc); + if (ret != null) { return ret; } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/MethodBuilder.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/MethodBuilder.java index afe2bc3faf..dd9ba92647 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/MethodBuilder.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/MethodBuilder.java @@ -13,23 +13,9 @@ * 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; +package net.fabricmc.filament.mappingpoet; -import javax.lang.model.element.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -39,6 +25,23 @@ import java.util.List; import java.util.Map; import java.util.Set; +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.filament.mappingpoet.signature.AnnotationAwareDescriptors; +import net.fabricmc.filament.mappingpoet.signature.AnnotationAwareSignatures; +import net.fabricmc.filament.mappingpoet.signature.MethodSignature; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationBank; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationMapping; +import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationStorage; + public class MethodBuilder { private static final Set RESERVED_KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", @@ -83,6 +86,7 @@ public class MethodBuilder { if (regularAnnotations == null || regularAnnotations.length <= index) { return; } + addDirectAnnotations(builder, regularAnnotations[index]); } @@ -90,6 +94,7 @@ public class MethodBuilder { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(FieldBuilder.parseAnnotation(annotation)); } @@ -104,8 +109,10 @@ public class MethodBuilder { usedNames.add(suggestedName); return suggestedName; } + int t = 2; String currentSuggestion = suggestedName + t; + while (usedNames.contains(currentSuggestion)) { t++; currentSuggestion = suggestedName + t; @@ -122,22 +129,29 @@ public class MethodBuilder { int newEnd = str.length(); int ltStart; ltStart = str.indexOf('<', newStart); + if (ltStart != -1 && ltStart < newEnd) { newEnd = ltStart; } + ltStart = str.indexOf('[', newStart); + if (ltStart != -1 && ltStart < newEnd) { newEnd = ltStart; } + int dotEnd; + if ((dotEnd = str.lastIndexOf(".", newEnd)) != -1) { newStart = dotEnd + 1; } + str = Character.toLowerCase(str.charAt(newStart)) + str.substring(newStart + 1, newEnd); if (str.equals("boolean")) { str = "bool"; } + return str; } @@ -165,6 +179,7 @@ public class MethodBuilder { if (regularAnnotations == null) { return; } + for (AnnotationNode annotation : regularAnnotations) { builder.addAnnotation(FieldBuilder.parseAnnotation(annotation)); } @@ -177,6 +192,7 @@ public class MethodBuilder { } TypeName typeName; + if (signature != null) { typeName = signature.result(); } else { @@ -185,6 +201,7 @@ public class MethodBuilder { } builder.returns(typeName); + if (typeName != TypeName.VOID && !builder.modifiers.contains(Modifier.ABSTRACT)) { builder.addStatement("throw new RuntimeException()"); } else if (methodNode.annotationDefault != null) { @@ -202,8 +219,10 @@ public class MethodBuilder { // generate receiver param for type annos TypeAnnotationBank receiverAnnos = typeAnnotations.getBank(TypeReference.newTypeReference(TypeReference.METHOD_RECEIVER)); + if (!receiverAnnos.isEmpty()) { ParameterSpec.Builder receiverBuilder; + // only instance inner class ctor can have receivers if (methodNode.name.equals("")) { TypeName annotatedReceiver = AnnotationAwareSignatures.parseSignature("L" + receiverSignature.substring(0, receiverSignature.lastIndexOf('.')) + ";", receiverAnnos, environment); @@ -217,6 +236,7 @@ public class MethodBuilder { 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 builder.addParameter(receiverBuilder.build()); } @@ -224,12 +244,15 @@ public class MethodBuilder { List[] visibleParameterAnnotations = methodNode.visibleParameterAnnotations; List[] invisibleParameterAnnotations = methodNode.invisibleParameterAnnotations; int index = 0; + for (ParamType paramType : paramTypes) { paramType.fillName(usedParamNames); ParameterSpec.Builder paramBuilder = ParameterSpec.builder(paramType.type, paramType.name, paramType.modifiers); + if (paramType.comment != null) { paramBuilder.addJavadoc(paramType.comment + "\n"); } + addDirectAnnotations(paramBuilder, visibleParameterAnnotations, index); addDirectAnnotations(paramBuilder, invisibleParameterAnnotations, index); builder.addParameter(paramBuilder.build()); @@ -246,9 +269,11 @@ public class MethodBuilder { if (desc.charAt(index) != '(') { throw invalidMethodDesc(desc, index); } + index++; // consume '(' Iterator signatureParamIterator = signature == null ? Collections.emptyIterator() : signature.parameters().iterator(); + while (desc.charAt(index) != ')') { int oldIndex = index; Map.Entry parsedParam = FieldBuilder.parseType(desc, index); @@ -257,19 +282,25 @@ public class MethodBuilder { if (paramIndex >= formalParamStartIndex) { // skip guessed synthetic/implicit params TypeName parsedType; + if (signatureParamIterator.hasNext()) { parsedType = signatureParamIterator.next(); } else { parsedType = AnnotationAwareDescriptors.parseDesc(desc.substring(oldIndex, index), typeAnnotations.getBank(TypeReference.newFormalParameterReference(paramIndex - formalParamStartIndex)), environment); } + 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)) { slot++; } + paramIndex++; } + /* bruh, we don't care about return type index++; // consume ')' Map.Entry parsedReturn = FieldBuilder.parseType(desc, index); @@ -283,11 +314,15 @@ public class MethodBuilder { for (TypeName each : signature.thrown()) { builder.addException(each); } + return; } + List exceptions = methodNode.exceptions; + if (exceptions != null) { int index = 0; + for (String internalName : exceptions) { builder.addException(AnnotationAwareDescriptors.parseType(internalName, typeAnnotations.getBank(TypeReference.newExceptionReference(index)), environment)); index++; @@ -309,8 +344,9 @@ public class MethodBuilder { private final Modifier[] modifiers; private String name; - public ParamType(Map.Entry nameAndDoc, TypeName type, Set usedNames, int slot) { + ParamType(Map.Entry nameAndDoc, TypeName type, Set usedNames, int slot) { this.name = nameAndDoc != null ? nameAndDoc.getKey() : null; + if (this.name != null) { if (usedNames.contains(this.name)) { System.err.printf("Overridden parameter name detected in %s %s %s slot %d, resetting%n", classNode.name, methodNode.name, methodNode.desc, slot); @@ -319,6 +355,7 @@ public class MethodBuilder { usedNames.add(this.name); } } + this.comment = nameAndDoc == null ? null : nameAndDoc.getValue(); this.type = type; this.modifiers = new ModifierBuilder(0) @@ -329,6 +366,7 @@ public class MethodBuilder { if (name != null) { return; } + name = reserveValidName(suggestName(type), usedNames); } } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/ModifierBuilder.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/ModifierBuilder.java index 926ee94895..c4f04585d8 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/ModifierBuilder.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/ModifierBuilder.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; -import org.objectweb.asm.tree.ClassNode; +package net.fabricmc.filament.mappingpoet; -import javax.lang.model.element.Modifier; import java.util.ArrayList; import java.util.List; -public class ModifierBuilder { +import javax.lang.model.element.Modifier; +import org.objectweb.asm.tree.ClassNode; + +public class ModifierBuilder { private final int access; private boolean needsUnseal; @@ -48,7 +49,6 @@ public class ModifierBuilder { needsUnseal = true; } - return this; } @@ -59,6 +59,7 @@ public class ModifierBuilder { if (java.lang.reflect.Modifier.isFinal(access)) { modifiers.add(Modifier.FINAL); } + return modifiers.toArray(new Modifier[]{}); } @@ -73,9 +74,11 @@ public class ModifierBuilder { if (java.lang.reflect.Modifier.isAbstract(access) && type != Type.ENUM) { modifiers.add(Modifier.ABSTRACT); } + if (java.lang.reflect.Modifier.isStatic(access)) { modifiers.add(Modifier.STATIC); } + if (!java.lang.reflect.Modifier.isAbstract(access) && !java.lang.reflect.Modifier.isStatic(access) && type == Type.METHOD) { modifiers.add(Modifier.DEFAULT); } @@ -83,18 +86,23 @@ public class ModifierBuilder { if (java.lang.reflect.Modifier.isFinal(access) && type != Type.ENUM && type != Type.RECORD) { modifiers.add(Modifier.FINAL); } + if (java.lang.reflect.Modifier.isTransient(access) && type == Type.FIELD) { modifiers.add(Modifier.TRANSIENT); } + if (java.lang.reflect.Modifier.isVolatile(access) && type == Type.FIELD) { modifiers.add(Modifier.VOLATILE); } + if (java.lang.reflect.Modifier.isSynchronized(access) && type == Type.METHOD) { modifiers.add(Modifier.SYNCHRONIZED); } + if (java.lang.reflect.Modifier.isNative(access) && type == Type.METHOD) { modifiers.add(Modifier.NATIVE); } + if (java.lang.reflect.Modifier.isStrict(access)) { modifiers.add(Modifier.STRICTFP); // obsolete as of Java 17 } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Signatures.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Signatures.java index c2b996879c..522a72a397 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/Signatures.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/Signatures.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet; + +package net.fabricmc.filament.mappingpoet; import java.util.AbstractMap; import java.util.Collections; @@ -30,27 +31,30 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; import com.squareup.javapoet.WildcardTypeName; -import net.fabricmc.mappingpoet.signature.ClassSignature; -import net.fabricmc.mappingpoet.signature.MethodSignature; +import net.fabricmc.filament.mappingpoet.signature.ClassSignature; +import net.fabricmc.filament.mappingpoet.signature.MethodSignature; public final class Signatures { - public static ClassSignature parseClassSignature(final String signature) { // ;B:Ljava/lang/Object>Ljava/lang/Object; etc etc int index = 0; char ch; List generics = Collections.emptyList(); + if (signature.charAt(0) == '<') { // parse generic decl index++; // consume '<' // parse type params e.g. generics = new LinkedList<>(); + while ((ch = signature.charAt(index)) != '>') { int genericNameStart = index; + if (ch == ':') { throw errorAt(signature, index); } + do { index++; } while (signature.charAt(index) != ':'); @@ -59,14 +63,17 @@ public final class Signatures { List bounds = new LinkedList<>(); boolean classBound = true; + while (signature.charAt(index) == ':') { // parse bounds index++; // consume ':' + if (classBound && signature.charAt(index) == ':') { // No class bound, only interface bounds, so '::' classBound = false; continue; } + classBound = false; Map.Entry bound = parseParameterizedType(signature, index); index = bound.getKey(); @@ -80,6 +87,7 @@ public final class Signatures { } LinkedList supers = new LinkedList<>(); + while (index < signature.length()) { Map.Entry bound = parseParameterizedType(signature, index); index = bound.getKey(); @@ -93,17 +101,21 @@ public final class Signatures { int index = 0; char ch; List generics = Collections.emptyList(); + if (signature.charAt(0) == '<') { // parse generic decl index++; // consume '<' // parse type params e.g. generics = new LinkedList<>(); + while ((ch = signature.charAt(index)) != '>') { int genericNameStart = index; + if (ch == ':') { throw errorAt(signature, index); } + do { index++; } while (signature.charAt(index) != ':'); @@ -112,14 +124,17 @@ public final class Signatures { List bounds = new LinkedList<>(); boolean classBound = true; + while (signature.charAt(index) == ':') { // parse bounds index++; // consume ':' + if (classBound && signature.charAt(index) == ':') { // No class bound, only interface bounds, so '::' classBound = false; continue; } + classBound = false; Map.Entry bound = parseParameterizedType(signature, index); index = bound.getKey(); @@ -135,9 +150,11 @@ public final class Signatures { if (signature.charAt(index) != '(') { throw errorAt(signature, index); } + index++; // consume '(' LinkedList params = new LinkedList<>(); + while (signature.charAt(index) != ')') { Map.Entry param = parseParameterizedType(signature, index); index = param.getKey(); @@ -147,6 +164,7 @@ public final class Signatures { index++; // consume ')' TypeName returnType; + if (signature.charAt(index) == 'V') { returnType = TypeName.VOID; index++; @@ -157,6 +175,7 @@ public final class Signatures { } LinkedList thrown = new LinkedList<>(); + while (index < signature.length() && signature.charAt(index) == '^') { index++; // consume '^' Map.Entry parsedThrown = parseParameterizedType(signature, index); @@ -175,6 +194,7 @@ public final class Signatures { GenericStack stack = new GenericStack(); int index = startOffset; + // the loop parses a type and try to quit levels if possible do { char ch = signature.charAt(index); @@ -208,6 +228,7 @@ public final class Signatures { if (parseExactType) { int arrayLevel = 0; + while ((ch = signature.charAt(index)) == '[') { index++; arrayLevel++; @@ -230,9 +251,11 @@ public final class Signatures { case 'T': { // "TE;" for int nameStart = index; + while (signature.charAt(index) != ';') { index++; } + String typeVarName = signature.substring(nameStart, index); stack.add(TypeVariableName.get(typeVarName), arrayLevel, bounded, extendsBound); index++; // read ending ";" @@ -245,6 +268,7 @@ public final class Signatures { int nameStart = index; ClassName currentClass = null; int nextSimpleNamePrev = -1; + do { ch = signature.charAt(index); @@ -252,6 +276,7 @@ public final class Signatures { if (currentClass != null) { throw errorAt(signature, index); } + nextSimpleNamePrev = index; } @@ -264,6 +289,7 @@ public final class Signatures { String simpleName = signature.substring(nextSimpleNamePrev + 1, index); currentClass = currentClass.nestedClass(simpleName); } + nextSimpleNamePrev = index; } @@ -271,6 +297,7 @@ public final class Signatures { } while (ch != '<' && ch != ';'); assert currentClass != null; + if (ch == ';') { stack.add(currentClass, arrayLevel, bounded, extendsBound); } @@ -278,6 +305,7 @@ public final class Signatures { if (ch == '<') { stack.push(Frame.ofClass(currentClass), arrayLevel, bounded, extendsBound); } + break; } default: { @@ -288,6 +316,7 @@ public final class Signatures { // quit generics quitLoop: + while (stack.canQuit() && signature.charAt(index) == '>') { // pop stack.popFrame(); @@ -298,6 +327,7 @@ public final class Signatures { if (ch != '.') { throw errorAt(signature, index); } + index++; int innerNameStart = index; final int checkIndex = index; @@ -309,10 +339,13 @@ public final class Signatures { while (true) { ch = signature.charAt(index); + if (ch == '.' || ch == ';' || ch == '<') { String simpleName = signature.substring(innerNameStart, index); + if (ch == '.' || ch == ';') { stack.tweakLast(name -> ((ParameterizedTypeName) name).nestedClass(simpleName)); + if (ch == ';') { index++; break; @@ -329,9 +362,7 @@ public final class Signatures { } else { index++; } - } - } while (stack.canQuit()); assert stack.deque.size() == 1; @@ -345,9 +376,11 @@ public final class Signatures { public static TypeName wrap(TypeName component, int level, boolean bounded, boolean extendsBound) { TypeName ret = component; + for (int i = 0; i < level; i++) { ret = ArrayTypeName.of(ret); } + return bounded ? extendsBound ? WildcardTypeName.subtypeOf(ret) : WildcardTypeName.supertypeOf(ret) : ret; } @@ -372,6 +405,7 @@ public final class Signatures { case 'Z': return TypeName.BOOLEAN; } + throw new IllegalArgumentException("Invalid primitive " + c); } @@ -390,6 +424,7 @@ public final class Signatures { if (parameters.size() != 1) { throw new IllegalStateException(); } + return parameters.get(0); }; } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/jd/MappingTaglet.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/jd/MappingTaglet.java index 08bc6a36d7..043f7f9dad 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/jd/MappingTaglet.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/jd/MappingTaglet.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.jd; + +package net.fabricmc.filament.mappingpoet.jd; import java.util.EnumSet; import java.util.List; @@ -30,7 +31,6 @@ import jdk.javadoc.doclet.Taglet; @SuppressWarnings("unused") public final class MappingTaglet implements Taglet { - public MappingTaglet() { // Required by javadoc } @@ -59,9 +59,11 @@ public final class MappingTaglet implements Taglet { builder.append("\n"); builder.append("Namespace\n"); builder.append("Name\n"); + if (!typeDecl) { builder.append("Mixin selector\n"); } + builder.append("\n"); builder.append("\n"); @@ -71,9 +73,11 @@ public final class MappingTaglet implements Taglet { builder.append("\n"); builder.append(String.format("%s\n", escaped(ans[0]))); builder.append(String.format("%s\n", escaped(ans[1]))); + if (!typeDecl) { builder.append(String.format("%s\n", escaped(ans[2]))); } + builder.append("\n"); } @@ -86,14 +90,17 @@ public final class MappingTaglet implements Taglet { private static String escaped(String original) { StringBuilder builder = new StringBuilder(original.length()); final int len = original.length(); + for (int i = 0; i < len; i++) { char c = original.charAt(i); + if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') { builder.append("&#").append((int) c).append(";"); } else { builder.append(c); } } + return builder.toString(); } } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareDescriptors.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareDescriptors.java index c845c8d656..1139cf48ad 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareDescriptors.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareDescriptors.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.AbstractMap; import java.util.ArrayDeque; @@ -31,10 +32,9 @@ import com.squareup.javapoet.TypeName; import org.objectweb.asm.TypePath; import org.objectweb.asm.TypeReference; -import net.fabricmc.mappingpoet.Signatures; +import net.fabricmc.filament.mappingpoet.Signatures; public final class AnnotationAwareDescriptors { - private AnnotationAwareDescriptors() { } @@ -43,6 +43,7 @@ public final class AnnotationAwareDescriptors { ClassName superName = parseType(rawSuper, mapping.getBank(TypeReference.newSuperTypeReference(-1)), context); List interfaces = new ArrayList<>(rawInterfaces.size()); + for (ListIterator itr = rawInterfaces.listIterator(); itr.hasNext(); ) { int i = itr.nextIndex(); String item = itr.next(); @@ -59,12 +60,14 @@ public final class AnnotationAwareDescriptors { Deque> arrayAnnotations = new ArrayDeque<>(); int len = desc.length(); int index; + for (index = 0; (index < len) && (desc.charAt(index) == '['); index++) { arrayAnnotations.push(bank.getCurrentAnnotations()); bank = bank.advance(TypePath.ARRAY_ELEMENT, 0); } TypeName current; + if (len - index == 1) { current = annotate(Signatures.getPrimitive(desc.charAt(index)), bank); } else { @@ -72,9 +75,11 @@ public final class AnnotationAwareDescriptors { assert desc.charAt(index) == 'L' && desc.charAt(len - 1) == ';'; current = parseType(desc.substring(index + 1, len - 1), bank, context); } + while (!arrayAnnotations.isEmpty()) { current = ArrayTypeName.of(current); List specs = arrayAnnotations.pop(); + if (!specs.isEmpty()) { current = current.annotated(specs); } @@ -101,10 +106,12 @@ public final class AnnotationAwareDescriptors { if (internalName.startsWith("L") && internalName.endsWith(";")) { throw new AssertionError(internalName); } + int slice = internalName.lastIndexOf('/'); String packageSt = slice < 0 ? "" : internalName.substring(0, slice).replace('/', '.'); int moneySign = internalName.indexOf('$', slice + 1); + if (moneySign == -1) { return new AbstractMap.SimpleImmutableEntry<>(ClassName.get(packageSt, internalName.substring(slice + 1)), bank); } @@ -113,8 +120,10 @@ public final class AnnotationAwareDescriptors { final int len = internalName.length(); boolean enteredInner = false; + for (int i = moneySign; i < len; ) { int t = internalName.indexOf('$', i + 1); + if (t < 0) { t = len; } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareSignatures.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareSignatures.java index d762dfc0a5..ae952ea872 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareSignatures.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/AnnotationAwareSignatures.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import com.squareup.javapoet.TypeName; import org.objectweb.asm.TypeReference; import org.objectweb.asm.signature.SignatureReader; public final class AnnotationAwareSignatures { - private AnnotationAwareSignatures() { } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassSignature.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassSignature.java index ab15942dcc..1fd16cfece 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassSignature.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassSignature.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.List; @@ -22,6 +23,5 @@ import com.squareup.javapoet.TypeVariableName; // no more a class signature but general super info about class public record ClassSignature(List generics, TypeName superclass, - List superinterfaces) { - + List superinterfaces) { } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassStaticContext.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassStaticContext.java index 22e0536280..0cfc4da43b 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassStaticContext.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/ClassStaticContext.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; /** * A context to retrieve if a class is an instance inner class. Useful for @@ -22,7 +23,6 @@ package net.fabricmc.mappingpoet.signature; * an example in JVM Specification 15. */ public interface ClassStaticContext { - /** * Returns if this class is an instance inner class. * diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/MethodSignature.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/MethodSignature.java index bea2f7222e..b45e800b64 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/MethodSignature.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/MethodSignature.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.List; @@ -23,5 +24,4 @@ import com.squareup.javapoet.TypeVariableName; public record MethodSignature(List generics, List parameters, TypeName result, List thrown) { - } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetClassMethodSignatureVisitor.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetClassMethodSignatureVisitor.java index a65c6ae575..ff5325dbd8 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetClassMethodSignatureVisitor.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetClassMethodSignatureVisitor.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.ArrayList; @@ -24,7 +25,6 @@ import org.objectweb.asm.TypeReference; import org.objectweb.asm.signature.SignatureVisitor; public final class PoetClassMethodSignatureVisitor extends SignatureVisitor { - private final TypeAnnotationMapping mapping; private final ClassStaticContext context; private final boolean forClass; @@ -91,8 +91,8 @@ public final class PoetClassMethodSignatureVisitor extends SignatureVisitor { private SignatureVisitor visitLowerBound() { collectLowerBound(); - TypeAnnotationBank bank = mapping.getBank(TypeReference.newTypeParameterBoundReference(forClass ? - TypeReference.CLASS_TYPE_PARAMETER_BOUND : TypeReference.METHOD_TYPE_PARAMETER_BOUND, generics.size(), + TypeAnnotationBank bank = mapping.getBank(TypeReference.newTypeParameterBoundReference(forClass + ? TypeReference.CLASS_TYPE_PARAMETER_BOUND : TypeReference.METHOD_TYPE_PARAMETER_BOUND, generics.size(), currentGenericBounds.size())); return pendingLowerBound = new PoetTypeSignatureWriter(bank, context); } diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetTypeSignatureWriter.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetTypeSignatureWriter.java index c4e920b3aa..e2633991f9 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetTypeSignatureWriter.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/PoetTypeSignatureWriter.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.ArrayList; import java.util.Map; @@ -29,7 +30,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.TypePath; import org.objectweb.asm.signature.SignatureVisitor; -import net.fabricmc.mappingpoet.Signatures; +import net.fabricmc.filament.mappingpoet.Signatures; /** * A type signature to javapoet visitor. @@ -39,7 +40,6 @@ import net.fabricmc.mappingpoet.Signatures; * can be defined.

*/ public final class PoetTypeSignatureWriter extends SignatureVisitor { - private final ClassStaticContext context; private final ArrayList params = new ArrayList<>(); private /* NonNull */ TypeAnnotationBank storage; // mutable @@ -132,6 +132,7 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor { } else { currentType = ((ClassName) currentType).nestedClass(nestedClassName); } + nestedClassName = null; } @@ -150,10 +151,10 @@ public final class PoetTypeSignatureWriter extends SignatureVisitor { if (activeTypeArgument != null) { TypeName hold = activeTypeArgument.compute(); TypeName used = switch (activeTypeArgumentKind) { - case SignatureVisitor.EXTENDS -> WildcardTypeName.subtypeOf(hold); - case SignatureVisitor.SUPER -> WildcardTypeName.supertypeOf(hold); - case SignatureVisitor.INSTANCEOF -> hold; - default -> throw new IllegalStateException(String.format("Illegal type argument wildcard %s", activeTypeArgumentKind)); + case SignatureVisitor.EXTENDS -> WildcardTypeName.subtypeOf(hold); + case SignatureVisitor.SUPER -> WildcardTypeName.supertypeOf(hold); + case SignatureVisitor.INSTANCEOF -> hold; + default -> throw new IllegalStateException(String.format("Illegal type argument wildcard %s", activeTypeArgumentKind)); }; used = AnnotationAwareDescriptors.annotate(used, storage.advance(TypePath.TYPE_ARGUMENT, params.size())); diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationBank.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationBank.java index 2a26517d47..3ee2995934 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationBank.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationBank.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.Collections; import java.util.List; diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationMapping.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationMapping.java index 340cd25e16..41bb1a76cf 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationMapping.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationMapping.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import org.objectweb.asm.TypeReference; @@ -21,7 +22,6 @@ import org.objectweb.asm.TypeReference; * The collection of type annotations from a bytecode structure that stores type annotations. */ public interface TypeAnnotationMapping { - TypeAnnotationMapping EMPTY = reference -> TypeAnnotationBank.EMPTY; // implNote: TypeReference is not a pojo! No equals or hash! diff --git a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationStorage.java b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationStorage.java index c1322661e0..df8bf47654 100644 --- a/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationStorage.java +++ b/filament/src/main/java/net/fabricmc/filament/mappingpoet/signature/TypeAnnotationStorage.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.fabricmc.mappingpoet.signature; + +package net.fabricmc.filament.mappingpoet.signature; import java.util.ArrayList; import java.util.Arrays; @@ -25,10 +26,9 @@ import org.objectweb.asm.TypePath; import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.TypeAnnotationNode; -import net.fabricmc.mappingpoet.FieldBuilder; +import net.fabricmc.filament.mappingpoet.FieldBuilder; public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeAnnotationBank { - private final int[] targets; // target type and info, only exist in mapping version private final String[] paths; private final AnnotationSpec[] contents; @@ -51,15 +51,18 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA static int comparePath(TypePath left, TypePath right) { int len = Math.min(left.getLength(), right.getLength()); + for (int i = 0; i < len; i++) { int leftStep = left.getStep(i); int rightStep = right.getStep(i); + if (leftStep != rightStep) { return Integer.compare(leftStep, rightStep); } int leftStepArg = left.getStepArgument(i); int rightStepArg = right.getStepArgument(i); + if (leftStepArg != rightStepArg) { return Integer.compare(leftStepArg, rightStepArg); } @@ -97,14 +100,15 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA String hiCheck = check.substring(0, check.length() - 1).concat(Character.toString((char) (check.charAt(check.length() - 1) + 1))); - int low = Arrays.binarySearch(paths, startIndex, endIndex, check); + if (low < 0) { low = -(low + 1); } // exclusive hi int hi = Arrays.binarySearch(paths, startIndex, endIndex, hiCheck); + if (hi < 0) { hi = -(hi + 1); } @@ -119,6 +123,7 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA } int hi = Arrays.binarySearch(paths, startIndex, endIndex, currentPath + '\u0000'); + if (hi < 0) { hi = -(hi + 1); } @@ -140,12 +145,14 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA int target = reference.getValue(); // inclusive low int low = Arrays.binarySearch(targets, startIndex, endIndex, target); + if (low < 0) { low = -(low + 1); } // exclusive hi int hi = Arrays.binarySearch(targets, startIndex, endIndex, target + 1); + if (hi < 0) { hi = -(hi + 1); } @@ -154,7 +161,6 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA } public static final class Builder { - final List entries = new ArrayList<>(); Builder() { @@ -169,9 +175,11 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA if (nodes == null) { return this; // thanks asm } + for (TypeAnnotationNode node : nodes) { entries.add(new Entry(node.typeRef, node.typePath == null ? "" : node.typePath.toString(), FieldBuilder.parseAnnotation(node))); } + return this; } @@ -184,6 +192,7 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA AnnotationSpec[] contents = new AnnotationSpec[len]; Iterator itr = this.entries.iterator(); + for (int i = 0; i < len; i++) { Entry entry = itr.next(); targets[i] = entry.target; @@ -212,6 +221,5 @@ public final class TypeAnnotationStorage implements TypeAnnotationMapping, TypeA return path.compareTo(o.path); } } - } }