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.Collection;
023: import java.util.LinkedList;
024: import java.util.Map;
025:
026: import javax.annotation.meta.When;
027:
028: import edu.umd.cs.findbugs.annotations.CheckForNull;
029: import edu.umd.cs.findbugs.annotations.NonNull;
030: import edu.umd.cs.findbugs.util.DualKeyHashMap;
031:
032: /**
033: * A type qualifier applied to a field, method, parameter, or return value.
034: *
035: * @author Bill Pugh
036: * @author David Hovemeyer
037: */
038: public class TypeQualifierAnnotation {
039:
040: public final TypeQualifierValue typeQualifier;
041: public final When when;
042:
043: private TypeQualifierAnnotation(TypeQualifierValue typeQualifier,
044: When when) {
045: this .typeQualifier = typeQualifier;
046: this .when = when;
047: }
048:
049: private static DualKeyHashMap<TypeQualifierValue, When, TypeQualifierAnnotation> map = new DualKeyHashMap<TypeQualifierValue, When, TypeQualifierAnnotation>();
050:
051: // public static synchronized @NonNull TypeQualifierAnnotation getValue(ClassDescriptor desc, Object value, When when) {
052: // return getValue(TypeQualifierValue.getValue(desc, value), when);
053: // }
054:
055: // When lattice:
056: //
057: // In subtypes:
058: // - return value type must be at least as narrow as supertypes
059: // - parameter types must be at least as wide as supertypes
060: //
061: // TOP TOP is invalid as return type:
062: // / | \ means that no When value is narrow enough
063: // / | \ for combination of supertype annotations
064: // / | \
065: // Always Unknown Never ^ Narrower
066: // \ | / |
067: // \ | / |
068: // \ | / |
069: // Maybe v Wider
070: //
071:
072: private static final When TOP = null;
073:
074: private static final When[][] combineReturnValueMatrix = {
075: // ALWAYS UNKNOWN MAYBE NEVER
076: /* ALWAYS */{ When.ALWAYS, },
077: /* UNKNOWN */{ When.ALWAYS, When.UNKNOWN, },
078: /* MAYBE */{ When.ALWAYS, When.UNKNOWN, When.MAYBE, },
079: /* NEVER */{ TOP, TOP, When.NEVER, When.NEVER }, };
080:
081: private static final When[][] combineParameterMatrix = {
082: // ALWAYS UNKNOWN MAYBE NEVER
083: /* ALWAYS */{ When.ALWAYS, },
084: /* UNKNOWN */{ When.UNKNOWN, When.UNKNOWN, },
085: /* MAYBE */{ When.MAYBE, When.MAYBE, When.MAYBE, },
086: /* NEVER */{ When.MAYBE, When.UNKNOWN, When.MAYBE,
087: When.NEVER }, };
088:
089: /**
090: * Combine return type annotations.
091: *
092: * @param a a TypeQualifierAnnotation used on a return value
093: * @param b another TypeQualifierAnnotation used on a return value
094: * @return combined return type annotation that is at least as narrow as
095: * both <code>a</code> or <code>b</code>,
096: * or null if no such TypeQualifierAnnotation exists
097: */
098: public static @CheckForNull
099: TypeQualifierAnnotation combineReturnTypeAnnotations(
100: TypeQualifierAnnotation a, TypeQualifierAnnotation b) {
101: return combineAnnotations(a, b, combineReturnValueMatrix);
102: }
103:
104: /**
105: *
106: * @param a a TypeQualifierAnnotation used on a method parameter
107: * @param b another TypeQualifierAnnotation used on a method parameter
108: * @return combined parameter annotation that is at least as wide
109: * as both a and b
110: */
111: public static @NonNull
112: TypeQualifierAnnotation combineParameterAnnotations(
113: TypeQualifierAnnotation a, TypeQualifierAnnotation b) {
114: return combineAnnotations(a, b, combineParameterMatrix);
115: }
116:
117: private static TypeQualifierAnnotation combineAnnotations(
118: TypeQualifierAnnotation a, TypeQualifierAnnotation b,
119: When[][] mergeMatrix) {
120: assert a.typeQualifier.equals(b.typeQualifier);
121:
122: When aWhen = a.when;
123: When bWhen = b.when;
124: if (aWhen.ordinal() < bWhen.ordinal()) {
125: When tmp = aWhen;
126: aWhen = bWhen;
127: bWhen = tmp;
128: }
129:
130: When combined = mergeMatrix[aWhen.ordinal()][bWhen.ordinal()];
131: if (combined != null) {
132: return getValue(a.typeQualifier, combined);
133: } else {
134: return null;
135: }
136: }
137:
138: public static @NonNull
139: Collection<TypeQualifierAnnotation> getValues(
140: Map<TypeQualifierValue, When> map) {
141: Collection<TypeQualifierAnnotation> result = new LinkedList<TypeQualifierAnnotation>();
142: for (Map.Entry<TypeQualifierValue, When> e : map.entrySet()) {
143: result.add(getValue(e.getKey(), e.getValue()));
144: }
145: return result;
146: }
147:
148: public static synchronized @NonNull
149: TypeQualifierAnnotation getValue(TypeQualifierValue desc, When when) {
150: TypeQualifierAnnotation result = map.get(desc, when);
151: if (result != null)
152: return result;
153: result = new TypeQualifierAnnotation(desc, when);
154: map.put(desc, when, result);
155: return result;
156: }
157:
158: @Override
159: public int hashCode() {
160: return typeQualifier.hashCode() * 37 + when.hashCode();
161: }
162:
163: @Override
164: public boolean equals(Object o) {
165: if (!(o instanceof TypeQualifierAnnotation))
166: return false;
167: TypeQualifierAnnotation other = (TypeQualifierAnnotation) o;
168: return typeQualifier.equals(other.typeQualifier)
169: && when.equals(other.when);
170: }
171:
172: @Override
173: public String toString() {
174: return typeQualifier + ":" + when;
175: }
176:
177: }
|