Example usage for org.objectweb.asm.tree.analysis Frame getStack

List of usage examples for org.objectweb.asm.tree.analysis Frame getStack

Introduction

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

Prototype

public V getStack(final int index) 

Source Link

Document

Returns the value of the given operand stack slot.

Usage

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

private void dumpCodeBlock(MethodVisitor mv, int idx, int skip) {
    int start = codeBlocks[idx].endInstruction;
    int end = codeBlocks[idx + 1].endInstruction;

    for (int i = start + skip; i < end; i++) {
        AbstractInsnNode ins = mn.instructions.get(i);
        switch (ins.getOpcode()) {
        case Opcodes.RETURN:
        case Opcodes.ARETURN:
        case Opcodes.IRETURN:
        case Opcodes.LRETURN:
        case Opcodes.FRETURN:
        case Opcodes.DRETURN:
            emitPopMethod(mv);//from  w  w w.  ja va2 s.c o  m
            break;

        case Opcodes.MONITORENTER:
        case Opcodes.MONITOREXIT:
            if (!db.isAllowMonitors()) {
                if (!className.equals("clojure/lang/LazySeq"))
                    throw new UnableToInstrumentException("synchronization", className, mn.name, mn.desc);
            } else if (!warnedAboutMonitors) {
                warnedAboutMonitors = true;
                db.log(LogLevel.WARNING, "Method %s#%s%s contains synchronization", className, mn.name,
                        mn.desc);
            }
            break;

        case Opcodes.INVOKESPECIAL:
            MethodInsnNode min = (MethodInsnNode) ins;
            if ("<init>".equals(min.name)) {
                int argSize = TypeAnalyzer.getNumArguments(min.desc);
                Frame frame = frames[i];
                int stackIndex = frame.getStackSize() - argSize - 1;
                Value thisValue = frame.getStack(stackIndex);
                if (stackIndex >= 1 && isNewValue(thisValue, true)
                        && isNewValue(frame.getStack(stackIndex - 1), false)) {
                    NewValue newValue = (NewValue) thisValue;
                    if (newValue.omitted) {
                        emitNewAndDup(mv, frame, stackIndex, min);
                    }
                } else {
                    db.log(LogLevel.WARNING, "Expected to find a NewValue on stack index %d: %s", stackIndex,
                            frame);
                }
            }
            break;
        }

        ins.accept(mv);
    }
}

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

private void emitNewAndDup(MethodVisitor mv, Frame frame, int stackIndex, MethodInsnNode min) {
    int arguments = frame.getStackSize() - stackIndex - 1;
    int neededLocals = 0;
    for (int i = arguments; i >= 1; i--) {
        BasicValue v = (BasicValue) frame.getStack(stackIndex + i);
        mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), lvarStack + NUM_LOCALS + neededLocals);
        neededLocals += v.getSize();//from  www .  jav  a2 s  .  c o  m
    }
    db.log(LogLevel.DEBUG, "Inserting NEW & DUP for constructor call %s%s with %d arguments (%d locals)",
            min.owner, min.desc, arguments, neededLocals);
    if (additionalLocals < neededLocals) {
        additionalLocals = neededLocals;
    }
    ((NewValue) frame.getStack(stackIndex - 1)).insn.accept(mv);
    ((NewValue) frame.getStack(stackIndex)).insn.accept(mv);
    for (int i = 1; i <= arguments; i++) {
        BasicValue v = (BasicValue) frame.getStack(stackIndex + i);
        neededLocals -= v.getSize();
        mv.visitVarInsn(v.getType().getOpcode(Opcodes.ILOAD), lvarStack + NUM_LOCALS + neededLocals);
    }
}

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

