KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > npe > IsNullValueFrameModelingVisitor


1 /*
2  * Bytecode Analysis Framework
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.ba.npe;
21
22 import java.util.Map JavaDoc;
23 import org.apache.bcel.generic.ACONST_NULL;
24 import org.apache.bcel.generic.ANEWARRAY;
25 import org.apache.bcel.generic.CHECKCAST;
26 import org.apache.bcel.generic.ConstantPoolGen;
27 import org.apache.bcel.generic.GETFIELD;
28 import org.apache.bcel.generic.GETSTATIC;
29 import org.apache.bcel.generic.INVOKEINTERFACE;
30 import org.apache.bcel.generic.INVOKESPECIAL;
31 import org.apache.bcel.generic.INVOKESTATIC;
32 import org.apache.bcel.generic.INVOKEVIRTUAL;
33 import org.apache.bcel.generic.Instruction;
34 import org.apache.bcel.generic.InvokeInstruction;
35 import org.apache.bcel.generic.LDC;
36 import org.apache.bcel.generic.LDC2_W;
37 import org.apache.bcel.generic.MULTIANEWARRAY;
38 import org.apache.bcel.generic.NEW;
39 import org.apache.bcel.generic.NEWARRAY;
40 import org.apache.bcel.generic.PUTFIELD;
41 import org.apache.bcel.generic.ReferenceType;
42 import org.apache.bcel.generic.Type;
43
44 import edu.umd.cs.findbugs.SystemProperties;
45 import edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor;
46 import edu.umd.cs.findbugs.ba.AnalysisContext;
47 import edu.umd.cs.findbugs.ba.AssertionMethods;
48 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
49 import edu.umd.cs.findbugs.ba.InstanceField;
50 import edu.umd.cs.findbugs.ba.NullnessAnnotation;
51 import edu.umd.cs.findbugs.ba.XFactory;
52 import edu.umd.cs.findbugs.ba.XField;
53 import edu.umd.cs.findbugs.ba.XMethod;
54 import edu.umd.cs.findbugs.ba.vna.AvailableLoad;
55 import edu.umd.cs.findbugs.ba.vna.ValueNumber;
56 import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
57 import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
58
59 public class IsNullValueFrameModelingVisitor extends AbstractFrameModelingVisitor<IsNullValue, IsNullValueFrame> {
60
61     private static final boolean NO_ASSERT_HACK = SystemProperties.getBoolean("inva.noAssertHack");
62
63     private AssertionMethods assertionMethods;
64     private ValueNumberDataflow vnaDataflow;
65     private final boolean trackValueNumbers;
66     private int slotContainingNewNullValue;
67
68     public IsNullValueFrameModelingVisitor(
69             ConstantPoolGen cpg,
70             AssertionMethods assertionMethods,
71             ValueNumberDataflow vnaDataflow,
72             boolean trackValueNumbers) {
73         super(cpg);
74         this.assertionMethods = assertionMethods;
75         this.vnaDataflow = vnaDataflow;
76         this.trackValueNumbers = trackValueNumbers;
77     }
78     
79     /* (non-Javadoc)
80      * @see edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor#analyzeInstruction(org.apache.bcel.generic.Instruction)
81      */

82     @Override JavaDoc
83     public void analyzeInstruction(Instruction ins) throws DataflowAnalysisException {
84         slotContainingNewNullValue = -1;
85         super.analyzeInstruction(ins);
86     }
87     
88     /**
89      * @return Returns the slotContainingNewNullValue; or -1 if no new null value
90      * was produced
91      */

92     public int getSlotContainingNewNullValue() {
93         return slotContainingNewNullValue;
94     }
95     
96     @Override JavaDoc
97     public IsNullValue getDefaultValue() {
98         return IsNullValue.nonReportingNotNullValue();
99     }
100
101     // Overrides of specific instruction visitor methods.
102
// ACONST_NULL obviously produces a value that is DEFINITELY NULL.
103
// LDC produces values that are NOT NULL.
104
// NEW produces values that are NOT NULL.
105

106     // Note that all instructions that have an implicit null
107
// check (field access, invoke, etc.) are handled in IsNullValueAnalysis,
108
// because handling them relies on control flow (the existence of
109
// an ETB and exception edge prior to the block containing the
110
// instruction with the null check.)
111

112     // Note that we don't override IFNULL and IFNONNULL.
113
// Those are handled in the analysis itself, because we need
114
// to produce different values in each of the control successors.
115

116     private void produce(IsNullValue value) {
117         IsNullValueFrame frame = getFrame();
118         frame.pushValue(value);
119         newValueOnTOS();
120     }
121
122     private void produce2(IsNullValue value) {
123         IsNullValueFrame frame = getFrame();
124         frame.pushValue(value);
125         frame.pushValue(value);
126     }
127     
128     /**
129      * Handle method invocations.
130      * Generally, we want to get rid of null information following a
131      * call to a likely exception thrower or assertion.
132      */

