blob: 70c236d81d69bde2a58c876550c9161a0452a553 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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 org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TTypes;
public class TypeSetIntersection extends TypeSet {
private TypeSet fLHS;
private TypeSet fRHS;
public TypeSetIntersection(TypeSet lhs, TypeSet rhs) {
super(lhs.getTypeSetEnvironment());
fLHS= lhs;
fRHS= rhs;
}
/**
* @return Returns the LHS.
*/
public TypeSet getLHS() {
return fLHS;
}
/**
* @return Returns the RHS.
*/
public TypeSet getRHS() {
return fRHS;
}
@Override
public boolean isUniverse() {
return fLHS.isUniverse() && fRHS.isUniverse();
}
@Override
public TypeSet makeClone() {
return this; //new TypeSetIntersection(fLHS.makeClone(), fRHS.makeClone());
}
@Override
public boolean isEmpty() {
if (fLHS.isEmpty() || fRHS.isEmpty())
return true;
if (fLHS.isUniverse() || fRHS.isUniverse())
return false;
// Another quick check we can make before jumping to the expensive stuff
if (fLHS.contains(getJavaLangObject()) && fRHS.contains(getJavaLangObject()))
return false;
// TypeSet lhsLB= fLHS.lowerBound();
// TypeSet rhsUB= fRHS.upperBound();
//
// // Avoid the infinite recursion that will occur if lhsLB == fLHS && rhsUB == fRHS
// if ((!lhsLB.equals(fLHS) || !rhsUB.equals(fRHS)) &&
// !lhsLB.intersectedWith(rhsUB).isEmpty())
// return false;
//
// if (areAllSuperTypesOf(lhsLB, rhsUB))
// return true;
//
// TypeSet lhsUB= fLHS.upperBound();
// TypeSet rhsLB= fRHS.lowerBound();
//
// if (!lhsUB.intersectedWith(rhsLB).isEmpty())
// return false;
//
// if (areAllSuperTypesOf(rhsLB, lhsUB))
// return true;
return false;
}
@Override
public boolean contains(TType t) {
return fLHS.contains(t) && fRHS.contains(t);
}
@Override
public boolean containsAll(TypeSet s) {
return fLHS.containsAll(s) && fRHS.containsAll(s);
}
@Override
public TypeSet subTypes() {
if (isUniverse() || contains(getJavaLangObject()))
return getTypeSetEnvironment().getUniverseTypeSet();
// sub(xsect(sub(a),sub(b))) == xsect(sub(a),sub(b))
if ((fLHS instanceof SubTypesSet || fLHS instanceof SubTypesOfSingleton) &&
(fRHS instanceof SubTypesSet || fRHS instanceof SubTypesOfSingleton))
return this;
return getTypeSetEnvironment().createSubTypesSet(this);
}
@Override
public TypeSet superTypes() {
// super(xsect(super(a),super(b))) == xsect(super(a),super(b))
if ((fLHS instanceof SuperTypesSet || fLHS instanceof SuperTypesOfSingleton) &&
(fRHS instanceof SuperTypesSet || fRHS instanceof SuperTypesOfSingleton))
return this;
return getTypeSetEnvironment().createSuperTypesSet(this);
}
@Override
public TypeSet upperBound() {
if (fLHS.contains(getJavaLangObject()) && fRHS.contains(getJavaLangObject()))
return new SingletonTypeSet(getTypeSetEnvironment().getJavaLangObject(), getTypeSetEnvironment());
if (fEnumCache != null) return fEnumCache.upperBound();
EnumeratedTypeSet lhsSet= fLHS.enumerate();
EnumeratedTypeSet rhsSet= fRHS.enumerate();
TypeSet xsect= lhsSet.intersectedWith(rhsSet);
return xsect.upperBound();
}
@Override
public TypeSet lowerBound() {
if (fLHS.hasUniqueLowerBound() && fRHS.hasUniqueLowerBound()) {
TType lhsBound= fLHS.uniqueLowerBound();
TType rhsBound= fRHS.uniqueLowerBound();
if (lhsBound.equals(rhsBound))
return new SingletonTypeSet(lhsBound, getTypeSetEnvironment());
else if (TTypes.canAssignTo(lhsBound, rhsBound))
return new SingletonTypeSet(rhsBound, getTypeSetEnvironment());
else if (TTypes.canAssignTo(rhsBound, lhsBound))
return new SingletonTypeSet(lhsBound, getTypeSetEnvironment());
}
if (fEnumCache != null) return fEnumCache.lowerBound();
EnumeratedTypeSet lhsSet= fLHS.enumerate();
EnumeratedTypeSet rhsSet= fRHS.enumerate();
TypeSet xsect= lhsSet.intersectedWith(rhsSet);
return xsect.lowerBound();
}
@Override
protected TypeSet specialCasesIntersectedWith(TypeSet s2) {
if (s2.equals(fLHS)) // xsect(s2,xsect(s2,?)) = xsect(s2,?)
return this;
if (s2.equals(fRHS)) // xsect(s2,xsect(?,s2)) = xsect(?,s2)
return this;
if (s2 instanceof TypeSetIntersection) {
TypeSetIntersection x2= (TypeSetIntersection) s2;
//
// The following should use a "quick equals()" guaranteed to be constant-time
//
// xsect(xsect(A,B),xsect(A,C)) = xsect(xsect(A,B),C)
if (fLHS.equals(x2.fLHS))
return new TypeSetIntersection(this, x2.fRHS);
// xsect(xsect(A,B),xsect(C,A)) = xsect(xsect(A,B),C)
if (fLHS.equals(x2.fRHS))
return new TypeSetIntersection(this, x2.fLHS);
// xsect(xsect(A,B),xsect(B,C)) = xsect(xsect(A,B),C)
if (fRHS.equals(x2.fLHS))
return new TypeSetIntersection(this, x2.fRHS);
// xsect(xsect(A,B),xsect(C,B)) = xsect(xsect(A,B),C)
if (fRHS.equals(x2.fRHS))
return new TypeSetIntersection(this, x2.fLHS);
}
return null;
}
@Override
public boolean isSingleton() {
if (fEnumCache != null) return fEnumCache.isSingleton();
int count= 0;
for(Iterator<TType> lhsIter= fLHS.iterator(); lhsIter.hasNext(); ) {
TType t= lhsIter.next();
if (fRHS.contains(t))
count++;
if (count > 1)
return false;
}
return (count == 1);
}
@Override
public TType anyMember() {
if (fEnumCache != null) return fEnumCache.anyMember();
for(Iterator<TType> lhsIter= fLHS.iterator(); lhsIter.hasNext(); ) {
TType t= lhsIter.next();
if (fRHS.contains(t))
return t;
}
return null;
}
@Override
public Iterator<TType> iterator() {
return enumerate().iterator();
// return new Iterator() {
// private Iterator fLHSIter= fLHS.iterator();
// private TType fNext= null;
// public void remove() {
// throw new IllegalStateException("Unimplemented");
// }
// private void advance() {
// for(; fLHSIter.hasNext(); ) {
// TType t= (TType) fLHSIter.next();
// if (fRHS.contains(t)) {
// fNext= t;
// break;
// }
// }
// }
// public boolean hasNext() {
// if (fNext == null)
// advance();
// return fNext != null;
// }
// public Object next() {
// if (fNext == null)
// advance();
// if (fNext == null)
// throw new NoSuchElementException("No more elements in TypeSetIntersection");
// TType result= fNext;
// fNext= null;
// return result;
// }
// };
}
@Override
public boolean equals(Object o) {
if (o instanceof TypeSetIntersection) {
TypeSetIntersection other= (TypeSetIntersection) o;
return other.fLHS.equals(fLHS) && other.fRHS.equals(fRHS);
} else
return false;
}
@Override
public int hashCode() {
return fLHS.hashCode() * 37 + fRHS.hashCode();
}
@Override
public String toString() {
return "<" + fID + ": intersect(" + fLHS + "," + fRHS + ")>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
@Override
public boolean hasUniqueLowerBound() {
return false;
}
@Override
public boolean hasUniqueUpperBound() {
return false;
}
@Override
public TType uniqueLowerBound() {
return null;
}
@Override
public TType uniqueUpperBound() {
return null;
}
private EnumeratedTypeSet fEnumCache= null;
@Override
public EnumeratedTypeSet enumerate() {
if (fEnumCache == null) {
EnumeratedTypeSet lhsSet= fLHS.enumerate();
EnumeratedTypeSet rhsSet= fRHS.enumerate();
fEnumCache= lhsSet.intersectedWith(rhsSet).enumerate();
}
return fEnumCache;
}
}