Example usage for org.objectweb.asm Opcodes INVOKEVIRTUAL

List of usage examples for org.objectweb.asm Opcodes INVOKEVIRTUAL

Introduction

In this page you can find the example usage for org.objectweb.asm Opcodes INVOKEVIRTUAL.

Prototype

int INVOKEVIRTUAL

To view the source code for org.objectweb.asm Opcodes INVOKEVIRTUAL.

Click Source Link

Usage

From source file:com.alibaba.hotswap.processor.jdk.reflect.modifier.ConstructorNewInstanceModifier.java

License:Open Source License

@Override
public void visitCode() {
    super.visitCode();
    Label old = new Label();

    mv.visitVarInsn(Opcodes.ALOAD, 0);/*  w w  w .  ja v  a  2s. c  o  m*/
    mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/reflect/Constructor", "parameterTypes",
            "[Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(MethodReflectHelper.class),
            "isUniformConstructorArgsType", "([Ljava/lang/Class;)Z");
    ifZCmp(NE, old);

    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/reflect/Constructor", "clazz", "Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(HotswapRuntime.class), "hasClassMeta",
            "(Ljava/lang/String;)Z");
    mv.visitJumpInsn(Opcodes.IFEQ, old);

    // check it as a primary constructor
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/reflect/Constructor", "clazz", "Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(HotswapRuntime.class), "getClassMeta",
            "(Ljava/lang/String;)Lcom/alibaba/hotswap/meta/ClassMeta;");
    mv.visitLdcInsn(HotswapConstants.INIT);
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Type.class), "getConstructorDescriptor",
            "(Ljava/lang/reflect/Constructor;)Ljava/lang/String;");
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(ClassMeta.class), "isPrimaryInitMethod",
            "(Ljava/lang/String;Ljava/lang/String;)Z");
    mv.visitJumpInsn(Opcodes.IFNE, old);

    // get uniform constructor
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/reflect/Constructor", "clazz", "Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(HotswapMethodUtil.class),
            "getConstructorParamTypes", "()[Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getConstructor",
            "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;");

    // index and objs
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/reflect/Constructor", "clazz", "Ljava/lang/Class;");
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
    mv.visitLdcInsn(HotswapConstants.INIT);
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Type.class), "getConstructorDescriptor",
            "(Ljava/lang/reflect/Constructor;)Ljava/lang/String;");
    loadArgs();
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(HotswapMethodUtil.class), "getMethodParams",
            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)[Ljava/lang/Object;");

    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance",
            "([Ljava/lang/Object;)Ljava/lang/Object;");
    mv.visitInsn(Opcodes.ARETURN);

    mv.visitLabel(old);
}

From source file:com.alibaba.hotswap.processor.jdk.reflect.modifier.DeclaredAnnotationsModifier.java

License:Open Source License

@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
    if (opcode == Opcodes.INVOKEVIRTUAL
            && (owner.equals("java/lang/reflect/Field") || owner.equals("java/lang/reflect/Constructor"))
            && name.equals("getDeclaringClass") && desc.equals("()Ljava/lang/Class;")) {
        super.visitMethodInsn(opcode, owner, name, desc);
        dup();//ww w  .  j  a  v  a 2s . c o  m
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(ReflectHelper.class), "getVClassByClass",
                "(Ljava/lang/Class;)Ljava/lang/Class;");
        dup();
        Label old = newLabel();
        ifNull(old);
        swap();

        mark(old);
        pop();
        return;
    }
    super.visitMethodInsn(opcode, owner, name, desc);
}

From source file:com.android.build.gradle.integration.application.ExternalBuildPluginTest.java

License:Apache License

