Ejemplo n.º 1
0
 private static boolean acceptExtendsBound(PsiClassType extendsBound, int depth) {
   PsiType[] parameters = extendsBound.getParameters();
   if (parameters.length == 1) {
     PsiType argType = parameters[0];
     if (argType instanceof PsiCapturedWildcardType && depth == 0) {
       argType = ((PsiCapturedWildcardType) argType).getWildcard();
     }
     if (argType instanceof PsiWildcardType) {
       if (!((PsiWildcardType) argType).isBounded()) return true;
       final PsiType bound = ((PsiWildcardType) argType).getExtendsBound();
       if (bound instanceof PsiClassType
           && TypeConversionUtil.erasure(bound).equals(TypeConversionUtil.erasure(extendsBound))) {
         return acceptExtendsBound((PsiClassType) bound, depth + 1);
       }
       if (bound instanceof PsiIntersectionType) {
         for (PsiType extendsType : ((PsiIntersectionType) bound).getConjuncts()) {
           if (acceptExtendsBound(extendsBound, extendsType)) {
             return true;
           }
         }
       }
     }
   }
   return false;
 }
    @NotNull
    @Override
    public MyResult weigh(@NotNull LookupElement item) {
      final Object object = item.getObject();

      if (object instanceof PsiClass) {
        if (object instanceof PsiTypeParameter) return MyResult.typeParameter;

        if (myTypeParameter != null
            && object.equals(
                PsiUtil.resolveClassInType(
                    TypeConversionUtil.typeParameterErasure(myTypeParameter)))) {
          return MyResult.exactlyExpected;
        }
      }

      if (myExpectedTypes == null) return MyResult.normal;

      PsiType itemType = JavaCompletionUtil.getLookupElementType(item);
      if (itemType == null || !itemType.isValid()) return MyResult.normal;

      if (object instanceof PsiClass) {
        for (final ExpectedTypeInfo info : myExpectedTypes) {
          if (TypeConversionUtil.erasure(info.getType().getDeepComponentType())
              .equals(TypeConversionUtil.erasure(itemType))) {
            return AbstractExpectedTypeSkipper.skips(item, myLocation)
                ? MyResult.expectedNoSelect
                : MyResult.exactlyExpected;
          }
        }
      }

      for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) {
        final PsiType defaultType = expectedInfo.getDefaultType();
        final PsiType expectedType = expectedInfo.getType();
        if (!expectedType.isValid()) {
          return MyResult.normal;
        }

        if (defaultType != expectedType) {
          if (defaultType.equals(itemType)) {
            return MyResult.exactlyDefault;
          }

          if (defaultType.isAssignableFrom(itemType)) {
            return MyResult.ofDefaultType;
          }
        }
        if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) {
          return MyResult.exactlyExpected;
        }
      }

      return MyResult.normal;
    }
  public static PsiType captureReturnType(
      PsiMethodCallExpression call,
      PsiMethod method,
      PsiType ret,
      JavaResolveResult result,
      LanguageLevel languageLevel) {
    PsiSubstitutor substitutor = result.getSubstitutor();
    PsiType substitutedReturnType = substitutor.substitute(ret);
    if (substitutedReturnType == null) {
      return TypeConversionUtil.erasure(ret);
    }

    if (InferenceSession.wasUncheckedConversionPerformed(call)) {
      // 18.5.2
      // if unchecked conversion was necessary, then this substitution provides the parameter types
      // of the invocation type,
      // while the return type and thrown types are given by the erasure of m's type (without
      // applying θ').
      // due to https://bugs.openjdk.java.net/browse/JDK-8135087 erasure is called on
      // substitutedReturnType and not on ret type itself as by spec
      return TypeConversionUtil.erasure(substitutedReturnType);
    }

    // 15.12.2.6. Method Invocation Type
    // If unchecked conversion was necessary for the method to be applicable,
    // the parameter types of the invocation type are the parameter types of the method's type,
    // and the return type and thrown types are given by the erasures of the return type and thrown
    // types of the method's type.
    if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)
        && (method.hasTypeParameters()
            || JavaVersionService.getInstance().isAtLeast(call, JavaSdkVersion.JDK_1_8))
        && result instanceof MethodCandidateInfo
        && ((MethodCandidateInfo) result).isApplicable()) {
      final PsiType[] args = call.getArgumentList().getExpressionTypes();
      final boolean allowUncheckedConversion = false;
      final int applicabilityLevel =
          PsiUtil.getApplicabilityLevel(
              method, substitutor, args, languageLevel, allowUncheckedConversion, true);
      if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
        return TypeConversionUtil.erasure(substitutedReturnType);
      }
    }

    if (PsiUtil.isRawSubstitutor(method, substitutor)) {
      final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret);
      if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) {
        return returnTypeErasure;
      }
    }
    return PsiUtil.captureToplevelWildcards(substitutedReturnType, call);
  }
 private boolean hardEquals(
     PsiModifierListOwner psiVar, PsiType varType, boolean negated, DfaVariableValue qualifier) {
   return psiVar == myVariable
       && Comparing.equal(
           TypeConversionUtil.erasure(varType), TypeConversionUtil.erasure(myVarType))
       && negated == myIsNegated
       && (myQualifier == null
           ? qualifier == null
           : myQualifier.hardEquals(
               qualifier.getPsiVariable(),
               qualifier.getVariableType(),
               qualifier.isNegated(),
               qualifier.getQualifier()));
 }
