001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2003-2007 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba.jsr305;
021:
022: import java.util.HashSet;
023: import java.util.Iterator;
024:
025: import javax.annotation.meta.When;
026:
027: import org.apache.bcel.Constants;
028: import org.apache.bcel.generic.ConstantPoolGen;
029: import org.apache.bcel.generic.FieldInstruction;
030: import org.apache.bcel.generic.InstructionHandle;
031: import org.apache.bcel.generic.InvokeInstruction;
032:
033: import edu.umd.cs.findbugs.ba.BasicBlock;
034: import edu.umd.cs.findbugs.ba.BlockOrder;
035: import edu.umd.cs.findbugs.ba.CFG;
036: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
037: import edu.umd.cs.findbugs.ba.DepthFirstSearch;
038: import edu.umd.cs.findbugs.ba.Edge;
039: import edu.umd.cs.findbugs.ba.Location;
040: import edu.umd.cs.findbugs.ba.ReverseDFSOrder;
041: import edu.umd.cs.findbugs.ba.ReverseDepthFirstSearch;
042: import edu.umd.cs.findbugs.ba.SignatureParser;
043: import edu.umd.cs.findbugs.ba.XFactory;
044: import edu.umd.cs.findbugs.ba.XField;
045: import edu.umd.cs.findbugs.ba.XMethod;
046: import edu.umd.cs.findbugs.ba.vna.ValueNumber;
047: import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
048: import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
049:
050: /**
051: * Backwards type qualifier dataflow analysis.
052: *
053: * @author David Hovemeyer
054: */
055: public class BackwardTypeQualifierDataflowAnalysis extends
056: TypeQualifierDataflowAnalysis {
057: private static final boolean PRUNE_CONFLICTING_VALUES = true; //SystemProperties.getBoolean("ctq.pruneconflicting");
058: private final DepthFirstSearch dfs;
059: private final ReverseDepthFirstSearch rdfs;
060: private ForwardTypeQualifierDataflow forwardTypeQualifierDataflow;
061:
062: /**
063: * Constructor.
064: *
065: * @param dfs DepthFirstSearch on the analyzed method
066: * @param rdfs ReverseDepthFirstSearch on the analyzed method
067: * @param xmethod XMethod for the analyzed method
068: * @param cfg CFG of the analyzed method
069: * @param vnaDataflow ValueNumberDataflow on the analyzed method
070: * @param cpg ConstantPoolGen of the analyzed method
071: * @param typeQualifierValue TypeQualifierValue representing type qualifier the analysis should check
072: */
073: public BackwardTypeQualifierDataflowAnalysis(DepthFirstSearch dfs,
074: ReverseDepthFirstSearch rdfs, XMethod xmethod, CFG cfg,
075: ValueNumberDataflow vnaDataflow, ConstantPoolGen cpg,
076: TypeQualifierValue typeQualifierValue) {
077: super (xmethod, cfg, vnaDataflow, cpg, typeQualifierValue);
078: this .dfs = dfs;
079: this .rdfs = rdfs;
080: }
081:
082: /**
083: * @param forwardTypeQualifierDataflow The forwardTypeQualifierDataflow to set.
084: */
085: public void setForwardTypeQualifierDataflow(
086: ForwardTypeQualifierDataflow forwardTypeQualifierDataflow) {
087: this .forwardTypeQualifierDataflow = forwardTypeQualifierDataflow;
088: }
089:
090: /* (non-Javadoc)
091: * @see edu.umd.cs.findbugs.ba.jsr305.TypeQualifierDataflowAnalysis#edgeTransfer(edu.umd.cs.findbugs.ba.Edge, edu.umd.cs.findbugs.ba.jsr305.TypeQualifierValueSet)
092: */
093: @Override
094: public void edgeTransfer(Edge edge, TypeQualifierValueSet fact)
095: throws DataflowAnalysisException {
096: if (PRUNE_CONFLICTING_VALUES
097: && forwardTypeQualifierDataflow != null) {
098: pruneConflictingValues(fact, forwardTypeQualifierDataflow
099: .getFactOnEdge(edge));
100: }
101:
102: super .edgeTransfer(edge, fact);
103: }
104:
105: /* (non-Javadoc)
106: * @see edu.umd.cs.findbugs.ba.AbstractDataflowAnalysis#transferInstruction(org.apache.bcel.generic.InstructionHandle, edu.umd.cs.findbugs.ba.BasicBlock, java.lang.Object)
107: */
108: @Override
109: public void transferInstruction(InstructionHandle handle,
110: BasicBlock basicBlock, TypeQualifierValueSet fact)
111: throws DataflowAnalysisException {
112:
113: if (!fact.isValid()) {
114: return;
115: }
116:
117: if (PRUNE_CONFLICTING_VALUES
118: && forwardTypeQualifierDataflow != null) {
119: Location location = new Location(handle, basicBlock);
120: pruneConflictingValues(fact, forwardTypeQualifierDataflow
121: .getFactAfterLocation(location));
122: }
123:
124: super .transferInstruction(handle, basicBlock, fact);
125: }
126:
127: private void pruneConflictingValues(TypeQualifierValueSet fact,
128: TypeQualifierValueSet forwardFact) {
129: if (forwardFact.isValid()) {
130: HashSet<ValueNumber> valueNumbers = new HashSet<ValueNumber>();
131: valueNumbers.addAll(fact.getValueNumbers());
132: valueNumbers.retainAll(forwardFact.getValueNumbers());
133:
134: for (ValueNumber vn : valueNumbers) {
135: if (FlowValue.valuesConflict(forwardFact.getValue(vn),
136: fact.getValue(vn))) {
137: fact.pruneValue(vn);
138: }
139: }
140: }
141: }
142:
143: /* (non-Javadoc)
144: * @see edu.umd.cs.findbugs.ba.DataflowAnalysis#getBlockOrder(edu.umd.cs.findbugs.ba.CFG)
145: */
146: public BlockOrder getBlockOrder(CFG cfg) {
147: return new ReverseDFSOrder(cfg, rdfs, dfs);
148: }
149:
150: /* (non-Javadoc)
151: * @see edu.umd.cs.findbugs.ba.DataflowAnalysis#isForwards()
152: */
153: public boolean isForwards() {
154: return false;
155: }
156:
157: /* (non-Javadoc)
158: * @see edu.umd.cs.findbugs.ba.jsr305.TypeQualifierDataflowAnalysis#registerSourceSinkLocations()
159: */
160: @Override
161: public void registerSourceSinkLocations()
162: throws DataflowAnalysisException {
163: registerInstructionSinks();
164: }
165:
166: private void registerInstructionSinks()
167: throws DataflowAnalysisException {
168: TypeQualifierAnnotation returnValueAnnotation = null;
169: if (xmethod.isReturnTypeReferenceType()) {
170: returnValueAnnotation =
171: //TypeQualifierApplications.getApplicableApplicationConsideringSupertypes(xmethod, typeQualifierValue);
172: TypeQualifierApplications
173: .getEffectiveTypeQualifierAnnotation(xmethod,
174: typeQualifierValue);
175: }
176:
177: for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
178: Location location = i.next();
179:
180: short opcode = location.getHandle().getInstruction()
181: .getOpcode();
182:
183: if (opcode == Constants.ARETURN) {
184: modelReturn(returnValueAnnotation, location);
185: } else if (opcode == Constants.PUTFIELD
186: || opcode == Constants.PUTSTATIC) {
187: modelFieldStore(location);
188: } else if (location.getHandle().getInstruction() instanceof InvokeInstruction) {
189: modelArguments(location);
190: }
191: }
192: }
193:
194: private void modelReturn(
195: TypeQualifierAnnotation returnValueAnnotation,
196: Location location) throws DataflowAnalysisException {
197: When when = (returnValueAnnotation != null) ? returnValueAnnotation.when
198: : When.UNKNOWN;
199:
200: // Model return statement
201: ValueNumberFrame vnaFrameAtReturn = vnaDataflow
202: .getFactAtLocation(location);
203: if (vnaFrameAtReturn.isValid()) {
204: ValueNumber topValue = vnaFrameAtReturn.getTopValue();
205: SourceSinkInfo sink = new SourceSinkInfo(
206: SourceSinkType.RETURN_VALUE, location, topValue,
207: when);
208: registerSourceSink(sink);
209: }
210: }
211:
212: private void modelFieldStore(Location location)
213: throws DataflowAnalysisException {
214: // Model field stores
215: XField writtenField = XFactory.createXField(
216: (FieldInstruction) location.getHandle()
217: .getInstruction(), cpg);
218: TypeQualifierAnnotation tqa =
219: //TypeQualifierApplications.getApplicableApplicationConsideringSupertypes(writtenField, typeQualifierValue);
220: TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(
221: writtenField, typeQualifierValue);
222: When when = (tqa != null) ? tqa.when : When.UNKNOWN;
223:
224: // The ValueNumberFrame *before* the FieldInstruction should
225: // have the ValueNumber of the stored value on the top of the stack.
226: ValueNumberFrame vnaFrameAtStore = vnaDataflow
227: .getFactAtLocation(location);
228: if (vnaFrameAtStore.isValid()) {
229: ValueNumber vn = vnaFrameAtStore.getTopValue();
230: SourceSinkInfo sink = new SourceSinkInfo(
231: SourceSinkType.FIELD_STORE, location, vn, when);
232: registerSourceSink(sink);
233: }
234: }
235:
236: private void modelArguments(Location location)
237: throws DataflowAnalysisException {
238: // Model arguments to called method
239: InvokeInstruction inv = (InvokeInstruction) location
240: .getHandle().getInstruction();
241: XMethod calledMethod = XFactory.createXMethod(inv, cpg);
242:
243: SignatureParser sigParser = new SignatureParser(calledMethod
244: .getSignature());
245: if (sigParser.getNumParameters() == 0)
246: return;
247: ValueNumberFrame vnaFrame = vnaDataflow
248: .getFactAtLocation(location);
249:
250: if (!vnaFrame.isValid()) {
251: // AnalysisContext.logError("bad vna frame in " + xmethod + " at location " + location.getHandle().getPosition() + " calling " + calledMethod);
252: return;
253: }
254:
255: for (Iterator<String> j = sigParser
256: .parameterSignatureIterator(); j.hasNext();) {
257: int param = 0;
258:
259: String paramSig = j.next();
260:
261: if (SignatureParser.isReferenceType(paramSig)) {
262:
263: TypeQualifierAnnotation tqa = TypeQualifierApplications
264: .getEffectiveTypeQualifierAnnotation(
265: calledMethod, param, typeQualifierValue);
266: When when = (tqa != null) ? tqa.when : When.UNKNOWN;
267:
268: ValueNumber vn = vnaFrame.getArgument(inv, cpg, param,
269: sigParser);
270:
271: SourceSinkInfo info = new SourceSinkInfo(
272: SourceSinkType.ARGUMENT_TO_CALLED_METHOD,
273: location, vn, when);
274: info.setParameter(param);
275:
276: registerSourceSink(info);
277: }
278:
279: param++;
280: }
281: }
282:
283: /* (non-Javadoc)
284: * @see edu.umd.cs.findbugs.ba.jsr305.TypeQualifierDataflowAnalysis#propagateAcrossPhiNode(edu.umd.cs.findbugs.ba.jsr305.TypeQualifierValueSet, edu.umd.cs.findbugs.ba.vna.ValueNumber, edu.umd.cs.findbugs.ba.vna.ValueNumber)
285: */
286: @Override
287: protected void propagateAcrossPhiNode(TypeQualifierValueSet fact,
288: ValueNumber sourceVN, ValueNumber targetVN) {
289: // Backwards analysis - propagate value from target to source
290: fact.propagateAcrossPhiNode(targetVN, sourceVN);
291: }
292: }
|