Exemplo n.º 1
0
    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);
          }
        }
      }
    }
Exemplo n.º 2
0
    public boolean isValid() {
      for (final PsiTypeVariable var : myBoundVariables) {
        final PsiType type = substitute(var);

        if (!var.isValidInContext(type)) {
          return false;
        }
      }

      return true;
    }
Exemplo n.º 3
0
    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);
          }
        }
      }
    }
Exemplo n.º 4
0
    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;
    }
Exemplo n.º 5
0
            @Override
            public Void visitTypeVariable(final PsiTypeVariable var) {
              if (var.getIndex() == index) {
                myFlag = true;
              }

              return null;
            }
Exemplo n.º 6
0
    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();
    }
Exemplo n.º 7
0
    BindingImpl(final PsiTypeVariable var, final PsiType type) {
      myBindings = new TIntObjectHashMap<PsiType>();
      myCyclic = type instanceof PsiTypeVariable;

      myBindings.put(var.getIndex(), type);
    }
Exemplo n.º 8
0
 public boolean binds(final PsiTypeVariable var) {
   return myBindings.get(var.getIndex()) != null;
 }
Exemplo n.º 9
0
    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;
    }
Exemplo n.º 10
0
    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;
    }