Ejemplo n.º 5
0
 public static boolean acceptExtendsBound(PsiType extendsType, PsiType extendsBound) {
   if (Comparing.equal(
       TypeConversionUtil.erasure(extendsType), TypeConversionUtil.erasure(extendsBound))) {
     if (extendsBound instanceof PsiClassType) {
       if (acceptExtendsBound((PsiClassType) extendsBound, 0)) return true;
     } else if (extendsBound instanceof PsiIntersectionType) {
       for (PsiType psiType : ((PsiIntersectionType) extendsBound).getConjuncts()) {
         if (psiType instanceof PsiClassType) {
           if (acceptExtendsBound((PsiClassType) psiType, 0)) return true;
         }
       }
     }
   }
   return false;
 }
  protected PsiType processLocalVariableInitializer(PsiExpression initializer) {
    PsiType result = null;
    if (null != initializer && !(initializer instanceof PsiArrayInitializerExpression)) {
      if (!recursionBreaker.get().contains(initializer)) {
        recursionBreaker.get().add(initializer);
        try {
          result = initializer.getType();
        } finally {
          recursionBreaker.get().remove(initializer);
        }

        if (initializer instanceof PsiNewExpression) {
          final PsiJavaCodeReferenceElement reference =
              ((PsiNewExpression) initializer).getClassOrAnonymousClassReference();
          if (reference != null) {
            final PsiReferenceParameterList parameterList = reference.getParameterList();
            if (parameterList != null) {
              final PsiTypeElement[] elements = parameterList.getTypeParameterElements();
              if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) {
                result = TypeConversionUtil.erasure(result);
              }
            }
          }
        }
      }
    }
    return result;
  }
