Example usage for org.objectweb.asm.tree.analysis Analyzer Analyzer

List of usage examples for org.objectweb.asm.tree.analysis Analyzer Analyzer

Introduction

In this page you can find the example usage for org.objectweb.asm.tree.analysis Analyzer Analyzer.

Prototype

public Analyzer(final Interpreter<V> interpreter) 

Source Link

Document

Constructs a new Analyzer .

Usage

From source file:cl.inria.stiq.instrumenter.BCIUtils.java

License:Open Source License

public static void checkMethod(ClassNode aClassNode, MethodNode aNode, Interpreter aInterpreter,
        boolean aAlwaysPrint) {
    checkLabels(aNode);/* w ww  .  ja v a2 s  . c  o m*/
    Analyzer theAnalyzer = new Analyzer(aInterpreter);
    try {
        theAnalyzer.analyze(aClassNode.name, aNode);
        if (aAlwaysPrint) {
            Frame[] theFrames = theAnalyzer.getFrames();
            printFrames(aNode, theFrames);
        }
    } catch (AnalyzerException e) {
        Frame[] theFrames = theAnalyzer.getFrames();
        printFrames(aNode, theFrames);

        Utils.rtex(e, "Error in %s.%s%s at instructions #(%s): %s", aClassNode.name, aNode.name, aNode.desc,
                "?", //e.nodes != null ? getBytecodeRanks(aNode, e.nodes) : "?",
                e.getMessage());
    } catch (Exception e) {
        Utils.rtex(e, "Exception while analyzing %s.%s%s", aClassNode.name, aNode.name, aNode.desc);
    }
}

From source file:com.android.build.gradle.internal.incremental.ConstructorBuilder.java

License:Apache License

/**
 * Deconstruct a constructor into its components and adds the necessary code to link the components
 * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor:
 * <pre>{@code/*from ww  w  .  j  a  va 2s  . c  om*/
 *   <init>(int x) {
 *     int a = 2;
 *     super(int b = 3, x = 1, expr2() ? 3 : a++)
 *     doSomething(x + a)
 *   }
 * }</pre>
 * it creates two parts:
 * <pre>{@code
 *   Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here
 *     int a = locals[0];
 *     int b = 3;
 *     Object[] args = new Object[3];
 *     args[0] = b;
 *     args[1] = (x = 1)
 *     args[2] = expr2() ? 3 : a++;
 *     locals = new Object[3]; // The arguments + the locals
 *     locals[0] = NULL;
 *     locals[1] = x;
 *     locals[2] = new Object[2];
 *     locals[2][0] = a;
 *     locals[2][1] = b;
 *     return new Object[] {locals, "myclass.<init>(I;I;)V", args};
 *   }
 *
 *   void init$body(int x, Object[] locals) {
 *     int a = locals[0];
 *     int b = locals[1];
 *     doSomething(x + a);
 *   }
 * }</pre>
 *
 * @param owner the owning class.
 * @param method the constructor method.
 */
