KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > SwitchFallthrough


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003-2005 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

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 JavaDoc
53          public void visitClassContext(ClassContext classContext) {
54         classContext.getJavaClass().accept(this);
55     }
56
57     Collection<SourceLineAnnotation> found = new LinkedList<SourceLineAnnotation>();
58     
59     @Override JavaDoc
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 JavaDoc
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                 // killed store
109
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 JavaDoc line = r.readLine();
167                     if (line == null) return false;
168                     }
169                 for (int i = 0; i < numLines; i++) {
170                     String JavaDoc 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                 //Problems with source file, mean report the bug
180
}
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