Ejemplo n.º 7
0
  public static void replaceMovedMemberTypeParameters(
      final PsiElement member,
      final Iterable<PsiTypeParameter> parametersIterable,
      final PsiSubstitutor substitutor,
      final GroovyPsiElementFactory factory) {
    final Map<PsiElement, PsiElement> replacement = new LinkedHashMap<PsiElement, PsiElement>();
    for (PsiTypeParameter parameter : parametersIterable) {
      PsiType substitutedType = substitutor.substitute(parameter);
      if (substitutedType == null) {
        substitutedType = TypeConversionUtil.erasure(factory.createType(parameter));
      }

      PsiElement scopeElement = member instanceof GrField ? member.getParent() : member;
      for (PsiReference reference :
          ReferencesSearch.search(parameter, new LocalSearchScope(scopeElement))) {
        final PsiElement element = reference.getElement();
        final PsiElement parent = element.getParent();
        if (parent instanceof PsiTypeElement) {
          replacement.put(parent, factory.createTypeElement(substitutedType));
        } else if (element instanceof GrCodeReferenceElement
            && substitutedType instanceof PsiClassType) {
          replacement.put(
              element, factory.createReferenceElementByType((PsiClassType) substitutedType));
        }
      }
    }

    for (PsiElement element : replacement.keySet()) {
      if (element.isValid()) {
        element.replace(replacement.get(element));
      }
    }
  }
 @Nullable
 private static PsiType getTypeFromMapAccess(@NotNull GrReferenceExpressionImpl ref) {
   // map access
   GrExpression qualifier = ref.getQualifierExpression();
   if (qualifier != null) {
     PsiType qType = qualifier.getNominalType();
     if (qType instanceof PsiClassType) {
       PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics();
       PsiClass clazz = qResult.getElement();
       if (clazz != null) {
         PsiClass mapClass =
             JavaPsiFacade.getInstance(ref.getProject())
                 .findClass(CommonClassNames.JAVA_UTIL_MAP, ref.getResolveScope());
         if (mapClass != null && mapClass.getTypeParameters().length == 2) {
           PsiSubstitutor substitutor =
               TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
           if (substitutor != null) {
             return TypeConversionUtil.erasure(
                 substitutor.substitute(mapClass.getTypeParameters()[1]));
           }
         }
       }
     }
   }
   return null;
 }
 @Nullable
 private static PsiType getInferredTypes(
     GrReferenceExpressionImpl refExpr, @Nullable PsiElement resolved) {
   final GrExpression qualifier = refExpr.getQualifier();
   if (qualifier == null && !(resolved instanceof PsiClass)) {
     return TypeInferenceHelper.getCurrentContext().getVariableType(refExpr);
   } else if (qualifier != null) {
     // map access
     PsiType qType = qualifier.getType();
     if (qType instanceof PsiClassType && !(qType instanceof GrMapType)) {
       PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics();
       PsiClass clazz = qResult.getElement();
       if (clazz != null) {
         PsiClass mapClass =
             JavaPsiFacade.getInstance(refExpr.getProject())
                 .findClass(CommonClassNames.JAVA_UTIL_MAP, refExpr.getResolveScope());
         if (mapClass != null && mapClass.getTypeParameters().length == 2) {
           PsiSubstitutor substitutor =
               TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
           if (substitutor != null) {
             return TypeConversionUtil.erasure(
                 substitutor.substitute(mapClass.getTypeParameters()[1]));
           }
         }
       }
     }
   }
   return null;
 }
  private PsiType addBounds(PsiType substituted, final PsiTypeParameter typeParameter) {
    PsiElement captureContext = null;
    if (substituted instanceof PsiCapturedWildcardType) {
      final PsiCapturedWildcardType captured = (PsiCapturedWildcardType) substituted;
      substituted = captured.getWildcard();
      captureContext = captured.getContext();
    }
    if (substituted instanceof PsiWildcardType && !((PsiWildcardType) substituted).isSuper()) {
      PsiType originalBound = ((PsiWildcardType) substituted).getBound();
      PsiManager manager = typeParameter.getManager();
      final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
      for (PsiType boundType : boundTypes) {
        PsiType substitutedBoundType = boundType.accept(mySimpleSubstitutionVisitor);
        PsiWildcardType wildcardType = (PsiWildcardType) substituted;
        if (substitutedBoundType != null
            && !(substitutedBoundType instanceof PsiWildcardType)
            && !substitutedBoundType.equalsToText("java.lang.Object")) {
          if (originalBound == null
              || (!TypeConversionUtil.erasure(substitutedBoundType)
                      .isAssignableFrom(TypeConversionUtil.erasure(originalBound))
                  && !TypeConversionUtil.erasure(substitutedBoundType)
                      .isAssignableFrom(
                          originalBound))) { // erasure is essential to avoid infinite recursion
            if (wildcardType.isExtends()) {
              final PsiType glb =
                  GenericsUtil.getGreatestLowerBound(wildcardType.getBound(), substitutedBoundType);
              if (glb != null) {
                substituted = PsiWildcardType.createExtends(manager, glb);
              }
            } else {
              // unbounded
              substituted = PsiWildcardType.createExtends(manager, substitutedBoundType);
            }
          }
        }
      }
    }

    if (captureContext != null) {
      LOG.assertTrue(substituted instanceof PsiWildcardType);
      substituted = PsiCapturedWildcardType.create((PsiWildcardType) substituted, captureContext);
    }
    return substituted;
  }
    private static PsiType doFun(GrReferenceExpression refExpr) {
      if (ResolveUtil.isClassReference(refExpr)) {
        GrExpression qualifier = refExpr.getQualifier();
        LOG.assertTrue(qualifier != null);
        return TypesUtil.createJavaLangClassType(
            qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope());
      }

      if (PsiUtil.isCompileStatic(refExpr)) {
        final GroovyResolveResult resolveResult = refExpr.advancedResolve();
        final PsiElement resolvedF = resolveResult.getElement();
        final PsiType type;
        if (resolvedF instanceof GrField) {
          type = ((GrField) resolvedF).getType();
        } else if (resolvedF instanceof GrAccessorMethod) {
          type = ((GrAccessorMethod) resolvedF).getProperty().getType();
        } else {
          type = null;
        }
        if (type != null) {
          return resolveResult.getSubstitutor().substitute(type);
        }
      }

      final PsiElement resolved = refExpr.resolve();
      final PsiType nominal = refExpr.getNominalType();

      Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr);
      if (reassigned != null && reassigned.booleanValue()) {
        return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true);
      }

      final PsiType inferred = getInferredTypes(refExpr, resolved);
      if (inferred == null) {
        if (nominal == null) {
          // inside nested closure we could still try to infer from variable initializer. Not sound,
          // but makes sense
          if (resolved instanceof GrVariable) {
            LOG.assertTrue(resolved.isValid());
            return ((GrVariable) resolved).getTypeGroovy();
          }
        }

        return nominal;
      }

      if (nominal == null) return inferred;
      if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) {
        if (resolved instanceof GrVariable
            && ((GrVariable) resolved).getTypeElementGroovy() != null) {
          return nominal;
        }
      }
      return inferred;
    }
 @NotNull
 private MethodResolverProcessor createMethodProcessor(
     boolean allVariants,
     @Nullable String name,
     final boolean byShape,
     @Nullable GrExpression upToArgument) {
   final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument, byShape);
   if (byShape && argTypes != null) {
     for (int i = 0; i < argTypes.length; i++) {
       argTypes[i] = TypeConversionUtil.erasure(argTypes[i]);
     }
   }
   PsiType qualifierType = PsiImplUtil.getQualifierType(this);
   return new MethodResolverProcessor(
       name, this, false, qualifierType, argTypes, getTypeArguments(), allVariants, byShape);
 }
