Esempio n. 1
0
 public static PsiSubstitutor composeSubstitutors(PsiSubstitutor s1, PsiSubstitutor s2) {
   final Map<PsiTypeParameter, PsiType> map = s1.getSubstitutionMap();
   Map<PsiTypeParameter, PsiType> result = new THashMap<PsiTypeParameter, PsiType>(map.size());
   for (PsiTypeParameter parameter : map.keySet()) {
     result.put(parameter, s2.substitute(map.get(parameter)));
   }
   final Map<PsiTypeParameter, PsiType> map2 = s2.getSubstitutionMap();
   for (PsiTypeParameter parameter : map2.keySet()) {
     if (!result.containsKey(parameter)) {
       result.put(parameter, map2.get(parameter));
     }
   }
   return PsiSubstitutorImpl.createSubstitutor(result);
 }
  private static PsiSubstitutor obtainFinalSubstitutor(
      PsiClass superClass,
      PsiSubstitutor superSubstitutor,
      PsiSubstitutor derivedSubstitutor,
      boolean inRawContext) {
    if (inRawContext) {
      Set<PsiTypeParameter> typeParams = superSubstitutor.getSubstitutionMap().keySet();
      PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject());
      superSubstitutor =
          factory.createRawSubstitutor(
              derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()]));
    }
    Map<PsiTypeParameter, PsiType> map = null;
    for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
      PsiType type = superSubstitutor.substitute(typeParameter);
      final PsiType t = derivedSubstitutor.substitute(type);
      if (map == null) {
        map = new THashMap<PsiTypeParameter, PsiType>();
      }
      map.put(typeParameter, t);
    }

    return map == null
        ? PsiSubstitutor.EMPTY
        : JavaPsiFacade.getInstance(superClass.getProject())
            .getElementFactory()
            .createSubstitutor(map);
  }
Esempio n. 3
0
  private Binding unify(final PsiType x, final PsiType y, final Unifier unifier) {
    final int indicator =
        (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0);

    switch (indicator) {
      case 0:
        if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) {
          return unifier.unify(x, y);
        } else if (x instanceof PsiArrayType || y instanceof PsiArrayType) {
          final PsiType xType =
              x instanceof PsiArrayType ? ((PsiArrayType) x).getComponentType() : x;
          final PsiType yType =
              y instanceof PsiArrayType ? ((PsiArrayType) y).getComponentType() : y;

          return unify(xType, yType, unifier);
        } else if (x instanceof PsiClassType && y instanceof PsiClassType) {
          final PsiClassType.ClassResolveResult resultX = Util.resolveType(x);
          final PsiClassType.ClassResolveResult resultY = Util.resolveType(y);

          final PsiClass xClass = resultX.getElement();
          final PsiClass yClass = resultY.getElement();

          if (xClass != null && yClass != null) {
            final PsiSubstitutor ySubst = resultY.getSubstitutor();

            final PsiSubstitutor xSubst = resultX.getSubstitutor();

            if (!xClass.equals(yClass)) {
              return null;
            }

            Binding b = create();

            for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) {
              final PsiType xType = xSubst.substitute(aParm);
              final PsiType yType = ySubst.substitute(aParm);

              final Binding b1 = unify(xType, yType, unifier);

              if (b1 == null) {
                return null;
              }

              b = b.compose(b1);
            }

            return b;
          }
        } else if (y instanceof Bottom) {
          return create();
        } else {
          return null;
        }

      default:
        return unifier.unify(x, y);
    }
  }