@NonNull
public static Constructor build(@NonNull String owner, @NonNull MethodNode method) {
    // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However
    // we need to distinguish one in particular. The value of the local variable 0, ie. the
    // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0
    // a LocalValue instance will be on the stack.
    BasicInterpreter interpreter = new BasicInterpreter() {
        boolean done = false;

        @Override
        // newValue is called first to initialize the frame values of all the local variables
        // we intercept the first one to create our own special value.
        public BasicValue newValue(Type type) {
            if (type == null) {
                return BasicValue.UNINITIALIZED_VALUE;
            } else if (type.getSort() == Type.VOID) {
                return null;
            } else {
                // If this is the first value created (i.e. the first local variable)
                // we use a special marker.
                BasicValue ret = done ? super.newValue(type) : new LocalValue(type);
                done = true;
                return ret;
            }
        }
    };

    Analyzer analyzer = new Analyzer(interpreter);
    AbstractInsnNode[] instructions = method.instructions.toArray();
    try {
        Frame[] frames = analyzer.analyze(owner, method);
        if (frames.length != instructions.length) {
            // Should never happen.
            throw new IllegalStateException("The number of frames is not equals to the number of instructions");
        }
        int stackAtThis = -1;
        boolean poppedThis = false;
        int firstLocal = 1;
        for (Type type : Type.getArgumentTypes(method.desc)) {
            firstLocal += type.getSize();
        }

        LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>();
        VarInsnNode lastThis = null;
        int localsAtLastThis = 0;
        // Records the most recent line number encountered. For javac, there should always be
        // a line number node before the call of interest to this(...) or super(...). For robustness,
        // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers
        // should check for -1 and recover in a reasonable way (for example, don't set the line
        // number in generated code).
        int recentLine = -1;
        for (int i = 0; i < instructions.length; i++) {
            AbstractInsnNode insn = instructions[i];
            Frame frame = frames[i];
            if (frame.getStackSize() < stackAtThis) {
                poppedThis = true;
            }
            if (insn instanceof MethodInsnNode) {
                // TODO: Do we need to check that the stack is empty after this super call?
                MethodInsnNode methodhInsn = (MethodInsnNode) insn;
                Type[] types = Type.getArgumentTypes(methodhInsn.desc);
                Value value = frame.getStack(frame.getStackSize() - types.length - 1);
                if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) {
                    if (poppedThis) {
                        throw new IllegalStateException("Unexpected constructor structure.");
                    }
                    return split(owner, method, lastThis, methodhInsn, recentLine,
                            new ArrayList<LocalVariable>(variables), localsAtLastThis);
                }
            } else if (insn instanceof VarInsnNode) {
                VarInsnNode var = (VarInsnNode) insn;
                if (var.var == 0) {
                    lastThis = var;
                    localsAtLastThis = variables.size();
                    stackAtThis = frame.getStackSize();
                    poppedThis = false;
                }
                Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode());
                if (type != null && var.var >= firstLocal) {
                    // Variables are equals based on their number, so they will be added
                    // to the set only if they are new, and in the order they are seen.
                    variables.add(new LocalVariable(type, var.var));
                }
            } else if (insn instanceof LineNumberNode) {
                // Record the most recent line number encountered so that call to this(...)
                // or super(...) has line number information. Ultimately used to emit a line
                // number in the generated code.
                LineNumberNode lineNumberNode = (LineNumberNode) insn;
                recentLine = lineNumberNode.line;
            }
        }
        throw new IllegalStateException("Unexpected constructor structure.");
    } catch (AnalyzerException e) {
        throw new IllegalStateException(e);
    }
}

From source file:com.android.build.gradle.internal.incremental.ConstructorDelegationDetector.java

License:Apache License

/**
 * Deconstruct a constructor into its components and adds the necessary code to link the components
 * later. The generated bytecode does not correspond exactly to this code, but in essence, for
 * a constructor of this form://from  w  w w  .java  2  s.  c  o m
 * <p/>
 * <code>
 *   <init>(int x) {
 *     super(x = 1, expr2() ? 3 : 7)
 *     doSomething(x)
 *   }
 * </code>
 * <p/>
 * it creates the two parts:
 * <code>
 *   Object[] init$args(Object[] locals, int x) {
 *     Object[] args = new Object[2];
 *     args[0] = (x = 1)
 *     args[1] = expr2() ? 3 : 7;
 *     locals[0] = x;
 *     return new Object[] {"myclass.<init>(I;I;)V", args};
 *   }
 *
 *   void init$body(int x) {
 *     doSomething(x);
 *   }
 * </code>
 *
 * @param owner the owning class.
 * @param method the constructor method.
 */
