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:
parent
06a02dc445
commit
077f726bae
|
|
@ -17,7 +17,6 @@ dependencies {
|
|||
compileOnly 'com.google.auto.service:auto-service:1.1.1'
|
||||
|
||||
implementation "net.fabricmc:sponge-mixin:0.12.5+"
|
||||
implementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
implementation project(":annotations")
|
||||
}
|
||||
|
||||
|
|
@ -30,4 +29,4 @@ spotless {
|
|||
removeUnusedImports()
|
||||
}
|
||||
}
|
||||
version = '1.1.0'
|
||||
version = '1.1.1'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package org.fury_phoenix.mixinAp.annotation;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -9,10 +13,10 @@ import java.util.stream.Stream;
|
|||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.AnnotatedConstruct;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
|
|
@ -28,24 +32,50 @@ public class ClientMixinValidator {
|
|||
|
||||
private final ITypeHandleProvider typeHandleProvider;
|
||||
|
||||
private final ProcessingEnvironment processingEnv;
|
||||
|
||||
private final Messager messager;
|
||||
|
||||
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.minecraftforge.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);
|
||||
processingEnv = env;
|
||||
debug = Boolean.valueOf(env.getOptions().get("org.fury_phoenix.mixinAp.validator.debug"));
|
||||
messager = env.getMessager();
|
||||
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) {
|
||||
|
|
@ -61,44 +91,52 @@ public class ClientMixinValidator {
|
|||
}
|
||||
|
||||
private boolean targetsClient(List<?> classTargets) {
|
||||
return classTargets.stream()
|
||||
.anyMatch(this::targetsClient);
|
||||
return classTargets.stream().anyMatch(this::targetsClient);
|
||||
}
|
||||
|
||||
private boolean targetsClient(Object classTarget) {
|
||||
return switch (classTarget) {
|
||||
case TypeMirror tm ->
|
||||
isClientMarked(tm);
|
||||
case TypeElement te ->
|
||||
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
|
||||
case String s ->
|
||||
targetsClient(elemUtils.getTypeElement(toSourceString(s.split("\\$")[0])).asType());
|
||||
case String s -> {
|
||||
var te =
|
||||
elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
|
||||
yield te != null ? targetsClient(te) : warn(s);
|
||||
}
|
||||
default ->
|
||||
throw new IllegalArgumentException("Unhandled type: " + classTarget.getClass() + "\n"
|
||||
+ "Stringified contents: " + classTarget.toString());
|
||||
throw new IllegalArgumentException("Unhandled type: "
|
||||
+ classTarget.getClass() + "\n" + "Stringified contents: "
|
||||
+ classTarget.toString());
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isClientMarked(AnnotatedConstruct ac) {
|
||||
TypeHandle handle = getTypeHandle(ac);
|
||||
if(handle == null) {
|
||||
messager.printMessage(Diagnostic.Kind.WARNING, "Class can't be loaded! " + ac);
|
||||
private boolean isClientMarked(TypeElement te) {
|
||||
Annotation marker = te.getAnnotation(markerClass);
|
||||
if(marker == null) {
|
||||
if(debug && unannotatedClasses.add(te.toString())) {
|
||||
messager.printMessage(Diagnostic.Kind.WARNING,
|
||||
"Missing " + markerClass.getCanonicalName() + " on " + te + "!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
IAnnotationHandle marker = handle.getAnnotation(markerClass);
|
||||
|
||||
if(marker == null) return false;
|
||||
|
||||
String[] markerEnum = marker.getValue("value");
|
||||
|
||||
if(markerEnum == null) return false;
|
||||
|
||||
String markerEnumValue = markerEnum[1];
|
||||
return markerEnumValue.toString().equals("CLIENT");
|
||||
try {
|
||||
Object value = enumValueAccessor.invoke(marker);
|
||||
return value.toString().equals("CLIENT");
|
||||
} catch (Throwable e) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
|
||||
Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Class<? extends Annotation> getMarkerClass() {
|
||||
for(var annotation : markers) {
|
||||
private static Class<? extends Annotation> getMarkerClass(Collection<String> markerSet) {
|
||||
for(var annotation : markerSet) {
|
||||
try {
|
||||
return (Class<Annotation>)Class.forName(annotation);
|
||||
} catch (ClassNotFoundException e) {}
|
||||
|
|
@ -106,8 +144,19 @@ public class ClientMixinValidator {
|
|||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +166,8 @@ public class ClientMixinValidator {
|
|||
annotatedMixinClass.getQualifiedName(),
|
||||
ClientMixinValidator.getTargets(
|
||||
getAnnotationHandle(annotatedMixinClass, Mixin.class)
|
||||
).stream().filter(this::targetsClient)
|
||||
).stream()
|
||||
.filter(this::targetsClient)
|
||||
.map(Object::toString)
|
||||
.map(ClientMixinValidator::toSourceString)
|
||||
.collect(Collectors.joining(", "))
|
||||
|
|
@ -128,7 +178,8 @@ public class ClientMixinValidator {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.fury_phoenix.mixinAp.annotation;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -23,7 +24,7 @@ import javax.tools.Diagnostic;
|
|||
import org.fury_phoenix.mixinAp.config.MixinConfig;
|
||||
|
||||
@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)
|
||||
@AutoService(Processor.class)
|
||||
public class MixinProcessor extends AbstractProcessor {
|
||||
|
|
@ -38,22 +39,28 @@ public class MixinProcessor extends AbstractProcessor {
|
|||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if(roundEnv.processingOver()){
|
||||
filterMixinSets();
|
||||
// create record for serialization, compute package name
|
||||
String packageName = mixinConfigList.get("mixins").get(0).split("(?<=mixin)")[0];
|
||||
finalizeMixinConfig();
|
||||
new MixinConfig(packageName,
|
||||
mixinConfigList.get("mixins"),
|
||||
mixinConfigList.get("client")
|
||||
).generateMixinConfig(processingEnv);
|
||||
} else {
|
||||
processMixins(annotations, roundEnv);
|
||||
try {
|
||||
if(roundEnv.processingOver()){
|
||||
filterMixinSets();
|
||||
// create record for serialization, compute package name
|
||||
String packageName = mixinConfigList.get("mixins").get(0).split("(?<=mixin)")[0];
|
||||
finalizeMixinConfig();
|
||||
new MixinConfig(packageName,
|
||||
mixinConfigList.get("mixins"),
|
||||
mixinConfigList.get("client")
|
||||
).generateMixinConfig(processingEnv);
|
||||
} else {
|
||||
processMixins(annotations, roundEnv);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
|
||||
Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
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) {
|
||||
Set<? extends Element> annotatedMixins = roundEnv.getElementsAnnotatedWith(annotation);
|
||||
|
||||
|
|
@ -78,7 +85,8 @@ public class MixinProcessor extends AbstractProcessor {
|
|||
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"))
|
||||
return;
|
||||
ClientMixinValidator validator = new ClientMixinValidator(processingEnv);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.fury_phoenix.mixinAp.config;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
|
@ -10,7 +9,6 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
public record MixinConfig(
|
||||
|
|
@ -37,12 +35,12 @@ public record MixinConfig(
|
|||
public static final OverwriteOptions DEFAULT = new OverwriteOptions(true);
|
||||
}
|
||||
|
||||
public void generateMixinConfig(ProcessingEnvironment env) {
|
||||
public void generateMixinConfig(ProcessingEnvironment env) throws IOException {
|
||||
try (
|
||||
Writer mixinConfigWriter = env.getFiler()
|
||||
.createResource(StandardLocation.SOURCE_OUTPUT, "",
|
||||
MixinConfig.computeMixinConfigPath(
|
||||
env.getOptions().get("rootProject.name"),
|
||||
Optional.of(env.getOptions().get("rootProject.name")),
|
||||
Optional.ofNullable(env.getOptions().get("project.name"))
|
||||
)
|
||||
).openWriter()
|
||||
|
|
@ -54,15 +52,12 @@ public record MixinConfig(
|
|||
|
||||
mixinConfigWriter.write(mixinConfig);
|
||||
mixinConfigWriter.write("\n");
|
||||
} catch (IOException e) {
|
||||
env.getMessager().printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
|
||||
Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
} catch (IOException e) { throw e; }
|
||||
}
|
||||
|
||||
private static String computeMixinConfigPath(String rootProjectName, Optional<String> projectName) {
|
||||
private static String computeMixinConfigPath(Optional<String> rootProjectName, Optional<String> projectName) {
|
||||
return "resources/" +
|
||||
rootProjectName +
|
||||
rootProjectName.get() +
|
||||
(projectName.isPresent() ? "-" : "") +
|
||||
projectName.orElse("") +
|
||||
".mixins.json";
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user