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

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

Introduction

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

Prototype

@SuppressWarnings("unchecked")
public Frame<V>[] analyze(final String owner, final MethodNode method) throws AnalyzerException 

Source Link

Document

Analyzes the given method.

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  va  2 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:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

public InstrumentMethod(MethodDatabase db, String className, MethodNode mn) throws AnalyzerException {
    this.db = db;
    this.className = className;
    this.mn = mn;

    try {//w  ww .ja v a 2  s . c  om
        Analyzer a = new TypeAnalyzer(db);
        this.frames = a.analyze(className, mn);
        this.lvarStack = mn.maxLocals;
        this.lvarResumed = mn.maxLocals + 1;
        this.lvarInvocationReturnValue = mn.maxLocals + 2;
        // this.lvarSuspendableCalled = (verifyInstrumentation ? mn.maxLocals + 3 : -1);
        this.firstLocal = ((mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) ? 0 : 1;
    } catch (UnsupportedOperationException ex) {
        throw new AnalyzerException(null, ex.getMessage(), ex);
    }
}

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   w  ww. jav a 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 ww w .java 2  s .co 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   w  ww . j  av  a  2s .co  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)/* ww w . java  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());
    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.  j av a2 s. 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) {//www.  j  a v a2 s  . 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) {//from  w  ww . j a v a2  s.c o  m
    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) {/*  ww  w . ja v a 2 s  .  co  m*/
    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
    }
}