@NonNull
public static Constructor deconstruct(@NonNull String owner, @NonNull MethodNode method) {
    // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However
    // we need to distinguish one in particular. The value of the local variable 0, ie. the
    // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0
    // a LocalValue instance will be on the stack.
    BasicInterpreter interpreter = new BasicInterpreter() {
        boolean done = false;

        @Override
        // newValue is called first to initialize the frame values of all the local variables
        // we intercept the first one to create our own special value.
        public BasicValue newValue(Type type) {
            if (type == null) {
                return BasicValue.UNINITIALIZED_VALUE;
            } else if (type.getSort() == Type.VOID) {
                return null;
            } else {
                // If this is the first value created (i.e. the first local variable)
                // we use a special marker.
                BasicValue ret = done ? super.newValue(type) : new LocalValue(type);
                done = true;
                return ret;
            }
        }
    };

    Analyzer analyzer = new Analyzer(interpreter);
    AbstractInsnNode[] instructions = method.instructions.toArray();
    try {
        Frame[] frames = analyzer.analyze(owner, method);
        if (frames.length != instructions.length) {
            // Should never happen.
            throw new IllegalStateException("The number of frames is not equals to the number of instructions");
        }
        VarInsnNode lastThis = null;
        int stackAtThis = -1;
        boolean poppedThis = false;
        // Records the most recent line number encountered. For javac, there should always be
        // a line number node before the call of interest to this(...) or super(...). For robustness,
        // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers
        // should check for -1 and recover in a reasonable way (for example, don't set the line
        // number in generated code).
        int recentLine = -1;
        for (int i = 0; i < instructions.length; i++) {
            AbstractInsnNode insn = instructions[i];
            Frame frame = frames[i];
            if (frame.getStackSize() < stackAtThis) {
                poppedThis = true;
            }
            if (insn instanceof MethodInsnNode) {
                // TODO: Do we need to check that the stack is empty after this super call?
                MethodInsnNode methodhInsn = (MethodInsnNode) insn;
                Type[] types = Type.getArgumentTypes(methodhInsn.desc);
                Value value = frame.getStack(frame.getStackSize() - types.length - 1);
                if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) {
                    if (poppedThis) {
                        throw new IllegalStateException("Unexpected constructor structure.");
                    }
                    return split(owner, method, lastThis, methodhInsn, recentLine);
                }
            } else if (insn instanceof VarInsnNode) {
                VarInsnNode var = (VarInsnNode) insn;
                if (var.var == 0) {
                    lastThis = var;
                    stackAtThis = frame.getStackSize();
                    poppedThis = false;
                }
            } else if (insn instanceof LineNumberNode) {
                // Record the most recent line number encountered so that call to this(...)
                // or super(...) has line number information. Ultimately used to emit a line
                // number in the generated code.
                LineNumberNode lineNumberNode = (LineNumberNode) insn;
                recentLine = lineNumberNode.line;
            }
        }
        throw new IllegalStateException("Unexpected constructor structure.");
    } catch (AnalyzerException e) {
        throw new IllegalStateException(e);
    }
}

From source file:com.android.build.gradle.internal2.incremental.ConstructorBuilder.java

License:Apache License

/**
 * Deconstruct a constructor into its components and adds the necessary code to link the components
 * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor:
 * <pre>{@code//from  ww w.  j  a v a2 s.  c  o  m
 *   <init>(int x) {
 *     int a = 2;
 *     super(int b = 3, x = 1, expr2() ? 3 : a++)
 *     doSomething(x + a)
 *   }
 * }</pre>
 * it creates two parts:
 * <pre>{@code
 *   Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here
 *     int a = locals[0];
 *     int b = 3;
 *     Object[] args = new Object[3];
 *     args[0] = b;
 *     args[1] = (x = 1)
 *     args[2] = expr2() ? 3 : a++;
 *     locals = new Object[3]; // The arguments + the locals
 *     locals[0] = NULL;
 *     locals[1] = x;
 *     locals[2] = new Object[2];
 *     locals[2][0] = a;
 *     locals[2][1] = b;
 *     return new Object[] {locals, "myclass.<init>(I;I;)V", args};
 *   }
 *
 *   void init$body(int x, Object[] locals) {
 *     int a = locals[0];
 *     int b = locals[1];
 *     doSomething(x + a);
 *   }
 * }</pre>
 *
 * @param owner the owning class.
 * @param method the constructor method.
 */
