class ImproperHandlingUnicodeDetector extends OpcodeStackDetector {

    private String IMPROPER_UNICODE_TYPE = "IMPROPER_UNICODE";

    private BugReporter bugReporter;

    public ImproperHandlingUnicodeDetector(BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }


    private void reportBug() {
        BugInstance bug = new BugInstance(this, IMPROPER_UNICODE_TYPE, Priorities.LOW_PRIORITY) //
                .addClass(this).addMethod(this).addSourceLine(this);
        bugReporter.reportBug(bug);
    }

    /**
     * Uppercase and Lowercase case mapping functions are very common.
     * To avoid massive number of false positives, we check for String comparison done in the same method.
     *
     * @return If the method String.equals() was found in the same method.
     */
    private boolean hasComparisonInMethod() {
        //boolean stringComparisonFound = false;

        ClassContext classCtx = getClassContext();
        ConstantPoolGen cpg = classCtx.getConstantPoolGen();
        CFG cfg;
        try {
            cfg = classCtx.getCFG(getMethod());
        } catch (CFGBuilderException e) {
            AnalysisContext.logError("Cannot get CFG", e);
            return false;
        }

        for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
            Location location = i.next();
            Instruction inst = location.getHandle().getInstruction();
//            ByteCode.printOpCode(inst,cpg);

            if(inst instanceof INVOKEVIRTUAL) {
                INVOKEVIRTUAL inv = (INVOKEVIRTUAL) inst;
                String className = inv.getClassName(cpg);
                String methodName = inv.getMethodName(cpg);
                if(className.equals("java.lang.String") &&
                        (methodName.equals("equals") || methodName.equals("indexOf"))) {
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public void sawOpcode(int seen) {<FILL_FUNCTION_BODY>}

}

        //printOpCode(seen);

        //        ImproperHandlingUnicodeDetector: [0398]  invokestatic   java/text/Normalizer.normalize (Ljava/lang/CharSequence;Ljava/text/Normalizer$Form;)Ljava/lang/String;
        if (seen == Const.INVOKESTATIC && getClassConstantOperand().equals("java/text/Normalizer")
                && getNameConstantOperand().equals("normalize")) {
            reportBug();
        }
        //        ImproperHandlingUnicodeDetector: [0281]  invokevirtual   java/net/URI.toASCIIString ()Ljava/lang/String;
        else if (seen == Const.INVOKEVIRTUAL && getClassConstantOperand().equals("java/net/URI")
                && getNameConstantOperand().equals("toASCIIString")) {
            reportBug();
        }
        //        ImproperHandlingUnicodeDetector: [0375]  invokestatic   java/net/IDN.toASCII (Ljava/lang/String;)Ljava/lang/String;
        else if (seen == Const.INVOKESTATIC && getClassConstantOperand().equals("java/net/IDN")
                && getNameConstantOperand().equals("toASCII")) {
            reportBug();
        }
        //        ImproperHandlingUnicodeDetector: [0392]  invokevirtual   java/lang/String.toUpperCase ()Ljava/lang/String;
        else if (seen == Const.INVOKEVIRTUAL && getClassConstantOperand().equals("java/lang/String")
                && (getNameConstantOperand().equals("toUpperCase") || getNameConstantOperand().equals("toLowerCase"))) {
            if(hasComparisonInMethod()) {
                reportBug();
            }
        }
        //        ImproperHandlingUnicodeDetector: [0446]  invokevirtual   java/lang/String.equalsIgnoreCase (Ljava/lang/String;)Z
        else if (seen == Const.INVOKEVIRTUAL && getClassConstantOperand().equals("java/lang/String")
                && getNameConstantOperand().equals("equalsIgnoreCase")) {
            reportBug();
        }

    
<no_super_class>