diff options
Diffstat (limited to 'src/main/java/ftbsc/lll/processor/containers/FieldContainer.java')
-rw-r--r-- | src/main/java/ftbsc/lll/processor/containers/FieldContainer.java | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/lll/processor/containers/FieldContainer.java b/src/main/java/ftbsc/lll/processor/containers/FieldContainer.java new file mode 100644 index 0000000..2299c93 --- /dev/null +++ b/src/main/java/ftbsc/lll/processor/containers/FieldContainer.java @@ -0,0 +1,109 @@ +package ftbsc.lll.processor.containers; + +import ftbsc.lll.exceptions.AmbiguousDefinitionException; +import ftbsc.lll.mapper.tools.MappingUtils; +import ftbsc.lll.mapper.tools.data.FieldData; +import ftbsc.lll.processor.annotations.Find; +import ftbsc.lll.processor.annotations.Patch; +import ftbsc.lll.processor.ProcessorOptions; +import org.objectweb.asm.Type; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; + +import static ftbsc.lll.processor.utils.ASTUtils.*; + +/** + * Container for information about a field. + * Used internally for efficiency reasons. + * @since 0.5.0 + */ +public class FieldContainer { + /** + * The {@link FieldData} for the field represented by this container. + */ + public final FieldData data; + + /** + * The descriptor of the field. + */ + public final String descriptor; + + /** + * The obfuscated descriptor of the field. + * If the mapper passed is null, then this will be identical to {@link #descriptor}. + */ + public final String descriptorObf; + + /** + * The {@link ClassContainer} representing the parent of this field. + */ + public final ClassContainer parent; + + /** + * The {@link VariableElement} corresponding to the field. + * May only be null intentionally i.e. when the field is + * a child of an anonymous class. + */ + public final VariableElement elem; + + /** + * Private constructor, called from {@link #from(VariableElement, ProcessorOptions)}. + * @param parent the {@link ClassContainer} representing the parent + * @param name the fully-qualified name of the target field + * @param descriptor the descriptor of the target field, may be null for verifiable fields + * @param options the {@link ProcessorOptions} to be used + */ + private FieldContainer(ClassContainer parent, String name, String descriptor, ProcessorOptions options) { + this.parent = parent; + if(parent.elem == null) { //unverified + if(descriptor == null) + throw new AmbiguousDefinitionException("Cannot use name-based lookups for fields of unverifiable classes!"); + this.elem = null; + this.descriptor = descriptor; + } else { + this.elem = (VariableElement) findMember(parent, name, descriptor, descriptor != null, true, options.env); + this.descriptor = descriptorFromType(this.elem.asType(), options.env); + name = this.elem.getSimpleName().toString(); + } + this.data = getFieldData(parent.data.name, name, options.mapper); + this.descriptorObf = options.mapper == null ? this.descriptor + : MappingUtils.mapType(Type.getType(this.descriptor), options.mapper, false).getDescriptor(); + } + + /** + * Finds a {@link FieldContainer} from a finder. + * @param finder the {@link VariableElement} annotated with {@link Find} for this field + * @param options the {@link ProcessorOptions} to be used + * @return the built {@link FieldContainer} + * @since 0.5.0 + */ + public static FieldContainer from(VariableElement finder, ProcessorOptions options) { + //the parent always has a @Patch annotation + Patch patchAnn = finder.getEnclosingElement().getAnnotation(Patch.class); + //the finder always has a @Find annotation + Find f = finder.getAnnotation(Find.class); + + ClassContainer parent = ClassContainer.findOrFallback( + ClassContainer.from((TypeElement) finder.getEnclosingElement(), options), patchAnn, f, options + ); + + String name = f.name().isEmpty() ? finder.getSimpleName().toString() : f.name(); + String descriptor; + TypeMirror fieldType = getTypeFromAnnotation(f, Find::type, options.env); + if(fieldType.toString().equals("java.lang.Object")) { + descriptor = null; + } else { + if(fieldType.getKind() != TypeKind.VOID && !fieldType.getKind().isPrimitive()) + descriptor = //jank af but this is temporary anyway + "L" + ClassContainer.from( + f, Find::type, f.typeInner(), options + ).data.nameMapped + ";"; + else descriptor = descriptorFromType(fieldType, options.env); + } + + return new FieldContainer(parent, name, descriptor, options); + } +} |