KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 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 package edu.umd.cs.findbugs.detect;
20
21 import edu.umd.cs.findbugs.*;
22 import edu.umd.cs.findbugs.ba.*;
23 import java.util.BitSet JavaDoc;
24 import org.apache.bcel.Constants;
25 import org.apache.bcel.classfile.*;
26
27 /**
28  * Look for calls to methods where the return value is erroneously ignored. This
29  * detector is meant as a simpler and faster replacement for
30  * BCPMethodReturnCheck.
31  *
32  * @author David Hovemeyer
33  */

34 public class MethodReturnCheck extends BytecodeScanningDetector {
35     private static final boolean DEBUG = SystemProperties.getBoolean("mrc.debug");
36
37     private static final int SCAN = 0;
38
39     private static final int SAW_INVOKE = 1;
40
41     private static final BitSet JavaDoc INVOKE_OPCODE_SET = new BitSet JavaDoc();
42     static {
43         INVOKE_OPCODE_SET.set(Constants.INVOKEINTERFACE);
44         INVOKE_OPCODE_SET.set(Constants.INVOKESPECIAL);
45         INVOKE_OPCODE_SET.set(Constants.INVOKESTATIC);
46         INVOKE_OPCODE_SET.set(Constants.INVOKEVIRTUAL);
47     }
48
49     boolean previousOpcodeWasNEW;
50
51     private BugReporter bugReporter;
52
53     private ClassContext classContext;
54
55     private CheckReturnAnnotationDatabase checkReturnAnnotationDatabase;
56
57     private Method method;
58
59     private XMethod callSeen;
60
61     private int state;
62
63     private int callPC;
64
65     private String JavaDoc className, methodName, signature;
66
67     public MethodReturnCheck(BugReporter bugReporter) {
68         this.bugReporter = bugReporter;
69     }
70
71     @Override JavaDoc
72     public void visitClassContext(ClassContext classContext) {
73         this.classContext = classContext;
74         checkReturnAnnotationDatabase = AnalysisContext
75                 .currentAnalysisContext().getCheckReturnAnnotationDatabase();
76         super.visitClassContext(classContext);
77         this.classContext = null;
78     }
79
80     @Override JavaDoc
81     public void visit(Method method) {
82         this.method = method;
83     }
84
85     @Override JavaDoc
86     public void visitCode(Code code) {
87         // Prescreen to find methods with POP or POP2 instructions,
88
// and at least one method invocation
89

90         if (DEBUG)
91             System.out.println("Visiting " + method);
92         super.visitCode(code);
93     }
94
95     @Override JavaDoc
96     public void sawOpcode(int seen) {
97
98         if (DEBUG)
99             System.out.println(state + " " + OPCODE_NAMES[seen]);
100         
101         if (state == SAW_INVOKE && isPop(seen)) {
102             CheckReturnValueAnnotation annotation = checkReturnAnnotationDatabase
103                     .getResolvedAnnotation(callSeen, false);
104             if (annotation != null
105                     && annotation != CheckReturnValueAnnotation.CHECK_RETURN_VALUE_IGNORE) {
106                 int popPC = getPC();
107                 if (DEBUG)
108                     System.out.println("Saw POP @" + popPC);
109                 int catchSize = getSizeOfSurroundingTryBlock(popPC);
110
111                 int priority = annotation.getPriority();
112                 if (catchSize <= 1)
113                     priority += 2;
114                 else if (catchSize <= 2)
115                     priority += 1;
116                 if (!checkReturnAnnotationDatabase.annotationIsDirect(callSeen)
117                         && !callSeen.getSignature()
118                                 .endsWith(
119                                         callSeen.getClassName().replace('.',
120                                                 '/')
121                                                 + ";"))
122                     priority++;
123                 BugInstance warning = new BugInstance(this,
124                         "RV_RETURN_VALUE_IGNORED", priority).addClassAndMethod(
125                         this).addMethod(className, methodName, signature,
126                         seen == Constants.INVOKESTATIC).describe(
127                         "METHOD_CALLED").addSourceLine(this, callPC);
128                 bugReporter.reportBug(warning);
129             }
130             state = SCAN;
131         } else if (INVOKE_OPCODE_SET.get(seen)) {
132             callPC = getPC();
133             className = getDottedClassConstantOperand();
134             methodName = getNameConstantOperand();
135             signature = getSigConstantOperand();
136             callSeen = XFactory.createXMethod(className, methodName, signature,
137                     seen == INVOKESTATIC);
138             state = SAW_INVOKE;
139             if (DEBUG) System.out.println(" invoking " + callSeen);
140         } else
141             state = SCAN;
142
143         if (seen == NEW) {
144             previousOpcodeWasNEW = true;
145         } else {
146             if (seen == INVOKESPECIAL && previousOpcodeWasNEW) {
147                 CheckReturnValueAnnotation annotation = checkReturnAnnotationDatabase
148                         .getResolvedAnnotation(callSeen, false);
149                 if (annotation != null
150                         && annotation != CheckReturnValueAnnotation.CHECK_RETURN_VALUE_IGNORE) {
151                     int priority = annotation.getPriority();
152                     if (!checkReturnAnnotationDatabase
153                             .annotationIsDirect(callSeen)
154                             && !callSeen.getSignature().endsWith(
155                                     callSeen.getClassName().replace('.', '/')
156                                             + ";"))
157                         priority++;
158                     bugReporter.reportBug(new BugInstance(this,
159                             "RV_RETURN_VALUE_IGNORED", priority)
160                             .addClassAndMethod(this).addCalledMethod(this).describe(
161                                     "METHOD_CALLED").addSourceLine(this));
162                 }
163                 
164             }
165             previousOpcodeWasNEW = false;
166         }
167
168     }
169
170     private boolean isPop(int seen) {
171         return seen == Constants.POP || seen == Constants.POP2;
172     }
173
174 }
175
Popular Tags