Fix platform support

- Prefer TypeElements over TypeMirrors
- Add debug option to log classes that couldn't be loaded
- Reorganize exception logging
This commit is contained in:
Fury_Phoenix 2023-12-09 19:03:45 -08:00
parent 06a02dc445
commit 077f726bae
No known key found for this signature in database
GPG Key ID: 0595F98084987DB8
4 changed files with 113 additions and 60 deletions

View File

@ -17,7 +17,6 @@ dependencies {
compileOnly 'com.google.auto.service:auto-service:1.1.1' compileOnly 'com.google.auto.service:auto-service:1.1.1'
implementation "net.fabricmc:sponge-mixin:0.12.5+" implementation "net.fabricmc:sponge-mixin:0.12.5+"
implementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
implementation project(":annotations") implementation project(":annotations")
} }
@ -30,4 +29,4 @@ spotless {
removeUnusedImports() removeUnusedImports()
} }
} }
version = '1.1.0' version = '1.1.1'

View File

@ -1,7 +1,11 @@
package org.fury_phoenix.mixinAp.annotation; package org.fury_phoenix.mixinAp.annotation;
import com.google.common.base.Throwables;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.invoke.*;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -9,10 +13,10 @@ import java.util.stream.Stream;
import javax.annotation.processing.Messager; import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
@ -28,24 +32,50 @@ public class ClientMixinValidator {
private final ITypeHandleProvider typeHandleProvider; private final ITypeHandleProvider typeHandleProvider;
private final ProcessingEnvironment processingEnv;
private final Messager messager; private final Messager messager;
private final Elements elemUtils; private final Elements elemUtils;
private final Class<? extends Annotation> markerClass = getMarkerClass(); private final Types types;
private static final Set<String> markers = Set.of( private final boolean debug;
private final Class<? extends Annotation> markerClass = getMarkerClass(markers);
private final Class<? extends Enum<?>> markerEnumClass = getMarkerEnumClass(markerEnums);
private static final Collection<String> markers = Set.of(
"net.fabricmc.api.Environment", "net.fabricmc.api.Environment",
"net.minecraftforge.api.distmarker.OnlyIn", "net.minecraftforge.api.distmarker.OnlyIn",
"net.neoforged.api.distmarker.OnlyIn"); "net.neoforged.api.distmarker.OnlyIn");
public ClientMixinValidator(ProcessingEnvironment env) { private static final Collection<String> markerEnums = Set.of(
"net.fabricmc.api.EnvType",
"net.minecraftforge.api.distmarker.Dist",
"net.neoforged.api.distmarker.Dist");
private static final Collection<String> unannotatedClasses = new HashSet<>();
private static final MethodHandles.Lookup lookup = MethodHandles.publicLookup();
private final MethodType enumValueAccessorType = MethodType.methodType(markerEnumClass);
private final MethodHandle enumValueAccessor;
public ClientMixinValidator(ProcessingEnvironment env)
throws ReflectiveOperationException {
typeHandleProvider = AnnotatedMixinsAccessor.getMixinAP(env); typeHandleProvider = AnnotatedMixinsAccessor.getMixinAP(env);
processingEnv = env; debug = Boolean.valueOf(env.getOptions().get("org.fury_phoenix.mixinAp.validator.debug"));
messager = env.getMessager(); messager = env.getMessager();
elemUtils = env.getElementUtils(); elemUtils = env.getElementUtils();
types = env.getTypeUtils();
try { enumValueAccessor = getMethod(markerClass); }
catch (ReflectiveOperationException e) { throw e; }
}
private MethodHandle getMethod(Class<?> clz)
throws ReflectiveOperationException {
return lookup.findVirtual(clz, "value", enumValueAccessorType);
} }
public boolean validateMixin(TypeElement annotatedMixinClass) { public boolean validateMixin(TypeElement annotatedMixinClass) {
@ -61,44 +91,52 @@ public class ClientMixinValidator {
} }
private boolean targetsClient(List<?> classTargets) { private boolean targetsClient(List<?> classTargets) {
return classTargets.stream() return classTargets.stream().anyMatch(this::targetsClient);
.anyMatch(this::targetsClient);
} }
private boolean targetsClient(Object classTarget) { private boolean targetsClient(Object classTarget) {
return switch (classTarget) { return switch (classTarget) {
case TypeMirror tm -> case TypeElement te ->
isClientMarked(tm); isClientMarked(te);
case TypeMirror tm -> {
var el = types.asElement(tm);
yield el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
}
// If you're using a dollar sign in class names you are insane // If you're using a dollar sign in class names you are insane
case String s -> case String s -> {
targetsClient(elemUtils.getTypeElement(toSourceString(s.split("\\$")[0])).asType()); var te =
elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
yield te != null ? targetsClient(te) : warn(s);
}
default -> default ->
throw new IllegalArgumentException("Unhandled type: " + classTarget.getClass() + "\n" throw new IllegalArgumentException("Unhandled type: "
+ "Stringified contents: " + classTarget.toString()); + classTarget.getClass() + "\n" + "Stringified contents: "
+ classTarget.toString());
}; };
} }
private boolean isClientMarked(AnnotatedConstruct ac) { private boolean isClientMarked(TypeElement te) {
TypeHandle handle = getTypeHandle(ac); Annotation marker = te.getAnnotation(markerClass);
if(handle == null) { if(marker == null) {
messager.printMessage(Diagnostic.Kind.WARNING, "Class can't be loaded! " + ac); if(debug && unannotatedClasses.add(te.toString())) {
messager.printMessage(Diagnostic.Kind.WARNING,
"Missing " + markerClass.getCanonicalName() + " on " + te + "!");
}
return false; return false;
} }
IAnnotationHandle marker = handle.getAnnotation(markerClass); try {
Object value = enumValueAccessor.invoke(marker);
if(marker == null) return false; return value.toString().equals("CLIENT");
} catch (Throwable e) {
String[] markerEnum = marker.getValue("value"); messager.printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
Throwables.getStackTraceAsString(e));
if(markerEnum == null) return false; }
return false;
String markerEnumValue = markerEnum[1];
return markerEnumValue.toString().equals("CLIENT");
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static Class<? extends Annotation> getMarkerClass() { private static Class<? extends Annotation> getMarkerClass(Collection<String> markerSet) {
for(var annotation : markers) { for(var annotation : markerSet) {
try { try {
return (Class<Annotation>)Class.forName(annotation); return (Class<Annotation>)Class.forName(annotation);
} catch (ClassNotFoundException e) {} } catch (ClassNotFoundException e) {}
@ -106,8 +144,19 @@ public class ClientMixinValidator {
return null; return null;
} }
@SuppressWarnings("unchecked")
private static Class<? extends Enum<?>> getMarkerEnumClass(Collection<String> enumSet) {
for(var enumClass : enumSet) {
try {
return (Class<Enum<?>>)Class.forName(enumClass);
} catch (ClassNotFoundException e) {}
}
return null;
}
private boolean warn(Object o) { private boolean warn(Object o) {
messager.printMessage(Diagnostic.Kind.WARNING, o + " can't be loaded, so it is skipped!"); messager.printMessage(Diagnostic.Kind.WARNING,
toSourceString(o.toString()) + " can't be loaded, so it is skipped!");
return false; return false;
} }
@ -117,7 +166,8 @@ public class ClientMixinValidator {
annotatedMixinClass.getQualifiedName(), annotatedMixinClass.getQualifiedName(),
ClientMixinValidator.getTargets( ClientMixinValidator.getTargets(
getAnnotationHandle(annotatedMixinClass, Mixin.class) getAnnotationHandle(annotatedMixinClass, Mixin.class)
).stream().filter(this::targetsClient) ).stream()
.filter(this::targetsClient)
.map(Object::toString) .map(Object::toString)
.map(ClientMixinValidator::toSourceString) .map(ClientMixinValidator::toSourceString)
.collect(Collectors.joining(", ")) .collect(Collectors.joining(", "))
@ -128,7 +178,8 @@ public class ClientMixinValidator {
return typeHandleProvider.getTypeHandle(annotatedClass); return typeHandleProvider.getTypeHandle(annotatedClass);
} }
private IAnnotationHandle getAnnotationHandle(Object annotatedClass, Class<? extends Annotation> annotation) { private IAnnotationHandle
getAnnotationHandle(Object annotatedClass, Class<? extends Annotation> annotation) {
return getTypeHandle(annotatedClass).getAnnotation(annotation); return getTypeHandle(annotatedClass).getAnnotation(annotation);
} }

View File

@ -1,6 +1,7 @@
package org.fury_phoenix.mixinAp.annotation; package org.fury_phoenix.mixinAp.annotation;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
import com.google.common.base.Throwables;
import java.util.List; import java.util.List;
import java.util.HashMap; import java.util.HashMap;
@ -23,7 +24,7 @@ import javax.tools.Diagnostic;
import org.fury_phoenix.mixinAp.config.MixinConfig; import org.fury_phoenix.mixinAp.config.MixinConfig;
@SupportedAnnotationTypes({"org.spongepowered.asm.mixin.Mixin", "org.embeddedt.modernfix.annotation.ClientOnlyMixin"}) @SupportedAnnotationTypes({"org.spongepowered.asm.mixin.Mixin", "org.embeddedt.modernfix.annotation.ClientOnlyMixin"})
@SupportedOptions({"rootProject.name", "project.name"}) @SupportedOptions({"rootProject.name", "project.name", "org.fury_phoenix.mixinAp.validator.debug"})
@SupportedSourceVersion(SourceVersion.RELEASE_17) @SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(Processor.class) @AutoService(Processor.class)
public class MixinProcessor extends AbstractProcessor { public class MixinProcessor extends AbstractProcessor {
@ -38,22 +39,28 @@ public class MixinProcessor extends AbstractProcessor {
@Override @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if(roundEnv.processingOver()){ try {
filterMixinSets(); if(roundEnv.processingOver()){
// create record for serialization, compute package name filterMixinSets();
String packageName = mixinConfigList.get("mixins").get(0).split("(?<=mixin)")[0]; // create record for serialization, compute package name
finalizeMixinConfig(); String packageName = mixinConfigList.get("mixins").get(0).split("(?<=mixin)")[0];
new MixinConfig(packageName, finalizeMixinConfig();
mixinConfigList.get("mixins"), new MixinConfig(packageName,
mixinConfigList.get("client") mixinConfigList.get("mixins"),
).generateMixinConfig(processingEnv); mixinConfigList.get("client")
} else { ).generateMixinConfig(processingEnv);
processMixins(annotations, roundEnv); } else {
processMixins(annotations, roundEnv);
}
} catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
Throwables.getStackTraceAsString(e));
} }
return false; return false;
} }
private void processMixins(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { private void processMixins(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
throws ReflectiveOperationException {
for (TypeElement annotation : annotations) { for (TypeElement annotation : annotations) {
Set<? extends Element> annotatedMixins = roundEnv.getElementsAnnotatedWith(annotation); Set<? extends Element> annotatedMixins = roundEnv.getElementsAnnotatedWith(annotation);
@ -78,7 +85,8 @@ public class MixinProcessor extends AbstractProcessor {
commonSet.removeAll(mixinConfigList.get("client")); commonSet.removeAll(mixinConfigList.get("client"));
} }
private void validateCommonMixins(TypeElement annotation, Stream<TypeElement> mixins) { private void validateCommonMixins(TypeElement annotation, Stream<TypeElement> mixins)
throws ReflectiveOperationException {
if(!annotation.getSimpleName().toString().equals("Mixin")) if(!annotation.getSimpleName().toString().equals("Mixin"))
return; return;
ClientMixinValidator validator = new ClientMixinValidator(processingEnv); ClientMixinValidator validator = new ClientMixinValidator(processingEnv);

View File

@ -1,6 +1,5 @@
package org.fury_phoenix.mixinAp.config; package org.fury_phoenix.mixinAp.config;
import com.google.common.base.Throwables;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
@ -10,7 +9,6 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.Diagnostic;
import javax.tools.StandardLocation; import javax.tools.StandardLocation;
public record MixinConfig( public record MixinConfig(
@ -37,12 +35,12 @@ public record MixinConfig(
public static final OverwriteOptions DEFAULT = new OverwriteOptions(true); public static final OverwriteOptions DEFAULT = new OverwriteOptions(true);
} }
public void generateMixinConfig(ProcessingEnvironment env) { public void generateMixinConfig(ProcessingEnvironment env) throws IOException {
try ( try (
Writer mixinConfigWriter = env.getFiler() Writer mixinConfigWriter = env.getFiler()
.createResource(StandardLocation.SOURCE_OUTPUT, "", .createResource(StandardLocation.SOURCE_OUTPUT, "",
MixinConfig.computeMixinConfigPath( MixinConfig.computeMixinConfigPath(
env.getOptions().get("rootProject.name"), Optional.of(env.getOptions().get("rootProject.name")),
Optional.ofNullable(env.getOptions().get("project.name")) Optional.ofNullable(env.getOptions().get("project.name"))
) )
).openWriter() ).openWriter()
@ -54,15 +52,12 @@ public record MixinConfig(
mixinConfigWriter.write(mixinConfig); mixinConfigWriter.write(mixinConfig);
mixinConfigWriter.write("\n"); mixinConfigWriter.write("\n");
} catch (IOException e) { } catch (IOException e) { throw e; }
env.getMessager().printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
Throwables.getStackTraceAsString(e));
}
} }
private static String computeMixinConfigPath(String rootProjectName, Optional<String> projectName) { private static String computeMixinConfigPath(Optional<String> rootProjectName, Optional<String> projectName) {
return "resources/" + return "resources/" +
rootProjectName + rootProjectName.get() +
(projectName.isPresent() ? "-" : "") + (projectName.isPresent() ? "-" : "") +
projectName.orElse("") + projectName.orElse("") +
".mixins.json"; ".mixins.json";