133     private void handleInvoke(InvokeInstruction obj) {
134         Type callType = obj.getLoadClassType(getCPG());
135         Type returnType = obj.getReturnType(getCPG());
136         String JavaDoc methodName = obj.getMethodName(getCPG());
137         
138         boolean stringMethodCall = callType.equals(Type.STRING) && returnType.equals(Type.STRING);
139
140         boolean isReadLine = methodName.equals("readLine");
141         // Determine if we are going to model the return value of this call.
142
boolean modelCallReturnValue = returnType instanceof ReferenceType;
143
144             
145         if( !modelCallReturnValue) {
146             // Normal case: Assume returned values are non-reporting non-null.
147
handleNormalInstruction(obj);
148         } else {
149             // Special case: some special value is pushed on the stack for the return value
150
IsNullValue pushValue = null;
151             if (false && isReadLine) {
152                 pushValue = IsNullValue.nullOnSimplePathValue().markInformationAsComingFromReturnValueOfMethod(null);
153             } else if (false && stringMethodCall) {
154                 // String methods always return a non-null value
155
pushValue = IsNullValue.nonNullValue();
156             } else {
157                 // Check to see if this method is in either database
158
XMethod calledMethod = XFactory.createXMethod(obj, getCPG());
159                 if (IsNullValueAnalysis.DEBUG) System.out.println("Check " + calledMethod + " for null return...");
160                 NullnessAnnotation annotation = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase().getResolvedAnnotation(calledMethod, false);
161                 if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
162                     if (IsNullValueAnalysis.DEBUG) {
163                         System.out.println("Null value returned from " + calledMethod);
164                     }
165                     pushValue = IsNullValue.nullOnSimplePathValue().markInformationAsComingFromReturnValueOfMethod(calledMethod);
166                 } else if (annotation == NullnessAnnotation.NONNULL) {
167                     // Method is declared NOT to return null
168
if (IsNullValueAnalysis.DEBUG) {
169                         System.out.println("NonNull value return from " + calledMethod);
170                     }
171                     pushValue = IsNullValue.nonNullValue().markInformationAsComingFromReturnValueOfMethod(calledMethod);
172                     
173                 } else {
174                     pushValue = IsNullValue.nonReportingNotNullValue();
175                 }
176             }
177             
178             modelInstruction(obj, getNumWordsConsumed(obj), getNumWordsProduced(obj), pushValue);
179             newValueOnTOS();
180         }
181
182         if (!NO_ASSERT_HACK) {
183             if (assertionMethods.isAssertionCall(obj)) {
184                 IsNullValueFrame frame = getFrame();
185                 for (int i = 0; i < frame.getNumSlots(); ++i) {
186                     IsNullValue value = frame.getValue(i);
187                     if (value.isDefinitelyNull() || value.isNullOnSomePath()) {
188                         frame.setValue(i, IsNullValue.nonReportingNotNullValue());
189                     }
190                 }
191                 for(Map.Entry JavaDoc<ValueNumber,IsNullValue> e : frame.getKnownValueMapEntrySet()) {
192                     IsNullValue value = e.getValue();
193                     if (value.isDefinitelyNull() || value.isNullOnSomePath())
194                         e.setValue(IsNullValue.nonReportingNotNullValue());
195                     
196                 }
197             }
198         }
199     }
200     
201     /**
202      * Hook indicating that a new (possibly-null) value is on the
203      * top of the stack.
204      */

205     private void newValueOnTOS() {
206         IsNullValueFrame frame= getFrame();
207         if (frame.getStackDepth() < 1) {
208             return;
209         }
210         int tosSlot = frame.getNumSlots() - 1;
211         IsNullValue tos = frame.getValue(tosSlot);
212         if (tos.isDefinitelyNull()) {
213             slotContainingNewNullValue = tosSlot;
214         }
215         if (trackValueNumbers) {
216             try {
217                 ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
218                 if (vnaFrameAfter.isValid()) {
219                     ValueNumber tosVN = vnaFrameAfter.getTopValue();
220                     getFrame().setKnownValue(tosVN, tos);
221                     }
222                 } catch (DataflowAnalysisException e) {
223                     AnalysisContext.logError("error", e);
224             }
225         }
226     }
227
228     @Override JavaDoc
229     public void visitPUTFIELD(PUTFIELD obj) {
230         if (getNumWordsConsumed(obj) != 2) {
231             super.visitPUTFIELD(obj);
232             return;
233         }
234         
235         IsNullValue nullValueStored = null;
236         try {
237             nullValueStored = getFrame().getTopValue();
238         } catch (DataflowAnalysisException e1) {
239             AnalysisContext.logError("Oops", e1);
240         }
241         super.visitPUTFIELD(obj);
242         InstanceField field = (InstanceField) XFactory.createXField(obj, cpg);
243         if (nullValueStored != null)
244             try {
245             ValueNumberFrame vnaFrameBefore = vnaDataflow.getFactAtLocation(getLocation());
246             ValueNumber refValue = vnaFrameBefore.getStackValue(1);
247             AvailableLoad load = new AvailableLoad(refValue, field);
248             ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
249             ValueNumber [] newValueNumbersForField = vnaFrameAfter.getAvailableLoad(load);
250             if (newValueNumbersForField != null && trackValueNumbers)
251                 for(ValueNumber v : newValueNumbersForField)
252                     getFrame().setKnownValue(v, nullValueStored);
253         } catch (DataflowAnalysisException e) {
254             AnalysisContext.logError("Oops", e);
255         }
256     }
257
258     @Override JavaDoc
259     public void visitGETFIELD(GETFIELD obj) {
260         if (getNumWordsProduced(obj) != 1) {
261             super.visitGETFIELD(obj);
262             return;
263         }
264
265         if (checkForKnownValue(obj)) {
266             return;
267         }
268
269         XField field = XFactory.createXField(obj, cpg);
270         
271         NullnessAnnotation annotation = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase().getResolvedAnnotation(field, false);
272         if (annotation == NullnessAnnotation.NONNULL) {
273             modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
274             produce(IsNullValue.nonNullValue());
275         }
276         else if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
277                 modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
278                 produce(IsNullValue.nullOnSimplePathValue());
279         } else {
280             
281             super.visitGETFIELD(obj);
282         }
283
284     }
285     
286     /* (non-Javadoc)
287      * @see edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor#visitGETSTATIC(org.apache.bcel.generic.GETSTATIC)
288      */

