private List<PsiType> matchingTypeParameters( PsiType[] paramVals, PsiTypeParameter[] params, ExpectedTypeInfo info) { PsiType type = info.getType(); int kind = info.getKind(); List<PsiType> result = new ArrayList<>(); for (int i = 0; i < paramVals.length; i++) { PsiType val = paramVals[i]; if (val != null) { switch (kind) { case ExpectedTypeInfo.TYPE_STRICTLY: if (val.equals(type)) result.add(myFactory.createType(params[i])); break; case ExpectedTypeInfo.TYPE_OR_SUBTYPE: if (type.isAssignableFrom(val)) result.add(myFactory.createType(params[i])); break; case ExpectedTypeInfo.TYPE_OR_SUPERTYPE: if (val.isAssignableFrom(type)) result.add(myFactory.createType(params[i])); break; } } } return result; }
@Override public void visitNewExpression(@NotNull PsiNewExpression expression) { if (!PsiUtil.isLanguageLevel5OrHigher(expression)) { return; } super.visitNewExpression(expression); final PsiType type = expression.getType(); if (type == null) { return; } final String canonicalText = type.getCanonicalText(); if (!cachedNumberTypes.contains(canonicalText)) { return; } final PsiClass aClass = ClassUtils.getContainingClass(expression); if (aClass != null && cachedNumberTypes.contains(aClass.getQualifiedName())) { return; } final PsiExpressionList argumentList = expression.getArgumentList(); if (argumentList == null) { return; } final PsiExpression[] arguments = argumentList.getExpressions(); if (arguments.length != 1) { return; } final PsiExpression argument = arguments[0]; final PsiType argumentType = argument.getType(); if (argumentType == null || argumentType.equalsToText("java.lang.String")) { return; } registerError(expression, expression); }
private void checkExpression(PsiExpression expression) { if (expression.getParent() instanceof PsiParenthesizedExpression) { return; } final PsiType expressionType = expression.getType(); if (expressionType == null) { return; } if (expressionType.getArrayDimensions() > 0) { // a horrible hack to get around what happens when you pass // an array to a vararg expression return; } if (TypeConversionUtil.isPrimitiveAndNotNull(expressionType)) { return; } final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(expressionType); if (unboxedType == null) { return; } final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false); if (expectedType == null) { return; } if (!TypeConversionUtil.isPrimitiveAndNotNull(expectedType)) { return; } if (!expectedType.isAssignableFrom(unboxedType)) { return; } registerError(expression, expression); }
@NotNull private String createConversionForExpression( @Nullable PsiExpression expression, @NotNull PsiType expectedType) { String conversion = ""; if (expression != null) { PsiType actualType = expression.getType(); boolean isPrimitiveTypeOrNull = actualType == null || Node.PRIMITIVE_TYPES.contains(actualType.getCanonicalText()); boolean isRef = (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression) expression).isQualified() || expression instanceof PsiMethodCallExpression); boolean containsQuestDot = expressionToExpression(expression).toKotlin().contains("?."); if (isPrimitiveTypeOrNull && isRef && containsQuestDot) { conversion += "!!"; } if (actualType != null) { if (isConversionNeeded(actualType, expectedType)) { conversion += getPrimitiveTypeConversion(expectedType.getCanonicalText()); } } } return conversion; }
@Nullable private static String formatTypeParameters( @NotNull final PsiSubstitutor substitutor, final PsiTypeParameter[] params) { final boolean space = showSpaceAfterComma(params[0]); StringBuilder buffer = new StringBuilder(); buffer.append("<"); for (int i = 0; i < params.length; i++) { final PsiTypeParameter param = params[i]; final PsiType type = substitutor.substitute(param); if (type == null) { return ""; } if (type instanceof PsiClassType && ((PsiClassType) type).getParameters().length > 0) { buffer.append(((PsiClassType) type).rawType().getPresentableText()).append("<...>"); } else { buffer.append(type.getPresentableText()); } if (i < params.length - 1) { buffer.append(","); if (space) { buffer.append(" "); } } } buffer.append(">"); return buffer.toString(); }
@Override public boolean isValid() { for (PsiType conjunct : myConjuncts) { if (!conjunct.isValid()) return false; } return true; }
@Override public boolean isValid() { for (PsiType type : mySubstitutionMap.values()) { if (type != null && !type.isValid()) return false; } return true; }
private void reportNullableReturns( DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors, @NotNull PsiElement block) { final PsiMethod method = getScopeMethod(block); if (method == null || NullableStuffInspectionBase.isNullableNotInferred(method, true)) return; boolean notNullRequired = NullableNotNullManager.isNotNull(method); if (!notNullRequired && !SUGGEST_NULLABLE_ANNOTATIONS) return; PsiType returnType = method.getReturnType(); // no warnings in void lambdas, where the expression is not returned anyway if (block instanceof PsiExpression && block.getParent() instanceof PsiLambdaExpression && returnType == PsiType.VOID) return; // no warnings for Void methods, where only null can be possibly returned if (returnType == null || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID)) return; for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) { assert statement instanceof PsiExpression; final PsiExpression expr = (PsiExpression) statement; if (!reportedAnchors.add(expr)) continue; if (notNullRequired) { final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.return.null.from.notnull") : InspectionsBundle.message("dataflow.message.return.nullable.from.notnull"); holder.registerProblem(expr, text); } else if (AnnotationUtil.isAnnotatingApplicable(statement)) { final NullableNotNullManager manager = NullableNotNullManager.getInstance(expr.getProject()); final String defaultNullable = manager.getDefaultNullable(); final String presentableNullable = StringUtil.getShortName(defaultNullable); final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message( "dataflow.message.return.null.from.notnullable", presentableNullable) : InspectionsBundle.message( "dataflow.message.return.nullable.from.notnullable", presentableNullable); final LocalQuickFix[] fixes = PsiTreeUtil.getParentOfType(expr, PsiMethod.class, PsiLambdaExpression.class) instanceof PsiLambdaExpression ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[] { new AnnotateMethodFix( defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) { @Override public int shouldAnnotateBaseMethod( PsiMethod method, PsiMethod superMethod, Project project) { return 1; } } }; holder.registerProblem(expr, text, fixes); } } }
private static void generateNamesForCollectionType( PsiType type, Set<String> possibleNames, NameValidator validator) { PsiType componentType = getCollectionComponentType(type, validator.getProject()); if (!(type instanceof PsiClassType) || componentType == null) return; PsiClass clazz = ((PsiClassType) type).resolve(); if (clazz == null) return; String collectionName = clazz.getName(); assert collectionName != null; String componentName = cleanTypeName(componentType.getPresentableText()); if (componentType instanceof PsiClassType) { PsiClassType classType = (PsiClassType) componentType; PsiClass psiClass = classType.resolve(); if (psiClass == null) return; componentName = psiClass.getName(); } assert componentName != null; String candidateName = StringUtil.pluralize(GroovyNamesUtil.fromLowerLetter(componentName)); generateCamelNames(possibleNames, validator, candidateName); ArrayList<String> camelizedName = GroovyNamesUtil.camelizeString(candidateName); candidateName = camelizedName.get(camelizedName.size() - 1); candidateName = collectionName.toLowerCase() + "Of" + fromUpperLetter(candidateName); possibleNames.add(validator.validateName(candidateName, true)); }
@Nullable private static PsiType doNormalizeWildcardByPosition( final PsiType type, final GrExpression expression, final GrExpression toplevel) { if (type instanceof PsiCapturedWildcardType) { return doNormalizeWildcardByPosition( ((PsiCapturedWildcardType) type).getWildcard(), expression, toplevel); } if (type instanceof PsiWildcardType) { final PsiWildcardType wildcardType = (PsiWildcardType) type; if (PsiUtil.isAccessedForWriting(toplevel)) { return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression); } else { if (wildcardType.isExtends()) { return wildcardType.getBound(); } else { return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope()); } } } else if (type instanceof PsiArrayType) { final PsiType componentType = ((PsiArrayType) type).getComponentType(); final PsiType normalizedComponentType = doNormalizeWildcardByPosition(componentType, expression, toplevel); if (normalizedComponentType != componentType) { assert normalizedComponentType != null; return normalizedComponentType.createArrayType(); } } return type; }
@Override public void visitBinaryExpression(GrBinaryExpression expression) { final IElementType type = expression.getOperationTokenType(); final GrExpression left = expression.getLeftOperand(); final GrExpression right = expression.getRightOperand(); if (type == mREGEX_FIND || type == mREGEX_MATCH) { final PsiClassType string = TypesUtil.createType(CommonClassNames.JAVA_LANG_STRING, expression); myResult = createSimpleSubTypeResult(string); return; } final GrExpression other = myExpression == left ? right : left; final PsiType otherType = other != null ? other.getType() : null; if (otherType == null) return; if (type == mPLUS && otherType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { final PsiClassType obj = TypesUtil.getJavaLangObject(expression); myResult = createSimpleSubTypeResult(obj); return; } myResult = createSimpleSubTypeResult(otherType); }
private static boolean isCatchParameterRedundant( PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) { for (PsiType exceptionType : thrownTypes) { if (exceptionType.isConvertibleFrom(catchParamType)) return false; } return true; }
@Override protected String buildErrorString(Object... args) { PsiType ltype = (PsiType) args[0]; PsiType rtype = (PsiType) args[1]; return GroovyInspectionBundle.message( "rtype.cannot.contain.ltype", ltype.getPresentableText(), rtype.getPresentableText()); }
@Override protected void addCompletions( @NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { final PsiElement context = parameters.getPosition(); final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context); if (pair == null) return; PsiExpression expression = PsiTreeUtil.getContextOfType(context, PsiExpression.class, true); if (expression != null) { ExpectedTypeInfo[] types = ExpectedTypesProvider.getExpectedTypes(expression, true, false, false); if (types.length > 0) { for (ExpectedTypeInfo info : types) { PsiType type = info.getType(); if (type instanceof PsiClassType && !type.equals(expression.getType())) { fillExpectedTypeArgs( resultSet, context, pair.first, pair.second, ((PsiClassType) type).resolveGenerics(), mySmart ? info.getTailType() : TailType.NONE); } } return; } } if (mySmart) { addInheritors(parameters, resultSet, pair.first, pair.second); } }
@Override @NotNull protected String buildErrorString(Object... infos) { final PsiType expectedType = (PsiType) infos[0]; final String typeText = expectedType.getPresentableText(); return InspectionGadgetsBundle.message("overly.strong.type.cast.problem.descriptor", typeText); }
private static Map<String, PsiType> getCompatibleTypeNames( @NotNull PsiType type, @Nullable PsiType min, PsiManager manager, GlobalSearchScope scope) { if (type instanceof PsiDisjunctionType) type = ((PsiDisjunctionType) type).getLeastUpperBound(); // if initial type is not assignable to min type we don't take into consideration min type. if (min != null && !TypesUtil.isAssignable(min, type, manager, scope)) { min = null; } Map<String, PsiType> map = new LinkedHashMap<String, PsiType>(); final PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(type); if (unboxed != null) type = unboxed; final Set<PsiType> set = new LinkedHashSet<PsiType>(); set.add(type); while (!set.isEmpty()) { PsiType cur = set.iterator().next(); set.remove(cur); if (!map.containsValue(cur) && (min == null || TypesUtil.isAssignable(min, cur, manager, scope))) { if (isPartiallySubstituted(cur)) { LOG.assertTrue(cur instanceof PsiClassType); PsiClassType rawType = ((PsiClassType) cur).rawType(); map.put(rawType.getPresentableText(), rawType); } else { map.put(cur.getPresentableText(), cur); } for (PsiType superType : cur.getSuperTypes()) { if (!map.containsValue(superType)) { set.add(superType); } } } } return map; }
@Override @NotNull public String buildErrorString(Object... infos) { final PsiType type = (PsiType) infos[0]; final String typeName = type.getPresentableText(); return InspectionGadgetsBundle.message("stringbuffer.field.problem.descriptor", typeName); }
@Nullable private static String getTypeText(GrVariable var) { final PsiType type = var.getTypeGroovy(); if (type == null) return null; return type.getCanonicalText(); }
@Override public PsiType fun(GrMethodBaseImpl method) { PsiType nominal = method.getNominalType(); if (nominal != null) { if (!(nominal instanceof PsiClassType && hasTypeParametersToInfer((PsiClassType) nominal))) { return nominal; } } if (!GppTypeConverter.hasTypedContext(method)) { LOG.assertTrue(method.isValid(), "invalid method"); final GrOpenBlock block = method.getBlock(); if (block != null) { LOG.assertTrue(block.isValid(), "invalid code block"); PsiType inferred = GroovyPsiManager.inferType(method, new MethodTypeInferencer(block)); if (inferred != null) { if (nominal == null || nominal.isAssignableFrom(inferred)) { return inferred; } } } } if (nominal != null) { return nominal; } return TypesUtil.getJavaLangObject(method); }
@Nullable @Override public Boolean visitWildcardType(PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); if (bound != null) return bound.accept(this); return false; }
public static boolean haveConstructorsGenericsParameters(@NotNull final PsiClass psiClass) { for (PsiMethod method : psiClass.getConstructors()) { for (PsiParameter parameter : method.getParameterList().getParameters()) { final PsiType type = parameter.getType(); final Boolean accept = type.accept( new PsiTypeVisitor<Boolean>() { @Override public Boolean visitArrayType(PsiArrayType arrayType) { return arrayType.getComponentType().accept(this); } @Override public Boolean visitClassType(PsiClassType classType) { for (PsiType psiType : classType.getParameters()) { if (psiType != null) { final Boolean typaParamFound = psiType.accept(this); if (typaParamFound != null && typaParamFound) return true; } } return PsiUtil.resolveClassInType(classType) instanceof PsiTypeParameter; } @Override public Boolean visitWildcardType(PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); if (bound == null) return false; return bound.accept(this); } }); if (accept != null && accept.booleanValue()) return true; } } return false; }
public String calcGenerics(@NotNull PsiElement context, InsertionContext insertionContext) { if (insertionContext.getCompletionChar() == '<') { return ""; } assert context.isValid(); if (myDiamond) { return "<>"; } if (getObject() instanceof PsiClass) { PsiClass psiClass = (PsiClass) getObject(); PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(psiClass.getProject()).getResolveHelper(); PsiSubstitutor substitutor = getSubstitutor(); StringBuilder builder = new StringBuilder(); for (PsiTypeParameter parameter : psiClass.getTypeParameters()) { PsiType substitute = substitutor.substitute(parameter); if (substitute == null || (PsiUtil.resolveClassInType(substitute) == parameter && resolveHelper.resolveReferencedClass(parameter.getName(), context) != CompletionUtil.getOriginalOrSelf(parameter))) { return ""; } if (builder.length() > 0) { builder.append(", "); } builder.append(substitute.getCanonicalText()); } if (builder.length() > 0) { return "<" + builder + ">"; } } return ""; }
@Nullable private static String getTypeName(PsiType type, boolean withIndices) { type = type.getDeepComponentType(); if (type instanceof PsiClassType) { final PsiClassType classType = (PsiClassType) type; final String className = classType.getClassName(); if (className != null || !withIndices) return className; final PsiClass aClass = classType.resolve(); return aClass instanceof PsiAnonymousClass ? ((PsiAnonymousClass) aClass).getBaseClassType().getClassName() : null; } else if (type instanceof PsiPrimitiveType) { return type.getPresentableText(); } else if (type instanceof PsiWildcardType) { return getTypeName(((PsiWildcardType) type).getExtendsBound(), withIndices); } else if (type instanceof PsiIntersectionType) { return getTypeName(((PsiIntersectionType) type).getRepresentative(), withIndices); } else if (type instanceof PsiCapturedWildcardType) { return getTypeName(((PsiCapturedWildcardType) type).getWildcard(), withIndices); } else if (type instanceof PsiDisjunctionType) { return getTypeName(((PsiDisjunctionType) type).getLeastUpperBound(), withIndices); } else { return null; } }
public static boolean areSignaturesEqualLightweight( @NotNull MethodSignature sig1, @NotNull MethodSignature sig2) { final boolean isConstructor1 = sig1.isConstructor(); final boolean isConstructor2 = sig2.isConstructor(); if (isConstructor1 != isConstructor2) return false; if (!isConstructor1 || !(sig1 instanceof HierarchicalMethodSignature || sig2 instanceof HierarchicalMethodSignature)) { final String name1 = sig1.getName(); final String name2 = sig2.getName(); if (!name1.equals(name2)) return false; } final PsiType[] parameterTypes1 = sig1.getParameterTypes(); final PsiType[] parameterTypes2 = sig2.getParameterTypes(); if (parameterTypes1.length != parameterTypes2.length) return false; // optimization: check for really different types in method parameters for (int i = 0; i < parameterTypes1.length; i++) { final PsiType type1 = parameterTypes1[i]; final PsiType type2 = parameterTypes2[i]; if (type1 instanceof PsiPrimitiveType != type2 instanceof PsiPrimitiveType) return false; if (type1 instanceof PsiPrimitiveType && !type1.equals(type2)) return false; } return true; }
public static boolean canBeMigrated(final PsiElement e) { if (e == null) { return false; } final PsiElement element = normalizeElement(e); if (!element.getManager().isInProject(element)) { return false; } final PsiType type = TypeMigrationLabeler.getElementType(element); if (type != null) { final PsiType elemenType = type instanceof PsiArrayType ? type.getDeepComponentType() : type; if (elemenType instanceof PsiPrimitiveType) { return !elemenType.equals(PsiType.VOID); } final PsiClass aClass = ((PsiClassType) elemenType).resolve(); return aClass != null /* && !aClass.hasTypeParameters()*/; } return false; }
public static String[] getParameterString(ExtractInfoHelper helper, boolean useCanonicalText) { int i = 0; ParameterInfo[] infos = helper.getParameterInfos(); int number = 0; for (ParameterInfo info : infos) { if (info.passAsParameter()) number++; } ArrayList<String> params = new ArrayList<String>(); for (ParameterInfo info : infos) { if (info.passAsParameter()) { PsiType paramType = info.getType(); final PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(paramType); if (unboxed != null) paramType = unboxed; String paramTypeText; if (paramType == null || paramType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { paramTypeText = ""; } else { paramTypeText = (useCanonicalText ? paramType.getCanonicalText() : paramType.getPresentableText()) + " "; } params.add(paramTypeText + info.getName() + (i < number - 1 ? ", " : "")); i++; } } return ArrayUtil.toStringArray(params); }
@Override public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) { final PsiType componentType = ellipsisType.getComponentType(); final PsiType substitutedComponentType = componentType.accept(this); if (substitutedComponentType == null) return null; if (substitutedComponentType == componentType) return ellipsisType; // optimization return new PsiEllipsisType(substitutedComponentType); }
public void testInferWithBounds1() throws Exception { PsiReferenceExpression ref = configure(); JavaResolveResult resolveResult = ref.advancedResolve(false); PsiSubstitutor substitutor = resolveResult.getSubstitutor(); PsiMethod method = (PsiMethod) resolveResult.getElement(); PsiType type = substitutor.substitute(method.getTypeParameters()[0]); assertEquals("java.lang.String", type.getCanonicalText()); }
@Override public PsiType visitArrayType(PsiArrayType arrayType) { final PsiType componentType = arrayType.getComponentType(); final PsiType substitutedComponentType = componentType.accept(this); if (substitutedComponentType == null) return null; if (substitutedComponentType == componentType) return arrayType; // optimization return new PsiArrayType(substitutedComponentType); }
@Override public boolean isValid() { Collection<PsiType> substitutorValues = mySubstitutionMap.values(); for (PsiType type : substitutorValues) { if (type != null && !type.isValid()) return false; } return true; }