private static byte[] hotswapChange(byte[] inputClass) {
    ClassReader cr = new ClassReader(inputClass);
    ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
    ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) {
        @Override/*from  w w w .  j a  v a2  s. co m*/
        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            return new MethodVisitor(Opcodes.ASM5, mv) {
                @Override
                public void visitCode() {
                    // add a useless logging to the method.
                    mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                    mv.visitLdcInsn("test changed !");
                    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                            "(Ljava/lang/String;)V", false);
                    super.visitCode();
                }
            };
        }
    };
    cr.accept(cv, ClassReader.EXPAND_FRAMES);
    return cw.toByteArray();
}

From source file:com.android.build.gradle.integration.packaging.NativeSoPackagingFromJarTest.java

License:Apache License

/**
 * Creates a class and returns the byte[] with the class
 * @return/*from  ww w  .ja  v a2  s.c o  m*/
 */
private static byte[] getDummyClassByteCode() {
    ClassWriter cw = new ClassWriter(0);
    FieldVisitor fv;
    MethodVisitor mv;
    AnnotationVisitor av0;

    cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, "com/foo/Foo", null, "java/lang/Object",
            null);

    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();

    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "aaa", "()V", null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "test/Aaa", "bbb", "()V", false);
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();

    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "bbb", "()V", null, null);
    mv.visitCode();
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(0, 1);
    mv.visitEnd();

    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "ccc", "()V", null, null);
    mv.visitCode();
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(0, 1);
    mv.visitEnd();

    cw.visitEnd();

    return cw.toByteArray();
}

From source file:com.android.ide.eclipse.apt.internal.analysis.InternalGetSetAnalyzer.java

License:Apache License

@Override
protected Collection<Problem> analyzeMethod(MethodNode methodNode) {
    final Collection<Problem> problems = new LinkedList<Problem>();
    final InsnList instructions = methodNode.instructions;
    for (int i = 0; i < instructions.size(); i++) {
        final AbstractInsnNode instruction = instructions.get(i);
        final int op = instruction.getOpcode();
        if (op == Opcodes.INVOKESTATIC || op == Opcodes.INVOKEVIRTUAL) {
            final MethodInsnNode method = (MethodInsnNode) instruction;
            if (isGetterOrSetter(method)) {
                final Problem problem = new Problem(instruction);
                problems.add(problem);//from ww w. j a  v  a2s .  c  o m
            }
        }
    }
    return problems;
}

