@Override
    public void sawOpcode(int seen) {
        Integer arraySize = null;
        String[] loadedTypes = null;

        try {
            stack.precomputation(this);

            switch (seen) {
                case Const.ANEWARRAY: {
                    if (Values.SLASHED_JAVA_LANG_CLASS.equals(getClassConstantOperand()) && (stack.getStackDepth() >= 1)) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        arraySize = (Integer) item.getConstant();
                    }
                }
                break;

                case Const.AASTORE: {
                    if (stack.getStackDepth() >= 3) {
                        OpcodeStack.Item arrayItem = stack.getStackItem(2);
                        String[] arrayTypes = (String[]) arrayItem.getUserValue();
                        if (arrayTypes != null) {
                            OpcodeStack.Item valueItem = stack.getStackItem(0);
                            String type = (String) valueItem.getConstant();
                            if (type != null) {
                                OpcodeStack.Item indexItem = stack.getStackItem(1);
                                Integer index = (Integer) indexItem.getConstant();
                                if (index != null) {
                                    arrayTypes[index.intValue()] = type;
                                }
                            }
                        }
                    }
                }
                break;

                case Const.PUTFIELD:
                case Const.PUTSTATIC: {
                    String name = getNameConstantOperand();
                    if (stack.getStackDepth() >= 1) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        String[] arrayTypes = (String[]) item.getUserValue();
                        if (arrayTypes != null) {
                            fieldClassTypes.put(name, arrayTypes);
                            return;
                        }
                    }
                    fieldClassTypes.remove(name);
                }
                break;

                case Const.GETFIELD:
                case Const.GETSTATIC: {
                    String name = getNameConstantOperand();
                    loadedTypes = fieldClassTypes.get(name);
                }
                break;

                case Const.ASTORE_0:
                case Const.ASTORE_1:
                case Const.ASTORE_2:
                case Const.ASTORE_3:
                case Const.ASTORE: {
                    Integer reg = Integer.valueOf(RegisterUtils.getAStoreReg(this, seen));
                    if (stack.getStackDepth() >= 1) {
                        OpcodeStack.Item item = stack.getStackItem(0);
                        String[] arrayTypes = (String[]) item.getUserValue();
                        if (arrayTypes != null) {
                            localClassTypes.put(reg, arrayTypes);
                            return;
                        }
                    }
                    localClassTypes.remove(reg);
                }
                break;

                case Const.ALOAD_0:
                case Const.ALOAD_1:
                case Const.ALOAD_2:
                case Const.ALOAD_3:
                case Const.ALOAD: {
                    int reg = RegisterUtils.getAStoreReg(this, seen);
                    loadedTypes = localClassTypes.get(Integer.valueOf(reg));
                }
                break;

                case Const.INVOKEVIRTUAL: {
                    String cls = getClassConstantOperand();
                    if (Values.SLASHED_JAVA_LANG_CLASS.equals(cls)) {
                        String method = getNameConstantOperand();
                        if ("getMethod".equals(method)) {
                            String sig = getSigConstantOperand();
                            if (SIG_STRING_AND_CLASS_ARRAY_TO_METHOD.equals(sig) && (stack.getStackDepth() >= 2)) {
                                OpcodeStack.Item clsArgs = stack.getStackItem(0);
                                String[] arrayTypes = (String[]) clsArgs.getUserValue();
                                if ((arrayTypes != null) || clsArgs.isNull()) {
                                    OpcodeStack.Item methodItem = stack.getStackItem(1);
                                    String methodName = (String) methodItem.getConstant();
                                    if (methodName != null) {
                                        String reflectionSig = sigWithoutReturn.withMethodName(methodName).withParamTypes(arrayTypes).build();
                                        if (objectSigs.contains(reflectionSig)) {
                                            loadedTypes = (arrayTypes == null) ? new String[0] : arrayTypes;
                                        }
                                    }
                                }
                            }
                        }
                    } else if ("java/lang/reflect/Method".equals(cls)) {
                        String method = getNameConstantOperand();
                        if ("invoke".equals(method) && (stack.getStackDepth() >= 3)) {
                            OpcodeStack.Item methodItem = stack.getStackItem(2);
                            String[] arrayTypes = (String[]) methodItem.getUserValue();
                            if (arrayTypes != null) {
                                bugReporter.reportBug(new BugInstance(this, BugType.ROOM_REFLECTION_ON_OBJECT_METHODS.name(), NORMAL_PRIORITY).addClass(this)
                                        .addMethod(this).addSourceLine(this));
                            }
                        }
                    }
                }
                break;

                default:
                break;
            }
        } finally {
            TernaryPatcher.pre(stack, seen);
            stack.sawOpcode(this, seen);
            TernaryPatcher.post(stack, seen);

            if (stack.getStackDepth() >= 1) {
                if (arraySize != null) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    item.setUserValue(new String[arraySize.intValue()]);
                } else if (loadedTypes != null) {
                    OpcodeStack.Item item = stack.getStackItem(0);
                    item.setUserValue(loadedTypes);
                }
            }
        }
    }
