1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 import edu.umd.cs.findbugs.ba.*; 25 import java.io.*; 26 import java.util.*; 27 28 import org.apache.bcel.classfile.Code; 29 30 31 public class SwitchFallthrough extends BytecodeScanningDetector implements StatelessDetector { 32 private static final boolean DEBUG = SystemProperties.getBoolean("switchFallthrough.debug"); 33 private static final boolean LOOK_IN_SOURCE_FOR_FALLTHRU_COMMENT = 34 SystemProperties.getBoolean("findbugs.sf.comment"); 35 36 private SwitchHandler switchHdlr; 37 private boolean reachable; 38 private BugReporter bugReporter; 39 private int lastPC; 40 private BitSet potentiallyDeadStores = new BitSet(); 41 private BitSet potentiallyDeadStoresFromBeforeFallthrough = new BitSet(); 42 private LocalVariableAnnotation deadStore = null; 43 private int priority; 44 private int fallthroughDistance; 45 46 public SwitchFallthrough(BugReporter bugReporter) { 47 this.bugReporter = bugReporter; 48 } 49 50 51 52 @Override 53 public void visitClassContext(ClassContext classContext) { 54 classContext.getJavaClass().accept(this); 55 } 56 57 Collection<SourceLineAnnotation> found = new LinkedList<SourceLineAnnotation>(); 58 59 @Override 60 public void visit(Code obj) { 61 reachable = false; 62 lastPC = 0; 63 found.clear(); 64 switchHdlr = new SwitchHandler(); 65 potentiallyDeadStores.clear(); 66 deadStore = null; 67 potentiallyDeadStoresFromBeforeFallthrough.clear(); 68 priority = NORMAL_PRIORITY; 69 fallthroughDistance = 1000; 70 super.visit(obj); 71 if (!found.isEmpty() && found.size() < 4) { 72 BugInstance bug = new BugInstance(this, "SF_SWITCH_FALLTHROUGH", priority) 73 .addClassAndMethod(this).addAnnotations(found); 74 bugReporter.reportBug(bug); 75 76 } 77 } 78 79 @Override 80 public void sawOpcode(int seen) { 81 if (reachable && switchHdlr.isOnSwitchOffset(this)) { 82 fallthroughDistance = 0; 83 potentiallyDeadStoresFromBeforeFallthrough = (BitSet) potentiallyDeadStores.clone(); 84 if (!hasFallThruComment(lastPC + 1, getPC() - 1)) { 85 SourceLineAnnotation sourceLineAnnotation = 86 SourceLineAnnotation.fromVisitedInstructionRange(getClassContext(), this, lastPC, getPC()); 87 if (sourceLineAnnotation != null) { 88 found.add(sourceLineAnnotation); 89 } 90 } 91 92 } 93 94 if (isBranch(seen) || isSwitch(seen) 95 || seen == GOTO || seen == ARETURN || seen == IRETURN || seen == RETURN || seen == LRETURN 96 || seen == DRETURN || seen == FRETURN) { 97 potentiallyDeadStores.clear(); 98 potentiallyDeadStoresFromBeforeFallthrough.clear(); 99 } 100 101 102 if (isRegisterLoad()) 103 potentiallyDeadStores.clear(getRegisterOperand()); 104 105 else if (isRegisterStore() && !atCatchBlock()) { 106 int register = getRegisterOperand(); 107 if (potentiallyDeadStores.get(register) && (potentiallyDeadStoresFromBeforeFallthrough.get(register))){ 108 priority = HIGH_PRIORITY; 110 deadStore = LocalVariableAnnotation.getLocalVariableAnnotation(getMethod(), register, getPC()-1, getPC()); 111 BugInstance bug = new BugInstance(this, "SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH", priority) 112 .addClassAndMethod(this).add(deadStore).addSourceLine(this); 113 bugReporter.reportBug(bug); 114 115 } 116 potentiallyDeadStores.set(register); 117 } 118 119 switch (seen) { 120 case TABLESWITCH: 121 case LOOKUPSWITCH: 122 reachable = false; 123 switchHdlr.enterSwitch(this); 124 break; 125 126 case ATHROW: 127 case RETURN: 128 case ARETURN: 129 case IRETURN: 130 case LRETURN: 131 case DRETURN: 132 case FRETURN: 133 case GOTO_W: 134 case GOTO: 135 reachable = false; 136 break; 137 138 case INVOKESTATIC: 139 reachable = !("exit".equals(getNameConstantOperand()) && "java/lang/System".equals(getClassConstantOperand())); 140 break; 141 142 default: 143 reachable = true; 144 } 145 146 lastPC = getPC(); 147 fallthroughDistance++; 148 } 149 150 private boolean hasFallThruComment( int startPC, int endPC ) { 151 if (LOOK_IN_SOURCE_FOR_FALLTHRU_COMMENT) { 152 BufferedReader r = null; 153 try { 154 SourceLineAnnotation srcLine 155 = SourceLineAnnotation.fromVisitedInstructionRange(this, lastPC, getPC()); 156 SourceFinder sourceFinder = AnalysisContext.currentAnalysisContext().getSourceFinder(); 157 SourceFile sourceFile = sourceFinder.findSourceFile(srcLine.getPackageName(), srcLine.getSourceFile()); 158 159 int startLine = srcLine.getStartLine(); 160 int numLines = srcLine.getEndLine() - startLine - 1; 161 if (numLines <= 0) 162 return false; 163 r = new BufferedReader( 164 new InputStreamReader(sourceFile.getInputStream())); 165 for (int i = 0; i < startLine; i++) { 166 String line = r.readLine(); 167 if (line == null) return false; 168 } 169 for (int i = 0; i < numLines; i++) { 170 String line = r.readLine(); 171 if (line == null) return false; 172 line = line.toLowerCase(); 173 if (line.indexOf("fall") >= 0 || line.indexOf("nobreak") >= 0) { 174 return true; 175 } 176 } 177 } 178 catch (IOException ioe) { 179 } 181 finally { 182 try { 183 if (r != null) 184 r.close(); 185 } catch (IOException ioe) { 186 } 187 } 188 } 189 return false; 190 } 191 } 192 | Popular Tags |