private static boolean isAcceptableAnnotationValueType(PsiType type) { //noinspection ConstantConditions return type instanceof PsiPrimitiveType || type.equalsToText(CommonClassNames.JAVA_LANG_STRING) || type.equalsToText(CommonClassNames.JAVA_LANG_CLASS) || type instanceof PsiClassType && ((PsiClassType) type).resolve() != null && ((PsiClassType) type).resolve().isEnum(); }
public static boolean isInjectable(@Nullable final PsiType type, final Project project) { if (type == null) return false; if (type instanceof PsiPrimitiveType) return false; if (project.isDefault()) { @NonNls final String text = type.getPresentableText(); if (text == null) return false; return text.equals("java.lang.String") || text.equals("java.lang.String...") || text.equals("java.lang.String[]"); } else { return type.equalsToText("java.lang.String") || type.equalsToText("java.lang.String...") || type.equalsToText("java.lang.String[]"); } }
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); } } }
@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); }
@Override protected void initialize() { final PsiMethod method = (PsiMethod) getElement(); LOG.assertTrue(method != null); setConstructor(method.isConstructor()); final PsiType returnType = method.getReturnType(); setFlag( returnType == null || PsiType.VOID.equals(returnType) || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID), IS_RETURN_VALUE_USED_MASK); if (!isReturnValueUsed()) { myReturnValueTemplate = RETURN_VALUE_UNDEFINED; } if (isConstructor()) { addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null); } if (getOwnerClass().isInterface()) { setAbstract(false); } else { setAbstract(method.hasModifierProperty(PsiModifier.ABSTRACT)); } setAppMain(isAppMain(method, this)); setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE)); initializeSuperMethods(method); if (isExternalOverride()) { ((RefClassImpl) getOwnerClass()).addLibraryOverrideMethod(this); } @NonNls final String name = method.getName(); if (getOwnerClass().isTestCase() && name.startsWith("test")) { setTestMethod(true); } PsiParameter[] paramList = method.getParameterList().getParameters(); if (paramList.length > 0) { myParameters = new RefParameterImpl[paramList.length]; for (int i = 0; i < paramList.length; i++) { PsiParameter parameter = paramList[i]; myParameters[i] = getRefJavaManager().getParameterReference(parameter, i); } } if (method.hasModifierProperty(PsiModifier.NATIVE)) { updateReturnValueTemplate(null); updateThrowsList(null); } collectUncaughtExceptions(method); }
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; }
public boolean incorporate() { final Collection<InferenceVariable> inferenceVariables = mySession.getInferenceVariables(); final PsiSubstitutor substitutor = mySession.retrieveNonPrimitiveEqualsBounds(inferenceVariables); for (InferenceVariable inferenceVariable : inferenceVariables) { if (inferenceVariable.getInstantiation() != PsiType.NULL) continue; final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); eqEq(eqBounds); upDown(lowerBounds, upperBounds, substitutor); upDown(eqBounds, upperBounds, substitutor); upDown(lowerBounds, eqBounds, substitutor); upUp(upperBounds); } for (Pair<PsiTypeParameter[], PsiClassType> capture : myCaptures) { final PsiClassType right = capture.second; final PsiClass gClass = right.resolve(); LOG.assertTrue(gClass != null); final PsiTypeParameter[] parameters = capture.first; PsiType[] typeArgs = right.getParameters(); if (parameters.length != typeArgs.length) continue; for (int i = 0; i < typeArgs.length; i++) { PsiType aType = typeArgs[i]; if (aType instanceof PsiCapturedWildcardType) { aType = ((PsiCapturedWildcardType) aType).getWildcard(); } final InferenceVariable inferenceVariable = mySession.getInferenceVariable(parameters[i]); LOG.assertTrue(inferenceVariable != null); final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); if (aType instanceof PsiWildcardType) { for (PsiType eqBound : eqBounds) { if (!isInferenceVariableOrFreshTypeParameter(eqBound)) return false; } final PsiClassType[] paramBounds = inferenceVariable.getParameter().getExtendsListTypes(); PsiType glb = null; for (PsiClassType paramBound : paramBounds) { if (glb == null) { glb = paramBound; } else { glb = GenericsUtil.getGreatestLowerBound(glb, paramBound); } } if (!((PsiWildcardType) aType).isBounded()) { for (PsiType upperBound : upperBounds) { if (glb != null && mySession.getInferenceVariable(upperBound) == null) { addConstraint( new StrictSubtypingConstraint( upperBound, mySession.substituteWithInferenceVariables(glb))); } } for (PsiType lowerBound : lowerBounds) { if (isInferenceVariableOrFreshTypeParameter(lowerBound)) return false; } } else if (((PsiWildcardType) aType).isExtends()) { final PsiType extendsBound = ((PsiWildcardType) aType).getExtendsBound(); for (PsiType upperBound : upperBounds) { if (mySession.getInferenceVariable(upperBound) == null) { if (paramBounds.length == 1 && paramBounds[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || paramBounds.length == 0) { addConstraint(new StrictSubtypingConstraint(upperBound, extendsBound)); } else if (extendsBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && glb != null) { addConstraint( new StrictSubtypingConstraint( upperBound, mySession.substituteWithInferenceVariables(glb))); } } } for (PsiType lowerBound : lowerBounds) { if (isInferenceVariableOrFreshTypeParameter(lowerBound)) return false; } } else { LOG.assertTrue(((PsiWildcardType) aType).isSuper()); final PsiType superBound = ((PsiWildcardType) aType).getSuperBound(); for (PsiType upperBound : upperBounds) { if (glb != null && mySession.getInferenceVariable(upperBound) == null) { addConstraint( new StrictSubtypingConstraint( mySession.substituteWithInferenceVariables(glb), upperBound)); } } for (PsiType lowerBound : lowerBounds) { if (mySession.getInferenceVariable(lowerBound) == null) { addConstraint(new StrictSubtypingConstraint(lowerBound, superBound)); } } } } else { inferenceVariable.addBound(aType, InferenceBound.EQ); } } } return true; }
private ParameterInfoImpl[] getNewParametersInfo( PsiExpression[] expressions, PsiMethod targetMethod, PsiSubstitutor substitutor, final StringBuilder buf, final HashSet<ParameterInfoImpl> newParams, final HashSet<ParameterInfoImpl> removedParams, final HashSet<ParameterInfoImpl> changedParams) { PsiParameter[] parameters = targetMethod.getParameterList().getParameters(); List<ParameterInfoImpl> result = new ArrayList<ParameterInfoImpl>(); if (expressions.length < parameters.length) { // find which parameters to remove int ei = 0; int pi = 0; while (ei < expressions.length && pi < parameters.length) { PsiExpression expression = expressions[ei]; PsiParameter parameter = parameters[pi]; PsiType paramType = substitutor.substitute(parameter.getType()); if (buf.length() > 0) buf.append(", "); final PsiType parameterType = PsiUtil.convertAnonymousToBaseType(paramType); final String presentableText = escapePresentableType(parameterType); final ParameterInfoImpl parameterInfo = new ParameterInfoImpl(pi, parameter.getName(), parameter.getType()); if (TypeConversionUtil.areTypesAssignmentCompatible(paramType, expression)) { buf.append(presentableText); result.add(parameterInfo); pi++; ei++; } else { buf.append("<s>").append(presentableText).append("</s>"); removedParams.add(parameterInfo); pi++; } } if (result.size() != expressions.length) return null; for (int i = pi; i < parameters.length; i++) { if (buf.length() > 0) buf.append(", "); buf.append("<s>").append(escapePresentableType(parameters[i].getType())).append("</s>"); final ParameterInfoImpl parameterInfo = new ParameterInfoImpl(pi, parameters[i].getName(), parameters[i].getType()); removedParams.add(parameterInfo); } } else if (expressions.length > parameters.length) { if (!findNewParamsPlace( expressions, targetMethod, substitutor, buf, newParams, parameters, result)) return null; } else { // parameter type changed for (int i = 0; i < parameters.length; i++) { if (buf.length() > 0) buf.append(", "); PsiParameter parameter = parameters[i]; PsiExpression expression = expressions[i]; PsiType paramType = substitutor.substitute(parameter.getType()); final String presentableText = escapePresentableType(paramType); if (TypeConversionUtil.areTypesAssignmentCompatible(paramType, expression)) { result.add(new ParameterInfoImpl(i, parameter.getName(), paramType)); buf.append(presentableText); } else { if (PsiPolyExpressionUtil.isPolyExpression(expression)) return null; PsiType exprType = RefactoringUtil.getTypeByExpression(expression); if (exprType == null) return null; if (exprType instanceof PsiDisjunctionType) { exprType = ((PsiDisjunctionType) exprType).getLeastUpperBound(); } final ParameterInfoImpl changedParameterInfo = new ParameterInfoImpl(i, parameter.getName(), exprType); result.add(changedParameterInfo); changedParams.add(changedParameterInfo); buf.append("<s>") .append(presentableText) .append("</s> <b>") .append(escapePresentableType(exprType)) .append("</b>"); } } // do not perform silly refactorings boolean isSilly = true; for (int i = 0; i < result.size(); i++) { PsiParameter parameter = parameters[i]; PsiType paramType = substitutor.substitute(parameter.getType()); ParameterInfoImpl parameterInfo = result.get(i); String typeText = parameterInfo.getTypeText(); if (!paramType.equalsToText(typeText) && !paramType.getPresentableText().equals(typeText)) { isSilly = false; break; } } if (isSilly) return null; } return result.toArray(new ParameterInfoImpl[result.size()]); }
@NotNull private static PsiType getLeastUpperBound( PsiType type1, PsiType type2, Set<Pair<PsiType, PsiType>> compared, PsiManager manager) { if (type1 instanceof PsiCapturedWildcardType) { return getLeastUpperBound( ((PsiCapturedWildcardType) type1).getUpperBound(), type2, compared, manager); } if (type2 instanceof PsiCapturedWildcardType) { return getLeastUpperBound( type1, ((PsiCapturedWildcardType) type2).getUpperBound(), compared, manager); } if (type1 instanceof PsiWildcardType) { return getLeastUpperBound( ((PsiWildcardType) type1).getExtendsBound(), type2, compared, manager); } if (type2 instanceof PsiWildcardType) { return getLeastUpperBound( type1, ((PsiWildcardType) type2).getExtendsBound(), compared, manager); } if (type1 instanceof PsiArrayType && type2 instanceof PsiArrayType) { final PsiType componentType1 = ((PsiArrayType) type1).getComponentType(); final PsiType componentType2 = ((PsiArrayType) type2).getComponentType(); final PsiType componentType = getLeastUpperBound(componentType1, componentType2, compared, manager); if (componentType1 instanceof PsiPrimitiveType && componentType2 instanceof PsiPrimitiveType && componentType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); final GlobalSearchScope resolveScope = GlobalSearchScope.allScope(manager.getProject()); final PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, resolveScope); final PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, resolveScope); return PsiIntersectionType.createIntersection(componentType, cloneable, serializable); } return componentType.createArrayType(); } if (type1 instanceof PsiIntersectionType) { Set<PsiType> newConjuncts = new LinkedHashSet<PsiType>(); final PsiType[] conjuncts = ((PsiIntersectionType) type1).getConjuncts(); for (PsiType type : conjuncts) { newConjuncts.add(getLeastUpperBound(type, type2, compared, manager)); } return PsiIntersectionType.createIntersection( newConjuncts.toArray(PsiType.createArray(newConjuncts.size()))); } if (type2 instanceof PsiIntersectionType) { return getLeastUpperBound(type2, type1, compared, manager); } if (type1 instanceof PsiClassType && type2 instanceof PsiClassType) { PsiClassType.ClassResolveResult classResolveResult1 = ((PsiClassType) type1).resolveGenerics(); PsiClassType.ClassResolveResult classResolveResult2 = ((PsiClassType) type2).resolveGenerics(); PsiClass aClass = classResolveResult1.getElement(); PsiClass bClass = classResolveResult2.getElement(); if (aClass == null || bClass == null) { return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject())); } PsiClass[] supers = getLeastUpperClasses(aClass, bClass); if (supers.length == 0) { return PsiType.getJavaLangObject(manager, aClass.getResolveScope()); } PsiClassType[] conjuncts = new PsiClassType[supers.length]; for (int i = 0; i < supers.length; i++) { PsiClass aSuper = supers[i]; PsiSubstitutor subst1 = TypeConversionUtil.getSuperClassSubstitutor( aSuper, aClass, classResolveResult1.getSubstitutor()); PsiSubstitutor subst2 = TypeConversionUtil.getSuperClassSubstitutor( aSuper, bClass, classResolveResult2.getSubstitutor()); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) { PsiType mapping1 = subst1.substitute(parameter); PsiType mapping2 = subst2.substitute(parameter); if (mapping1 != null && mapping2 != null) { substitutor = substitutor.put( parameter, getLeastContainingTypeArgument( mapping1, mapping2, compared, manager, type1.equals(mapping1) && type2.equals(mapping2) ? aSuper : null, parameter)); } else { substitutor = substitutor.put(parameter, null); } } conjuncts[i] = JavaPsiFacade.getInstance(manager.getProject()) .getElementFactory() .createType(aSuper, substitutor); } return PsiIntersectionType.createIntersection(conjuncts); } if (type2 instanceof PsiArrayType && !(type1 instanceof PsiArrayType)) { return getLeastUpperBound(type2, type1, compared, manager); } if (type1 instanceof PsiArrayType) { PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); GlobalSearchScope all = GlobalSearchScope.allScope(manager.getProject()); PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, all); PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, all); PsiType arraySupers = PsiIntersectionType.createIntersection(serializable, cloneable); return getLeastUpperBound(arraySupers, type2, compared, manager); } return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject())); }