@NonNull
public static Constructor build(@NonNull String owner, @NonNull MethodNode method) {
    // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However
    // we need to distinguish one in particular. The value of the local variable 0, ie. the
    // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0
    // a LocalValue instance will be on the stack.
    BasicInterpreter interpreter = new BasicInterpreter() {
        boolean done = false;

        @Override
        // newValue is called first to initialize the frame values of all the local variables
        // we intercept the first one to create our own special value.
        public BasicValue newValue(Type type) {
            if (type == null) {
                return BasicValue.UNINITIALIZED_VALUE;
            } else if (type.getSort() == Type.VOID) {
                return null;
            } else {
                // If this is the first value created (i.e. the first local variable)
                // we use a special marker.
                BasicValue ret = done ? super.newValue(type) : new LocalValue(type);
                done = true;
                return ret;
            }
        }
    };

    Analyzer analyzer = new Analyzer(interpreter);
    AbstractInsnNode[] instructions = method.instructions.toArray();
    try {
        Frame[] frames = analyzer.analyze(owner, method);
        if (frames.length != instructions.length) {
            // Should never happen.
            throw new IllegalStateException("The number of frames is not equals to the number of instructions");
        }
        int stackAtThis = -1;
        boolean poppedThis = false;
        int firstLocal = 1;
        for (Type type : Type.getArgumentTypes(method.desc)) {
            firstLocal += type.getSize();
        }

        LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>();
        VarInsnNode lastThis = null;
        int localsAtLastThis = 0;
        // Records the most recent line number encountered. For javac, there should always be
        // a line number node before the call of interest to this(...) or super(...). For robustness,
        // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers
        // should check for -1 and recover in a reasonable way (for example, don't set the line
        // number in generated code).
        int recentLine = -1;
        for (int i = 0; i < instructions.length; i++) {
            AbstractInsnNode insn = instructions[i];
            Frame frame = frames[i];
            if (frame.getStackSize() < stackAtThis) {
                poppedThis = true;
            }
            if (insn instanceof MethodInsnNode) {
                // TODO: Do we need to check that the stack is empty after this super call?
                MethodInsnNode methodhInsn = (MethodInsnNode) insn;
                Type[] types = Type.getArgumentTypes(methodhInsn.desc);
                Value value = frame.getStack(frame.getStackSize() - types.length - 1);
                if (value instanceof LocalValue && methodhInsn.name.equals(ByteCodeUtils.CONSTRUCTOR)) {
                    if (poppedThis) {
                        throw new IllegalStateException("Unexpected constructor structure.");
                    }
                    return split(owner, method, lastThis, methodhInsn, recentLine,
                            new ArrayList<LocalVariable>(variables), localsAtLastThis);
                }
            } else if (insn instanceof VarInsnNode) {
                VarInsnNode var = (VarInsnNode) insn;
                if (var.var == 0) {
                    lastThis = var;
                    localsAtLastThis = variables.size();
                    stackAtThis = frame.getStackSize();
                    poppedThis = false;
                }
                Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode());
                if (type != null && var.var >= firstLocal) {
                    // Variables are equals based on their number, so they will be added
                    // to the set only if they are new, and in the order they are seen.
                    variables.add(new LocalVariable(type, var.var));
                }
            } else if (insn instanceof LineNumberNode) {
                // Record the most recent line number encountered so that call to this(...)
                // or super(...) has line number information. Ultimately used to emit a line
                // number in the generated code.
                LineNumberNode lineNumberNode = (LineNumberNode) insn;
                recentLine = lineNumberNode.line;
            }
        }
        throw new IllegalStateException("Unexpected constructor structure.");
    } catch (AnalyzerException e) {
        throw new IllegalStateException(e);
    }
}

From source file:com.android.tools.klint.checks.ControlFlowGraph.java

License:Apache License

/**
 * Creates a new {@link ControlFlowGraph} and populates it with the flow
 * control for the given method. If the optional {@code initial} parameter is
 * provided with an existing graph, then the graph is simply populated, not
 * created. This allows subclassing of the graph instance, if necessary.
 *
 * @param initial usually null, but can point to an existing instance of a
 *            {@link ControlFlowGraph} in which that graph is reused (but
 *            populated with new edges)//from  w  ww  . j  a  v  a  2s .com
 * @param classNode the class containing the method to be analyzed
 * @param method the method to be analyzed
 * @return a {@link ControlFlowGraph} with nodes for the control flow in the
 *         given method
 * @throws AnalyzerException if the underlying bytecode library is unable to
 *             analyze the method bytecode
 */