Ejemplo n.º 13
0
 @SuppressWarnings({"HardCodedStringLiteral"})
 private static void appendJVMSignature(JVMNameBuffer buffer, PsiType type) {
   if (type == null) {
     return;
   }
   final PsiType psiType = TypeConversionUtil.erasure(type);
   if (psiType instanceof PsiArrayType) {
     buffer.append(new JVMRawText("["));
     appendJVMSignature(buffer, ((PsiArrayType) psiType).getComponentType());
   } else if (psiType instanceof PsiClassType) {
     final JVMName jvmName = getJVMQualifiedName(psiType);
     appendJvmClassQualifiedName(buffer, jvmName);
   } else if (psiType instanceof PsiPrimitiveType) {
     buffer.append(getPrimitiveSignature(psiType.getCanonicalText()));
   } else {
     LOG.error("unknown type " + type.getCanonicalText());
   }
 }
 @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;
 }
    @Nullable
    public PsiType fun(GrReferenceExpressionImpl refExpr) {
      PsiType result = GrReassignedLocalVarsChecker.checkReassignedVar(refExpr, true);
      if (result != null) return result;

      if (GrUnresolvedAccessInspection.isClassReference(refExpr)) {
        GrExpression qualifier = refExpr.getQualifier();
        LOG.assertTrue(qualifier != null);
        return TypesUtil.createJavaLangClassType(
            qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope());
      }

      final PsiElement resolved = refExpr.resolve();
      final PsiType inferred = getInferredTypes(refExpr, resolved);
      final PsiType nominal = refExpr.getNominalType();
      if (inferred == null || PsiType.NULL.equals(inferred)) {
        if (nominal == null) {
          // inside nested closure we could still try to infer from variable initializer. Not sound,
          // but makes sense
          if (resolved instanceof GrVariable) {
            LOG.assertTrue(resolved.isValid());
            return ((GrVariable) resolved).getTypeGroovy();
          }
        }

        return nominal;
      }

      if (nominal == null) return inferred;
      if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) {
        if (resolved instanceof GrVariable
            && ((GrVariable) resolved).getTypeElementGroovy() != null) {
          return nominal;
        }
      }
      return inferred;
    }
    @Nullable
    private static PsiType getResultType(
        PsiMethodCallExpression call,
        PsiReferenceExpression methodExpression,
        JavaResolveResult result,
        @NotNull final LanguageLevel languageLevel) {
      final PsiMethod method = (PsiMethod) result.getElement();
      if (method == null) return null;

      boolean is15OrHigher = languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0;
      final PsiType getClassReturnType =
          PsiTypesUtil.patchMethodGetClassReturnType(
              call,
              methodExpression,
              method,
              new Condition<IElementType>() {
                @Override
                public boolean value(IElementType type) {
                  return type != JavaElementType.CLASS;
                }
              },
              languageLevel);

      if (getClassReturnType != null) {
        return getClassReturnType;
      }

      PsiType ret = method.getReturnType();
      if (ret == null) return null;
      if (ret instanceof PsiClassType) {
        ret = ((PsiClassType) ret).setLanguageLevel(languageLevel);
      }
      if (is15OrHigher) {
        return captureReturnType(call, method, ret, result, languageLevel);
      }
      return TypeConversionUtil.erasure(ret);
    }
Ejemplo n.º 17
0
 public static PsiType unboxPrimitiveTypeWrapperAndEraseGenerics(PsiType result) {
   return TypeConversionUtil.erasure(unboxPrimitiveTypeWrapper(result));
 }
