/* * Copyright (c) 2006 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit.internal.classGeneration; import java.util.*; import javax.annotation.*; import static java.lang.reflect.Modifier.*; import mockit.external.asm.*; import mockit.internal.*; import mockit.internal.reflection.*; import mockit.internal.reflection.GenericTypeReflection.*; import static mockit.external.asm.Opcodes.*; @SuppressWarnings("AbstractClassExtendsConcreteClass") public abstract class BaseImplementationGenerator extends BaseClassModifier { private static final int CLASS_ACCESS = ACC_PUBLIC + ACC_FINAL; @Nonnull private final List<String> implementedMethods; @Nonnull private final String implementationClassDesc; @Nullable private String[] initialSuperInterfaces; protected String methodOwner; protected BaseImplementationGenerator(@Nonnull ClassReader classReader, @Nonnull String implementationClassName) { super(classReader); implementedMethods = new ArrayList<String>(); implementationClassDesc = implementationClassName.replace('.', '/'); } @Override public void visit( int version, int access, @Nonnull String name, @Nullable String signature, @Nullable String superName, @Nullable String[] interfaces) { methodOwner = name; initialSuperInterfaces = interfaces; String[] implementedInterfaces = {name}; super.visit(version, CLASS_ACCESS, implementationClassDesc, signature, superName, implementedInterfaces); generateNoArgsConstructor(); } private void generateNoArgsConstructor() { mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); generateEmptyImplementation(); } @Override public final void visitInnerClass(String name, String outerName, String innerName, int access) {} @Override public final void visitOuterClass(String owner, @Nullable String name, @Nullable String desc) {} @Override public final void visitAttribute(Attribute attr) {} @Override public final void visitSource(@Nullable String source, @Nullable String debug) {} @Nullable @Override public final FieldVisitor visitField( int access, String name, String desc, @Nullable String signature, @Nullable Object value) { return null; } @Nullable @Override public final MethodVisitor visitMethod( int access, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) { generateMethodImplementation(access, name, desc, signature, exceptions); return null; } @Override public final void visitEnd() { assert initialSuperInterfaces != null; for (String superInterface : initialSuperInterfaces) { new MethodGeneratorForImplementedSuperInterface(superInterface); } } protected final void generateMethodImplementation( int access, @Nonnull String name, @Nonnull String desc, @Nullable String signature, @Nullable String[] exceptions) { if (!isStatic(access)) { String methodNameAndDesc = name + desc; if (!implementedMethods.contains(methodNameAndDesc)) { generateMethodBody(access, name, desc, signature, exceptions); implementedMethods.add(methodNameAndDesc); } } } protected abstract void generateMethodBody( int access, @Nonnull String name, @Nonnull String desc, @Nullable String signature, @Nullable String[] exceptions); protected final boolean isOverrideOfMethodFromSuperInterface(@Nonnull String name, @Nonnull String desc) { if (!implementedMethods.isEmpty()) { int p = desc.lastIndexOf(')'); String descNoReturnType = desc.substring(0, p + 1); for (String implementedMethod : implementedMethods) { if (sameMethodName(implementedMethod, name) && implementedMethod.contains(descNoReturnType)) { return true; } } } return false; } private static boolean sameMethodName(@Nonnull String implementedMethod, @Nonnull String name) { return implementedMethod.startsWith(name) && implementedMethod.charAt(name.length()) == '('; } @Nullable protected final String getSubInterfaceOverride( @Nonnull GenericTypeReflection genericTypeMap, @Nonnull String name, @Nonnull String genericSignature) { if (!implementedMethods.isEmpty()) { GenericSignature parsedSignature = genericTypeMap.parseSignature(genericSignature); for (String implementedMethod : implementedMethods) { if (sameMethodName(implementedMethod, name) && parsedSignature.satisfiesSignature(implementedMethod)) { return implementedMethod; } } } return null; } private final class MethodGeneratorForImplementedSuperInterface extends ClassVisitor { private String[] superInterfaces; MethodGeneratorForImplementedSuperInterface(@Nonnull String interfaceName) { ClassFile.visitClass(interfaceName, this); } @Override public void visit( int version, int access, String name, @Nullable String signature, @Nullable String superName, @Nullable String[] interfaces) { methodOwner = name; superInterfaces = interfaces; } @Nullable @Override public FieldVisitor visitField( int access, String name, String desc, @Nullable String signature, @Nullable Object value) { return null; } @Nullable @Override public MethodVisitor visitMethod( int access, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) { generateMethodImplementation(access, name, desc, signature, exceptions); return null; } @Override public void visitEnd() { for (String superInterface : superInterfaces) { new MethodGeneratorForImplementedSuperInterface(superInterface); } } } }