KT-5455 Need warning about redundant type cast
#KT-5455 Fixed
This commit is contained in:
+1
-1
@@ -252,7 +252,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(ABSTRACT_SUPER_CALL, "Abstract member cannot be accessed directly");
|
||||
MAP.put(NOT_A_SUPERTYPE, "Not a supertype");
|
||||
MAP.put(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER, "Type arguments do not need to be specified in a 'super' qualifier");
|
||||
MAP.put(USELESS_CAST_STATIC_ASSERT_IS_FINE, "No cast needed, use ':' instead");
|
||||
MAP.put(USELESS_CAST_STATIC_ASSERT_IS_FINE, "No cast needed. You can use ':' if you need a cast to a super type");
|
||||
MAP.put(USELESS_CAST, "No cast needed");
|
||||
MAP.put(CAST_NEVER_SUCCEEDS, "This cast can never succeed");
|
||||
MAP.put(USELESS_NULLABLE_CHECK, "Non-null type is checked for instance of nullable type");
|
||||
|
||||
+1
-3
@@ -80,9 +80,7 @@ public class SmartCastUtils {
|
||||
return collectSmartCastReceiverValues(dataFlowInfo, dataFlowValue);
|
||||
}
|
||||
else if (receiverToCast instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver receiver = (ExpressionReceiver) receiverToCast;
|
||||
DataFlowValue dataFlowValue =
|
||||
DataFlowValueFactory.createDataFlowValue(receiver.getExpression(), receiver.getType(), bindingContext);
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverToCast, bindingContext);
|
||||
return collectSmartCastReceiverValues(dataFlowInfo, dataFlowValue);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -42,6 +43,7 @@ public class CastDiagnosticsUtil {
|
||||
@NotNull JetType rhsType,
|
||||
@NotNull PlatformToKotlinClassMap platformToKotlinClassMap
|
||||
) {
|
||||
if (KotlinBuiltIns.getInstance().isNullableNothing(lhsType) && !TypeUtils.isNullableType(rhsType)) return false;
|
||||
if (isRelated(lhsType, rhsType, platformToKotlinClassMap)) return true;
|
||||
// This is an oversimplification (which does not render the method incomplete):
|
||||
// we consider any type parameter capable of taking any value, which may be made more precise if we considered bounds
|
||||
@@ -61,8 +63,8 @@ public class CastDiagnosticsUtil {
|
||||
* (i.e. java.lang.String -> kotlin.String) and ignore mappings that go the other way.
|
||||
*/
|
||||
private static boolean isRelated(@NotNull JetType a, @NotNull JetType b, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) {
|
||||
List<JetType> aTypes = mapToPlatformIndependentTypes(a, platformToKotlinClassMap);
|
||||
List<JetType> bTypes = mapToPlatformIndependentTypes(b, platformToKotlinClassMap);
|
||||
List<JetType> aTypes = mapToPlatformIndependentTypes(TypeUtils.makeNotNullable(a), platformToKotlinClassMap);
|
||||
List<JetType> bTypes = mapToPlatformIndependentTypes(TypeUtils.makeNotNullable(b), platformToKotlinClassMap);
|
||||
|
||||
for (JetType aType : aTypes) {
|
||||
for (JetType bType : bTypes) {
|
||||
|
||||
+24
-24
@@ -27,7 +27,6 @@ import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
@@ -45,7 +44,6 @@ import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImp
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowValue;
|
||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowValueFactory;
|
||||
import org.jetbrains.jet.lang.resolve.calls.smartcasts.Nullability;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
@@ -76,6 +74,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowValueFactory.createDataFlowValue;
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
||||
import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
@@ -174,7 +173,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType);
|
||||
dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||
if (operationType == AS_KEYWORD) {
|
||||
DataFlowValue value = DataFlowValueFactory.createDataFlowValue(left, subjectType, context.trace.getBindingContext());
|
||||
DataFlowValue value = createDataFlowValue(left, subjectType, context.trace.getBindingContext());
|
||||
dataFlowInfo = dataFlowInfo.establishSubtyping(value, targetType);
|
||||
}
|
||||
}
|
||||
@@ -199,10 +198,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
context.trace.report(UNSUPPORTED.on(operationSign, "binary operation with type RHS"));
|
||||
return;
|
||||
}
|
||||
checkForCastImpossibility(expression, actualType, targetType, context);
|
||||
checkForCastImpossibilityOrRedundancy(expression, actualType, targetType, context);
|
||||
}
|
||||
|
||||
private void checkForCastImpossibility(
|
||||
private void checkForCastImpossibilityOrRedundancy(
|
||||
JetBinaryExpressionWithTypeRHS expression,
|
||||
JetType actualType,
|
||||
JetType targetType,
|
||||
@@ -212,24 +211,25 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
if (!CastDiagnosticsUtil.isCastPossible(actualType, targetType, components.platformToKotlinClassMap)) {
|
||||
context.trace.report(CAST_NEVER_SUCCEEDS.on(expression.getOperationReference()));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
JetTypeChecker typeChecker = JetTypeChecker.DEFAULT;
|
||||
// Upcast?
|
||||
if (typeChecker.isSubtypeOf(actualType, targetType)) {
|
||||
if (!typeChecker.isSubtypeOf(targetType, actualType)) {
|
||||
// proper upcast: String as Any
|
||||
context.trace.report(USELESS_CAST_STATIC_ASSERT_IS_FINE.on(expression.getOperationReference()));
|
||||
}
|
||||
else {
|
||||
// cast to itself: String as String
|
||||
context.trace.report(USELESS_CAST.on(expression.getOperationReference()));
|
||||
}
|
||||
}
|
||||
else if (CastDiagnosticsUtil.isCastErased(actualType, targetType, typeChecker)) {
|
||||
context.trace.report(Errors.UNCHECKED_CAST.on(expression, actualType, targetType));
|
||||
JetTypeChecker typeChecker = JetTypeChecker.DEFAULT;
|
||||
if (actualType.equals(targetType)) {
|
||||
// cast to itself: String as String
|
||||
context.trace.report(USELESS_CAST.on(expression.getOperationReference()));
|
||||
return;
|
||||
}
|
||||
Collection<JetType> possibleTypes = DataFlowUtils.getAllPossibleTypes(
|
||||
expression.getLeft(), context.dataFlowInfo, actualType, context.trace.getBindingContext());
|
||||
for (JetType possibleType : possibleTypes) {
|
||||
if (typeChecker.isSubtypeOf(possibleType, targetType)) {
|
||||
context.trace.report(USELESS_CAST_STATIC_ASSERT_IS_FINE.on(expression.getOperationReference()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (CastDiagnosticsUtil.isCastErased(actualType, targetType, typeChecker)) {
|
||||
context.trace.report(UNCHECKED_CAST.on(expression, actualType, targetType));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -803,7 +803,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, baseType));
|
||||
}
|
||||
else {
|
||||
DataFlowValue value = DataFlowValueFactory.createDataFlowValue(baseExpression, baseType, context.trace.getBindingContext());
|
||||
DataFlowValue value = createDataFlowValue(baseExpression, baseType, context.trace.getBindingContext());
|
||||
dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL);
|
||||
}
|
||||
return JetTypeInfo.create(TypeUtils.makeNotNullable(baseType), dataFlowInfo);
|
||||
@@ -835,7 +835,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
|
||||
private static boolean isKnownToBeNotNull(JetExpression expression, JetType jetType, ExpressionTypingContext context) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, jetType, context.trace.getBindingContext());
|
||||
DataFlowValue dataFlowValue = createDataFlowValue(expression, jetType, context.trace.getBindingContext());
|
||||
return !context.dataFlowInfo.getNullability(dataFlowValue).canBeNull();
|
||||
}
|
||||
|
||||
@@ -1075,7 +1075,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
DataFlowInfo dataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
|
||||
if (leftType != null && rightType != null && KotlinBuiltIns.getInstance().isNothingOrNullableNothing(rightType) && !rightType.isNullable()) {
|
||||
DataFlowValue value = DataFlowValueFactory.createDataFlowValue(left, leftType, context.trace.getBindingContext());
|
||||
DataFlowValue value = createDataFlowValue(left, leftType, context.trace.getBindingContext());
|
||||
dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL);
|
||||
}
|
||||
JetType type = resolvedCall.getResultingDescriptor().getReturnType();
|
||||
@@ -1158,7 +1158,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetType type = facade.getTypeInfo(expr, context).getType();
|
||||
if (type == null || type.isError()) return;
|
||||
|
||||
DataFlowValue value = DataFlowValueFactory.createDataFlowValue(expr, type, context.trace.getBindingContext());
|
||||
DataFlowValue value = createDataFlowValue(expr, type, context.trace.getBindingContext());
|
||||
Nullability nullability = context.dataFlowInfo.getNullability(value);
|
||||
|
||||
boolean expressionIsAlways;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.lang.types.expressions;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -39,6 +40,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
@@ -265,4 +267,19 @@ public class DataFlowUtils {
|
||||
context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Collection<JetType> getAllPossibleTypes(
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull JetType type,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, bindingContext);
|
||||
Collection<JetType> possibleTypes = Sets.newHashSet(type);
|
||||
if (dataFlowValue.isStableIdentifier()) {
|
||||
possibleTypes.addAll(dataFlowInfo.getPossibleTypes(dataFlowValue));
|
||||
}
|
||||
return possibleTypes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user