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 edu.umd.cs.findbugs.SystemProperties;
023: import edu.umd.cs.findbugs.annotations.CheckForNull;
024: import edu.umd.cs.findbugs.annotations.NonNull;
025: import edu.umd.cs.findbugs.ba.AnalysisContext;
026: import edu.umd.cs.findbugs.ba.MissingClassException;
027: import edu.umd.cs.findbugs.ba.XClass;
028: import edu.umd.cs.findbugs.ba.XMethod;
029: import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
030: import edu.umd.cs.findbugs.classfile.ClassDescriptor;
031: import edu.umd.cs.findbugs.classfile.Global;
032: import edu.umd.cs.findbugs.util.DualKeyHashMap;
033: import edu.umd.cs.findbugs.util.Util;
034:
035: /**
036: * A TypeQualifierValue is a pair specifying a type qualifier annotation
037: * and a value. Each TypeQualifierValue is effectively a different
038: * type qualifier. For example, if Foo is a type qualifier annotation
039: * having an int value, then Foo(0), Foo(1), etc. are all
040: * different type qualifiers which must be checked separately.
041: *
042: * @author William Pugh
043: */
044: public class TypeQualifierValue {
045: private static final boolean DEBUG = SystemProperties
046: .getBoolean("tqv.debug");
047:
048: public final ClassDescriptor typeQualifier;
049: public final @CheckForNull
050: Object value;
051: private boolean isStrict;
052:
053: private TypeQualifierValue(ClassDescriptor typeQualifier,
054: @CheckForNull
055: Object value) {
056: this .typeQualifier = typeQualifier;
057: this .value = value;
058: this .isStrict = false; // will be set to true if this is a strict type qualifier value
059: }
060:
061: private static DualKeyHashMap<ClassDescriptor, Object, TypeQualifierValue> map = new DualKeyHashMap<ClassDescriptor, Object, TypeQualifierValue>();
062:
063: /**
064: * Given a ClassDescriptor/value pair, return the
065: * interned TypeQualifierValue representing that pair.
066: *
067: * @param desc a ClassDescriptor denoting a type qualifier annotation
068: * @param value a value
069: * @return an interned TypeQualifierValue object
070: */
071: public static synchronized @NonNull
072: TypeQualifierValue getValue(ClassDescriptor desc, Object value) {
073: TypeQualifierValue result = map.get(desc, value);
074: if (result != null)
075: return result;
076: result = new TypeQualifierValue(desc, value);
077: determineIfQualifierIsStrict(desc, result);
078: map.put(desc, value, result);
079: return result;
080: }
081:
082: private static void determineIfQualifierIsStrict(
083: ClassDescriptor desc, TypeQualifierValue result) {
084: if (DEBUG) {
085: System.out.print("Checking to see if " + desc
086: + " requires strict checking...");
087: }
088: // Check to see if the type qualifier should be checked strictly
089: try {
090: XClass xclass = Global.getAnalysisCache().getClassAnalysis(
091: XClass.class, desc);
092:
093: // Annotation elements appear as abstract methods in the annotation class (interface).
094: // So, if the type qualifier annotation has specified a default When value,
095: // it will appear as an abstract method called "when".
096: XMethod whenMethod = xclass.findMethod("when",
097: "()Ljavax/annotation/meta/When;", false);
098: if (whenMethod == null) {
099: result.setIsStrict();
100: }
101: } catch (MissingClassException e) {
102: AnalysisContext.currentAnalysisContext()
103: .getLookupFailureCallback().reportMissingClass(
104: e.getClassNotFoundException());
105: } catch (CheckedAnalysisException e) {
106: AnalysisContext.logError(
107: "Error looking up annotation class "
108: + desc.toDottedClassName(), e);
109: }
110: if (DEBUG) {
111: System.out.println(result.isStrictQualifier() ? "yes"
112: : "no");
113: }
114: }
115:
116: /**
117: * Get the ClassDescriptor which specifies the type qualifier annotation.
118: *
119: * @return ClassDescriptor which specifies the type qualifier annotation
120: */
121: public ClassDescriptor getTypeQualifierClassDescriptor() {
122: return typeQualifier;
123: }
124:
125: /**
126: * Mark this as a type qualifier value that should
127: * be checked strictly.
128: */
129: private void setIsStrict() {
130: this .isStrict = true;
131: }
132:
133: /**
134: * Return whether or not this TypeQualifierValue denotes
135: * a strict qualifier.
136: *
137: * @return true if type qualifier is strict, false otherwise
138: */
139: public boolean isStrictQualifier() {
140: return isStrict;
141: }
142:
143: @Override
144: public int hashCode() {
145: int result = typeQualifier.hashCode();
146: if (value != null)
147: result += 37 * value.hashCode();
148: return result;
149: }
150:
151: @Override
152: public boolean equals(Object o) {
153: if (!(o instanceof TypeQualifierValue))
154: return false;
155: TypeQualifierValue other = (TypeQualifierValue) o;
156: return typeQualifier.equals(other.typeQualifier)
157: && Util.nullSafeEquals(value, other.value);
158: }
159:
160: /* (non-Javadoc)
161: * @see java.lang.Object#toString()
162: */
163: @Override
164: public String toString() {
165: StringBuffer buf = new StringBuffer();
166: buf.append(typeQualifier.toString());
167: if (value != null) {
168: buf.append(':');
169: buf.append(value.toString());
170: }
171: return buf.toString();
172: }
173:
174: }
|