public void merge(final Binding b, final boolean removeObject) { for (final PsiTypeVariable var : b.getBoundVariables()) { final int index = var.getIndex(); if (myBindings.get(index) != null) { LOG.error("Oops... Binding conflict..."); } else { final PsiType type = b.apply(var); final PsiClassType javaLangObject = PsiType.getJavaLangObject( PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject)); if (removeObject && javaLangObject.equals(type)) { final HashSet<PsiTypeVariable> cluster = myFactory.getClusterOf(var.getIndex()); if (cluster != null) { for (final PsiTypeVariable war : cluster) { final PsiType wtype = b.apply(war); if (!javaLangObject.equals(wtype)) { myBindings.put(index, type); break; } } } } else { myBindings.put(index, type); } } } }
public boolean isValid() { for (final PsiTypeVariable var : myBoundVariables) { final PsiType type = substitute(var); if (!var.isValidInContext(type)) { return false; } } return true; }
BindingImpl(final int index, final PsiType type) { myBindings = new TIntObjectHashMap<PsiType>(); myCyclic = type instanceof PsiTypeVariable; myBindings.put(index, type); if (type instanceof Bottom) { final HashSet<PsiTypeVariable> cluster = myFactory.getClusterOf(index); if (cluster != null) { for (PsiTypeVariable var : cluster) { myBindings.put(var.getIndex(), type); } } } }
public Binding reduceRecursive() { final BindingImpl binding = (BindingImpl) create(); for (final PsiTypeVariable var : myBoundVariables) { final int index = var.getIndex(); final PsiType type = myBindings.get(index); if (type != null) { class Verifier extends PsiExtendedTypeVisitor<Void> { boolean myFlag = false; @Override public Void visitTypeVariable(final PsiTypeVariable var) { if (var.getIndex() == index) { myFlag = true; } return null; } } final Verifier verifier = new Verifier(); type.accept(verifier); if (verifier.myFlag) { myBindings.put(index, Bottom.BOTTOM); binding.myBindings.put(index, Bottom.BOTTOM); } else { binding.myBindings.put(index, type); } } else { binding.myBindings.put(index, type); } } for (final PsiTypeVariable var : myBoundVariables) { final int index = var.getIndex(); final PsiType type = myBindings.get(index); if (type != null) { myBindings.put(index, binding.apply(type)); } } return this; }
@Override public Void visitTypeVariable(final PsiTypeVariable var) { if (var.getIndex() == index) { myFlag = true; } return null; }
public String toString() { final StringBuffer buffer = new StringBuffer(); for (PsiTypeVariable boundVariable : myBoundVariables) { final int i = boundVariable.getIndex(); final PsiType binding = myBindings.get(i); if (binding != null) { buffer .append("#") .append(i) .append(" -> ") .append(binding.getPresentableText()) .append("; "); } } return buffer.toString(); }
BindingImpl(final PsiTypeVariable var, final PsiType type) { myBindings = new TIntObjectHashMap<PsiType>(); myCyclic = type instanceof PsiTypeVariable; myBindings.put(var.getIndex(), type); }
public boolean binds(final PsiTypeVariable var) { return myBindings.get(var.getIndex()) != null; }
public int compare(final Binding binding) { final BindingImpl b2 = (BindingImpl) binding; final BindingImpl b1 = this; int directoin = Binding.NONCOMPARABLE; boolean first = true; for (PsiTypeVariable boundVariable : myBoundVariables) { final int index = boundVariable.getIndex(); final PsiType x = normalize(b1.myBindings.get(index)); final PsiType y = normalize(b2.myBindings.get(index)); final int comp = new Object() { int compare(final PsiType x, final PsiType y) { final int[] kinds = new Object() { private int classify(final PsiType type) { if (type == null) { return 0; } if (type instanceof PsiPrimitiveType) { return 1; } if (type instanceof PsiArrayType) { return 2; } if (type instanceof PsiClassType) { return 3; } return 4; // Bottom } int[] classify2(final PsiType x, final PsiType y) { return new int[] {classify(x), classify(y)}; } }.classify2(x, y); final int kindX = kinds[0]; final int kindY = kinds[1]; // Break your brain here... if (kindX + kindY == 0) { return Binding.SAME; } if (kindX * kindY == 0) { if (kindX == 0) { return Binding.WORSE; } return Binding.BETTER; } if (kindX * kindY == 1) { if (x.equals(y)) { return Binding.SAME; } return Binding.NONCOMPARABLE; } if (kindX != kindY) { if (kindX == 4) { return Binding.WORSE; } if (kindY == 4) { return Binding.BETTER; } if (kindX + kindY == 5) { try { final PsiElementFactory f = JavaPsiFacade.getInstance(myProject).getElementFactory(); final PsiType cloneable = f.createTypeFromText("java.lang.Cloneable", null); final PsiType object = f.createTypeFromText("java.lang.Object", null); final PsiType serializable = f.createTypeFromText("java.io.Serializable", null); PsiType type; int flag; if (kindX == 3) { type = x; flag = Binding.WORSE; } else { type = y; flag = Binding.BETTER; } if (type.equals(object) || type.equals(cloneable) || type.equals(serializable)) { return flag; } } catch (IncorrectOperationException e) { LOG.error(e); } } return Binding.NONCOMPARABLE; } if (kindX == 2) { return compare( ((PsiArrayType) x).getComponentType(), ((PsiArrayType) y).getComponentType()); } if (x.equals(y)) { return Binding.SAME; } // End of breaking... final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); final PsiClass xClass = resultX.getElement(); final PsiClass yClass = resultY.getElement(); final PsiSubstitutor xSubst = resultX.getSubstitutor(); final PsiSubstitutor ySubst = resultY.getSubstitutor(); if (xClass == null || yClass == null) { return Binding.NONCOMPARABLE; } if (xClass.equals(yClass)) { boolean first = true; int direction = Binding.SAME; for (final PsiTypeParameter p : xSubst.getSubstitutionMap().keySet()) { final PsiType xParm = xSubst.substitute(p); final PsiType yParm = ySubst.substitute(p); final int comp = compare(xParm, yParm); if (comp == Binding.NONCOMPARABLE) { return Binding.NONCOMPARABLE; } if (first) { first = false; direction = comp; } if (direction != comp) { return Binding.NONCOMPARABLE; } } return direction; } else { if (InheritanceUtil.isCorrectDescendant(xClass, yClass, true)) { return Binding.BETTER; } else if (InheritanceUtil.isCorrectDescendant(yClass, xClass, true)) { return Binding.WORSE; } return Binding.NONCOMPARABLE; } } }.compare(x, y); if (comp == Binding.NONCOMPARABLE) { return Binding.NONCOMPARABLE; } if (first) { first = false; directoin = comp; } if (directoin != SAME) { if (comp != Binding.SAME && directoin != comp) { return Binding.NONCOMPARABLE; } } else if (comp != SAME) { directoin = comp; } } return directoin; }
public Binding compose(final Binding b) { LOG.assertTrue(b instanceof BindingImpl); final BindingImpl b1 = this; final BindingImpl b2 = (BindingImpl) b; final BindingImpl b3 = new BindingImpl(); for (PsiTypeVariable boundVariable : myBoundVariables) { final int i = boundVariable.getIndex(); final PsiType b1i = b1.myBindings.get(i); final PsiType b2i = b2.myBindings.get(i); final int flag = (b1i == null ? 0 : 1) + (b2i == null ? 0 : 2); switch (flag) { case 0: break; case 1: /* b1(i)\b2(i) */ { final PsiType type = b2.apply(b1i); if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } break; case 2: /* b2(i)\b1(i) */ { final PsiType type = b1.apply(b2i); if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } break; case 3: /* b2(i) \cap b1(i) */ { final Binding common = rise(b1i, b2i, null); if (common == null) { return null; } final PsiType type = common.apply(b1i); if (type == null) { return null; } if (type == null) { return null; } b3.myBindings.put(i, type); b3.myCyclic = type instanceof PsiTypeVariable; } } } return b3; }