From source file:com.android.tools.lint.checks.ApiDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//  w ww.ja  v a  2 s . c  o m
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (mApiDatabase == null) {
        return;
    }

    if (AOSP_BUILD && classNode.name.startsWith("android/support/")) { //$NON-NLS-1$
        return;
    }

    // Requires util package (add prebuilts/tools/common/asm-tools/asm-debug-all-4.0.jar)
    //classNode.accept(new TraceClassVisitor(new PrintWriter(System.out)));

    int classMinSdk = getClassMinSdk(context, classNode);
    if (classMinSdk == -1) {
        classMinSdk = getMinSdk(context);
    }

    List methodList = classNode.methods;
    if (methodList.isEmpty()) {
        return;
    }

    boolean checkCalls = context.isEnabled(UNSUPPORTED) || context.isEnabled(INLINED);
    boolean checkMethods = context.isEnabled(OVERRIDE) && context.getMainProject().getBuildSdk() >= 1;
    String frameworkParent = null;
    if (checkMethods) {
        LintDriver driver = context.getDriver();
        String owner = classNode.superName;
        while (owner != null) {
            // For virtual dispatch, walk up the inheritance chain checking
            // each inherited method
            if ((owner.startsWith("android/") //$NON-NLS-1$
                    && !owner.startsWith("android/support/")) //$NON-NLS-1$
                    || owner.startsWith("java/") //$NON-NLS-1$
                    || owner.startsWith("javax/")) { //$NON-NLS-1$
                frameworkParent = owner;
                break;
            }
            owner = driver.getSuperClass(owner);
        }
        if (frameworkParent == null) {
            checkMethods = false;
        }
    }

    if (checkCalls) { // Check implements/extends
        if (classNode.superName != null) {
            String signature = classNode.superName;
            checkExtendsClass(context, classNode, classMinSdk, signature);
        }
        if (classNode.interfaces != null) {
            @SuppressWarnings("unchecked") // ASM API
            List<String> interfaceList = classNode.interfaces;
            for (String signature : interfaceList) {
                checkExtendsClass(context, classNode, classMinSdk, signature);
            }
        }
    }

    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        int minSdk = getLocalMinSdk(method.invisibleAnnotations);
        if (minSdk == -1) {
            minSdk = classMinSdk;
        }

        InsnList nodes = method.instructions;

        if (checkMethods && Character.isJavaIdentifierStart(method.name.charAt(0))) {
            int buildSdk = context.getMainProject().getBuildSdk();
            String name = method.name;
            assert frameworkParent != null;
            int api = mApiDatabase.getCallVersion(frameworkParent, name, method.desc);
            if (api > buildSdk && buildSdk != -1) {
                // TODO: Don't complain if it's annotated with @Override; that means
                // somehow the build target isn't correct.
                String fqcn;
                String owner = classNode.name;
                if (CONSTRUCTOR_NAME.equals(name)) {
                    fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                } else {
                    fqcn = ClassContext.getFqcn(owner) + '#' + name;
                }
                String message = String.format(
                        "This method is not overriding anything with the current build "
                                + "target, but will in API level %1$d (current target is %2$d): %3$s",
                        api, buildSdk, fqcn);

                Location location = context.getLocation(method, classNode);
                context.report(OVERRIDE, method, null, location, message, null);
            }
        }

        if (!checkCalls) {
            continue;
        }

        if (CHECK_DECLARATIONS) {
            // Check types in parameter list and types of local variables
            List localVariables = method.localVariables;
            if (localVariables != null) {
                for (Object v : localVariables) {
                    LocalVariableNode var = (LocalVariableNode) v;
                    String desc = var.desc;
                    if (desc.charAt(0) == 'L') {
                        // "Lpackage/Class;" => "package/Bar"
                        String className = desc.substring(1, desc.length() - 1);
                        int api = mApiDatabase.getClassVersion(className);
                        if (api > minSdk) {
                            String fqcn = ClassContext.getFqcn(className);
                            String message = String.format(
                                    "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk,
                                    fqcn);
                            report(context, message, var.start, method,
                                    className.substring(className.lastIndexOf('/') + 1), null,
                                    SearchHints.create(NEAREST).matchJavaSymbol());
                        }
                    }
                }
            }

            // Check return type
            // The parameter types are already handled as local variables so we can skip
            // right to the return type.
            // Check types in parameter list
            String signature = method.desc;
            if (signature != null) {
                int args = signature.indexOf(')');
                if (args != -1 && signature.charAt(args + 1) == 'L') {
                    String type = signature.substring(args + 2, signature.length() - 1);
                    int api = mApiDatabase.getClassVersion(type);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(type);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                        report(context, message, first, method, method.name, null,
                                SearchHints.create(BACKWARD).matchJavaSymbol());
                    }
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                String desc = node.desc;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                boolean checkingSuperClass = false;
                while (owner != null) {
                    int api = mApiDatabase.getCallVersion(owner, name, desc);
                    if (api > minSdk) {
                        if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                            // We're in a compiler-generated method to generate an
                            // array indexed by enum ordinal values to enum values. The enum
                            // itself must be requiring a higher API number than is
                            // currently used, but the call site for the switch statement
                            // will also be referencing it, so no need to report these
                            // calls.
                            break;
                        }

                        if (!checkingSuperClass && node.getOpcode() == Opcodes.INVOKEVIRTUAL
                                && methodDefinedLocally(classNode, name, desc)) {
                            break;
                        }

                        String fqcn;
                        if (CONSTRUCTOR_NAME.equals(name)) {
                            fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                        } else {
                            fqcn = ClassContext.getFqcn(owner) + '#' + name;
                        }
                        String message = String.format(
                                "Call requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);

                        if (name.equals(ORDINAL_METHOD) && instruction.getNext() != null
                                && instruction.getNext().getNext() != null
                                && instruction.getNext().getOpcode() == Opcodes.IALOAD
                                && instruction.getNext().getNext().getOpcode() == Opcodes.TABLESWITCH) {
                            message = String.format(
                                    "Enum for switch requires API level %1$d " + "(current min is %2$d): %3$s",
                                    api, minSdk, ClassContext.getFqcn(owner));
                        }

                        report(context, message, node, method, name, null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith("javax/")) { //$NON-NLS-1$
                        // The API map has already inlined all inherited methods
                        // so no need to keep checking up the chain
                        // -- unless it's the support library which is also in
                        // the android/ namespace:
                        if (owner.startsWith("android/support/")) { //$NON-NLS-1$
                            owner = context.getDriver().getSuperClass(owner);
                        } else {
                            owner = null;
                        }
                    } else if (owner.startsWith("java/")) { //$NON-NLS-1$
                        if (owner.equals(LocaleDetector.DATE_FORMAT_OWNER)) {
                            checkSimpleDateFormat(context, method, node, minSdk);
                        }
                        // Already inlined; see comment above
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC && api == -1) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }

                    checkingSuperClass = true;
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                int api = mApiDatabase.getFieldVersion(owner, name);
                if (api > minSdk) {
                    if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                        checkSwitchBlock(context, classNode, node, method, name, owner, api, minSdk);
                        continue;
                    }
                    String fqcn = ClassContext.getFqcn(owner) + '#' + name;
                    if (mPendingFields != null) {
                        mPendingFields.remove(fqcn);
                    }
                    String message = String.format("Field requires API level %1$d (current min is %2$d): %3$s",
                            api, minSdk, fqcn);
                    report(context, message, node, method, name, null,
                            SearchHints.create(FORWARD).matchJavaSymbol());
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();

                    int api = mApiDatabase.getClassVersion(className);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(className);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        report(context, message, node, method,
                                className.substring(className.lastIndexOf('/') + 1), null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.ApiDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
private static void checkSwitchBlock(ClassContext context, ClassNode classNode, FieldInsnNode field,
        MethodNode method, String name, String owner, int api, int minSdk) {
    // Switch statements on enums are tricky. The compiler will generate a method
    // which returns an array of the enum constants, indexed by their ordinal() values.
    // However, we only want to complain if the code is actually referencing one of
    // the non-available enum fields.
    ///*from   www . ja  v a2  s  . c o m*/
    // For the android.graphics.PorterDuff.Mode enum for example, the first few items
    // in the array are populated like this:
    //
    //   L0
    //    ALOAD 0
    //    GETSTATIC android/graphics/PorterDuff$Mode.ADD : Landroid/graphics/PorterDuff$Mode;
    //    INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //    ICONST_1
    //    IASTORE
    //   L1
    //    GOTO L3
    //   L2
    //   FRAME FULL [[I] [java/lang/NoSuchFieldError]
    //    POP
    //   L3
    //   FRAME SAME
    //    ALOAD 0
    //    GETSTATIC android/graphics/PorterDuff$Mode.CLEAR : Landroid/graphics/PorterDuff$Mode;
    //    INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //    ICONST_2
    //    IASTORE
    //    ...
    // So if we for example find that the "ADD" field isn't accessible, since it requires
    // API 11, we need to
    //   (1) First find out what its ordinal number is. We can look at the following
    //       instructions to discover this; it's the "ICONST_1" and "IASTORE" instructions.
    //       (After ICONST_5 it moves on to BIPUSH 6, BIPUSH 7, etc.)
    //   (2) Find the corresponding *usage* of this switch method. For the above enum,
    //       the switch ordinal lookup method will be called
    //         "$SWITCH_TABLE$android$graphics$PorterDuff$Mode" with desc "()[I".
    //       This means we will be looking for an invocation in some other method which looks
    //       like this:
    //         INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
    //       (obviously, it can be invoked more than once)
    //       Note that it can be used more than once in this class and all sites should be
    //       checked!
    //   (3) Look up the corresponding table switch, which should look something like this:
    //        INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
    //        ALOAD 0
    //        INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //        IALOAD
    //        LOOKUPSWITCH
    //          2: L1
    //          11: L2
    //          default: L3
    //       Here we need to see if the LOOKUPSWITCH instruction is referencing our target
    //       case. Above we were looking for the "ADD" case which had ordinal 1. Since this
    //       isn't explicitly referenced, we can ignore this field reference.
    AbstractInsnNode next = field.getNext();
    if (next == null || next.getOpcode() != Opcodes.INVOKEVIRTUAL) {
        return;
    }
    next = next.getNext();
    if (next == null) {
        return;
    }
    int ordinal;
    switch (next.getOpcode()) {
    case Opcodes.ICONST_0:
        ordinal = 0;
        break;
    case Opcodes.ICONST_1:
        ordinal = 1;
        break;
    case Opcodes.ICONST_2:
        ordinal = 2;
        break;
    case Opcodes.ICONST_3:
        ordinal = 3;
        break;
    case Opcodes.ICONST_4:
        ordinal = 4;
        break;
    case Opcodes.ICONST_5:
        ordinal = 5;
        break;
    case Opcodes.BIPUSH: {
        IntInsnNode iin = (IntInsnNode) next;
        ordinal = iin.operand;
        break;
    }
    default:
        return;
    }

    // Find usages of this call site
    List methodList = classNode.methods;
    for (Object m : methodList) {
        InsnList nodes = ((MethodNode) m).instructions;
        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            if (instruction.getOpcode() != Opcodes.INVOKESTATIC) {
                continue;
            }
            MethodInsnNode node = (MethodInsnNode) instruction;
            if (node.name.equals(method.name) && node.desc.equals(method.desc)
                    && node.owner.equals(classNode.name)) {
                // Find lookup switch
                AbstractInsnNode target = getNextInstruction(node);
                while (target != null) {
                    if (target.getOpcode() == Opcodes.LOOKUPSWITCH) {
                        LookupSwitchInsnNode lookup = (LookupSwitchInsnNode) target;
                        @SuppressWarnings("unchecked") // ASM API
                        List<Integer> keys = lookup.keys;
                        if (keys != null && keys.contains(ordinal)) {
                            String fqcn = ClassContext.getFqcn(owner) + '#' + name;
                            String message = String.format(
                                    "Enum value requires API level %1$d " + "(current min is %2$d): %3$s", api,
                                    minSdk, fqcn);
                            report(context, message, lookup, (MethodNode) m, name, null,
                                    SearchHints.create(FORWARD).matchJavaSymbol());

                            // Break out of the inner target search only; the switch
                            // statement could be used in other places in this class as
                            // well and we want to report all problematic usages.
                            break;
                        }
                    }
                    target = getNextInstruction(target);
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.FieldGetterDetector.java

License:Apache License

@Override
public void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
        @NonNull MethodNode method, @NonNull AbstractInsnNode instruction) {
    // As of Gingerbread/API 9, Dalvik performs this optimization automatically
    if (context.getProject().getMinSdk() >= 9) {
        return;/*from  w w w  . j a va2 s. com*/
    }

    if ((method.access & Opcodes.ACC_STATIC) != 0) {
        // Not an instance method
        return;
    }

    if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) {
        return;
    }

    MethodInsnNode node = (MethodInsnNode) instruction;
    String name = node.name;
    String owner = node.owner;

    AbstractInsnNode prev = LintUtils.getPrevInstruction(instruction);
    if (prev == null || prev.getOpcode() != Opcodes.ALOAD) {
        return;
    }
    VarInsnNode prevVar = (VarInsnNode) prev;
    if (prevVar.var != 0) { // Not on "this", variable 0 in instance methods?
        return;
    }

    if (((name.startsWith("get") && name.length() > 3 //$NON-NLS-1$
            && Character.isUpperCase(name.charAt(3)))
            || (name.startsWith("is") && name.length() > 2 //$NON-NLS-1$
                    && Character.isUpperCase(name.charAt(2))))
            && owner.equals(classNode.name)) {
        // Calling a potential getter method on self. We now need to
        // investigate the method body of the getter call and make sure
        // it's really a plain getter, not just a method which happens
        // to have a method name like a getter, or a method which not
        // only returns a field but possibly computes it or performs
        // other initialization or side effects. This is done in a
        // second pass over the bytecode, initiated by the finish()
        // method.
        if (mPendingCalls == null) {
            mPendingCalls = new ArrayList<Entry>();
        }

        mPendingCalls.add(new Entry(name, node, method));
    }

    super.checkInstruction(context, classNode, method, instruction);
}

From source file:com.android.tools.lint.checks.InvalidPackageDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//from w w w  .  j  av a2 s.c o  m
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!context.isFromClassLibrary() || shouldSkip(context.file)) {
        return;
    }

    if (mApiDatabase == null) {
        return;
    }

    if (classNode.name.startsWith(JAVAX_PKG_PREFIX)) {
        mJavaxLibraryClasses.add(classNode.name);
    }

    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        InsnList nodes = method.instructions;

        // Check return type
        // The parameter types are already handled as local variables so we can skip
        // right to the return type.
        // Check types in parameter list
        String signature = method.desc;
        if (signature != null) {
            int args = signature.indexOf(')');
            if (args != -1 && signature.charAt(args + 1) == 'L') {
                String type = signature.substring(args + 2, signature.length() - 1);
                if (isInvalidPackage(type)) {
                    AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                    record(context, method, first, type);
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String owner = node.owner;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                while (owner != null) {
                    if (isInvalidPackage(owner)) {
                        record(context, method, instruction, owner);
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith(JAVA_PKG_PREFIX) || owner.startsWith(JAVAX_PKG_PREFIX)) {
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String owner = node.owner;
                if (isInvalidPackage(owner)) {
                    record(context, method, instruction, owner);
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();
                    if (isInvalidPackage(className)) {
                        record(context, method, instruction, className);
                    }
                }
            }
        }
    }
}

From source file:com.asakusafw.dag.compiler.builtin.BranchOperatorGenerator.java

License:Apache License

static void branch(MethodVisitor method, Context context, UserOperator operator, LocalVarRef input,
        Map<OperatorProperty, FieldRef> dependencies) {
    OperatorOutput[] outputs = outputs(context, operator);
    Label[] caseLabels = Stream.of(outputs).map(o -> new Label()).toArray(Label[]::new);
    Label defaultLabel = new Label();
    Label endLabel = new Label();

    method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, typeOf(Enum.class).getInternalName(), "ordinal",
            Type.getMethodDescriptor(Type.INT_TYPE), false);
    method.visitTableSwitchInsn(0, caseLabels.length - 1, defaultLabel, caseLabels);

    for (int i = 0; i < outputs.length; i++) {
        method.visitLabel(caseLabels[i]);
        FieldRef ref = Invariants.requireNonNull(dependencies.get(outputs[i]));
        ref.load(method);/*from   w  w w. jav a 2s  .co  m*/
        input.load(method);
        invokeResultAdd(method);
        method.visitJumpInsn(Opcodes.GOTO, endLabel);
    }
    method.visitLabel(defaultLabel);
    getNew(method, Descriptions.typeOf(AssertionError.class));
    method.visitInsn(Opcodes.ATHROW);

    method.visitLabel(endLabel);
}