@ Override public void sawOpcode ( int seen ) { Integer arraySize = null ; String [ ] loadedTypes = null ; try { stack . precomputation ( this ) ; switch ( seen ) { case Const . ANEWARRAY : { if ( Values . SLASHED_JAVA_LANG_CLASS . equals ( getClassConstantOperand ( ) ) && ( stack . getStackDepth ( ) >= 1 ) ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; arraySize = ( Integer ) item . getConstant ( ) ; } } break ; case Const . AASTORE : { if ( stack . getStackDepth ( ) >= 3 ) { OpcodeStack . Item arrayItem = stack . getStackItem ( 2 ) ; String [ ] arrayTypes = ( String [ ] ) arrayItem . getUserValue ( ) ; if ( arrayTypes != null ) { OpcodeStack . Item valueItem = stack . getStackItem ( 0 ) ; String type = ( String ) valueItem . getConstant ( ) ; if ( type != null ) { OpcodeStack . Item indexItem = stack . getStackItem ( 1 ) ; Integer index = ( Integer ) indexItem . getConstant ( ) ; if ( index != null ) { arrayTypes [ index . intValue ( ) ] = type ; } } } } } break ; case Const . PUTFIELD : case Const . PUTSTATIC : { String name = getNameConstantOperand ( ) ; if ( stack . getStackDepth ( ) >= 1 ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; String [ ] arrayTypes = ( String [ ] ) item . getUserValue ( ) ; if ( arrayTypes != null ) { fieldClassTypes . put ( name , arrayTypes ) ; return ; } } fieldClassTypes . remove ( name ) ; } break ; case Const . GETFIELD : case Const . GETSTATIC : { String name = getNameConstantOperand ( ) ; loadedTypes = fieldClassTypes . get ( name ) ; } break ; case Const . ASTORE_0 : case Const . ASTORE_1 : case Const . ASTORE_2 : case Const . ASTORE_3 : case Const . ASTORE : { Integer reg = Integer . valueOf ( RegisterUtils . getAStoreReg ( this , seen ) ) ; if ( stack . getStackDepth ( ) >= 1 ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; String [ ] arrayTypes = ( String [ ] ) item . getUserValue ( ) ; if ( arrayTypes != null ) { localClassTypes . put ( reg , arrayTypes ) ; return ; } } localClassTypes . remove ( reg ) ; } break ; case Const . ALOAD_0 : case Const . ALOAD_1 : case Const . ALOAD_2 : case Const . ALOAD_3 : case Const . ALOAD : { int reg = RegisterUtils . getAStoreReg ( this , seen ) ; loadedTypes = localClassTypes . get ( Integer . valueOf ( reg ) ) ; } break ; case Const . INVOKEVIRTUAL : { String cls = getClassConstantOperand ( ) ; if ( Values . SLASHED_JAVA_LANG_CLASS . equals ( cls ) ) { String method = getNameConstantOperand ( ) ; if ( "getMethod" . equals ( method ) ) { String sig = getSigConstantOperand ( ) ; if ( SIG_STRING_AND_CLASS_ARRAY_TO_METHOD . equals ( sig ) && ( stack . getStackDepth ( ) >= 2 ) ) { OpcodeStack . Item clsArgs = stack . getStackItem ( 0 ) ; String [ ] arrayTypes = ( String [ ] ) clsArgs . getUserValue ( ) ; if ( ( arrayTypes != null ) || clsArgs . isNull ( ) ) { OpcodeStack . Item methodItem = stack . getStackItem ( 1 ) ; String methodName = ( String ) methodItem . getConstant ( ) ; if ( methodName != null ) { String reflectionSig = sigWithoutReturn . withMethodName ( methodName ) . withParamTypes ( arrayTypes ) . build ( ) ; if ( objectSigs . contains ( reflectionSig ) ) { loadedTypes = ( arrayTypes == null ) ? new String [ 0 ] : arrayTypes ; } } } } } } else if ( "java/lang/reflect/Method" . equals ( cls ) ) { String method = getNameConstantOperand ( ) ; if ( "invoke" . equals ( method ) && ( stack . getStackDepth ( ) >= 3 ) ) { OpcodeStack . Item methodItem = stack . getStackItem ( 2 ) ; String [ ] arrayTypes = ( String [ ] ) methodItem . getUserValue ( ) ; if ( arrayTypes != null ) { bugReporter . reportBug ( new BugInstance ( this , BugType . ROOM_REFLECTION_ON_OBJECT_METHODS . name ( ) , NORMAL_PRIORITY ) . addClass ( this ) . addMethod ( this ) . addSourceLine ( this ) ) ; } } } } break ; default : break ; } } finally { TernaryPatcher . pre ( stack , seen ) ; stack . sawOpcode ( this , seen ) ; TernaryPatcher . post ( stack , seen ) ; if ( stack . getStackDepth ( ) >= 1 ) { if ( arraySize != null ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; item . setUserValue ( new String [ arraySize . intValue ( ) ] ) ; } else if ( loadedTypes != null ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; item . setUserValue ( loadedTypes ) ; } } } }
implements the visitor to look for calls that invoke a method through reflection where the method is defined in java.lang.Object

@param seen
the currently parsed opcode