@NonNull
public static ControlFlowGraph create(@Nullable ControlFlowGraph initial, @NonNull ClassNode classNode,
        @NonNull MethodNode method) throws AnalyzerException {
    final ControlFlowGraph graph = initial != null ? initial : new ControlFlowGraph();
    final InsnList instructions = method.instructions;
    graph.mNodeMap = Maps.newHashMapWithExpectedSize(instructions.size());
    graph.mMethod = method;

    // Create a flow control graph using ASM5's analyzer. According to the ASM 4 guide
    // (download.forge.objectweb.org/asm/asm4-guide.pdf) there are faster ways to construct
    // it, but those require a lot more code.
    Analyzer analyzer = new Analyzer(new BasicInterpreter()) {
        @Override
        protected void newControlFlowEdge(int insn, int successor) {
            // Update the information as of whether the this object has been
            // initialized at the given instruction.
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.add(from, to);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, TryCatchBlockNode tcb) {
            AbstractInsnNode from = instructions.get(insn);
            graph.exception(from, tcb);
            return super.newControlFlowExceptionEdge(insn, tcb);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, int successor) {
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.exception(from, to);
            return super.newControlFlowExceptionEdge(insn, successor);
        }
    };

    analyzer.analyze(classNode.name, method);
    return graph;
}

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

License:Apache License

/**
 * Creates a new {@link ControlFlowGraph} and populates it with the flow
 * control for the given method. If the optional {@code initial} parameter is
 * provided with an existing graph, then the graph is simply populated, not
 * created. This allows subclassing of the graph instance, if necessary.
 *
 * @param initial usually null, but can point to an existing instance of a
 *            {@link ControlFlowGraph} in which that graph is reused (but
 *            populated with new edges)/*  ww  w  .  ja v a 2s .  c  o  m*/
 * @param classNode the class containing the method to be analyzed
 * @param method the method to be analyzed
 * @return a {@link ControlFlowGraph} with nodes for the control flow in the
 *         given method
 * @throws AnalyzerException if the underlying bytecode library is unable to
 *             analyze the method bytecode
 */
@NonNull
public static ControlFlowGraph create(@Nullable ControlFlowGraph initial, @NonNull ClassNode classNode,
        @NonNull MethodNode method) throws AnalyzerException {
    final ControlFlowGraph graph = initial != null ? initial : new ControlFlowGraph();
    final InsnList instructions = method.instructions;
    graph.mNodeMap = Maps.newHashMapWithExpectedSize(instructions.size());

    // Create a flow control graph using ASM4's analyzer. According to the ASM 4 guide
    // (download.forge.objectweb.org/asm/asm4-guide.pdf) there are faster ways to construct
    // it, but those require a lot more code.
    Analyzer analyzer = new Analyzer(new BasicInterpreter()) {
        @Override
        protected void newControlFlowEdge(int insn, int successor) {
            // Update the information as of whether the this object has been
            // initialized at the given instruction.
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.add(from, to);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, TryCatchBlockNode tcb) {
            AbstractInsnNode from = instructions.get(insn);
            graph.exception(from, tcb);
            return super.newControlFlowExceptionEdge(insn, tcb);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, int successor) {
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.exception(from, to);
            return super.newControlFlowExceptionEdge(insn, successor);
        }
    };

    analyzer.analyze(classNode.name, method);
    return graph;
}

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

License:Apache License