Esempio n. 4
0
    public PsiType substitute(final PsiType t) {
      if (t instanceof PsiWildcardType) {
        final PsiWildcardType wcType = (PsiWildcardType) t;
        final PsiType bound = wcType.getBound();

        if (bound == null) {
          return t;
        }

        final PsiManager manager = PsiManager.getInstance(myProject);
        final PsiType subst = substitute(bound);
        if (subst == null) return null;
        return subst instanceof PsiWildcardType
            ? subst
            : wcType.isExtends()
                ? PsiWildcardType.createExtends(manager, subst)
                : PsiWildcardType.createSuper(manager, subst);
      } else if (t instanceof PsiTypeVariable) {
        final PsiType b = apply(t);

        if (b instanceof Bottom || b instanceof PsiTypeVariable) {
          return null;
        }

        return substitute(b);
      } else if (t instanceof Bottom) {
        return null;
      } else if (t instanceof PsiArrayType) {
        return substitute(((PsiArrayType) t).getComponentType()).createArrayType();
      } else if (t instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult result = ((PsiClassType) t).resolveGenerics();

        final PsiClass aClass = result.getElement();
        final PsiSubstitutor aSubst = result.getSubstitutor();

        if (aClass != null) {
          PsiSubstitutor theSubst = PsiSubstitutor.EMPTY;

          for (final PsiTypeParameter parm : aSubst.getSubstitutionMap().keySet()) {
            final PsiType type = aSubst.substitute(parm);

            theSubst = theSubst.put(parm, substitute(type));
          }

          return JavaPsiFacade.getInstance(aClass.getProject())
              .getElementFactory()
              .createType(aClass, theSubst);
        }
      }
      return t;
    }