Ejemplo n.º 18
0
 @NotNull
 public static GrImmediateClosureParameterImpl createErasedParameter(@NotNull PsiParameter param) {
   PsiType type = TypeConversionUtil.erasure(param.getType());
   return new GrImmediateClosureParameterImpl(
       type, getParameterName(param), isParameterOptional(param), getDefaultInitializer(param));
 }
  // This methods works equally well for primary usages as well as for propagated callers' usages
  private static void fixActualArgumentsList(
      PsiExpressionList list,
      JavaChangeInfo changeInfo,
      boolean toInsertDefaultValue,
      PsiSubstitutor substitutor)
      throws IncorrectOperationException {
    final PsiElementFactory factory =
        JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
    if (changeInfo.isParameterSetOrOrderChanged()) {
      if (changeInfo instanceof JavaChangeInfoImpl
          && ((JavaChangeInfoImpl) changeInfo).isPropagationEnabled) {
        final ParameterInfoImpl[] createdParmsInfo =
            ((JavaChangeInfoImpl) changeInfo).getCreatedParmsInfoWithoutVarargs();
        for (ParameterInfoImpl info : createdParmsInfo) {
          PsiExpression newArg;
          if (toInsertDefaultValue) {
            newArg = createDefaultValue(changeInfo, factory, info, list);
          } else {
            newArg = factory.createExpressionFromText(info.getName(), list);
          }
          JavaCodeStyleManager.getInstance(list.getProject())
              .shortenClassReferences(list.add(newArg));
        }
      } else {
        final PsiExpression[] args = list.getExpressions();
        final int nonVarargCount = getNonVarargCount(changeInfo, args);
        final int varargCount = args.length - nonVarargCount;
        if (varargCount < 0) return;
        PsiExpression[] newVarargInitializers = null;

        final int newArgsLength;
        final int newNonVarargCount;
        final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
        if (changeInfo.isArrayToVarargs()) {
          newNonVarargCount = newParms.length - 1;
          final JavaParameterInfo lastNewParm = newParms[newParms.length - 1];
          final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()];
          if (arrayToConvert instanceof PsiNewExpression) {
            final PsiNewExpression expression = (PsiNewExpression) arrayToConvert;
            final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
            if (arrayInitializer != null) {
              newVarargInitializers = arrayInitializer.getInitializers();
            }
          }
          newArgsLength =
              newVarargInitializers == null
                  ? newParms.length
                  : newNonVarargCount + newVarargInitializers.length;
        } else if (changeInfo.isRetainsVarargs()) {
          newNonVarargCount = newParms.length - 1;
          newArgsLength = newNonVarargCount + varargCount;
        } else if (changeInfo.isObtainsVarags()) {
          newNonVarargCount = newParms.length - 1;
          newArgsLength = newNonVarargCount;
        } else {
          newNonVarargCount = newParms.length;
          newArgsLength = newParms.length;
        }

        String[] oldVarargs = null;
        if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) {
          oldVarargs = new String[varargCount];
          for (int i = nonVarargCount; i < args.length; i++) {
            oldVarargs[i - nonVarargCount] = args[i].getText();
          }
        }

        final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
        for (int i = 0; i < newNonVarargCount; i++) {
          if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) {
            PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager());
            if (type instanceof PsiArrayType) {
              type = substitutor.substitute(type);
              type = TypeConversionUtil.erasure(type);
              String typeText = type.getCanonicalText();
              if (type instanceof PsiEllipsisType) {
                typeText = typeText.replace("...", "[]");
              }
              String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}";
              newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod());
              continue;
            }
          }
          newArgs[i] =
              createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args);
        }
        if (changeInfo.isArrayToVarargs()) {
          if (newVarargInitializers == null) {
            newArgs[newNonVarargCount] =
                createActualArgument(
                    changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args);
          } else {
            System.arraycopy(
                newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
          }
        } else {
          final int newVarargCount = newArgsLength - newNonVarargCount;
          LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
          for (int i = newNonVarargCount; i < newArgsLength; i++) {
            final int oldIndex = newParms[newNonVarargCount].getOldIndex();
            if (oldIndex >= 0 && oldIndex != nonVarargCount) {
              newArgs[i] =
                  createActualArgument(
                      changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args);
            } else {
              System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
              break;
            }
          }
        }
        ChangeSignatureUtil.synchronizeList(
            list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm());
      }
    }
  }
  private Specifics isMoreSpecific(
      @NotNull MethodCandidateInfo info1,
      @NotNull MethodCandidateInfo info2,
      @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel,
      @NotNull LanguageLevel languageLevel) {
    PsiMethod method1 = info1.getElement();
    PsiMethod method2 = info2.getElement();
    final PsiClass class1 = method1.getContainingClass();
    final PsiClass class2 = method2.getContainingClass();

    final PsiParameter[] params1 = method1.getParameterList().getParameters();
    final PsiParameter[] params2 = method2.getParameterList().getParameters();

    final PsiTypeParameter[] typeParameters1 = method1.getTypeParameters();
    final PsiTypeParameter[] typeParameters2 = method2.getTypeParameters();
    final PsiSubstitutor classSubstitutor1 =
        info1.getSubstitutor(false); // substitutions for method type parameters will be ignored
    final PsiSubstitutor classSubstitutor2 = info2.getSubstitutor(false);

    final int max = Math.max(params1.length, params2.length);
    PsiType[] types1 = PsiType.createArray(max);
    PsiType[] types2 = PsiType.createArray(max);
    final boolean varargsPosition =
        applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS;
    for (int i = 0; i < max; i++) {
      ProgressManager.checkCanceled();
      PsiType type1 =
          params1.length > 0 ? params1[Math.min(i, params1.length - 1)].getType() : null;
      PsiType type2 =
          params2.length > 0 ? params2[Math.min(i, params2.length - 1)].getType() : null;
      if (varargsPosition) {
        if (type1 instanceof PsiEllipsisType
            && type2 instanceof PsiEllipsisType
            && params1.length == params2.length
            && class1 != null
            && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7)
                || ((PsiArrayType) type1)
                    .getComponentType()
                    .equalsToText(CommonClassNames.JAVA_LANG_OBJECT)
                || ((PsiArrayType) type2)
                    .getComponentType()
                    .equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) {
          type1 = ((PsiEllipsisType) type1).toArrayType();
          type2 = ((PsiEllipsisType) type2).toArrayType();
        } else {
          type1 =
              type1 instanceof PsiEllipsisType ? ((PsiArrayType) type1).getComponentType() : type1;
          type2 =
              type2 instanceof PsiEllipsisType ? ((PsiArrayType) type2).getComponentType() : type2;
        }
      }

      types1[i] = type1;
      types2[i] = type2;
    }

    boolean sameBoxing = true;
    int[] boxingHappened = new int[2];
    for (int i = 0; i < types1.length; i++) {
      ProgressManager.checkCanceled();
      PsiType type1 = classSubstitutor1.substitute(types1[i]);
      PsiType type2 = classSubstitutor2.substitute(types2[i]);
      PsiType argType = i < getActualParameterTypes().length ? getActualParameterTypes()[i] : null;

      boolean boxingInFirst = false;
      if (isBoxingHappened(argType, type1, languageLevel)) {
        boxingHappened[0] += 1;
        boxingInFirst = true;
      }

      boolean boxingInSecond = false;
      if (isBoxingHappened(argType, type2, languageLevel)) {
        boxingHappened[1] += 1;
        boxingInSecond = true;
      }
      sameBoxing &= boxingInFirst == boxingInSecond;
    }
    if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST;
    if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND;

    if (sameBoxing) {
      final PsiSubstitutor siteSubstitutor1 = info1.getSiteSubstitutor();
      final PsiSubstitutor siteSubstitutor2 = info2.getSiteSubstitutor();

      final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2);
      final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1);

      final PsiSubstitutor methodSubstitutor1 =
          calculateMethodSubstitutor(
              typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel);
      boolean applicable12 =
          isApplicableTo(
              types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2);

      final PsiSubstitutor methodSubstitutor2 =
          calculateMethodSubstitutor(
              typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel);
      boolean applicable21 =
          isApplicableTo(
              types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1);

      if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
        final boolean typeArgsApplicable12 =
            GenericsUtil.isTypeArgumentsApplicable(
                typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21);
        final boolean typeArgsApplicable21 =
            GenericsUtil.isTypeArgumentsApplicable(
                typeParameters2, methodSubstitutor2, myArgumentsList, !applicable12);

        if (!typeArgsApplicable12) {
          applicable12 = false;
        }

        if (!typeArgsApplicable21) {
          applicable21 = false;
        }
      }

      if (applicable12 || applicable21) {

        if (applicable12 && !applicable21) return Specifics.SECOND;
        if (applicable21 && !applicable12) return Specifics.FIRST;

        final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT);
        final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT);
        if (abstract1 && !abstract2) {
          return Specifics.SECOND;
        }
        if (abstract2 && !abstract1) {
          return Specifics.FIRST;
        }
      }

      if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)
          && myArgumentsList instanceof PsiExpressionList
          && (typeParameters1.length == 0 || typeParameters2.length == 0)) {
        boolean toCompareFunctional = false;
        if (types1.length > 0 && types2.length > 0) {
          for (int i = 0; i < getActualParametersLength(); i++) {
            final PsiType type1 = types1[Math.min(i, types1.length - 1)];
            final PsiType type2 = types2[Math.min(i, types2.length - 1)];
            // from 15.12.2.5 Choosing the Most Specific Method
            // In addition, a functional interface type S is more specific than a functional
            // interface type T for an expression exp
            // if T is not a subtype of S and one of the following conditions apply.
            if (LambdaUtil.isFunctionalType(type1)
                && !TypeConversionUtil.erasure(type1).isAssignableFrom(type2)
                && LambdaUtil.isFunctionalType(type2)
                && !TypeConversionUtil.erasure(type2).isAssignableFrom(type1)) {
              types1AtSite[Math.min(i, types1.length - 1)] = PsiType.NULL;
              types2AtSite[Math.min(i, types2.length - 1)] = PsiType.NULL;
              toCompareFunctional = true;
            }
          }
        }

        if (toCompareFunctional) {
          final boolean applicable12ignoreFunctionalType =
              isApplicableTo(
                  types2AtSite,
                  method1,
                  languageLevel,
                  varargsPosition,
                  calculateMethodSubstitutor(
                      typeParameters1,
                      method1,
                      siteSubstitutor1,
                      types1,
                      types2AtSite,
                      languageLevel),
                  null);
          final boolean applicable21ignoreFunctionalType =
              isApplicableTo(
                  types1AtSite,
                  method2,
                  languageLevel,
                  varargsPosition,
                  calculateMethodSubstitutor(
                      typeParameters2,
                      method2,
                      siteSubstitutor2,
                      types2,
                      types1AtSite,
                      languageLevel),
                  null);

          if (applicable12ignoreFunctionalType || applicable21ignoreFunctionalType) {
            Specifics specifics = null;
            for (int i = 0; i < getActualParametersLength(); i++) {
              if (types1AtSite[Math.min(i, types1.length - 1)] == PsiType.NULL
                  && types2AtSite[Math.min(i, types2.length - 1)] == PsiType.NULL) {
                Specifics specific =
                    isFunctionalTypeMoreSpecific(
                        info1, info2, ((PsiExpressionList) myArgumentsList).getExpressions()[i], i);
                if (specific == Specifics.NEITHER) {
                  specifics = Specifics.NEITHER;
                  break;
                }

                if (specifics == null) {
                  specifics = specific;
                } else if (specifics != specific) {
                  specifics = Specifics.NEITHER;
                  break;
                }
              }
            }

            if (!applicable12ignoreFunctionalType && applicable21ignoreFunctionalType) {
              return specifics == Specifics.FIRST ? Specifics.FIRST : Specifics.NEITHER;
            }

            if (!applicable21ignoreFunctionalType && applicable12ignoreFunctionalType) {
              return specifics == Specifics.SECOND ? Specifics.SECOND : Specifics.NEITHER;
            }

            return specifics;
          }
        }
      }
    } else if (varargsPosition) {
      final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]);
      final PsiType lastParamType2 = classSubstitutor2.substitute(types2[types1.length - 1]);
      final boolean assignable1 = TypeConversionUtil.isAssignable(lastParamType2, lastParamType1);
      final boolean assignable2 = TypeConversionUtil.isAssignable(lastParamType1, lastParamType2);
      if (assignable1 && !assignable2) {
        return Specifics.FIRST;
      }
      if (assignable2 && !assignable1) {
        return Specifics.SECOND;
      }
    }

    if (class1 != class2) {
      if (class2.isInheritor(class1, true) || class1.isInterface() && !class2.isInterface()) {
        if (MethodSignatureUtil.isSubsignature(
            method1.getSignature(info1.getSubstitutor(false)),
            method2.getSignature(info2.getSubstitutor(false)))) {
          return Specifics.SECOND;
        } else if (method1.hasModifierProperty(PsiModifier.STATIC)
            && method2.hasModifierProperty(PsiModifier.STATIC)
            && boxingHappened[0] == 0) {
          return Specifics.SECOND;
        }
      } else if (MethodSignatureUtil.areErasedParametersEqual(
              method1.getSignature(PsiSubstitutor.EMPTY),
              method2.getSignature(PsiSubstitutor.EMPTY))
          && MethodSignatureUtil.isSubsignature(
              method2.getSignature(info2.getSubstitutor(false)),
              method1.getSignature(info1.getSubstitutor(false)))) {
        return Specifics.FIRST;
      } else if (class1.isInheritor(class2, true) || class2.isInterface()) {
        if (method1.hasModifierProperty(PsiModifier.STATIC)
            && method2.hasModifierProperty(PsiModifier.STATIC)
            && boxingHappened[0] == 0) {
          return Specifics.FIRST;
        }
      }
    }

    final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1);
    final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2);
    if (raw1 ^ raw2) {
      return raw1 ? Specifics.SECOND : Specifics.FIRST;
    }

    final boolean varargs1 = info1.isVarargs();
    final boolean varargs2 = info2.isVarargs();
    if (varargs1 ^ varargs2) {
      return varargs1 ? Specifics.SECOND : Specifics.FIRST;
    }

    return Specifics.NEITHER;
  }
