Skip to content

Commit

Permalink
Resolve anonymous inner classes in AP via classpath + ASM where possible
Browse files Browse the repository at this point in the history
Fixes #518
  • Loading branch information
Mumfrey committed Nov 4, 2021
1 parent a9581dd commit 1e1aa7f
Show file tree
Hide file tree
Showing 24 changed files with 606 additions and 79 deletions.
61 changes: 40 additions & 21 deletions src/ap/java/org/spongepowered/tools/obfuscation/AnnotatedMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.MixinEnvironment.Option;
Expand Down Expand Up @@ -62,6 +60,7 @@
import org.spongepowered.tools.obfuscation.interfaces.ITypeHandleProvider;
import org.spongepowered.tools.obfuscation.mapping.IMappingConsumer;
import org.spongepowered.tools.obfuscation.mirror.AnnotationHandle;
import org.spongepowered.tools.obfuscation.mirror.MethodHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeUtils;
import org.spongepowered.tools.obfuscation.struct.InjectorRemap;
Expand All @@ -76,7 +75,7 @@ class AnnotatedMixin implements IMixinContext, IAnnotatedElement {
/**
* Mixin annotation
*/
private final AnnotationHandle annotation;
private final IAnnotationHandle annotation;

/**
* Messager
Expand Down Expand Up @@ -106,7 +105,7 @@ class AnnotatedMixin implements IMixinContext, IAnnotatedElement {
/**
* Methods
*/
private final List<ExecutableElement> methods;
private final List<MethodHandle> methods;

/**
* Mixin class
Expand Down Expand Up @@ -178,7 +177,7 @@ public AnnotatedMixin(IMixinAnnotationProcessor ap, TypeElement type) {
this.messager = ap;
this.mixin = type;
this.handle = new TypeHandle(type);
this.methods = new ArrayList<ExecutableElement>(this.handle.<ExecutableElement>getEnclosedElements(ElementKind.METHOD));
this.methods = new ArrayList<MethodHandle>(this.handle.getMethods());
this.virtual = this.handle.getAnnotation(Pseudo.class).exists();
this.annotation = this.handle.getAnnotation(Mixin.class);
this.classRef = TypeUtils.getInternalName(type);
Expand Down Expand Up @@ -212,9 +211,9 @@ private TypeHandle initTargets(IMixinAnnotationProcessor ap) {

// Public targets, referenced by class
try {
for (TypeMirror target : this.annotation.<TypeMirror>getList()) {
TypeHandle type = new TypeHandle((DeclaredType)target);
if (this.targets.contains(type)) {
for (Object target : this.annotation.<Object>getList()) {
TypeHandle type = this.typeProvider.getTypeHandle(target);
if (type == null || this.targets.contains(type)) {
continue;
}
this.addTarget(type);
Expand All @@ -237,16 +236,24 @@ private TypeHandle initTargets(IMixinAnnotationProcessor ap) {
type = this.typeProvider.getSimulatedHandle(softTarget, this.mixin.asType());
} else if (type == null) {
this.printMessage(MessageType.MIXIN_SOFT_TARGET_NOT_FOUND, "Mixin target " + softTarget + " could not be found");
return null;
if (MessageType.MIXIN_SOFT_TARGET_NOT_FOUND.isError()) {
return null;
}
type = this.typeProvider.getSimulatedHandle(softTarget, this.mixin.asType());
} else if (type.isImaginary()) {
this.printMessage(MessageType.MIXIN_SOFT_TARGET_NOT_RESOLVED, "Mixin target " + softTarget + " could not be fully resolved.",
SuppressedBy.UNRESOLVABLE_TARGET);
return null;
if (MessageType.MIXIN_SOFT_TARGET_NOT_RESOLVED.isError()) {
return null;
}
} else if (type.isPublic()) {
SuppressedBy suppressedBy = (type.getPackage().isUnnamed()) ? SuppressedBy.DEFAULT_PACKAGE : SuppressedBy.PUBLIC_TARGET;
String must = MessageType.MIXIN_SOFT_TARGET_IS_PUBLIC.isError() ? "must" : "should";
this.printMessage(MessageType.MIXIN_SOFT_TARGET_IS_PUBLIC, "Mixin target " + softTarget
+ " is public and must be specified in value", suppressedBy);
return null;
+ " is public and " + must + " be specified in value", suppressedBy);
if (MessageType.MIXIN_SOFT_TARGET_IS_PUBLIC.isError()) {
return null;
}
}
this.addSoftTarget(type, softTarget);
if (primaryTarget == null) {
Expand All @@ -268,14 +275,14 @@ private TypeHandle initTargets(IMixinAnnotationProcessor ap) {
* Print a message to the AP messager
*/
private void printMessage(MessageType type, CharSequence msg) {
this.messager.printMessage(type, msg, this.mixin, this.annotation.asMirror());
this.messager.printMessage(type, msg, this.mixin, AnnotationHandle.asMirror(this.annotation));
}

/**
* Print a suppressible message to the AP messager
*/
private void printMessage(MessageType type, CharSequence msg, SuppressedBy suppressedBy) {
this.messager.printMessage(type, msg, this.mixin, this.annotation.asMirror(), suppressedBy);
this.messager.printMessage(type, msg, this.mixin, AnnotationHandle.asMirror(this.annotation), suppressedBy);
}

private void addSoftTarget(TypeHandle type, String reference) {
Expand All @@ -296,7 +303,7 @@ public String toString() {
return this.mixin.getSimpleName().toString();
}

public AnnotationHandle getAnnotation() {
public IAnnotationHandle getAnnotation() {
return this.annotation;
}

Expand Down Expand Up @@ -363,13 +370,25 @@ public IMappingConsumer getMappings() {
}

private void runFinalValidation() {
for (ExecutableElement method : this.methods) {
for (MethodHandle method : this.methods) {
this.overwrites.registerMerge(method);
}
}

private void removeMethod(ExecutableElement method) {
MethodHandle handle = null;
for (MethodHandle methodHandle : this.methods) {
if (methodHandle.getElement() == method) {
handle = methodHandle;
}
}
if (handle != null) {
this.methods.remove(handle);
}
}

public void registerOverwrite(ExecutableElement method, AnnotationHandle overwrite, boolean shouldRemap) {
this.methods.remove(method);
this.removeMethod(method);
this.overwrites.registerOverwrite(new AnnotatedElementOverwrite(method, overwrite, shouldRemap));
}

Expand All @@ -378,12 +397,12 @@ public void registerShadow(VariableElement field, AnnotationHandle shadow, boole
}

public void registerShadow(ExecutableElement method, AnnotationHandle shadow, boolean shouldRemap) {
this.methods.remove(method);
this.removeMethod(method);
this.shadows.registerShadow(this.shadows.new AnnotatedElementShadowMethod(method, shadow, shouldRemap));
}

public void registerInjector(ExecutableElement method, AnnotationHandle inject, InjectorRemap remap) {
this.methods.remove(method);
this.removeMethod(method);
AnnotatedElementInjector injectorElement = new AnnotatedElementInjector(method, inject, this, remap);
this.injectors.registerInjector(injectorElement);

Expand Down Expand Up @@ -426,12 +445,12 @@ public void registerSliceInjectionPoint(ExecutableElement element, AnnotationHan
}

public void registerAccessor(ExecutableElement element, AnnotationHandle accessor, boolean shouldRemap) {
this.methods.remove(element);
this.removeMethod(element);
this.accessors.registerAccessor(new AnnotatedElementAccessor(element, accessor, this, shouldRemap));
}

public void registerInvoker(ExecutableElement element, AnnotationHandle invoker, boolean shouldRemap) {
this.methods.remove(element);
this.removeMethod(element);
this.accessors.registerAccessor(new AnnotatedElementInvoker(element, invoker, this, shouldRemap));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.spongepowered.asm.obfuscation.mapping.IMapping;
import org.spongepowered.asm.obfuscation.mapping.common.MappingField;
import org.spongepowered.asm.obfuscation.mapping.common.MappingMethod;
import org.spongepowered.asm.util.Bytecode.Visibility;
import org.spongepowered.asm.util.ConstraintParser;
import org.spongepowered.asm.util.ConstraintParser.Constraint;
import org.spongepowered.asm.util.asm.IAnnotatedElement;
Expand All @@ -55,7 +56,6 @@
import org.spongepowered.tools.obfuscation.mirror.MethodHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeUtils;
import org.spongepowered.tools.obfuscation.mirror.Visibility;

/**
* Base class for module for {@link AnnotatedMixin} which handle different
Expand Down Expand Up @@ -194,6 +194,11 @@ public AliasedElementName(Element element, AnnotationHandle annotation) {
this.aliases = annotation.<String>getList("aliases");
}

public AliasedElementName(MethodHandle method, AnnotationHandle annotation) {
this.originalName = method.getName();
this.aliases = annotation.<String>getList("aliases");
}

public AliasedElementName setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,17 @@ private void registerInvokerForTarget(AnnotatedElementInvoker elem, TypeHandle t
}

private void registerFactoryForTarget(AnnotatedElementInvoker elem, TypeHandle target) {
EquivalencyResult equivalency = TypeUtils.isEquivalentType(this.ap.getProcessingEnvironment(), elem.getReturnType(), target.getType());
EquivalencyResult equivalency = TypeUtils.isEquivalentType(this.ap.getProcessingEnvironment(), elem.getReturnType(), target.getTypeMirror());
if (equivalency.type != Equivalency.EQUIVALENT) {
if (equivalency.type == Equivalency.EQUIVALENT_BUT_RAW && equivalency.rawType == 1) {
elem.printMessage(this.ap, MessageType.INVOKER_RAW_RETURN_TYPE, "Raw return type for Factory @Invoker", SuppressedBy.RAW_TYPES);
} else if (equivalency.type == Equivalency.BOUNDS_MISMATCH) {
elem.printMessage(this.ap, MessageType.FACTORY_INVOKER_GENERIC_ARGS, "Invalid Factory @Invoker return type, generic type args of "
+ target.getType() + " are incompatible with " + elem.getReturnType() + ". " + equivalency);
+ target.getTypeMirror() + " are incompatible with " + elem.getReturnType() + ". " + equivalency);
return;
} else {
elem.printMessage(this.ap, MessageType.FACTORY_INVOKER_RETURN_TYPE, "Invalid Factory @Invoker return type, expected "
+ target.getType() + " but found " + elem.getReturnType());
+ target.getTypeMirror() + " but found " + elem.getReturnType());
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.spongepowered.tools.obfuscation.interfaces.IMessagerEx.MessageType;
import org.spongepowered.tools.obfuscation.interfaces.IMixinAnnotationProcessor;
import org.spongepowered.tools.obfuscation.mirror.AnnotationHandle;
import org.spongepowered.tools.obfuscation.mirror.MethodHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;

/**
Expand Down Expand Up @@ -63,8 +64,10 @@ public boolean shouldRemap() {
super(ap, mixin);
}

public void registerMerge(ExecutableElement method) {
this.validateTargetMethod(method, null, new AliasedElementName(method, AnnotationHandle.MISSING), "overwrite", true, true);
public void registerMerge(MethodHandle method) {
if (!method.isImaginary()) {
this.validateTargetMethod(method.getElement(), null, new AliasedElementName(method, AnnotationHandle.MISSING), "overwrite", true, true);
}
}

public void registerOverwrite(AnnotatedElementOverwrite elem) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import java.util.List;

import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.DeclaredType;

import org.spongepowered.asm.mixin.Interface.Remap;
Expand All @@ -37,7 +35,6 @@
import org.spongepowered.tools.obfuscation.interfaces.IMixinAnnotationProcessor;
import org.spongepowered.tools.obfuscation.mirror.AnnotationHandle;
import org.spongepowered.tools.obfuscation.mirror.MethodHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeUtils;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;

/**
Expand Down Expand Up @@ -99,7 +96,7 @@ public void process(AnnotationHandle implementsAnnotation) {
* @param prefix Prefix declared in the soft-implements decoration
*/
private void processSoftImplements(Remap remap, TypeHandle iface, String prefix) {
for (ExecutableElement method : iface.<ExecutableElement>getEnclosedElements(ElementKind.METHOD)) {
for (MethodHandle method : iface.getMethods()) {
this.processMethod(remap, iface, prefix, method);
}

Expand All @@ -118,10 +115,10 @@ private void processSoftImplements(Remap remap, TypeHandle iface, String prefix)
* @param prefix Prefix declared in the soft-implements decoration
* @param method Interface method to search for
*/
private void processMethod(Remap remap, TypeHandle iface, String prefix, ExecutableElement method) {
String name = method.getSimpleName().toString();
String sig = TypeUtils.getJavaSignature(method);
String desc = TypeUtils.getDescriptor(method);
private void processMethod(Remap remap, TypeHandle iface, String prefix, MethodHandle method) {
String name = method.getName();
String sig = method.getJavaSignature();
String desc = method.getDesc();

if (remap != Remap.ONLY_PREFIXED) {
MethodHandle mixinMethod = this.mixin.getHandle().findMethod(name, sig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import javax.tools.FileObject;
import javax.tools.StandardLocation;

import org.objectweb.asm.Type;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.gen.Accessor;
Expand All @@ -69,6 +70,7 @@
import org.spongepowered.tools.obfuscation.interfaces.ITypeHandleProvider;
import org.spongepowered.tools.obfuscation.mirror.AnnotationHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandleASM;
import org.spongepowered.tools.obfuscation.mirror.TypeHandleSimulated;
import org.spongepowered.tools.obfuscation.mirror.TypeReference;
import org.spongepowered.tools.obfuscation.struct.InjectorRemap;
Expand Down Expand Up @@ -377,8 +379,8 @@ public Collection<TypeMirror> getMixinsTargeting(TypeElement targetType) {

for (TypeReference mixin : this.targets.getMixinsTargeting(targetType)) {
TypeHandle handle = mixin.getHandle(this.processingEnv);
if (handle != null) {
minions.add(handle.getType());
if (handle != null && handle.hasTypeMirror()) {
minions.add(handle.getTypeMirror());
}
}

Expand Down Expand Up @@ -697,13 +699,43 @@ public TypeHandle getTypeHandle(String name) {

int lastDotPos = name.lastIndexOf('.');
if (lastDotPos > -1) {
String pkg = name.substring(0, lastDotPos);
PackageElement packageElement = elements.getPackageElement(pkg);
if (packageElement != null) {
return new TypeHandle(packageElement, name);
String pkgName = name.substring(0, lastDotPos);
PackageElement pkg = elements.getPackageElement(pkgName);
if (pkg != null) {
// If we can resolve the package but not the class, it's possible
// we're dealing with a class that mirror can't access, such as
// an anonymous class. The class might be available via the
// classpath though, so let's attempt to read the class with ASM
TypeHandle asmTypeHandle = TypeHandleASM.of(pkg, name.substring(lastDotPos + 1), this);
if (asmTypeHandle != null) {
return asmTypeHandle;
}

// Couldn't resolve the class, so just return an imaginary handle
return new TypeHandle(pkg, name);
}
}


return null;
}

/**
* Get a TypeHandle representing the supplied type in the current processing
* environment
*/
@Override
public TypeHandle getTypeHandle(Object type) {
if (type instanceof TypeHandle) {
return (TypeHandle)type;
} else if (type instanceof DeclaredType) {
return new TypeHandle((DeclaredType)type);
} else if (type instanceof Type) {
return this.getTypeHandle(((Type)type).getClassName());
} else if (type instanceof TypeElement) {
return new TypeHandle((DeclaredType)((TypeElement)type).asType());
} else if (type instanceof String) {
return this.getTypeHandle(type.toString());
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

import org.spongepowered.asm.util.asm.IAnnotationHandle;
import org.spongepowered.tools.obfuscation.interfaces.IMessagerSuppressible;
import org.spongepowered.tools.obfuscation.interfaces.IMixinAnnotationProcessor;
import org.spongepowered.tools.obfuscation.interfaces.IMixinValidator;
import org.spongepowered.tools.obfuscation.interfaces.IOptionProvider;
import org.spongepowered.tools.obfuscation.mirror.AnnotationHandle;
import org.spongepowered.tools.obfuscation.mirror.TypeHandle;

/**
Expand Down Expand Up @@ -84,15 +84,15 @@ public MixinValidator(IMixinAnnotationProcessor ap, ValidationPass pass) {
* java.util.Collection)
*/
@Override
public final boolean validate(ValidationPass pass, TypeElement mixin, AnnotationHandle annotation, Collection<TypeHandle> targets) {
public final boolean validate(ValidationPass pass, TypeElement mixin, IAnnotationHandle annotation, Collection<TypeHandle> targets) {
if (pass != this.pass) {
return true;
}

return this.validate(mixin, annotation, targets);
}

protected abstract boolean validate(TypeElement mixin, AnnotationHandle annotation, Collection<TypeHandle> targets);
protected abstract boolean validate(TypeElement mixin, IAnnotationHandle annotation, Collection<TypeHandle> targets);

protected final Collection<TypeMirror> getMixinsTargeting(TypeMirror targetType) {
return AnnotatedMixins.getMixinsForEnvironment(this.processingEnv).getMixinsTargeting(targetType);
Expand Down
Loading

0 comments on commit 1e1aa7f

Please sign in to comment.