<commit_before>/*
 * fb-contrib - Auxiliary detectors for Java programs
 * Copyright (C) 2005-2016 <NAME>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package com.mebigfatguy.fbcontrib.detect;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.bcel.classfile.Code;
import org.apache.bcel.generic.Type;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.BytecodeScanningDetector;

/**
 * looks for methods that use floating point indexes for loops. Since floating
 * point math is inprecise, rounding errors will occur each time through the
 * loop causing hard to find problems. It is usually better to use integer
 * indexing, and calculating the correct floating point value from the index.
 */
public class FloatingPointLoops extends BytecodeScanningDetector {
    enum State {
        SAW_LOAD, SAW_CMPX, SAW_IFX, SAW_STORE
    }

    BugReporter bugReporter;
    private Set<FloatForLoop> forLoops = new HashSet<FloatForLoop>(5);

    /**
     * constructs a FPL detector given the reporter to report bugs on
     * 
     * @param bugReporter
     *            the sync of bug reports
     */
    public FloatingPointLoops(BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }

    /**
     * implements the visitor to clear the forLoops set
     * 
     * @param obj
     *            the context object for the currently parsed code block
     */
    @Override
    public void visitCode(Code obj) {
        forLoops = new HashSet<FloatForLoop>();
        super.visitCode(obj);
        forLoops = null;
    }

    /**
     * implements the visitor to find for loops using floating point indexes
     * 
     * @param seen
     *            the opcode of the currently parsed instruction
     */
    @Override
    public void sawOpcode(int seen) {
        if (forLoops.size() > 0) {
            Iterator<FloatForLoop> ffl = forLoops.iterator();
            while (ffl.hasNext()) {
                if (!ffl.next().sawOpcode(seen))
                    ffl.remove();
            }
        }

        if ((seen == FLOAD) || (seen == DLOAD))
            forLoops.add(new FloatForLoop(getRegisterOperand(), getPC()));
        else if ((seen >= FLOAD_0) && (seen <= FLOAD_3))
            forLoops.add(new FloatForLoop(seen - FLOAD_0, getPC()));
        else if ((seen >= DLOAD_0) && (seen <= DLOAD_3))
            forLoops.add(new FloatForLoop(seen - DLOAD_0, getPC()));
    }

    /**
     * maintains the state of a previously found for loop
     */
    public class FloatForLoop {
        private State state;
        private final int loopPC;
        private final int loopReg;
        private int gotoPC;

        public FloatForLoop(int reg, int pc) {
            loopReg = reg;
            loopPC = pc;
            state = State.SAW_LOAD;
            gotoPC = -1;
        }

        public boolean sawOpcode(final int seen) {
            switch (state) {
            case SAW_LOAD:
                if ((seen == FCMPG) || (seen == FCMPL) || (seen == DCMPG) || (seen == DCMPL)) {
                    state = State.SAW_CMPX;
                    return true;
                } else if ((seen == INVOKEVIRTUAL) || (seen == INVOKESTATIC) || (seen == INVOKEINTERFACE) || (seen == INVOKESPECIAL)) {
                    String methodSig = FloatingPointLoops.this.getSigConstantOperand();<commit_msg>GitHub Issue #108: use OpcodeUtils methods to simplify<commit_after>/*
 * fb-contrib - Auxiliary detectors for Java programs
 * Copyright (C) 2005-2016 <NAME>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package com.mebigfatguy.fbcontrib.detect;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.bcel.classfile.Code;
import org.apache.bcel.generic.Type;

import com.mebigfatguy.fbcontrib.utils.OpcodeUtils;
import com.mebigfatguy.fbcontrib.utils.RegisterUtils;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.BytecodeScanningDetector;

/**
 * looks for methods that use floating point indexes for loops. Since floating
 * point math is inprecise, rounding errors will occur each time through the
 * loop causing hard to find problems. It is usually better to use integer
 * indexing, and calculating the correct floating point value from the index.
 */
public class FloatingPointLoops extends BytecodeScanningDetector {
    enum State {
        SAW_LOAD, SAW_CMPX, SAW_IFX, SAW_STORE
    }

    BugReporter bugReporter;
    private Set<FloatForLoop> forLoops = new HashSet<FloatForLoop>(5);

    /**
     * constructs a FPL detector given the reporter to report bugs on
     * 
     * @param bugReporter
     *            the sync of bug reports
     */
    public FloatingPointLoops(BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }

    /**
     * implements the visitor to clear the forLoops set
     * 
     * @param obj
     *            the context object for the currently parsed code block
     */
    @Override
    public void visitCode(Code obj) {
        forLoops = new HashSet<FloatForLoop>();
        super.visitCode(obj);
        forLoops = null;
    }

    /**
     * implements the visitor to find for loops using floating point indexes
     * 
     * @param seen
     *            the opcode of the currently parsed instruction
     */
    @Override
    public void sawOpcode(int seen) {
        if (forLoops.size() > 0) {
            Iterator<FloatForLoop> ffl = forLoops.iterator();
            while (ffl.hasNext()) {
                if (!ffl.next().sawOpcode(seen))
                    ffl.remove();
            }
        }

        if (OpcodeUtils.isFLoad(seen) || OpcodeUtils.isDLoad(seen)) {
            forLoops.add(new FloatForLoop(RegisterUtils.getLoadReg(this, seen), getPC()));
        }
    }

    /**
     * maintains the state of a previously found for loop
     */
    public class FloatForLoop {
        private State state;
        private final int loopPC;
        private final int loopReg;
        private int gotoPC;

        public FloatForLoop(int reg, int pc) {
            loopReg = reg;
            loopPC = pc;
            state = State.SAW_LOAD;
            gotoPC = -1;
        }

        public boolean sawOpcode(final int seen) {
            switch (state) {
            case SAW_LOAD:
                if ((seen == FCMPG) || (seen == FCMPL) || (seen == DCMPG) || (seen == DCMPL)) {
                    state = State.SAW_CMPX;
                    return true;
                } else if ((seen == INVOKEVIRTUAL) || (seen == INVOKESTATIC) || (seen == INVOKEINTERFACE) || (seen == INVOKESPECIAL)) {
                    String methodSig = FloatingPointLoops.this.getSigConstantOperand();
{'fraction_non_alphanumeric': 0.087573385518591, 'fraction_numerical': 0.007705479452054794, 'mean_word_length': 2.428511530398323, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1790287', 'n_tokens_mistral': 2397, 'n_tokens_neox': 2277, 'n_words': 793}