@Nullable
private String findFirstArgType(ClassContext context, ClassNode classNode, MethodNode method,
        MethodInsnNode call) {//from  www  .j av a  2s .  co m
    // Find object being passed in as the first argument
    Analyzer analyzer = new Analyzer(new SourceInterpreter() {
        @Override
        public SourceValue newOperation(AbstractInsnNode insn) {
            if (insn.getOpcode() == Opcodes.NEW) {
                String desc = ((TypeInsnNode) insn).desc;
                return new TypeValue(1, desc);
            }
            return super.newOperation(insn);
        }

        @Override
        public SourceValue newValue(Type type) {
            if (type != null && type.getSort() == Type.VOID) {
                return null;
            } else if (type != null) {
                return new TypeValue(1, type.getInternalName());
            }
            return super.newValue(type);
        }

        @Override
        public SourceValue copyOperation(AbstractInsnNode insn, SourceValue value) {
            return value;
        }
    });
    try {
        Frame[] frames = analyzer.analyze(classNode.name, method);
        InsnList instructions = method.instructions;
        Frame frame = frames[instructions.indexOf(call)];
        if (frame.getStackSize() <= 1) {
            return null;
        }
        SourceValue stackValue = (SourceValue) frame.getStack(1);
        if (stackValue instanceof TypeValue) {
            return ((TypeValue) stackValue).getFqcn();
        }
    } catch (AnalyzerException e) {
        context.log(e, null);
    }

    return null;
}

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

License:Apache License

@Override
public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode call) {/*  ww  w  .j  av  a  2 s . c  om*/
    String owner = call.owner;
    String desc = call.desc;
    String name = call.name;
    if (owner.equals(DATE_FORMAT_OWNER)) {
        if (!name.equals(CONSTRUCTOR_NAME)) {
            return;
        }
        if (desc.equals("(Ljava/lang/String;Ljava/text/DateFormatSymbols;)V") //$NON-NLS-1$
                || desc.equals("()V") //$NON-NLS-1$
                || desc.equals("(Ljava/lang/String;)V")) { //$NON-NLS-1$
            Location location = context.getLocation(call);
            String message = "To get local formatting use getDateInstance(), getDateTimeInstance(), "
                    + "or getTimeInstance(), or use new SimpleDateFormat(String template, "
                    + "Locale locale) with for example Locale.US for ASCII dates.";
            context.report(DATE_FORMAT, method, call, location, message, null);
        }
        return;
    } else if (!owner.equals(STRING_OWNER)) {
        return;
    }

    if (name.equals(FORMAT_METHOD)) {
        // Only check the non-locale version of String.format
        if (!desc.equals("(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;")) { //$NON-NLS-1$
            return;
        }
        // Find the formatting string
        Analyzer analyzer = new Analyzer(new SourceInterpreter() {
            @Override
            public SourceValue newOperation(AbstractInsnNode insn) {
                if (insn.getOpcode() == Opcodes.LDC) {
                    Object cst = ((LdcInsnNode) insn).cst;
                    if (cst instanceof String) {
                        return new StringValue(1, (String) cst);
                    }
                }
                return super.newOperation(insn);
            }
        });
        try {
            Frame[] frames = analyzer.analyze(classNode.name, method);
            InsnList instructions = method.instructions;
            Frame frame = frames[instructions.indexOf(call)];
            if (frame.getStackSize() == 0) {
                return;
            }
            SourceValue stackValue = (SourceValue) frame.getStack(0);
            if (stackValue instanceof StringValue) {
                String format = ((StringValue) stackValue).getString();
                if (format != null && StringFormatDetector.isLocaleSpecific(format)) {
                    Location location = context.getLocation(call);
                    String message = "Implicitly using the default locale is a common source of bugs: "
                            + "Use String.format(Locale, ...) instead";
                    context.report(STRING_LOCALE, method, call, location, message, null);
                }
            }
        } catch (AnalyzerException e) {
            context.log(e, null);
        }
    } else {
        if (desc.equals("()Ljava/lang/String;")) { //$NON-NLS-1$
            Location location = context.getLocation(call);
            String message = String.format("Implicitly using the default locale is a common source of bugs: "
                    + "Use %1$s(Locale) instead", name);
            context.report(STRING_LOCALE, method, call, location, message, null);
        }
    }
}

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

License:Apache License

