/* * 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)); } } }