Esempio n. 5
0
    public PsiType apply(final PsiType type) {
      if (type instanceof PsiTypeVariable) {
        final PsiType t = myBindings.get(((PsiTypeVariable) type).getIndex());
        return t == null ? type : t;
      } else if (type instanceof PsiArrayType) {
        return apply(((PsiArrayType) type).getComponentType()).createArrayType();
      } else if (type instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult result = Util.resolveType(type);
        final PsiClass theClass = result.getElement();
        final PsiSubstitutor aSubst = result.getSubstitutor();

        PsiSubstitutor theSubst = PsiSubstitutor.EMPTY;

        if (theClass != null) {
          for (final PsiTypeParameter aParm : aSubst.getSubstitutionMap().keySet()) {
            final PsiType aType = aSubst.substitute(aParm);

            theSubst = theSubst.put(aParm, apply(aType));
          }

          return JavaPsiFacade.getInstance(theClass.getProject())
              .getElementFactory()
              .createType(theClass, theSubst);
        } else {
          return type;
        }
      } else if (type instanceof PsiWildcardType) {
        final PsiWildcardType wcType = (PsiWildcardType) type;
        final PsiType bound = wcType.getBound();

        if (bound != null) {
          final PsiType abound = apply(bound);

          if (abound instanceof PsiWildcardType) {
            return null;
          }

          return wcType.isExtends()
              ? PsiWildcardType.createExtends(PsiManager.getInstance(myProject), abound)
              : PsiWildcardType.createSuper(PsiManager.getInstance(myProject), abound);
        }

        return type;
      } else {
        return type;
      }
    }
  @NotNull
  private PsiSubstitutor mapSubstitutor(
      PsiClass originalClass, PsiClass mappedClass, PsiSubstitutor substitutor) {
    PsiTypeParameter[] typeParameters = mappedClass.getTypeParameters();
    PsiTypeParameter[] originalTypeParameters = originalClass.getTypeParameters();
    if (typeParameters.length != originalTypeParameters.length) {
      if (originalTypeParameters.length == 0) {
        return JavaPsiFacade.getElementFactory(mappedClass.getProject())
            .createRawSubstitutor(mappedClass);
      }
      return substitutor;
    }

    Map<PsiTypeParameter, PsiType> substitutionMap = substitutor.getSubstitutionMap();

    PsiSubstitutor mappedSubstitutor = PsiSubstitutor.EMPTY;
    for (int i = 0; i < originalTypeParameters.length; i++) {
      if (!substitutionMap.containsKey(originalTypeParameters[i])) continue;

      PsiType originalSubstitute = substitutor.substitute(originalTypeParameters[i]);
      if (originalSubstitute != null) {
        PsiType substitute = mapType(originalSubstitute);
        if (substitute == null) return substitutor;

        mappedSubstitutor = mappedSubstitutor.put(typeParameters[i], substitute);
      } else {
        mappedSubstitutor = mappedSubstitutor.put(typeParameters[i], null);
      }
    }

    if (mappedClass.hasModifierProperty(PsiModifier.STATIC)) {
      return mappedSubstitutor;
    }
    PsiClass mappedContaining = mappedClass.getContainingClass();
    PsiClass originalContaining = originalClass.getContainingClass();
    //noinspection DoubleNegation
    if ((mappedContaining != null) != (originalContaining != null)) {
      return substitutor;
    }

    if (mappedContaining != null) {
      return mappedSubstitutor.putAll(
          mapSubstitutor(originalContaining, mappedContaining, substitutor));
    }

    return mappedSubstitutor;
  }
 @NotNull
 private static PsiSubstitutor calculateMethodSubstitutor(
     @NotNull PsiTypeParameter[] typeParameters,
     @NotNull PsiMethod method,
     @NotNull PsiSubstitutor siteSubstitutor,
     @NotNull PsiType[] types1,
     @NotNull PsiType[] types2,
     @NotNull LanguageLevel languageLevel) {
   PsiSubstitutor substitutor =
       PsiResolveHelper.SERVICE
           .getInstance(method.getProject())
           .inferTypeArguments(typeParameters, types1, types2, languageLevel);
   for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(method)) {
     ProgressManager.checkCanceled();
     LOG.assertTrue(typeParameter != null);
     if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) {
       PsiType type = siteSubstitutor.substitute(typeParameter);
       if (type instanceof PsiClassType && typeParameter.getOwner() == method) {
         final PsiClass aClass = ((PsiClassType) type).resolve();
         if (aClass instanceof PsiTypeParameter
             && ((PsiTypeParameter) aClass).getOwner() == method) {
           type = TypeConversionUtil.erasure(type, siteSubstitutor);
         }
       }
       substitutor = substitutor.put(typeParameter, type);
     } else {
       final PsiType type = substitutor.substitute(typeParameter);
       if (type instanceof PsiClassType) {
         final PsiClass aClass = ((PsiClassType) type).resolve();
         if (aClass instanceof PsiTypeParameter) {
           substitutor =
               substitutor.put(
                   typeParameter,
                   JavaPsiFacade.getElementFactory(aClass.getProject())
                       .createType(aClass, siteSubstitutor));
         }
       }
     }
   }
   return substitutor;
 }
  public static PsiSubstitutor combineSubstitutors(
      PsiSubstitutor substitutor1, PsiSubstitutor substitutor2) {
    if (substitutor1 == PsiSubstitutor.EMPTY) return substitutor2;
    Set<PsiTypeParameter> parameters1 = substitutor1.getSubstitutionMap().keySet();
    final PsiTypeParameter[] typeParameters =
        parameters1.toArray(new PsiTypeParameter[parameters1.size()]);
    for (PsiTypeParameter typeParameter : typeParameters) {
      final PsiType type = substitutor1.substitute(typeParameter);
      PsiType otherSubstituted;
      if (type instanceof PsiClassType) {
        final PsiClass resolved = ((PsiClassType) type).resolve();
        otherSubstituted =
            resolved instanceof PsiTypeParameter
                ? substitutor2.substitute((PsiTypeParameter) resolved)
                : substitutor2.substitute(type);
      } else {
        otherSubstituted = substitutor2.substitute(type);
      }

      substitutor1 = substitutor1.put(typeParameter, otherSubstituted);
    }
    return substitutor1;
  }
  private static boolean provablyDistinct(PsiType type1, PsiType type2, int level) {
    if (type1 instanceof PsiClassType
        && ((PsiClassType) type1).resolve() instanceof PsiTypeParameter) return false;
    if (type2 instanceof PsiClassType
        && ((PsiClassType) type2).resolve() instanceof PsiTypeParameter) return false;
    if (type1 instanceof PsiWildcardType) {
      if (type2 instanceof PsiWildcardType) {
        return provablyDistinct((PsiWildcardType) type1, (PsiWildcardType) type2);
      }

      if (type2 instanceof PsiCapturedWildcardType) {
        return ((PsiWildcardType) type1).isExtends() && level > 0
            || provablyDistinct(
                (PsiWildcardType) type1, ((PsiCapturedWildcardType) type2).getWildcard());
      }

      if (type2 instanceof PsiClassType) {
        final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2);
        if (psiClass2 == null) return false;

        if (((PsiWildcardType) type1).isExtends()) {
          final PsiType extendsBound = ((PsiWildcardType) type1).getExtendsBound();
          if (extendsBound instanceof PsiArrayType
              && proveArrayTypeDistinct(
                  ((PsiWildcardType) type1).getManager().getProject(),
                  (PsiArrayType) extendsBound,
                  type2)) return true;
          final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound);
          if (boundClass1 == null) return false;
          return proveExtendsBoundsDistinct(type1, type2, boundClass1, psiClass2);
        }

        if (((PsiWildcardType) type1).isSuper()) {
          final PsiType superBound = ((PsiWildcardType) type1).getSuperBound();
          if (superBound instanceof PsiArrayType
              && proveArrayTypeDistinct(
                  ((PsiWildcardType) type1).getManager().getProject(),
                  (PsiArrayType) superBound,
                  type2)) return true;

          final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound);
          if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false;
          return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true);
        }

        final PsiType bound = ((PsiWildcardType) type1).getBound();
        return bound != null && !bound.equals(psiClass2);
      }

      if (type2 instanceof PsiArrayType) {
        return proveArrayTypeDistinct(
            ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) type2, type1);
      }
    }
    if (type1 instanceof PsiCapturedWildcardType)
      return provablyDistinct(((PsiCapturedWildcardType) type1).getWildcard(), type2, level);

    if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType)
      return provablyDistinct(type2, type1, level);

    final PsiClassType.ClassResolveResult classResolveResult1 =
        PsiUtil.resolveGenericsClassInType(type1);
    final PsiClassType.ClassResolveResult classResolveResult2 =
        PsiUtil.resolveGenericsClassInType(type2);
    if (Comparing.equal(TypeConversionUtil.erasure(type1), TypeConversionUtil.erasure(type2))) {
      final PsiSubstitutor substitutor1 = classResolveResult1.getSubstitutor();
      final PsiSubstitutor substitutor2 = classResolveResult2.getSubstitutor();
      for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) {
        final PsiType substitutedType1 = substitutor1.substitute(parameter);
        final PsiType substitutedType2 = substitutor2.substitute(parameter);
        if (substitutedType1 == null && substitutedType2 == null) return false;
        if (substitutedType1 == null || substitutedType2 == null) {
          return true;
        } else {
          if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true;
          if (substitutedType1 instanceof PsiWildcardType
              && !((PsiWildcardType) substitutedType1).isBounded()) return true;
        }
      }
      return false;
    }

    final PsiClass boundClass1 = classResolveResult1.getElement();
    final PsiClass boundClass2 = classResolveResult2.getElement();
    return type2 != null
        && type1 != null
        && !type1.equals(type2)
        && (!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true)
            || !InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true));
  }
