1 20 21 package edu.umd.cs.findbugs.detect; 22 23 import edu.umd.cs.findbugs.*; 24 import java.util.*; 25 import org.apache.bcel.classfile.Code; 26 27 public class FindFloatEquality extends BytecodeScanningDetector implements StatelessDetector 28 { 29 private static final int SAW_NOTHING = 0; 30 private static final int SAW_COMP = 1; 31 private int priority; 32 private BugReporter bugReporter; 33 private OpcodeStack opStack = new OpcodeStack(); 34 private int state; 35 36 public FindFloatEquality(BugReporter bugReporter) { 37 this.bugReporter = bugReporter; 38 } 39 40 41 Collection<SourceLineAnnotation> found = new LinkedList<SourceLineAnnotation>(); 42 43 @Override 44 public void visit(Code obj) { 45 found.clear(); 46 priority = LOW_PRIORITY; 47 48 49 opStack.resetForMethodEntry(this); 50 state = SAW_NOTHING; 51 52 super.visit(obj); 53 if (!found.isEmpty()) { 54 BugInstance bug = new BugInstance(this, "FE_FLOATING_POINT_EQUALITY", priority) 55 .addClassAndMethod(this); 56 57 for(SourceLineAnnotation s : found) 58 bug.add(s); 59 bugReporter.reportBug(bug); 60 61 found.clear(); 62 } 63 } 64 65 public boolean okValueToCompareAgainst(Number n) { 66 if (n == null) return false; 67 double v = n.doubleValue(); 68 if (Double.isInfinite(v) || Double.isNaN(v)) return true; 69 v = v - Math.floor(v); 70 return v == 0.0; 71 } 72 @Override 73 public void sawOpcode(int seen) { 74 if (false) System.out.println(OPCODE_NAMES[seen] + " " + state); 75 opStack.mergeJumps(this); 76 try { 77 switch ( seen ) { 78 case FCMPG: 79 case FCMPL: 80 case DCMPG: 81 case DCMPL: 82 if (opStack.getStackDepth() >= 2) { 83 OpcodeStack.Item first = opStack.getStackItem(0); 84 OpcodeStack.Item second = opStack.getStackItem(1); 85 86 Number n1 = (Number )first.getConstant(); 87 Number n2 = (Number )second.getConstant(); 88 if (n1 != null && Double.isNaN(n1.doubleValue()) 89 || n2 != null && Double.isNaN(n2.doubleValue()) ) { 90 BugInstance bug = new BugInstance(this, "FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER", HIGH_PRIORITY) 91 .addClassAndMethod(this).addSourceLine(this); 92 bugReporter.reportBug(bug); 93 state = SAW_NOTHING; 94 break; 95 } 96 if (first.getSpecialKind() == OpcodeStack.Item.FLOAT_MATH && !okValueToCompareAgainst(n2) 97 || second.getSpecialKind() == OpcodeStack.Item.FLOAT_MATH && !okValueToCompareAgainst(n1)) { 98 if (priority != HIGH_PRIORITY) found.clear(); 99 priority = HIGH_PRIORITY; 100 state = SAW_COMP; 101 break; 102 } 103 if (priority == HIGH_PRIORITY) break; 104 if (first.isInitialParameter() && n2 != null) break; 105 if (second.isInitialParameter() && n1 != null) break; 106 if (first.getRegisterNumber() == second.getRegisterNumber()) break; 107 if (first.isInitialParameter() && second.isInitialParameter()) break; 108 if (n1 != null && n2 != null) break; 109 110 if (okValueToCompareAgainst(n1) || okValueToCompareAgainst(n2)) break; 111 if (n1 != null || n2 != null) { 112 if (priority == LOW_PRIORITY) found.clear(); 113 priority = NORMAL_PRIORITY; 114 115 } 116 else if (priority == NORMAL_PRIORITY) break; 117 state = SAW_COMP; 118 } 119 break; 120 121 case IFEQ: 122 case IFNE: 123 if (state == SAW_COMP) { 124 SourceLineAnnotation sourceLineAnnotation = 125 SourceLineAnnotation.fromVisitedInstruction(getClassContext(), this, getPC()); 126 if (sourceLineAnnotation != null) { 127 found.add(sourceLineAnnotation); 128 } 129 } 130 state = SAW_NOTHING; 131 break; 132 133 default: 134 state = SAW_NOTHING; 135 break; 136 } 137 } 138 finally { 139 opStack.sawOpcode(this, seen); 140 } 141 } 142 } 143 | Popular Tags |