001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2004, 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.generic;
021:
022: import java.util.Collections;
023: import java.util.List;
024:
025: import org.apache.bcel.generic.ObjectType;
026: import org.apache.bcel.generic.ReferenceType;
027: import org.apache.bcel.generic.Type;
028:
029: import edu.umd.cs.findbugs.annotations.CheckForNull;
030: import edu.umd.cs.findbugs.annotations.NonNull;
031: import edu.umd.cs.findbugs.util.Util;
032:
033: /**
034: * Extension to ObjectType that includes additional information
035: * about the generic signature. <p>
036: *
037: * A GenericObjectType is either a parameterized type e.g.
038: * <code>List<String></code>, or a type variable e.g.
039: * <code>T</code>. <p>
040: *
041: * This class cannot be initialized directly. Instead, create a GenericObjectType
042: * by calling GenericUtilities.getType(String) and passing in the bytecode
043: * signature for the type.
044: *
045: * @author Nat Ayewah
046: */
047: public class GenericObjectType extends ObjectType {
048:
049: final List<? extends ReferenceType> parameters;
050:
051: final @CheckForNull
052: String variable;
053:
054: final @CheckForNull
055: Type extension;
056:
057: @Override
058: public int hashCode() {
059: return 13 * super .hashCode() + 9
060: * Util.nullSafeHashcode(parameters) + 7
061: * Util.nullSafeHashcode(variable)
062: + Util.nullSafeHashcode(extension);
063: }
064:
065: @Override
066: public boolean equals(Object o) {
067: if (!(o instanceof GenericObjectType))
068: return false;
069: if (!super .equals(o))
070: return false;
071: GenericObjectType that = (GenericObjectType) o;
072: return Util.nullSafeEquals(this .parameters, that.parameters)
073: && Util.nullSafeEquals(this .variable, that.variable)
074: && Util.nullSafeEquals(this .extension, that.extension);
075: }
076:
077: public Type getUpperBound() {
078: if ("+".equals(variable))
079: return extension;
080: return this ;
081: }
082:
083: /**
084: * @return Returns the extension.
085: */
086: public Type getExtension() {
087: return extension;
088: }
089:
090: /**
091: * @return Returns the variable.
092: */
093: public String getVariable() {
094: return variable;
095: }
096:
097: /**
098: * Get the TypeCategory that represents this Object
099: * @see GenericUtilities.TypeCategory
100: */
101: public GenericUtilities.TypeCategory getTypeCategory() {
102: if (hasParameters() && variable == null && extension == null) {
103: return GenericUtilities.TypeCategory.PARAMETERIZED;
104:
105: } else if (!hasParameters() && variable != null
106: && extension == null) {
107: if (variable.equals("*"))
108: return GenericUtilities.TypeCategory.WILDCARD;
109: else
110: return GenericUtilities.TypeCategory.TYPE_VARIABLE;
111:
112: } else if (!hasParameters() && variable != null
113: && extension != null) {
114: if (variable.equals("+"))
115: return GenericUtilities.TypeCategory.WILDCARD_EXTENDS;
116: else if (variable.equals("-"))
117: return GenericUtilities.TypeCategory.WILDCARD_SUPER;
118:
119: }
120: // this should never happen
121: throw new IllegalStateException(
122: "The Generic Object Type is badly initialized");
123: }
124:
125: /**
126: * @return true if this GenericObjectType represents a parameterized type e.g.
127: * <code>List<String></code>. This implies that isVariable() is falses
128: */
129: public boolean hasParameters() {
130: return parameters != null && parameters.size() > 0;
131: }
132:
133: /**
134: * @return the number of parameters if this is a parameterized class, 0 otherwise
135: */
136: public int getNumParameters() {
137: return parameters != null ? parameters.size() : 0;
138: }
139:
140: /**
141: * @param index should be less than getNumParameters()
142: * @return the type parameter at index
143: */
144: public ReferenceType getParameterAt(int index) {
145: if (index < getNumParameters())
146: return parameters.get(index);
147: else
148: throw new IndexOutOfBoundsException("The index " + index
149: + " is too large");
150: }
151:
152: public List<? extends ReferenceType> getParameters() {
153: if (parameters == null)
154: return null;
155: return Collections.unmodifiableList(parameters);
156: }
157:
158: // Package Level constructors
159:
160: /**
161: * Create a GenericObjectType that represents a Simple Type Variable
162: * or a simple wildcard with no extensions
163: * @param variable the type variable e.g. <code>T</code>
164: */
165: GenericObjectType(@NonNull
166: String variable) {
167: this (variable, (Type) null);
168: }
169:
170: /**
171: * Create a GenericObjectType that represents a Wildcard
172: * with extensions
173: * @param variable the type variable e.g. <code>T</code>
174: */
175: GenericObjectType(@NonNull
176: String wildcard, Type extension) {
177: super (Type.OBJECT.getClassName());
178: this .variable = wildcard;
179: this .extension = extension;
180: parameters = null;
181: }
182:
183: /**
184: * Create a GenericObjectType that represents a parameterized class
185: * @param class_name the class that is parameterized. e.g. <code>java.util.List</code>
186: * @param parameters the parameters of this class, must be at least 1 parameter
187: */
188: GenericObjectType(String class_name,
189: List<? extends ReferenceType> parameters) {
190: super (class_name);
191: variable = null;
192: extension = null;
193: if (parameters == null || parameters.size() == 0)
194: throw new IllegalStateException(
195: "argument 'parameters' must contain at least 1 parameter");
196: this .parameters = parameters;
197: }
198:
199: /**
200: * @return the underlying ObjectType for this Generic Object
201: */
202: public ObjectType getObjectType() {
203: return (ObjectType) Type.getType(getSignature());
204: }
205:
206: /**
207: * Return a string representation of this object.
208: * (I do not override <code>toString()</code> in case
209: * any existing code assumes that this object is an
210: * ObjectType and expects similar string representation.
211: * i.e. <code>toString()</code> is equivalent to
212: * <code>toString(false)</code>)
213: *
214: * @param includeGenerics if true then the string includes generic information
215: * in this object. Otherwise this returns the same value as ObjectType.toString()
216: */
217: public String toString(boolean includeGenerics) {
218: // if (!includeGenerics) return super.toString();
219:
220: return getTypeCategory().asString(this );
221: }
222:
223: @Override
224: public String toString() {
225: return getTypeCategory().asString(this );
226: }
227:
228: public String toPlainString() {
229: return super.toString();
230: }
231: }
|