Esempio n. 10
0
  public Binding balance(
      final PsiType x,
      final PsiType y,
      final Balancer balancer,
      final HashSet<Constraint> constraints) {
    final int indicator =
        (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0);

    switch (indicator) {
      case 0:
        if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) {
          final PsiType xType = x instanceof PsiWildcardType ? ((PsiWildcardType) x).getBound() : x;
          final PsiType yType = y instanceof PsiWildcardType ? ((PsiWildcardType) y).getBound() : y;

          switch ((x instanceof PsiWildcardType ? 1 : 0) + (y instanceof PsiWildcardType ? 2 : 0)) {
            case 1:
              if (((PsiWildcardType) x).isExtends()) {
                /* ? extends T1, T2 */
                return null;
              } else {
                /* ? super T1, T2 */
                if (xType != null && !"java.lang.Object".equals(xType.getCanonicalText())) {
                  return null;
                }
                return create();
              }

            case 2:
              if (((PsiWildcardType) y).isExtends()) {
                /* T1, ? extends T2 */
                if (yType instanceof PsiTypeVariable) {
                  final PsiTypeVariable beta = myFactory.create();

                  if (constraints != null) {
                    constraints.add(new Subtype(beta, yType));
                    if (x != null) {
                      constraints.add(new Subtype(x, yType));
                    }
                  }

                  return create();
                } else {
                  if (constraints != null && xType != null && yType != null) {
                    constraints.add(new Subtype(xType, yType));
                  }

                  return balance(xType, yType, balancer, constraints);
                }
              } else {
                /* T1, ? super T2 */
                if (yType instanceof PsiTypeVariable) {
                  final PsiTypeVariable beta = myFactory.create();

                  if (constraints != null) {
                    if (x != null) constraints.add(new Subtype(x, beta));
                    constraints.add(new Subtype(yType, beta));
                  }

                  return create();
                } else {
                  if (constraints != null && yType != null && xType != null) {
                    constraints.add(new Subtype(yType, xType));
                  }

                  return balance(xType, yType, balancer, constraints);
                }
              }

            case 3:
              switch ((((PsiWildcardType) x).isExtends() ? 0 : 1)
                  + (((PsiWildcardType) y).isExtends() ? 0 : 2)) {
                case 0: /* ? super T1, ? super T2 */
                  if (constraints != null && xType != null && yType != null) {
                    constraints.add(new Subtype(yType, xType));
                  }
                  return balance(xType, yType, balancer, constraints);

                case 1: /* ? extends T1, ? super T2 */
                  if (constraints != null && xType != null && yType != null) {
                    constraints.add(new Subtype(xType, yType));
                  }
                  return balance(xType, yType, balancer, constraints);

                case 2: /* ? super T1, ? extends T2*/
                  return null;

                case 3: /* ? extends T1, ? extends T2*/
                  if (constraints != null && xType != null && yType != null) {
                    constraints.add(new Subtype(xType, yType));
                  }
                  return balance(xType, yType, balancer, constraints);
              }
          }

          return create();
        } else if (x instanceof PsiArrayType || y instanceof PsiArrayType) {
          final PsiType xType =
              x instanceof PsiArrayType ? ((PsiArrayType) x).getComponentType() : x;
          final PsiType yType =
              y instanceof PsiArrayType ? ((PsiArrayType) y).getComponentType() : y;

          return balance(xType, yType, balancer, constraints);
        } else if (x instanceof PsiClassType && y instanceof PsiClassType) {
          final PsiClassType.ClassResolveResult resultX = Util.resolveType(x);
          final PsiClassType.ClassResolveResult resultY = Util.resolveType(y);

          final PsiClass xClass = resultX.getElement();
          final PsiClass yClass = resultY.getElement();

          if (xClass != null && yClass != null) {
            final PsiSubstitutor ySubst = resultY.getSubstitutor();

            PsiSubstitutor xSubst =
                TypeConversionUtil.getClassSubstitutor(yClass, xClass, resultX.getSubstitutor());
            if (xSubst == null) return null;

            Binding b = create();

            for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) {
              final PsiType xType = xSubst.substitute(aParm);
              final PsiType yType = ySubst.substitute(aParm);

              final Binding b1 =
                  unify(
                      xType,
                      yType,
                      new Unifier() {
                        public Binding unify(final PsiType x, final PsiType y) {
                          return balance(x, y, balancer, constraints);
                        }
                      });

              if (b1 == null) {
                return null;
              }

              b = b.compose(b1);
            }

            return b;
          }
        } else if (y instanceof Bottom) {
          return create();
        } else {
          return null;
        }
        break;

      case 1:
        return balancer.varType((PsiTypeVariable) x, y);

      case 2:
        return balancer.typeVar(x, (PsiTypeVariable) y);

      case 3:
        return balancer.varVar((PsiTypeVariable) x, (PsiTypeVariable) y);
    }

    return null;
  }
  public void setupTypeElement(
      PsiTypeElement typeElement,
      ExpectedTypeInfo[] infos,
      PsiSubstitutor substitutor,
      TemplateBuilder builder,
      @Nullable PsiElement context,
      PsiClass targetClass) {
    LOG.assertTrue(typeElement.isValid());
    ApplicationManager.getApplication().assertWriteAccessAllowed();

    PsiManager manager = typeElement.getManager();
    GlobalSearchScope scope = typeElement.getResolveScope();
    Project project = manager.getProject();

    if (infos.length == 1 && substitutor != null && substitutor != PsiSubstitutor.EMPTY) {
      ExpectedTypeInfo info = infos[0];
      Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap();
      PsiType[] vals = map.values().toArray(PsiType.createArray(map.size()));
      PsiTypeParameter[] params = map.keySet().toArray(new PsiTypeParameter[map.size()]);

      List<PsiType> types = matchingTypeParameters(vals, params, info);
      if (!types.isEmpty()) {
        ContainerUtil.addAll(
            types,
            ExpectedTypesProvider.processExpectedTypes(
                infos, new MyTypeVisitor(manager, scope), project));
        builder.replaceElement(
            typeElement,
            new TypeExpression(project, types.toArray(PsiType.createArray(types.size()))));
        return;
      } else {
        PsiElementFactory factory =
            JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
        PsiType type = info.getType();
        PsiType defaultType = info.getDefaultType();
        try {
          PsiTypeElement inplaceTypeElement =
              ((PsiVariable)
                      factory.createVariableDeclarationStatement("foo", type, null)
                          .getDeclaredElements()[0])
                  .getTypeElement();

          PsiSubstitutor rawingSubstitutor = getRawingSubstitutor(context, targetClass);
          int substitionResult =
              substituteToTypeParameters(
                  typeElement, inplaceTypeElement, vals, params, builder, rawingSubstitutor, true);
          if (substitionResult != SUBSTITUTED_NONE) {
            if (substitionResult == SUBSTITUTED_IN_PARAMETERS) {
              PsiJavaCodeReferenceElement refElement =
                  typeElement.getInnermostComponentReferenceElement();
              LOG.assertTrue(refElement != null && refElement.getReferenceNameElement() != null);
              type = getComponentType(type);
              LOG.assertTrue(type != null);
              defaultType = getComponentType(defaultType);
              LOG.assertTrue(defaultType != null);
              ExpectedTypeInfo info1 =
                  ExpectedTypesProvider.createInfo(
                      ((PsiClassType) defaultType).rawType(),
                      ExpectedTypeInfo.TYPE_STRICTLY,
                      ((PsiClassType) defaultType).rawType(),
                      info.getTailType());
              MyTypeVisitor visitor = new MyTypeVisitor(manager, scope);
              builder.replaceElement(
                  refElement.getReferenceNameElement(),
                  new TypeExpression(
                      project,
                      ExpectedTypesProvider.processExpectedTypes(
                          new ExpectedTypeInfo[] {info1}, visitor, project)));
            }

            return;
          }
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }
    }

    PsiType[] types =
        infos.length == 0
            ? new PsiType[] {typeElement.getType()}
            : ExpectedTypesProvider.processExpectedTypes(
                infos, new MyTypeVisitor(manager, scope), project);
    builder.replaceElement(typeElement, new TypeExpression(project, types));
  }