/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2003-2007 University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.ba.jsr305;
import javax.annotation.meta.When;
/**
* Flow value type for type qualifier dataflow analysis.
*
* @author David Hovemeyer
*/
public enum FlowValue {
TOP(0), ALWAYS(Bits.YES), NEVER(Bits.NO), UNKNOWN(Bits.YES | Bits.NO | Bits.UNCERTAIN);
private interface Bits {
public static final int YES = 1;
public static final int UNCERTAIN = 2;
public static final int NO = 4;
}
private final int bits;
private FlowValue(int bits) {
this.bits = bits;
}
public boolean isYes() {
return (bits & Bits.YES) != 0;
}
public boolean isUncertain() {
return (bits & Bits.UNCERTAIN) != 0;
}
public boolean isNo() {
return (bits & Bits.NO) != 0;
}
// Dataflow lattice:
//
// Top
// / \
// Always Never
// \ /
// Unknown
//
private static final FlowValue[][] mergeMatrix = {
// TOP ALWAYS NEVER UNKNOWN
/* TOP */{ TOP, },
/* ALWAYS */{ ALWAYS, ALWAYS, },
/* NEVER */{ NEVER, UNKNOWN, NEVER, },
/* UNKNOWN */{ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }, };
public static final FlowValue meet(FlowValue a, FlowValue b) {
int aIndex = a.ordinal();
int bIndex = b.ordinal();
if (aIndex < bIndex) {
int tmp = aIndex;
aIndex = bIndex;
bIndex = tmp;
}
return mergeMatrix[aIndex][bIndex];
}
/**
* Determine whether given flow values conflict.
*
* @param forward
* a forwards flow value
* @param backward
* a backwards flow value
* @return true if values conflict, false otherwise
*/
public static boolean valuesConflict(FlowValue forward, FlowValue backward) {
if (forward == TOP || backward == TOP) {
return false;
}
return (forward == ALWAYS && backward == NEVER) || (forward == NEVER && backward == ALWAYS);
}
/**
* Convert a When value to a FlowValue value.
*
* @param when
* a When value
* @return the corresponding FlowValue
*/
public static FlowValue flowValueFromWhen(When when) {
switch (when) {
case ALWAYS:
return FlowValue.ALWAYS;
case MAYBE:
return FlowValue.UNKNOWN;
case NEVER:
return FlowValue.NEVER;
case UNKNOWN:
return FlowValue.UNKNOWN;
default:
throw new IllegalStateException();
}
}
/**
* Determine whether given backwards FlowValue conflicts with given source.
*
* @param backwardsFlowValue
* a backwards FlowValue
* @param source
* SourceSinkInfo object representing a source reached by the
* backwards flow value
* @param typeQualifierValue
* TypeQualifierValue being checked
* @return true if backwards value conflicts with source, false if not
*/
public static boolean backwardsValueConflictsWithSource(FlowValue backwardsFlowValue, SourceSinkInfo source,
TypeQualifierValue typeQualifierValue) {
When sourceWhen = source.getWhen();
if (typeQualifierValue.isStrictQualifier()) {
// strict checking
return (backwardsFlowValue == ALWAYS && sourceWhen != When.ALWAYS)
|| (backwardsFlowValue == NEVER && sourceWhen != When.NEVER);
} else {
// NOT strict checking
return (backwardsFlowValue == ALWAYS && (sourceWhen == When.NEVER || sourceWhen == When.MAYBE))
|| (backwardsFlowValue == NEVER && (sourceWhen == When.ALWAYS || sourceWhen == When.MAYBE));
}
}
}