private void emitStoreState(MethodVisitor mv, int idx, FrameInfo fi, int numArgsToPreserve) {
    Frame f = frames[fi.endInstruction];

    if (fi.lBefore != null)
        fi.lBefore.accept(mv);/*from   w w  w .  j  a  v  a 2 s  .  co  m*/

    mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
    emitConst(mv, idx);
    emitConst(mv, fi.numSlots);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "pushMethod", "(II)V");

    // store operand stack
    for (int i = f.getStackSize(); i-- > 0;) {
        BasicValue v = (BasicValue) f.getStack(i);
        if (!isOmitted(v)) {
            if (!isNullType(v)) {
                int slotIdx = fi.stackSlotIndices[i];
                assert slotIdx >= 0 && slotIdx < fi.numSlots;
                emitStoreValue(mv, v, lvarStack, slotIdx, -1);
            } else {
                db.log(LogLevel.DEBUG, "NULL stack entry: type=%s size=%d", v.getType(), v.getSize());
                mv.visitInsn(Opcodes.POP);
            }
        }
    }

    // store local vars
    for (int i = firstLocal; i < f.getLocals(); i++) {
        BasicValue v = (BasicValue) f.getLocal(i);
        if (!isNullType(v)) {
            mv.visitVarInsn(v.getType().getOpcode(Opcodes.ILOAD), i);
            int slotIdx = fi.localSlotIndices[i];
            assert slotIdx >= 0 && slotIdx < fi.numSlots;
            emitStoreValue(mv, v, lvarStack, slotIdx, i);
        }
    }

    // restore last numArgsToPreserve operands
    for (int i = f.getStackSize() - numArgsToPreserve; i < f.getStackSize(); i++) {
        BasicValue v = (BasicValue) f.getStack(i);
        if (!isOmitted(v)) {
            if (!isNullType(v)) {
                int slotIdx = fi.stackSlotIndices[i];
                assert slotIdx >= 0 && slotIdx < fi.numSlots;
                emitRestoreValue(mv, v, lvarStack, slotIdx, -1);
            } else {
                mv.visitInsn(Opcodes.ACONST_NULL);
            }
        }
    }
}

From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java

License:Open Source License

private void emitRestoreState(MethodVisitor mv, int idx, FrameInfo fi, int numArgsPreserved) {
    Frame f = frames[fi.endInstruction];

    // restore local vars
    for (int i = firstLocal; i < f.getLocals(); i++) {
        BasicValue v = (BasicValue) f.getLocal(i);
        if (!isNullType(v)) {
            int slotIdx = fi.localSlotIndices[i];
            assert slotIdx >= 0 && slotIdx < fi.numSlots;
            emitRestoreValue(mv, v, lvarStack, slotIdx, i);
            mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), i);
        } else if (v != BasicValue.UNINITIALIZED_VALUE) {
            mv.visitInsn(Opcodes.ACONST_NULL);
            mv.visitVarInsn(Opcodes.ASTORE, i);
        }/*from  ww  w  .  ja  va2 s  .  c  o m*/
    }

    // restore operand stack
    for (int i = 0; i < f.getStackSize() - numArgsPreserved; i++) {
        BasicValue v = (BasicValue) f.getStack(i);
        if (!isOmitted(v)) {
            if (!isNullType(v)) {
                int slotIdx = fi.stackSlotIndices[i];
                assert slotIdx >= 0 && slotIdx < fi.numSlots;
                emitRestoreValue(mv, v, lvarStack, slotIdx, -1);
            } else {
                mv.visitInsn(Opcodes.ACONST_NULL);
            }
        }
    }

    if (fi.lAfter != null) {
        fi.lAfter.accept(mv);
    }
}

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.ja v  a2s .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("<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 .  ja va  2s .  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//ww w .  ja  v  a2  s .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.lint.checks.JavaScriptInterfaceDetector.java

License:Apache License

@Nullable
private String findFirstArgType(ClassContext context, ClassNode classNode, MethodNode method,
        MethodInsnNode call) {/*www.  j av a2s  . com*/
    // 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  w  w .ja va  2s . 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.ja v a 2 s  . c  o 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
    }
}