Ejemplo n.º 21
0
  public static boolean isAcceptable(
      PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) {
    if (leftType instanceof PsiIntersectionType) {
      for (PsiType conjunctType : ((PsiIntersectionType) leftType).getConjuncts()) {
        if (isAcceptable(lambdaExpression, conjunctType, checkReturnType)) return true;
      }
      return false;
    }
    final PsiClassType.ClassResolveResult resolveResult =
        PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(leftType));
    final PsiClass psiClass = resolveResult.getElement();
    if (psiClass instanceof PsiAnonymousClass) {
      return isAcceptable(
          lambdaExpression, ((PsiAnonymousClass) psiClass).getBaseClassType(), checkReturnType);
    }
    final MethodSignature methodSignature = getFunction(psiClass);
    if (methodSignature == null) return false;
    final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters();
    final PsiType[] parameterTypes = methodSignature.getParameterTypes();
    if (lambdaParameters.length != parameterTypes.length) return false;
    for (int lambdaParamIdx = 0, length = lambdaParameters.length;
        lambdaParamIdx < length;
        lambdaParamIdx++) {
      PsiParameter parameter = lambdaParameters[lambdaParamIdx];
      final PsiTypeElement typeElement = parameter.getTypeElement();
      if (typeElement != null) {
        final PsiType lambdaFormalType = typeElement.getType();
        final PsiType methodParameterType = parameterTypes[lambdaParamIdx];
        if (lambdaFormalType instanceof PsiPrimitiveType) {
          if (methodParameterType instanceof PsiPrimitiveType)
            return methodParameterType.equals(lambdaFormalType);
          return false;
        }

        if (!TypeConversionUtil.erasure(lambdaFormalType)
            .isAssignableFrom(
                TypeConversionUtil.erasure(
                    GenericsUtil.eliminateWildcards(
                        resolveResult
                            .getSubstitutor()
                            .substitute(
                                methodSignature
                                    .getSubstitutor()
                                    .substitute(methodParameterType)))))) {
          return false;
        }
      }
    }
    if (checkReturnType) {
      final String uniqueVarName =
          JavaCodeStyleManager.getInstance(lambdaExpression.getProject())
              .suggestUniqueVariableName("l", lambdaExpression, true);
      String canonicalText = leftType.getCanonicalText();
      if (leftType instanceof PsiEllipsisType) {
        canonicalText = ((PsiEllipsisType) leftType).toArrayType().getCanonicalText();
      }
      final PsiStatement assignmentFromText =
          JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
              .createStatementFromText(
                  canonicalText + " " + uniqueVarName + " = " + lambdaExpression.getText(),
                  lambdaExpression);
      final PsiLocalVariable localVariable =
          (PsiLocalVariable)
              ((PsiDeclarationStatement) assignmentFromText).getDeclaredElements()[0];
      LOG.assertTrue(psiClass != null);
      PsiType methodReturnType = getReturnType(psiClass, methodSignature);
      if (methodReturnType != null) {
        methodReturnType =
            resolveResult
                .getSubstitutor()
                .substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
        return LambdaHighlightingUtil.checkReturnTypeCompatible(
                (PsiLambdaExpression) localVariable.getInitializer(), methodReturnType)
            == null;
      }
    }
    return true;
  }
  // method1 has more general parameter types thn method2
  private boolean secondMethodIsPreferable(
      @NotNull PsiMethod method1,
      @NotNull PsiSubstitutor substitutor1,
      @Nullable PsiElement resolveContext1,
      @NotNull PsiMethod method2,
      @NotNull PsiSubstitutor substitutor2,
      @Nullable PsiElement resolveContext2) {
    if (!method1.getName().equals(method2.getName())) return false;

    final Boolean custom =
        GrMethodComparator.checkDominated(method1, substitutor1, method2, substitutor2, this);
    if (custom != null) return custom;

    PsiType[] argTypes = myArgumentTypes;
    if (method1 instanceof GrGdkMethod && method2 instanceof GrGdkMethod) {
      method1 = ((GrGdkMethod) method1).getStaticMethod();
      method2 = ((GrGdkMethod) method2).getStaticMethod();
      if (myArgumentTypes != null) {
        argTypes = PsiType.createArray(argTypes.length + 1);
        System.arraycopy(myArgumentTypes, 0, argTypes, 1, myArgumentTypes.length);
        argTypes[0] = myThisType;
      }
    }

    if (myIsConstructor && argTypes != null && argTypes.length == 1) {
      if (method1.getParameterList().getParametersCount() == 0) return true;
      if (method2.getParameterList().getParametersCount() == 0) return false;
    }

    PsiParameter[] params1 = method1.getParameterList().getParameters();
    PsiParameter[] params2 = method2.getParameterList().getParameters();
    if (argTypes == null && params1.length != params2.length) return false;

    if (params1.length < params2.length) {
      if (params1.length == 0) return false;
      final PsiType lastType = params1[params1.length - 1].getType(); // varargs applicability
      return lastType instanceof PsiArrayType;
    }

    for (int i = 0; i < params2.length; i++) {
      final PsiType ptype1 = params1[i].getType();
      final PsiType ptype2 = params2[i].getType();
      PsiType type1 = substitutor1.substitute(ptype1);
      PsiType type2 = substitutor2.substitute(ptype2);

      if (argTypes != null && argTypes.length > i) {
        PsiType argType = argTypes[i];
        if (argType != null) {
          final boolean converts1 =
              TypesUtil.isAssignableWithoutConversions(
                  TypeConversionUtil.erasure(type1), argType, myPlace);
          final boolean converts2 =
              TypesUtil.isAssignableWithoutConversions(
                  TypeConversionUtil.erasure(type2), argType, myPlace);
          if (converts1 != converts2) {
            return converts2;
          }

          // see groovy.lang.GroovyCallable
          if (TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_UTIL_CONCURRENT_CALLABLE)
              && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_RUNNABLE)) {
            if (InheritanceUtil.isInheritor(
                argType, GroovyCommonClassNames.GROOVY_LANG_GROOVY_CALLABLE)) return true;
          }
        }
      }

      if (!typesAgree(TypeConversionUtil.erasure(ptype1), TypeConversionUtil.erasure(ptype2)))
        return false;

      if (resolveContext1 != null && resolveContext2 == null) {
        return !(TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_LANG_OBJECT)
            && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_OBJECT));
      }

      if (resolveContext1 == null && resolveContext2 != null) {
        return true;
      }
    }

    if (!(method1 instanceof SyntheticElement) && !(method2 instanceof SyntheticElement)) {
      final PsiType returnType1 = substitutor1.substitute(method1.getReturnType());
      final PsiType returnType2 = substitutor2.substitute(method2.getReturnType());

      if (!TypesUtil.isAssignableWithoutConversions(returnType1, returnType2, myPlace)
          && TypesUtil.isAssignableWithoutConversions(returnType2, returnType1, myPlace)) {
        return false;
      }
    }

    return true;
  }
  private static PsiMethod generateDelegateMethod(
      PsiMethod method,
      PsiClass superClass,
      PsiSubstitutor substitutor,
      boolean keepParameterAnnotations) {
    final LightMethodBuilder builder =
        new LightMethodBuilder(
            superClass.getManager(), GroovyFileType.GROOVY_LANGUAGE, method.getName());
    builder.setContainingClass(superClass);
    builder.setMethodReturnType(substitutor.substitute(method.getReturnType()));
    builder.setNavigationElement(method);
    builder.addModifier(PsiModifier.PUBLIC);

    final PsiTypeParameter[] typeParameters = method.getTypeParameters();

    final PsiClass containingClass = method.getContainingClass();
    boolean isRaw =
        containingClass != null && PsiUtil.isRawSubstitutor(containingClass, substitutor);
    if (isRaw) {
      substitutor =
          JavaPsiFacade.getInstance(method.getProject())
              .getElementFactory()
              .createRawSubstitutor(substitutor, typeParameters);
    }

    if (!isRaw) {
      for (PsiTypeParameter typeParameter : typeParameters) {
        builder.addTypeParameter(typeParameter);
      }
    }

    final PsiParameter[] originalParameters = method.getParameterList().getParameters();

    for (int i = 0; i < originalParameters.length; i++) {
      PsiParameter originalParameter = originalParameters[i];
      PsiType type;
      if (isRaw) {
        type = TypeConversionUtil.erasure(substitutor.substitute(originalParameter.getType()));
      } else {
        type = substitutor.substitute(originalParameter.getType());
      }
      if (type == null) {
        type = PsiType.getJavaLangObject(superClass.getManager(), superClass.getResolveScope());
      }
      final LightParameter lightParameter =
          new LightParameter(
              StringUtil.notNullize(originalParameter.getName(), "p" + i),
              type,
              builder,
              JavaLanguage.INSTANCE);
      if (keepParameterAnnotations) {
        final PsiCompositeModifierList delegatingModifierList =
            new PsiCompositeModifierList(
                method.getManager(),
                Collections.singletonList(originalParameter.getModifierList()));
        lightParameter.setModifierList(delegatingModifierList);
      }
      builder.addParameter(lightParameter);
    }
    builder.setBaseIcon(JetgroovyIcons.Groovy.Method);

    return new DelegatedMethod(builder, method);
  }
 private PsiType getCategoryTargetType(PsiMethod method) {
   final PsiType parameterType = method.getParameterList().getParameters()[0].getType();
   return TypesUtil.boxPrimitiveType(
       TypeConversionUtil.erasure(parameterType), myPsiManager, myScope);
 }