List of usage examples for org.objectweb.asm Opcodes INVOKESTATIC
int INVOKESTATIC
To view the source code for org.objectweb.asm Opcodes INVOKESTATIC.
Click Source Link
From source file:com.android.tools.layoutlib.create.DelegateMethodAdapter.java
License:Apache License
/** * Generates the new code for the method. * <p/>/*www . j av a 2s .c o m*/ * For native methods, this must be invoked directly by {@link DelegateClassAdapter} * (since they have no code to visit). * <p/> * Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to * return this instance of {@link DelegateMethodAdapter} and let the normal visitor pattern * invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then * this method will be invoked from {@link MethodVisitor#visitEnd()}. */ public void generateCode() { /* * The goal is to generate a call to a static delegate method. * If this method is non-static, the first parameter will be 'this'. * All the parameters must be passed and then the eventual return type returned. * * Example, let's say we have a method such as * public void method_1(int a, Object b, ArrayList<String> c) { ... } * * We'll want to create a body that calls a delegate method like this: * TheClass_Delegate.method_1(this, a, b, c); * * If the method is non-static and the class name is an inner class (e.g. has $ in its * last segment), we want to push the 'this' of the outer class first: * OuterClass_InnerClass_Delegate.method_1( * OuterClass.this, * OuterClass$InnerClass.this, * a, b, c); * * Only one level of inner class is supported right now, for simplicity and because * we don't need more. * * The generated class name is the current class name with "_Delegate" appended to it. * One thing to realize is that we don't care about generics -- since generic types * are erased at runtime, they have no influence on the method name being called. */ // Add our annotation AnnotationVisitor aw = mParentVisitor.visitAnnotation( Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(), true); // visible at runtime aw.visitEnd(); if (!mVisitCodeCalled) { // If this is a direct call to generateCode() as done by DelegateClassAdapter // for natives, visitCode() hasn't been called yet. mParentVisitor.visitCode(); mVisitCodeCalled = true; } ArrayList<Type> paramTypes = new ArrayList<Type>(); String delegateClassName = mClassName + DELEGATE_SUFFIX; boolean pushedArg0 = false; int maxStack = 0; // For an instance method (e.g. non-static), push the 'this' preceded // by the 'this' of any outer class, if any. if (!mIsStatic) { // Check if the last segment of the class name has inner an class. // Right now we only support one level of inner classes. int slash = mClassName.lastIndexOf('/'); int dol = mClassName.lastIndexOf('$'); if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) { String outerClass = mClassName.substring(0, dol); Type outerType = Type.getObjectType(outerClass); // Change a delegate class name to "com/foo/Outer_Inner_Delegate" delegateClassName = delegateClassName.replace('$', '_'); // The first-level inner class has a package-protected member called 'this$0' // that points to the outer class. // Push this.getField("this$0") on the call stack. mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0); // var 0 = this mParentVisitor.visitFieldInsn(Opcodes.GETFIELD, mClassName, // class where the field is defined "this$0", // field name outerType.getDescriptor()); // type of the field maxStack++; paramTypes.add(outerType); } // Push "this" for the instance method, which is always ALOAD 0 mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0); maxStack++; pushedArg0 = true; paramTypes.add(Type.getObjectType(mClassName)); } // Push all other arguments. Start at arg 1 if we already pushed 'this' above. Type[] argTypes = Type.getArgumentTypes(mDesc); int maxLocals = pushedArg0 ? 1 : 0; for (Type t : argTypes) { int size = t.getSize(); mParentVisitor.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals); maxLocals += size; maxStack += size; paramTypes.add(t); } // Construct the descriptor of the delegate based on the parameters // we pushed on the call stack. The return type remains unchanged. String desc = Type.getMethodDescriptor(Type.getReturnType(mDesc), paramTypes.toArray(new Type[paramTypes.size()])); // Invoke the static delegate mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, mMethodName, desc); Type returnType = Type.getReturnType(mDesc); mParentVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); mParentVisitor.visitMaxs(maxStack, maxLocals); mParentVisitor.visitEnd(); // For debugging now. Maybe we should collect these and store them in // a text file for helping create the delegates. We could also compare // the text file to a golden and break the build on unsupported changes // or regressions. Even better we could fancy-print something that looks // like the expected Java method declaration. mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc); }
From source file:com.android.tools.layoutlib.create.DelegateMethodAdapter2.java
License:Apache License
/** * Generates the new code for the method. * <p/>/* w ww .j av a 2 s . c om*/ * For native methods, this must be invoked directly by {@link DelegateClassAdapter} * (since they have no code to visit). * <p/> * Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to * return this instance of {@link DelegateMethodAdapter2} and let the normal visitor pattern * invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then * this method will be invoked from {@link MethodVisitor#visitEnd()}. */ public void generateDelegateCode() { /* * The goal is to generate a call to a static delegate method. * If this method is non-static, the first parameter will be 'this'. * All the parameters must be passed and then the eventual return type returned. * * Example, let's say we have a method such as * public void myMethod(int a, Object b, ArrayList<String> c) { ... } * * We'll want to create a body that calls a delegate method like this: * TheClass_Delegate.myMethod(this, a, b, c); * * If the method is non-static and the class name is an inner class (e.g. has $ in its * last segment), we want to push the 'this' of the outer class first: * OuterClass_InnerClass_Delegate.myMethod( * OuterClass.this, * OuterClass$InnerClass.this, * a, b, c); * * Only one level of inner class is supported right now, for simplicity and because * we don't need more. * * The generated class name is the current class name with "_Delegate" appended to it. * One thing to realize is that we don't care about generics -- since generic types * are erased at build time, they have no influence on the method name being called. */ // Add our annotation AnnotationVisitor aw = mDelWriter.visitAnnotation( Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(), true); // visible at runtime if (aw != null) { aw.visitEnd(); } mDelWriter.visitCode(); if (mDelegateLineNumber != null) { Object[] p = mDelegateLineNumber; mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]); } ArrayList<Type> paramTypes = new ArrayList<Type>(); String delegateClassName = mClassName + DELEGATE_SUFFIX; boolean pushedArg0 = false; int maxStack = 0; // Check if the last segment of the class name has inner an class. // Right now we only support one level of inner classes. Type outerType = null; int slash = mClassName.lastIndexOf('/'); int dol = mClassName.lastIndexOf('$'); if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) { String outerClass = mClassName.substring(0, dol); outerType = Type.getObjectType(outerClass); // Change a delegate class name to "com/foo/Outer_Inner_Delegate" delegateClassName = delegateClassName.replace('$', '_'); } // For an instance method (e.g. non-static), push the 'this' preceded // by the 'this' of any outer class, if any. if (!mIsStatic) { if (outerType != null) { // The first-level inner class has a package-protected member called 'this$0' // that points to the outer class. // Push this.getField("this$0") on the call stack. mDelWriter.visitVarInsn(Opcodes.ALOAD, 0); // var 0 = this mDelWriter.visitFieldInsn(Opcodes.GETFIELD, mClassName, // class where the field is defined "this$0", // field name outerType.getDescriptor()); // type of the field maxStack++; paramTypes.add(outerType); } // Push "this" for the instance method, which is always ALOAD 0 mDelWriter.visitVarInsn(Opcodes.ALOAD, 0); maxStack++; pushedArg0 = true; paramTypes.add(Type.getObjectType(mClassName)); } // Push all other arguments. Start at arg 1 if we already pushed 'this' above. Type[] argTypes = Type.getArgumentTypes(mDesc); int maxLocals = pushedArg0 ? 1 : 0; for (Type t : argTypes) { int size = t.getSize(); mDelWriter.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals); maxLocals += size; maxStack += size; paramTypes.add(t); } // Construct the descriptor of the delegate based on the parameters // we pushed on the call stack. The return type remains unchanged. String desc = Type.getMethodDescriptor(Type.getReturnType(mDesc), paramTypes.toArray(new Type[paramTypes.size()])); // Invoke the static delegate mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, mMethodName, desc); Type returnType = Type.getReturnType(mDesc); mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); mDelWriter.visitMaxs(maxStack, maxLocals); mDelWriter.visitEnd(); // For debugging now. Maybe we should collect these and store them in // a text file for helping create the delegates. We could also compare // the text file to a golden and break the build on unsupported changes // or regressions. Even better we could fancy-print something that looks // like the expected Java method declaration. mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc); }
From source file:com.android.tools.layoutlib.create.StubMethodAdapter.java
License:Apache License
private void generateInvoke() { /* Generates the code: * OverrideMethod.invoke("signature", mIsNative ? true : false, null or this); *///from w w w . java 2s .c om mParentVisitor.visitLdcInsn(mInvokeSignature); // push true or false mParentVisitor.visitInsn(mIsNative ? Opcodes.ICONST_1 : Opcodes.ICONST_0); // push null or this if (mIsStatic) { mParentVisitor.visitInsn(Opcodes.ACONST_NULL); } else { mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0); } int sort = mReturnType != null ? mReturnType.getSort() : Type.VOID; switch (sort) { case Type.VOID: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeV", "(Ljava/lang/String;ZLjava/lang/Object;)V"); mParentVisitor.visitInsn(Opcodes.RETURN); break; case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeI", "(Ljava/lang/String;ZLjava/lang/Object;)I"); switch (sort) { case Type.BOOLEAN: Label l1 = new Label(); mParentVisitor.visitJumpInsn(Opcodes.IFEQ, l1); mParentVisitor.visitInsn(Opcodes.ICONST_1); mParentVisitor.visitInsn(Opcodes.IRETURN); mParentVisitor.visitLabel(l1); mParentVisitor.visitInsn(Opcodes.ICONST_0); break; case Type.CHAR: mParentVisitor.visitInsn(Opcodes.I2C); break; case Type.BYTE: mParentVisitor.visitInsn(Opcodes.I2B); break; case Type.SHORT: mParentVisitor.visitInsn(Opcodes.I2S); break; } mParentVisitor.visitInsn(Opcodes.IRETURN); break; case Type.LONG: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeL", "(Ljava/lang/String;ZLjava/lang/Object;)J"); mParentVisitor.visitInsn(Opcodes.LRETURN); break; case Type.FLOAT: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeF", "(Ljava/lang/String;ZLjava/lang/Object;)F"); mParentVisitor.visitInsn(Opcodes.FRETURN); break; case Type.DOUBLE: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeD", "(Ljava/lang/String;ZLjava/lang/Object;)D"); mParentVisitor.visitInsn(Opcodes.DRETURN); break; case Type.ARRAY: case Type.OBJECT: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeA", "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;"); mParentVisitor.visitTypeInsn(Opcodes.CHECKCAST, mReturnType.getInternalName()); mParentVisitor.visitInsn(Opcodes.ARETURN); break; } }
From source file:com.android.tools.lint.checks.ApiDetector.java
License:Apache License
@SuppressWarnings("rawtypes") // ASM API @Override/*from ww w . j a va2 s. c o m*/ public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) { if (mApiDatabase == null) { return; } if (AOSP_BUILD && classNode.name.startsWith("android/support/")) { //$NON-NLS-1$ return; } // Requires util package (add prebuilts/tools/common/asm-tools/asm-debug-all-4.0.jar) //classNode.accept(new TraceClassVisitor(new PrintWriter(System.out))); int classMinSdk = getClassMinSdk(context, classNode); if (classMinSdk == -1) { classMinSdk = getMinSdk(context); } List methodList = classNode.methods; if (methodList.isEmpty()) { return; } boolean checkCalls = context.isEnabled(UNSUPPORTED) || context.isEnabled(INLINED); boolean checkMethods = context.isEnabled(OVERRIDE) && context.getMainProject().getBuildSdk() >= 1; String frameworkParent = null; if (checkMethods) { LintDriver driver = context.getDriver(); String owner = classNode.superName; while (owner != null) { // For virtual dispatch, walk up the inheritance chain checking // each inherited method if ((owner.startsWith("android/") //$NON-NLS-1$ && !owner.startsWith("android/support/")) //$NON-NLS-1$ || owner.startsWith("java/") //$NON-NLS-1$ || owner.startsWith("javax/")) { //$NON-NLS-1$ frameworkParent = owner; break; } owner = driver.getSuperClass(owner); } if (frameworkParent == null) { checkMethods = false; } } if (checkCalls) { // Check implements/extends if (classNode.superName != null) { String signature = classNode.superName; checkExtendsClass(context, classNode, classMinSdk, signature); } if (classNode.interfaces != null) { @SuppressWarnings("unchecked") // ASM API List<String> interfaceList = classNode.interfaces; for (String signature : interfaceList) { checkExtendsClass(context, classNode, classMinSdk, signature); } } } for (Object m : methodList) { MethodNode method = (MethodNode) m; int minSdk = getLocalMinSdk(method.invisibleAnnotations); if (minSdk == -1) { minSdk = classMinSdk; } InsnList nodes = method.instructions; if (checkMethods && Character.isJavaIdentifierStart(method.name.charAt(0))) { int buildSdk = context.getMainProject().getBuildSdk(); String name = method.name; assert frameworkParent != null; int api = mApiDatabase.getCallVersion(frameworkParent, name, method.desc); if (api > buildSdk && buildSdk != -1) { // TODO: Don't complain if it's annotated with @Override; that means // somehow the build target isn't correct. String fqcn; String owner = classNode.name; if (CONSTRUCTOR_NAME.equals(name)) { fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$ } else { fqcn = ClassContext.getFqcn(owner) + '#' + name; } String message = String.format( "This method is not overriding anything with the current build " + "target, but will in API level %1$d (current target is %2$d): %3$s", api, buildSdk, fqcn); Location location = context.getLocation(method, classNode); context.report(OVERRIDE, method, null, location, message, null); } } if (!checkCalls) { continue; } if (CHECK_DECLARATIONS) { // Check types in parameter list and types of local variables List localVariables = method.localVariables; if (localVariables != null) { for (Object v : localVariables) { LocalVariableNode var = (LocalVariableNode) v; String desc = var.desc; if (desc.charAt(0) == 'L') { // "Lpackage/Class;" => "package/Bar" String className = desc.substring(1, desc.length() - 1); int api = mApiDatabase.getClassVersion(className); if (api > minSdk) { String fqcn = ClassContext.getFqcn(className); String message = String.format( "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn); report(context, message, var.start, method, className.substring(className.lastIndexOf('/') + 1), null, SearchHints.create(NEAREST).matchJavaSymbol()); } } } } // Check return type // The parameter types are already handled as local variables so we can skip // right to the return type. // Check types in parameter list String signature = method.desc; if (signature != null) { int args = signature.indexOf(')'); if (args != -1 && signature.charAt(args + 1) == 'L') { String type = signature.substring(args + 2, signature.length() - 1); int api = mApiDatabase.getClassVersion(type); if (api > minSdk) { String fqcn = ClassContext.getFqcn(type); String message = String.format( "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn); AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null; report(context, message, first, method, method.name, null, SearchHints.create(BACKWARD).matchJavaSymbol()); } } } } for (int i = 0, n = nodes.size(); i < n; i++) { AbstractInsnNode instruction = nodes.get(i); int type = instruction.getType(); if (type == AbstractInsnNode.METHOD_INSN) { MethodInsnNode node = (MethodInsnNode) instruction; String name = node.name; String owner = node.owner; String desc = node.desc; // No need to check methods in this local class; we know they // won't be an API match if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) { owner = classNode.superName; } boolean checkingSuperClass = false; while (owner != null) { int api = mApiDatabase.getCallVersion(owner, name, desc); if (api > minSdk) { if (method.name.startsWith(SWITCH_TABLE_PREFIX)) { // We're in a compiler-generated method to generate an // array indexed by enum ordinal values to enum values. The enum // itself must be requiring a higher API number than is // currently used, but the call site for the switch statement // will also be referencing it, so no need to report these // calls. break; } if (!checkingSuperClass && node.getOpcode() == Opcodes.INVOKEVIRTUAL && methodDefinedLocally(classNode, name, desc)) { break; } String fqcn; if (CONSTRUCTOR_NAME.equals(name)) { fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$ } else { fqcn = ClassContext.getFqcn(owner) + '#' + name; } String message = String.format( "Call requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn); if (name.equals(ORDINAL_METHOD) && instruction.getNext() != null && instruction.getNext().getNext() != null && instruction.getNext().getOpcode() == Opcodes.IALOAD && instruction.getNext().getNext().getOpcode() == Opcodes.TABLESWITCH) { message = String.format( "Enum for switch requires API level %1$d " + "(current min is %2$d): %3$s", api, minSdk, ClassContext.getFqcn(owner)); } report(context, message, node, method, name, null, SearchHints.create(FORWARD).matchJavaSymbol()); } // For virtual dispatch, walk up the inheritance chain checking // each inherited method if (owner.startsWith("android/") //$NON-NLS-1$ || owner.startsWith("javax/")) { //$NON-NLS-1$ // The API map has already inlined all inherited methods // so no need to keep checking up the chain // -- unless it's the support library which is also in // the android/ namespace: if (owner.startsWith("android/support/")) { //$NON-NLS-1$ owner = context.getDriver().getSuperClass(owner); } else { owner = null; } } else if (owner.startsWith("java/")) { //$NON-NLS-1$ if (owner.equals(LocaleDetector.DATE_FORMAT_OWNER)) { checkSimpleDateFormat(context, method, node, minSdk); } // Already inlined; see comment above owner = null; } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) { owner = context.getDriver().getSuperClass(owner); } else if (node.getOpcode() == Opcodes.INVOKESTATIC && api == -1) { // Inherit through static classes as well owner = context.getDriver().getSuperClass(owner); } else { owner = null; } checkingSuperClass = true; } } else if (type == AbstractInsnNode.FIELD_INSN) { FieldInsnNode node = (FieldInsnNode) instruction; String name = node.name; String owner = node.owner; int api = mApiDatabase.getFieldVersion(owner, name); if (api > minSdk) { if (method.name.startsWith(SWITCH_TABLE_PREFIX)) { checkSwitchBlock(context, classNode, node, method, name, owner, api, minSdk); continue; } String fqcn = ClassContext.getFqcn(owner) + '#' + name; if (mPendingFields != null) { mPendingFields.remove(fqcn); } String message = String.format("Field requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn); report(context, message, node, method, name, null, SearchHints.create(FORWARD).matchJavaSymbol()); } } else if (type == AbstractInsnNode.LDC_INSN) { LdcInsnNode node = (LdcInsnNode) instruction; if (node.cst instanceof Type) { Type t = (Type) node.cst; String className = t.getInternalName(); int api = mApiDatabase.getClassVersion(className); if (api > minSdk) { String fqcn = ClassContext.getFqcn(className); String message = String.format( "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn); report(context, message, node, method, className.substring(className.lastIndexOf('/') + 1), null, SearchHints.create(FORWARD).matchJavaSymbol()); } } } } } }
From source file:com.android.tools.lint.checks.ApiDetector.java
License:Apache License
@SuppressWarnings("rawtypes") // ASM API private static void checkSwitchBlock(ClassContext context, ClassNode classNode, FieldInsnNode field, MethodNode method, String name, String owner, int api, int minSdk) { // Switch statements on enums are tricky. The compiler will generate a method // which returns an array of the enum constants, indexed by their ordinal() values. // However, we only want to complain if the code is actually referencing one of // the non-available enum fields. ////from w ww .ja v a2 s . c om // For the android.graphics.PorterDuff.Mode enum for example, the first few items // in the array are populated like this: // // L0 // ALOAD 0 // GETSTATIC android/graphics/PorterDuff$Mode.ADD : Landroid/graphics/PorterDuff$Mode; // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I // ICONST_1 // IASTORE // L1 // GOTO L3 // L2 // FRAME FULL [[I] [java/lang/NoSuchFieldError] // POP // L3 // FRAME SAME // ALOAD 0 // GETSTATIC android/graphics/PorterDuff$Mode.CLEAR : Landroid/graphics/PorterDuff$Mode; // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I // ICONST_2 // IASTORE // ... // So if we for example find that the "ADD" field isn't accessible, since it requires // API 11, we need to // (1) First find out what its ordinal number is. We can look at the following // instructions to discover this; it's the "ICONST_1" and "IASTORE" instructions. // (After ICONST_5 it moves on to BIPUSH 6, BIPUSH 7, etc.) // (2) Find the corresponding *usage* of this switch method. For the above enum, // the switch ordinal lookup method will be called // "$SWITCH_TABLE$android$graphics$PorterDuff$Mode" with desc "()[I". // This means we will be looking for an invocation in some other method which looks // like this: // INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I // (obviously, it can be invoked more than once) // Note that it can be used more than once in this class and all sites should be // checked! // (3) Look up the corresponding table switch, which should look something like this: // INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I // ALOAD 0 // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I // IALOAD // LOOKUPSWITCH // 2: L1 // 11: L2 // default: L3 // Here we need to see if the LOOKUPSWITCH instruction is referencing our target // case. Above we were looking for the "ADD" case which had ordinal 1. Since this // isn't explicitly referenced, we can ignore this field reference. AbstractInsnNode next = field.getNext(); if (next == null || next.getOpcode() != Opcodes.INVOKEVIRTUAL) { return; } next = next.getNext(); if (next == null) { return; } int ordinal; switch (next.getOpcode()) { case Opcodes.ICONST_0: ordinal = 0; break; case Opcodes.ICONST_1: ordinal = 1; break; case Opcodes.ICONST_2: ordinal = 2; break; case Opcodes.ICONST_3: ordinal = 3; break; case Opcodes.ICONST_4: ordinal = 4; break; case Opcodes.ICONST_5: ordinal = 5; break; case Opcodes.BIPUSH: { IntInsnNode iin = (IntInsnNode) next; ordinal = iin.operand; break; } default: return; } // Find usages of this call site List methodList = classNode.methods; for (Object m : methodList) { InsnList nodes = ((MethodNode) m).instructions; for (int i = 0, n = nodes.size(); i < n; i++) { AbstractInsnNode instruction = nodes.get(i); if (instruction.getOpcode() != Opcodes.INVOKESTATIC) { continue; } MethodInsnNode node = (MethodInsnNode) instruction; if (node.name.equals(method.name) && node.desc.equals(method.desc) && node.owner.equals(classNode.name)) { // Find lookup switch AbstractInsnNode target = getNextInstruction(node); while (target != null) { if (target.getOpcode() == Opcodes.LOOKUPSWITCH) { LookupSwitchInsnNode lookup = (LookupSwitchInsnNode) target; @SuppressWarnings("unchecked") // ASM API List<Integer> keys = lookup.keys; if (keys != null && keys.contains(ordinal)) { String fqcn = ClassContext.getFqcn(owner) + '#' + name; String message = String.format( "Enum value requires API level %1$d " + "(current min is %2$d): %3$s", api, minSdk, fqcn); report(context, message, lookup, (MethodNode) m, name, null, SearchHints.create(FORWARD).matchJavaSymbol()); // Break out of the inner target search only; the switch // statement could be used in other places in this class as // well and we want to report all problematic usages. break; } } target = getNextInstruction(target); } } } } }
From source file:com.android.tools.lint.checks.InvalidPackageDetector.java
License:Apache License
@SuppressWarnings("rawtypes") // ASM API @Override// w w w . j a v a 2 s.co m public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) { if (!context.isFromClassLibrary() || shouldSkip(context.file)) { return; } if (mApiDatabase == null) { return; } if (classNode.name.startsWith(JAVAX_PKG_PREFIX)) { mJavaxLibraryClasses.add(classNode.name); } List methodList = classNode.methods; for (Object m : methodList) { MethodNode method = (MethodNode) m; InsnList nodes = method.instructions; // Check return type // The parameter types are already handled as local variables so we can skip // right to the return type. // Check types in parameter list String signature = method.desc; if (signature != null) { int args = signature.indexOf(')'); if (args != -1 && signature.charAt(args + 1) == 'L') { String type = signature.substring(args + 2, signature.length() - 1); if (isInvalidPackage(type)) { AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null; record(context, method, first, type); } } } for (int i = 0, n = nodes.size(); i < n; i++) { AbstractInsnNode instruction = nodes.get(i); int type = instruction.getType(); if (type == AbstractInsnNode.METHOD_INSN) { MethodInsnNode node = (MethodInsnNode) instruction; String owner = node.owner; // No need to check methods in this local class; we know they // won't be an API match if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) { owner = classNode.superName; } while (owner != null) { if (isInvalidPackage(owner)) { record(context, method, instruction, owner); } // For virtual dispatch, walk up the inheritance chain checking // each inherited method if (owner.startsWith("android/") //$NON-NLS-1$ || owner.startsWith(JAVA_PKG_PREFIX) || owner.startsWith(JAVAX_PKG_PREFIX)) { owner = null; } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) { owner = context.getDriver().getSuperClass(owner); } else if (node.getOpcode() == Opcodes.INVOKESTATIC) { // Inherit through static classes as well owner = context.getDriver().getSuperClass(owner); } else { owner = null; } } } else if (type == AbstractInsnNode.FIELD_INSN) { FieldInsnNode node = (FieldInsnNode) instruction; String owner = node.owner; if (isInvalidPackage(owner)) { record(context, method, instruction, owner); } } else if (type == AbstractInsnNode.LDC_INSN) { LdcInsnNode node = (LdcInsnNode) instruction; if (node.cst instanceof Type) { Type t = (Type) node.cst; String className = t.getInternalName(); if (isInvalidPackage(className)) { record(context, method, instruction, className); } } } } } }
From source file:com.android.tools.lint.checks.SecureRandomDetector.java
License:Apache License
private static void checkValidSetSeed(ClassContext context, MethodInsnNode call) { assert call.name.equals(SET_SEED); // Make sure the argument passed is not a literal AbstractInsnNode prev = LintUtils.getPrevInstruction(call); if (prev == null) { return;/*from www .j a v a 2 s. c o m*/ } int opcode = prev.getOpcode(); if (opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 || opcode == Opcodes.LDC) { context.report(ISSUE, context.getLocation(call), "Do not call setSeed() on a SecureRandom with a fixed seed: " + "it is not secure. Use getSeed().", null); } else if (opcode == Opcodes.INVOKESTATIC) { String methodName = ((MethodInsnNode) prev).name; if (methodName.equals("currentTimeMillis") || methodName.equals("nanoTime")) { context.report(ISSUE, context.getLocation(call), "It is dangerous to seed SecureRandom with the current time because " + "that value is more predictable to an attacker than the default seed.", null); } } }
From source file:com.android.tools.lint.checks.SecureRandomGeneratorDetector.java
License:Apache License
@Override public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) {//from w w w . j av a2s .co m if (mIgnore) { return; } String owner = call.owner; String name = call.name; // Look for the workaround code: if we see a Class.forName on the harmony NativeCrypto, // we'll consider that a sign. if (name.equals(FOR_NAME)) { if (call.getOpcode() != Opcodes.INVOKESTATIC || !owner.equals(JAVA_LANG_CLASS)) { return; } AbstractInsnNode prev = LintUtils.getPrevInstruction(call); if (prev instanceof LdcInsnNode) { Object cst = ((LdcInsnNode) prev).cst; //noinspection SpellCheckingInspection if (cst instanceof String && "org.apache.harmony.xnet.provider.jsse.NativeCrypto".equals(cst)) { mIgnore = true; } } return; } // Look for calls that probably require a properly initialized random number generator. assert owner.equals(JAVAX_CRYPTO_KEY_GENERATOR) || owner.equals(JAVA_SECURITY_KEY_PAIR_GENERATOR) || owner.equals(JAVAX_CRYPTO_KEY_AGREEMENT) || owner.equals(OWNER_SECURE_RANDOM) || owner.equals(JAVAX_CRYPTO_CIPHER) || owner.equals(JAVAX_CRYPTO_SIGNATURE) || owner.equals(JAVAX_NET_SSL_SSLENGINE) : owner; boolean warn = false; if (owner.equals(JAVAX_CRYPTO_SIGNATURE)) { warn = name.equals(INIT_SIGN); } else if (owner.equals(JAVAX_CRYPTO_CIPHER)) { if (name.equals(INIT)) { int arity = getDescArity(call.desc); AbstractInsnNode node = call; for (int i = 0; i < arity; i++) { node = LintUtils.getPrevInstruction(node); if (node == null) { break; } } if (node != null) { int opcode = node.getOpcode(); if (opcode == Opcodes.ICONST_3 || // Cipher.WRAP_MODE opcode == Opcodes.ICONST_1) { // Cipher.ENCRYPT_MODE warn = true; } } } } else if (name.equals(GET_INSTANCE) || name.equals(CONSTRUCTOR_NAME) || name.equals(WRAP) || name.equals(UNWRAP)) { // For SSLEngine warn = true; } if (warn) { if (mLocation != null) { return; } if (context.getMainProject().getMinSdk() > 18) { // Fix no longer needed mIgnore = true; return; } if (context.getDriver().isSuppressed(ISSUE, classNode, method, call)) { mIgnore = true; } else { mLocation = context.getLocation(call); } } }
From source file:com.asakusafw.dag.compiler.builtin.LoggingOperatorGenerator.java
License:Apache License
private ClassData generateClass(Context context, UserOperator operator, ClassDescription target) { String report = getReportName(context, operator); OperatorInput input = operator.getInput(Logging.ID_INPUT); OperatorOutput output = operator.getOutput(Logging.ID_OUTPUT); ClassWriter writer = newWriter(target, Object.class, Result.class); FieldRef impl = defineOperatorField(writer, operator, target); Map<OperatorProperty, FieldRef> map = defineConstructor(context, operator, target, writer, method -> { setOperatorField(method, operator, impl); });/*from w w w.j a va 2s. c o m*/ defineResultAdd(writer, method -> { cast(method, 1, input.getDataType()); List<ValueRef> arguments = new ArrayList<>(); arguments.add(impl); arguments.add(new LocalVarRef(Opcodes.ALOAD, 1)); appendSecondaryInputs(arguments::add, operator, map::get); appendArguments(arguments::add, operator, map::get); invoke(method, context, operator, arguments); method.visitMethodInsn(Opcodes.INVOKESTATIC, typeOf(Report.class).getInternalName(), report, Type.getMethodDescriptor(Type.VOID_TYPE, typeOf(String.class)), false); method.visitVarInsn(Opcodes.ALOAD, 0); getField(method, map.get(output)); method.visitVarInsn(Opcodes.ALOAD, 1); invokeResultAdd(method); }); return new ClassData(target, writer::toByteArray); }
From source file:com.asakusafw.dag.compiler.builtin.SummarizeOperatorGenerator.java
License:Apache License
private static void checkNull(MethodVisitor method, ClassDescription target, PropertyReference property, LocalVarRef variable, Set<PropertyReference> finished) { if (finished.contains(property)) { return;//from ww w.j a v a 2 s . c o m } finished.add(property); method.visitInsn(Opcodes.DUP); variable.load(method); getConst(method, property.getName().toName()); method.visitMethodInsn(Opcodes.INVOKESTATIC, typeOf(target).getInternalName(), METHOD_CHECK_NON_NULL, Type.getMethodDescriptor(Type.VOID_TYPE, typeOf(ValueOption.class), typeOf(Object.class), typeOf(String.class)), false); }