| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Robert M. Fuhrer (rfuhrer@watson.ibm.com), IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets; |
| |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.Assert; |
| |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.ArrayType; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; |
| import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TTypes; |
| |
| /** |
| * A type-safe wrapper for Set<TType> that also adds TType-specific |
| * functionality, e.g. subTypes() and superTypes(). |
| */ |
| public class EnumeratedTypeSet extends TypeSet { |
| static private int sCount= 0; |
| |
| static public int getCount() { |
| return sCount; |
| } |
| |
| static public void resetCount() { |
| sCount= 0; |
| } |
| |
| /** |
| * Set containing the TTypes in this EnumeratedTypeSet. |
| */ |
| Set/*<TType>*/ fMembers= new LinkedHashSet(); |
| |
| /** |
| * Constructs a new EnumeratedTypeSet with the members of Set s in it. |
| * All elements of s must be TTypes. |
| */ |
| public EnumeratedTypeSet(Iterator types, TypeSetEnvironment typeSetEnvironment) { |
| super(typeSetEnvironment); |
| while (types.hasNext()) { |
| fMembers.add(types.next()); |
| } |
| sCount++; |
| } |
| |
| /** |
| * Constructs an empty EnumeratedTypeSet. |
| */ |
| public EnumeratedTypeSet(TypeSetEnvironment typeSetEnvironment) { |
| super(typeSetEnvironment); |
| sCount++; |
| } |
| |
| /** |
| * Constructs a new EnumeratedTypeSet with the given single TType in it. |
| */ |
| public EnumeratedTypeSet(TType t, TypeSetEnvironment typeSetEnvironment) { |
| super(typeSetEnvironment); |
| Assert.isNotNull(t); |
| fMembers.add(t); |
| sCount++; |
| } |
| |
| /** |
| * @return <code>true</code> iff this set represents the universe of TTypes |
| */ |
| public boolean isUniverse() { |
| return false; |
| } |
| |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o instanceof EnumeratedTypeSet) { |
| EnumeratedTypeSet other= (EnumeratedTypeSet) o; |
| |
| return fMembers.equals(other.fMembers); |
| } else if (o instanceof SingletonTypeSet) { |
| SingletonTypeSet other= (SingletonTypeSet) o; |
| |
| return (fMembers.size() == 1) && fMembers.contains(other.anyMember()); |
| } else if (o instanceof TypeSet) { |
| TypeSet other= (TypeSet) o; |
| |
| for(Iterator otherIter= other.iterator(); otherIter.hasNext(); ) { |
| if (!fMembers.contains(otherIter.next())) |
| return false; |
| } |
| for(Iterator myIter= fMembers.iterator(); myIter.hasNext(); ) { |
| if (!other.contains((TType) myIter.next())) |
| return false; |
| } |
| return true; |
| } else |
| return false; |
| } |
| |
| public int hashCode() { |
| return 37 + fMembers.hashCode(); |
| } |
| |
| /** |
| * Computes and returns a <em>new</em> EnumeratedTypeSet representing the intersection of the |
| * receiver with s2. Does not modify the receiver. |
| * @param s2 |
| */ |
| protected TypeSet specialCasesIntersectedWith(TypeSet s2) { |
| if (s2 instanceof EnumeratedTypeSet) { |
| EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); |
| |
| result.addAll(this); // copy first since retainAll() modifies in-place |
| result.retainAll(s2); |
| if (result.size() > 0) |
| return result; |
| else |
| return getTypeSetEnvironment().getEmptyTypeSet(); |
| } |
| return null; |
| } |
| |
| /** |
| * Modifies this EnumeratedTypeSet to represent the intersection of the receiver with s2. |
| * @param s2 |
| */ |
| public void intersectWith(TypeSet s2) { |
| if (isUniverse()) { |
| if (s2.isUniverse()) |
| return; |
| // More than an optimization: the universe never contains array types, so |
| // if s2 has array types, the following will retain them, as it should. |
| EnumeratedTypeSet ets2= (EnumeratedTypeSet) s2; |
| fMembers= new LinkedHashSet(); |
| fMembers.addAll(ets2.fMembers); |
| } else |
| retainAll(s2); |
| } |
| |
| /** |
| * @return a new TypeSet representing the set of all sub-types of the |
| * types in the receiver |
| */ |
| public TypeSet subTypes() { |
| if (isUniverse()) |
| return makeClone(); // subtypes(universe) = universe |
| |
| if (fMembers.contains(getJavaLangObject())) |
| return getTypeSetEnvironment().getUniverseTypeSet(); |
| |
| return getTypeSetEnvironment().createSubTypesSet(this); |
| } |
| |
| public static EnumeratedTypeSet makeArrayTypesForElements(Iterator/*<TType>*/ elemTypes, TypeSetEnvironment typeSetEnvironment) { |
| EnumeratedTypeSet result= new EnumeratedTypeSet(typeSetEnvironment); |
| |
| while (elemTypes.hasNext()) { |
| TType t= (TType) elemTypes.next(); |
| result.add(TTypes.createArrayType(t, 1)); |
| } |
| // result.initComplete(); |
| return result; |
| } |
| |
| /** |
| * @return a new TypeSet representing the set of all super-types of the |
| * types in the receiver |
| */ |
| public TypeSet superTypes() { |
| if (isUniverse()) |
| return makeClone(); // The supertypes of the universe is the universe |
| |
| return getTypeSetEnvironment().createSuperTypesSet(this); |
| } |
| |
| public TypeSet makeClone() { |
| EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); |
| |
| result.fMembers.addAll(fMembers); |
| result.initComplete(); |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#size() |
| */ |
| public int size() { |
| return fMembers.size(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#clear() |
| */ |
| public void clear() { |
| if (isUniverse()) |
| fMembers= new LinkedHashSet(); |
| else |
| fMembers.clear(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#isEmpty() |
| */ |
| public boolean isEmpty() { |
| return fMembers.isEmpty(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#toArray() |
| */ |
| public TType[] toArray() { |
| return (TType[]) fMembers.toArray(new TType[fMembers.size()]); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#add(java.lang.Object) |
| */ |
| public boolean add(TType t) { |
| // Doesn't make sense to do here what other methods do (copy-and-modify) |
| Assert.isTrue(!isUniverse(), "Someone's trying to expand the universe!"); //$NON-NLS-1$ |
| return fMembers.add(t); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#contains(java.lang.Object) |
| */ |
| public boolean contains(TType t) { |
| if (isUniverse()) |
| return true; |
| return fMembers.contains(t); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#remove(java.lang.Object) |
| */ |
| public boolean remove(TType t) { |
| if (isUniverse()) |
| fMembers= cloneSet(fMembers); |
| return fMembers.remove(t); |
| } |
| |
| private Set cloneSet(Set members) { |
| Set result= new LinkedHashSet(); |
| result.addAll(members); |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#addAll(java.util.Collection) |
| */ |
| public boolean addAll(TypeSet s) { |
| if (s instanceof EnumeratedTypeSet) { |
| EnumeratedTypeSet ets= (EnumeratedTypeSet) s; |
| |
| return fMembers.addAll(ets.fMembers); |
| } else { |
| EnumeratedTypeSet ets= s.enumerate(); |
| |
| return fMembers.addAll(ets.fMembers); |
| } |
| } |
| |
| public TypeSet addedTo(TypeSet that) { |
| EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); |
| |
| result.addAll(this); |
| result.addAll(that); |
| result.initComplete(); |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#containsAll(java.util.Collection) |
| */ |
| public boolean containsAll(TypeSet s) { |
| if (isUniverse()) |
| return true; |
| if (s.isUniverse()) |
| return false; |
| EnumeratedTypeSet ets= s.enumerate(); |
| |
| return fMembers.containsAll(ets.fMembers); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#removeAll(java.util.Collection) |
| */ |
| public boolean removeAll(EnumeratedTypeSet s) { |
| if (isUniverse()) |
| fMembers= cloneSet(fMembers); |
| return fMembers.removeAll(s.fMembers); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#retainAll(java.util.Collection) |
| */ |
| public boolean retainAll(TypeSet s) { |
| if (s.isUniverse()) return false; |
| |
| EnumeratedTypeSet ets= (EnumeratedTypeSet) s; |
| |
| if (isUniverse()) { |
| fMembers= cloneSet(ets.fMembers); |
| return true; |
| } else |
| return fMembers.retainAll(ets.fMembers); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isSingleton() |
| */ |
| public boolean isSingleton() { |
| return fMembers.size() == 1; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#anyMember() |
| */ |
| public TType anyMember() { |
| return (TType) fMembers.iterator().next(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#upperBound() |
| */ |
| public TypeSet upperBound() { |
| if (fMembers.size() == 1) |
| return new SingletonTypeSet((TType) fMembers.iterator().next(), getTypeSetEnvironment()); |
| if (fMembers.contains(getJavaLangObject())) |
| return new SingletonTypeSet(getJavaLangObject(), getTypeSetEnvironment()); |
| |
| EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); |
| |
| // Add to result each element of fMembers that has no proper supertype in fMembers |
| result.fMembers.addAll(fMembers); |
| for(Iterator iter= fMembers.iterator(); iter.hasNext(); ) { |
| TType t= (TType) iter.next(); |
| |
| if (t.isArrayType()) { |
| ArrayType at= (ArrayType) t; |
| int numDims= at.getDimensions(); |
| for(Iterator subIter=TTypes.getAllSubTypesIterator(at.getElementType()); subIter.hasNext(); ) { |
| result.fMembers.remove(TTypes.createArrayType(((TType) subIter.next()), numDims)); |
| } |
| } else { |
| for (Iterator iterator= TTypes.getAllSubTypesIterator(t); iterator.hasNext();) { |
| result.fMembers.remove(iterator.next()); |
| } |
| } |
| } |
| result.initComplete(); |
| return result; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#lowerBound() |
| */ |
| public TypeSet lowerBound() { |
| if (fMembers.size() == 1) |
| return new SingletonTypeSet((TType) fMembers.iterator().next(), getTypeSetEnvironment()); |
| |
| EnumeratedTypeSet result= new EnumeratedTypeSet(getTypeSetEnvironment()); |
| |
| // Add to result each element of fMembers that has no proper subtype in fMembers |
| result.fMembers.addAll(fMembers); |
| |
| for(Iterator iter= fMembers.iterator(); iter.hasNext(); ) { |
| TType t= (TType) iter.next(); |
| |
| // java.lang.Object is only in the lower bound if fMembers consists |
| // of only java.lang.Object, but that case is handled above. |
| if (t.equals(getJavaLangObject())) { |
| result.fMembers.remove(t); |
| continue; |
| } |
| |
| if (t instanceof ArrayType) { |
| ArrayType at= (ArrayType) t; |
| int numDims= at.getDimensions(); |
| for(Iterator superIter=TTypes.getAllSuperTypesIterator(at.getElementType()); superIter.hasNext(); ) { |
| result.fMembers.remove(TTypes.createArrayType(((TType) superIter.next()), numDims)); |
| } |
| } else { |
| for (Iterator iterator= TTypes.getAllSuperTypesIterator(t); iterator.hasNext();) { |
| result.fMembers.remove(iterator.next()); |
| } |
| } |
| } |
| if (result.size() > 0) |
| return result; |
| else |
| return getTypeSetEnvironment().getEmptyTypeSet(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueLowerBound() |
| */ |
| public boolean hasUniqueLowerBound() { |
| return fMembers.size() == 1; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueUpperBound() |
| */ |
| public boolean hasUniqueUpperBound() { |
| return fMembers.size() == 1; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueLowerBound() |
| */ |
| public TType uniqueLowerBound() { |
| if (fMembers.size() == 1) |
| return (TType) fMembers.iterator().next(); |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueUpperBound() |
| */ |
| public TType uniqueUpperBound() { |
| if (fMembers.size() == 1) |
| return (TType) fMembers.iterator().next(); |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#iterator() |
| */ |
| public Iterator iterator() { |
| return fMembers.iterator(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Set#toArray(java.lang.Object[]) |
| */ |
| public TType[] toArray(TType[] a) { |
| return (TType[]) fMembers.toArray(a); |
| } |
| |
| /** |
| * Limits the display of set elements to the first sMaxElements. |
| */ |
| private static final int sMaxElements= 10; // Integer.MAX_VALUE; |
| |
| /* |
| * (non-Javadoc) |
| * @see java.lang.Object#toString() |
| */ |
| public String toString() { |
| StringBuffer b= new StringBuffer(); |
| b.append("{" + fID+ ":"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (isUniverse()) |
| b.append(" <universe>"); //$NON-NLS-1$ |
| else { |
| int count=0; |
| Iterator iter; |
| for(iter= iterator(); iter.hasNext() && count < sMaxElements; count++) { |
| TType type= (TType) iter.next(); |
| b.append(' ') |
| .append(type.getPrettySignature()); |
| if (iter.hasNext()) |
| b.append(','); |
| } |
| if (iter.hasNext()) |
| b.append(" ..."); //$NON-NLS-1$ |
| } |
| b.append(" }"); //$NON-NLS-1$ |
| return b.toString(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#enumerate() |
| */ |
| public EnumeratedTypeSet enumerate() { |
| return this; // (EnumeratedTypeSet) makeClone(); |
| } |
| |
| public void initComplete() { |
| Assert.isTrue(! fMembers.isEmpty()); |
| } |
| |
| } |