don't report USELESS_CAST in case of casting to superype using 'as'
This commit is contained in:
+26
-2
@@ -20,6 +20,7 @@ import com.google.common.collect.Lists;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.psi.tree.TokenSet;
|
import com.intellij.psi.tree.TokenSet;
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import kotlin.Function0;
|
import kotlin.Function0;
|
||||||
import kotlin.Function1;
|
import kotlin.Function1;
|
||||||
import kotlin.KotlinPackage;
|
import kotlin.KotlinPackage;
|
||||||
@@ -62,7 +63,6 @@ import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl;
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
|
|
||||||
import org.jetbrains.kotlin.types.*;
|
import org.jetbrains.kotlin.types.*;
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
|
||||||
@@ -249,8 +249,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
Collection<JetType> possibleTypes = DataFlowUtils.getAllPossibleTypes(
|
Collection<JetType> possibleTypes = DataFlowUtils.getAllPossibleTypes(
|
||||||
expression.getLeft(), context.dataFlowInfo, actualType, context);
|
expression.getLeft(), context.dataFlowInfo, actualType, context);
|
||||||
|
|
||||||
|
boolean checkExactType = checkExactTypeForUselessCast(expression);
|
||||||
for (JetType possibleType : possibleTypes) {
|
for (JetType possibleType : possibleTypes) {
|
||||||
if (typeChecker.isSubtypeOf(possibleType, targetType)) {
|
boolean castIsUseless = checkExactType
|
||||||
|
? possibleType.equals(targetType)
|
||||||
|
: typeChecker.isSubtypeOf(possibleType, targetType);
|
||||||
|
if (castIsUseless) {
|
||||||
context.trace.report(USELESS_CAST.on(expression));
|
context.trace.report(USELESS_CAST.on(expression));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -260,6 +265,25 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Casting an argument or a receiver to a supertype may be useful to select an exact overload of a method.
|
||||||
|
// Casting to a supertype in other contexts is unlikely to be useful.
|
||||||
|
private static boolean checkExactTypeForUselessCast(JetBinaryExpressionWithTypeRHS expression) {
|
||||||
|
PsiElement parent = expression.getParent();
|
||||||
|
while (parent instanceof JetParenthesizedExpression ||
|
||||||
|
parent instanceof JetLabeledExpression ||
|
||||||
|
parent instanceof JetAnnotatedExpression) {
|
||||||
|
parent = parent.getParent();
|
||||||
|
}
|
||||||
|
if (parent instanceof JetValueArgument) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (parent instanceof JetQualifiedExpression) {
|
||||||
|
JetExpression receiver = ((JetQualifiedExpression) parent).getReceiverExpression();
|
||||||
|
return PsiTreeUtil.isAncestor(receiver, expression, false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetTypeInfo visitThisExpression(@NotNull JetThisExpression expression, ExpressionTypingContext context) {
|
public JetTypeInfo visitThisExpression(@NotNull JetThisExpression expression, ExpressionTypingContext context) {
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
|
|||||||
@@ -9,10 +9,15 @@ fun test() : Unit {
|
|||||||
checkSubtype<Int>(x as Int)
|
checkSubtype<Int>(x as Int)
|
||||||
checkSubtype<Int>(y <!USELESS_CAST!>as Int<!>)
|
checkSubtype<Int>(y <!USELESS_CAST!>as Int<!>)
|
||||||
checkSubtype<Int?>(x <!USELESS_CAST!>as Int?<!>)
|
checkSubtype<Int?>(x <!USELESS_CAST!>as Int?<!>)
|
||||||
checkSubtype<Int?>(y <!USELESS_CAST!>as Int?<!>)
|
checkSubtype<Int?>(y as Int?)
|
||||||
checkSubtype<Int?>(x <!USELESS_CAST!>as? Int<!>)
|
checkSubtype<Int?>(x <!USELESS_CAST!>as? Int<!>)
|
||||||
checkSubtype<Int?>(y <!USELESS_CAST!>as? Int<!>)
|
checkSubtype<Int?>(y <!USELESS_CAST!>as? Int<!>)
|
||||||
checkSubtype<Int?>(x <!USELESS_CAST!>as? Int?<!>)
|
checkSubtype<Int?>(x <!USELESS_CAST!>as? Int?<!>)
|
||||||
checkSubtype<Int?>(y <!USELESS_CAST!>as? Int?<!>)
|
checkSubtype<Int?>(y as? Int?)
|
||||||
|
|
||||||
|
val <!UNUSED_VARIABLE!>s<!> = "" <!USELESS_CAST!>as Any<!>
|
||||||
|
("" as String?)?.length()
|
||||||
|
(@data("" as String?))?.length()
|
||||||
|
([data]( "" as String?))?.length()
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ fun bar() {
|
|||||||
val x = X
|
val x = X
|
||||||
x.foo()
|
x.foo()
|
||||||
X.foo()
|
X.foo()
|
||||||
(X <!USELESS_CAST!>as C<!>).foo()
|
(X as C).foo()
|
||||||
((if (1<2) X else Y) <!USELESS_CAST!>as C<!>).foo()
|
((if (1<2) X else Y) <!USELESS_CAST!>as C<!>).foo()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ class B: A()
|
|||||||
|
|
||||||
fun test(a: Any?) {
|
fun test(a: Any?) {
|
||||||
if (a is B) {
|
if (a is B) {
|
||||||
(a <!USELESS_CAST!>as A<!>).foo()
|
(a as A).foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test1(a: B) {
|
fun test1(a: B) {
|
||||||
(a <!USELESS_CAST!>as A?<!>)?.foo()
|
(a as A?)?.foo()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test2(b: B?) {
|
fun test2(b: B?) {
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
(b <!USELESS_CAST!>as A<!>).foo()
|
(b as A).foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user