@ Override public void sawOpcode ( int seen ) { ImmutabilityType imType = null ; try { stack . precomputation ( this ) ; switch ( seen ) { case Const . INVOKESTATIC : case Const . INVOKEINTERFACE : case Const . INVOKESPECIAL : case Const . INVOKEVIRTUAL : { String className = getClassConstantOperand ( ) ; String methodName = getNameConstantOperand ( ) ; String signature = getSigConstantOperand ( ) ; MethodInfo mi = Statistics . getStatistics ( ) . getMethodStatistics ( className , methodName , signature ) ; imType = mi . getImmutabilityType ( ) ; if ( seen == Const . INVOKEINTERFACE ) { Integer collectionOffset = MODIFYING_METHODS . get ( new QMethod ( methodName , signature ) ) ; if ( ( collectionOffset != null ) && CollectionUtils . isListSetMap ( className ) && ( stack . getStackDepth ( ) > collectionOffset . intValue ( ) ) ) { OpcodeStack . Item item = stack . getStackItem ( collectionOffset . intValue ( ) ) ; ImmutabilityType type = ( ImmutabilityType ) item . getUserValue ( ) ; if ( ( type == ImmutabilityType . IMMUTABLE ) || ( ( type == ImmutabilityType . POSSIBLY_IMMUTABLE ) && ( reportedType != ImmutabilityType . POSSIBLY_IMMUTABLE ) ) ) { bugReporter . reportBug ( new BugInstance ( this , BugType . MUC_MODIFYING_UNMODIFIABLE_COLLECTION . name ( ) , ( type == ImmutabilityType . IMMUTABLE ) ? HIGH_PRIORITY : NORMAL_PRIORITY ) . addClass ( this ) . addMethod ( this ) . addSourceLine ( this ) ) ; if ( type == ImmutabilityType . IMMUTABLE ) { throw new StopOpcodeParsingException ( ) ; } reportedType = type ; } } } } break ; default : break ; } } catch ( ClassNotFoundException cnfe ) { bugReporter . reportMissingClass ( cnfe ) ; } finally { stack . sawOpcode ( this , seen ) ; if ( ( imType != null ) && ( stack . getStackDepth ( ) > 0 ) ) { OpcodeStack . Item item = stack . getStackItem ( 0 ) ; item . setUserValue ( imType ) ; } } }
overrides the visitor to find method mutations on collections that have previously been determined to have been created as immutable collections