289     @Override JavaDoc
290     public void visitGETSTATIC(GETSTATIC obj) {
291         if (getNumWordsProduced(obj) != 1) {
292             super.visitGETSTATIC(obj);
293             return;
294         }
295
296         if (checkForKnownValue(obj)) {
297             return;
298         }
299         XField field = XFactory.createXField(obj, cpg);
300         if (field.getName().startsWith("class$")) {
301             produce(IsNullValue.nonNullValue());
302             return;
303         }
304         NullnessAnnotation annotation = AnalysisContext
305                 .currentAnalysisContext().getNullnessAnnotationDatabase()
306                 .getResolvedAnnotation(field, false);
307         if (annotation == NullnessAnnotation.NONNULL) {
308             modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
309             produce(IsNullValue.nonNullValue());
310         } else if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
311             modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
312             produce(IsNullValue.nullOnSimplePathValue());
313         } else {
314
315             super.visitGETSTATIC(obj);
316         }
317     }
318     
319     /**
320      * Check given Instruction to see if it produces a known value.
321      * If so, model the instruction and return true.
322      * Otherwise, do nothing and return false.
323      * Should only be used for instructions that produce a single
324      * value on the top of the stack.
325      *
326      * @param obj the Instruction the instruction
327      * @return true if the instruction produced a known value and was modeled,
328      * false otherwise
329      */

330     private boolean checkForKnownValue(Instruction obj) {
331         if (trackValueNumbers) {
332             try {
333                 // See if the value number loaded here is a known value
334
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
335                 if (vnaFrameAfter.isValid()) {
336                     ValueNumber tosVN = vnaFrameAfter.getTopValue();
337                     IsNullValue knownValue = getFrame().getKnownValue(tosVN);
338                     if (knownValue != null) {
339                         //System.out.println("Produce known value!");
340
// The value produced by this instruction is known.
341
// Push the known value.
342
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
343                         produce(knownValue);
344                         return true;
345                     }
346                 }
347             } catch (DataflowAnalysisException e) {
348                 // Ignore...
349
}
350         }
351         return false;
352     }
353
354     @Override JavaDoc
355     public void visitACONST_NULL(ACONST_NULL obj) {
356         produce(IsNullValue.nullValue());
357     }
358     @Override JavaDoc
359     public void visitNEW(NEW obj) {
360         produce(IsNullValue.nonNullValue());
361     }
362
363     @Override JavaDoc
364     public void visitNEWARRAY(NEWARRAY obj) {
365         modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
366         produce(IsNullValue.nonNullValue());
367     }
368     @Override JavaDoc
369     public void visitANEWARRAY(ANEWARRAY obj) {
370         modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
371         produce(IsNullValue.nonNullValue());
372     }
373     @Override JavaDoc
374     public void visitMULTIANEWARRAY(MULTIANEWARRAY obj) {
375         modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
376         produce(IsNullValue.nonNullValue());
377     }
378     @Override JavaDoc
379     public void visitLDC(LDC obj) {
380         produce(IsNullValue.nonNullValue());
381     }
382
383     @Override JavaDoc
384     public void visitLDC2_W(LDC2_W obj) {
385         produce2(IsNullValue.nonNullValue());
386     }
387
388     @Override JavaDoc
389     public void visitCHECKCAST(CHECKCAST obj) {
390         // Do nothing
391
}
392     @Override JavaDoc
393     public void visitINVOKESTATIC(INVOKESTATIC obj) {
394         handleInvoke(obj);
395     }
396     @Override JavaDoc
397     public void visitINVOKESPECIAL(INVOKESPECIAL obj) {
398         handleInvoke(obj);
399     }
400     @Override JavaDoc
401     public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) {
402         handleInvoke(obj);
403     }
404     @Override JavaDoc
405     public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {
406         handleInvoke(obj);
407     }
408
409 }
410
411 // vim:ts=4
412
Popular Tags