@Override
public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode call) {/*from ww w  .  j av  a2 s. c  om*/
    String owner = call.owner;
    String desc = call.desc;
    if (owner.equals(OWNER_SECURE_RANDOM)) {
        if (desc.startsWith(LONG_ARG)) {
            checkValidSetSeed(context, call);
        } else if (desc.startsWith("([B)")) { //$NON-NLS-1$
            // setSeed(byte[]) ...
            // We could do some flow analysis here to see whether the byte array getting
            // passed in appears to be fixed.
            // However, people calling this constructor rather than the simpler one
            // with a fixed integer are probably less likely to make that mistake... right?
        }
    } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) {
        // Called setSeed(long) on an instanceof a Random object. Flag this if the instance
        // is likely a SecureRandom.

        // Track allocations such that we know whether the type of the call
        // is on a SecureRandom rather than a Random
        Analyzer analyzer = new Analyzer(new BasicInterpreter() {
            @Override
            public BasicValue newValue(Type type) {
                if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) {
                    return new BasicValue(type);
                }
                return super.newValue(type);
            }
        });
        try {
            Frame[] frames = analyzer.analyze(classNode.name, method);
            InsnList instructions = method.instructions;
            Frame frame = frames[instructions.indexOf(call)];
            int stackSlot = frame.getStackSize();
            for (Type type : Type.getArgumentTypes(desc)) {
                stackSlot -= type.getSize();
            }
            BasicValue stackValue = (BasicValue) frame.getStack(stackSlot);
            Type type = stackValue.getType();
            if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) {
                checkValidSetSeed(context, call);
            }
        } catch (AnalyzerException e) {
            context.log(e, null);
        }
    } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) {
        // Called setSeed(long) on an instanceof a Random object. Flag this if the instance
        // is likely a SecureRandom.
        // TODO
    }
}

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

License:Apache License

@Override
public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode call) {/* w w w  . j a  v a  2  s .  com*/
    // The leak behavior is fixed in ICS:
    // http://code.google.com/p/android/issues/detail?id=18273
    if (context.getMainProject().getMinSdk() >= 14) {
        return;
    }

    String owner = call.owner;
    String desc = call.desc;
    if (owner.equals("android/view/View") //$NON-NLS-1$
            && desc.equals("(ILjava/lang/Object;)V")) { //$NON-NLS-1$
        Analyzer analyzer = new Analyzer(new BasicInterpreter() {
            @Override
            public BasicValue newValue(Type type) {
                if (type == null) {
                    return BasicValue.UNINITIALIZED_VALUE;
                } else if (type.getSort() == Type.VOID) {
                    return null;
                } else {
                    return new BasicValue(type);
                }
            }
        });
        try {
            Frame[] frames = analyzer.analyze(classNode.name, method);
            InsnList instructions = method.instructions;
            Frame frame = frames[instructions.indexOf(call)];
            if (frame.getStackSize() < 3) {
                return;
            }
            BasicValue stackValue = (BasicValue) frame.getStack(2);
            Type type = stackValue.getType();
            if (type == null) {
                return;
            }

            String internalName = type.getInternalName();
            String className = type.getClassName();
            LintDriver driver = context.getDriver();

            SdkInfo sdkInfo = context.getClient().getSdkInfo(context.getMainProject());
            String objectType = null;
            while (className != null) {
                if (className.equals("android.view.View")) { //$NON-NLS-1$
                    objectType = "views";
                    break;
                } else if (className.endsWith("ViewHolder")) { //$NON-NLS-1$
                    objectType = "view holders";
                    break;
                } else if (className.endsWith("Cursor") //$NON-NLS-1$
                        && className.startsWith("android.")) { //$NON-NLS-1$
                    objectType = "cursors";
                    break;
                }

                // TBD: Bitmaps, drawables? That's tricky, because as explained in
                // http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
                // apparently these are used along with nulling out the callbacks,
                // and that's harder to detect here

                String parent = sdkInfo.getParentViewClass(className);
                if (parent == null) {
                    if (internalName == null) {
                        internalName = className.replace('.', '/');
                    }
                    assert internalName != null;
                    parent = driver.getSuperClass(internalName);
                }
                className = parent;
                internalName = null;
            }

            if (objectType != null) {
                Location location = context.getLocation(call);
                String message = String.format("Avoid setting %1$s as values for setTag: "
                        + "Can lead to memory leaks in versions older than Android 4.0", objectType);
                context.report(ISSUE, method, call, location, message, null);
            }
        } catch (AnalyzerException e) {
            context.log(e, null);
        }
    }
}