@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; }
@Override public boolean isValid() { for (PsiType conjunct : myConjuncts) { if (!conjunct.isValid()) return false; } return true; }
@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 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; }
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); } } }
@Nullable @Override public Boolean visitWildcardType(PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); if (bound != null) return bound.accept(this); return false; }
private static boolean isCatchParameterRedundant( PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) { for (PsiType exceptionType : thrownTypes) { if (exceptionType.isConvertibleFrom(catchParamType)) return false; } return true; }
@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; } }
@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); }
@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; }
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(); }
private static boolean isReturnTypeIsMoreSpecificThan( @NotNull HierarchicalMethodSignature thisSig, @NotNull HierarchicalMethodSignature thatSig) { PsiType thisRet = thisSig.getSubstitutor().substitute(thisSig.getMethod().getReturnType()); PsiType thatRet = thatSig.getSubstitutor().substitute(thatSig.getMethod().getReturnType()); return thatRet != null && thisRet != null && !thatRet.equals(thisRet) && TypeConversionUtil.isAssignable(thatRet, thisRet, false); }
private static PsiType createType(PsiClass cls, PsiSubstitutor currentSubstitutor, int arrayDim) { final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(cls.getProject()).getElementFactory(); PsiType newType = elementFactory.createType(cls, currentSubstitutor); for (int i = 0; i < arrayDim; i++) { newType = newType.createArrayType(); } return newType; }
@Override public String handleEmptyLookup( @NotNull final CompletionParameters parameters, final Editor editor) { if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null; final String ad = advertise(parameters); final String suffix = ad == null ? "" : "; " + StringUtil.decapitalize(ad); if (parameters.getCompletionType() == CompletionType.SMART) { if (!ApplicationManager.getApplication().isUnitTestMode()) { final Project project = parameters.getPosition().getProject(); final PsiFile file = parameters.getOriginalFile(); PsiExpression expression = PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true); if (expression != null && expression.getParent() instanceof PsiExpressionList) { int lbraceOffset = expression.getParent().getTextRange().getStartOffset(); ShowParameterInfoHandler.invoke(project, editor, file, lbraceOffset, null); } if (expression instanceof PsiLiteralExpression) { return LangBundle.message("completion.no.suggestions") + suffix; } if (expression instanceof PsiInstanceOfExpression) { final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) expression; if (PsiTreeUtil.isAncestor( instanceOfExpression.getCheckType(), parameters.getPosition(), false)) { return LangBundle.message("completion.no.suggestions") + suffix; } } } final Set<PsiType> expectedTypes = JavaCompletionUtil.getExpectedTypes(parameters); if (expectedTypes != null) { PsiType type = expectedTypes.size() == 1 ? expectedTypes.iterator().next() : null; if (type != null) { final PsiType deepComponentType = type.getDeepComponentType(); if (deepComponentType instanceof PsiClassType) { if (((PsiClassType) deepComponentType).resolve() != null) { return CompletionBundle.message( "completion.no.suggestions.of.type", type.getPresentableText()) + suffix; } return CompletionBundle.message("completion.unknown.type", type.getPresentableText()) + suffix; } if (!PsiType.NULL.equals(type)) { return CompletionBundle.message( "completion.no.suggestions.of.type", type.getPresentableText()) + suffix; } } } } return LangBundle.message("completion.no.suggestions") + suffix; }
public Boolean visitClassType(final PsiClassType classType) { final PsiClass aClass = classType.resolve(); if (aClass instanceof PsiTypeParameter && myTypeParams.contains((PsiTypeParameter) aClass)) return true; final PsiType[] types = classType.getParameters(); for (final PsiType psiType : types) { if (psiType.accept(this).booleanValue()) return true; } return false; }
@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); }
@Nullable private ExceptionInfo findCatch(PsiType thrownType) { final Iterator<ExceptionInfo> iterator = myCaughtExceptionInfos.descendingIterator(); while (iterator.hasNext()) { final ExceptionInfo info = iterator.next(); final GrCatchClause clause = info.myClause; final GrParameter parameter = clause.getParameter(); if (parameter != null) { final PsiType type = parameter.getType(); if (type.isAssignableFrom(thrownType)) return info; } } return null; }
private void suggestNamesForCollectionInheritors( final PsiType type, final VariableKind variableKind, final Collection<String> suggestions, final boolean correctKeywords) { PsiType componentType = PsiUtil.extractIterableTypeParameter(type, false); if (componentType == null || componentType.equals(type)) { return; } String typeName = normalizeTypeName(getTypeName(componentType)); if (typeName != null) { ContainerUtil.addAll( suggestions, getSuggestionsByName(typeName, variableKind, true, correctKeywords)); } }
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 static AllowedValues getAllowedValuesFromMagic( @NotNull PsiModifierListOwner element, @NotNull PsiType type, PsiAnnotation magic) { if (magic == null) return null; PsiAnnotationMemberValue[] allowedValues; final boolean canBeOred; if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.LONG_RANK) { PsiAnnotationMemberValue intValues = magic.findAttributeValue("intValues"); allowedValues = intValues instanceof PsiArrayInitializerMemberValue ? ((PsiArrayInitializerMemberValue) intValues).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY; if (allowedValues.length == 0) { PsiAnnotationMemberValue orValue = magic.findAttributeValue("flags"); allowedValues = orValue instanceof PsiArrayInitializerMemberValue ? ((PsiArrayInitializerMemberValue) orValue).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY; canBeOred = true; } else { canBeOred = false; } } else if (type.equals( PsiType.getJavaLangString( element.getManager(), GlobalSearchScope.allScope(element.getProject())))) { PsiAnnotationMemberValue strValuesAttr = magic.findAttributeValue("stringValues"); allowedValues = strValuesAttr instanceof PsiArrayInitializerMemberValue ? ((PsiArrayInitializerMemberValue) strValuesAttr).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY; canBeOred = false; } else { return null; // other types not supported } if (allowedValues.length != 0) { return new AllowedValues(allowedValues, canBeOred); } // last resort: try valuesFromClass PsiAnnotationMemberValue[] values = readFromClass("valuesFromClass", magic, type); boolean ored = false; if (values == null) { values = readFromClass("flagsFromClass", magic, type); ored = true; } if (values == null) return null; return new AllowedValues(values, ored); }
@Nullable private static String getLongTypeName(PsiType type) { if (type instanceof PsiClassType) { PsiClass aClass = ((PsiClassType) type).resolve(); if (aClass == null) { return null; } else if (aClass instanceof PsiAnonymousClass) { PsiClass baseClass = ((PsiAnonymousClass) aClass).getBaseClassType().resolve(); return baseClass != null ? baseClass.getQualifiedName() : null; } else { return aClass.getQualifiedName(); } } else if (type instanceof PsiArrayType) { return getLongTypeName(((PsiArrayType) type).getComponentType()) + "[]"; } else if (type instanceof PsiPrimitiveType) { return type.getPresentableText(); } else if (type instanceof PsiWildcardType) { final PsiType bound = ((PsiWildcardType) type).getBound(); return bound != null ? getLongTypeName(bound) : CommonClassNames.JAVA_LANG_OBJECT; } else if (type instanceof PsiCapturedWildcardType) { final PsiType bound = ((PsiCapturedWildcardType) type).getWildcard().getBound(); return bound != null ? getLongTypeName(bound) : CommonClassNames.JAVA_LANG_OBJECT; } else if (type instanceof PsiIntersectionType) { return getLongTypeName(((PsiIntersectionType) type).getRepresentative()); } else if (type instanceof PsiDisjunctionType) { return getLongTypeName(((PsiDisjunctionType) type).getLeastUpperBound()); } else { return null; } }
@Override public PsiType[] guessContainerElementType(PsiExpression containerExpr, TextRange rangeToIgnore) { HashSet<PsiType> typesSet = new HashSet<>(); PsiType type = containerExpr.getType(); PsiType elemType; if ((elemType = getGenericElementType(type)) != null) return new PsiType[] {elemType}; if (containerExpr instanceof PsiReferenceExpression) { PsiElement refElement = ((PsiReferenceExpression) containerExpr).resolve(); if (refElement instanceof PsiVariable) { PsiFile file = refElement.getContainingFile(); if (file == null) { file = containerExpr.getContainingFile(); // implicit variable in jsp } HashSet<PsiVariable> checkedVariables = new HashSet<>(); addTypesByVariable( typesSet, (PsiVariable) refElement, file, checkedVariables, CHECK_USAGE | CHECK_DOWN, rangeToIgnore); checkedVariables.clear(); addTypesByVariable( typesSet, (PsiVariable) refElement, file, checkedVariables, CHECK_UP, rangeToIgnore); } } return typesSet.toArray(PsiType.createArray(typesSet.size())); }
@NotNull public Type typeToType(@Nullable PsiType type) { if (type == null) return Type.EMPTY_TYPE; TypeVisitor typeVisitor = new TypeVisitor(this); type.accept(typeVisitor); return typeVisitor.getResult(); }
@Nullable private static String formatTypesList(ParameterInfoImpl[] infos, PsiElement context) { if (infos == null) return null; StringBuilder result = new StringBuilder(); try { for (ParameterInfoImpl info : infos) { PsiType type = info.createType(context); if (type == null) return null; if (result.length() != 0) result.append(", "); result.append(type.getPresentableText()); } return result.toString(); } catch (IncorrectOperationException e) { return null; } }
private String[] suggestVariableNameByType( PsiType type, final VariableKind variableKind, boolean correctKeywords) { String longTypeName = getLongTypeName(type); CodeStyleSettings.TypeToNameMap map = getMapByVariableKind(variableKind); if (map != null && longTypeName != null) { if (type.equals(PsiType.NULL)) { longTypeName = CommonClassNames.JAVA_LANG_OBJECT; } String name = map.nameByType(longTypeName); if (name != null && isIdentifier(name)) { return new String[] {name}; } } Collection<String> suggestions = new LinkedHashSet<String>(); suggestNamesForCollectionInheritors(type, variableKind, suggestions, correctKeywords); suggestNamesFromGenericParameters(type, variableKind, suggestions, correctKeywords); String typeName = normalizeTypeName(getTypeName(type)); if (typeName != null) { ContainerUtil.addAll( suggestions, getSuggestionsByName( typeName, variableKind, type instanceof PsiArrayType, correctKeywords)); } return ArrayUtil.toStringArray(suggestions); }
static boolean depends(PsiType type, TypeParamsChecker visitor, PsiTypeParameter... param2Check) { if (!visitor.startedInference()) return false; final Boolean accept = type.accept(visitor); if (param2Check.length > 0) { return visitor.used(param2Check); } return accept != null && accept.booleanValue(); }
@Override public Boolean visitClassType(PsiClassType classType) { boolean used = false; for (PsiType paramType : classType.getParameters()) { final Boolean paramAccepted = paramType.accept(this); used |= paramAccepted != null && paramAccepted.booleanValue(); } final PsiClass resolve = classType.resolve(); if (resolve instanceof PsiTypeParameter) { final PsiTypeParameter typeParameter = (PsiTypeParameter) resolve; if (check(typeParameter)) { myUsedTypeParams.add(typeParameter); return true; } } return used; }
private static boolean isConversionNeeded(@Nullable PsiType actual, @Nullable PsiType expected) { if (actual == null || expected == null) { return false; } Map<String, String> typeMap = new HashMap<String, String>(); typeMap.put(JAVA_LANG_BYTE, "byte"); typeMap.put(JAVA_LANG_SHORT, "short"); typeMap.put(JAVA_LANG_INTEGER, "int"); typeMap.put(JAVA_LANG_LONG, "long"); typeMap.put(JAVA_LANG_FLOAT, "float"); typeMap.put(JAVA_LANG_DOUBLE, "double"); typeMap.put(JAVA_LANG_CHARACTER, "char"); String expectedStr = expected.getCanonicalText(); String actualStr = actual.getCanonicalText(); boolean o1 = AstUtil.getOrElse(typeMap, actualStr, "").equals(expectedStr); boolean o2 = AstUtil.getOrElse(typeMap, expectedStr, "").equals(actualStr); return !actualStr.equals(expectedStr) && (!(o1 ^ o2)); }
public MethodReturnTypeFix( @NotNull PsiMethod method, @NotNull PsiType returnType, boolean fixWholeHierarchy) { super(method); myReturnTypePointer = SmartTypePointerManager.getInstance(method.getProject()).createSmartTypePointer(returnType); myFixWholeHierarchy = fixWholeHierarchy; myName = method.getName(); myCanonicalText = returnType.getCanonicalText(); }