Use only completed arguments of special call
This commit is contained in:
@@ -792,9 +792,11 @@ public interface Errors {
|
||||
DiagnosticFactory0<PsiElement> UNEXPECTED_SAFE_CALL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNNECESSARY_NOT_NULL_ASSERTION = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtBinaryExpression, KotlinType> USELESS_ELVIS = DiagnosticFactory1.create(WARNING, PositioningStrategies.USELESS_ELVIS);
|
||||
DiagnosticFactory0<PsiElement> USELESS_ELVIS_ON_LAMBDA_EXPRESSION = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> USELESS_ELVIS_ON_CALLABLE_REFERENCE = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtBinaryExpression> USELESS_ELVIS_RIGHT_IS_NULL =
|
||||
DiagnosticFactory0.create(WARNING, PositioningStrategies.USELESS_ELVIS);
|
||||
|
||||
|
||||
+2
@@ -479,6 +479,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(DYNAMIC_UPPER_BOUND, "Dynamic type can not be used as an upper bound");
|
||||
MAP.put(USELESS_ELVIS, "Elvis operator (?:) always returns the left operand of non-nullable type {0}", RENDER_TYPE);
|
||||
MAP.put(USELESS_ELVIS_ON_LAMBDA_EXPRESSION, "Left operand of elvis operator (?:) is a lambda expression");
|
||||
MAP.put(USELESS_ELVIS_ON_CALLABLE_REFERENCE, "Left operand of elvis operator (?:) is a callable reference expression");
|
||||
MAP.put(USELESS_ELVIS_RIGHT_IS_NULL, "Right operand of elvis operator (?:) is useless if it is null");
|
||||
MAP.put(CONFLICTING_UPPER_BOUNDS, "Upper bounds of {0} have empty intersection", NAME);
|
||||
|
||||
@@ -583,6 +584,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(UNEXPECTED_SAFE_CALL, "Safe-call is not allowed here");
|
||||
MAP.put(UNNECESSARY_NOT_NULL_ASSERTION, "Unnecessary non-null assertion (!!) on a non-null receiver of type {0}", RENDER_TYPE);
|
||||
MAP.put(NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION, "Non-null assertion (!!) is called on a lambda expression");
|
||||
MAP.put(NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE, "Non-null assertion (!!) is called on a callable reference expression");
|
||||
MAP.put(NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER, "{0} does not refer to a type parameter of {1}", (typeConstraint, context) -> {
|
||||
//noinspection ConstantConditions
|
||||
return typeConstraint.getSubjectTypeParameterName().getReferencedName();
|
||||
|
||||
@@ -162,6 +162,18 @@ public class ArgumentTypeResolver {
|
||||
return getFunctionLiteralArgumentIfAny(expression, context) != null;
|
||||
}
|
||||
|
||||
public static boolean isCallableReferenceArgument(
|
||||
@NotNull KtExpression expression, @NotNull ResolutionContext context
|
||||
) {
|
||||
return getCallableReferenceExpressionIfAny(expression, context) != null;
|
||||
}
|
||||
|
||||
public static boolean isFunctionLiteralOrCallableReference(
|
||||
@NotNull KtExpression expression, @NotNull ResolutionContext context
|
||||
) {
|
||||
return isFunctionLiteralArgument(expression, context) || isCallableReferenceArgument(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static KtFunction getFunctionLiteralArgument(
|
||||
@NotNull KtExpression expression, @NotNull ResolutionContext context
|
||||
@@ -188,7 +200,7 @@ public class ArgumentTypeResolver {
|
||||
@Nullable
|
||||
public static KtCallableReferenceExpression getCallableReferenceExpressionIfAny(
|
||||
@NotNull KtExpression expression,
|
||||
@NotNull CallResolutionContext<?> context
|
||||
@NotNull ResolutionContext context
|
||||
) {
|
||||
KtExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context.statementFilter);
|
||||
if (deparenthesizedExpression instanceof KtCallableReferenceExpression) {
|
||||
|
||||
+15
-6
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
@@ -826,8 +827,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
call, ResolveConstruct.EXCL_EXCL, Collections.singletonList("baseExpr"), Collections.singletonList(true), context, null);
|
||||
KotlinTypeInfo baseTypeInfo = BindingContextUtils.getRecordedTypeInfo(baseExpression, context.trace.getBindingContext());
|
||||
|
||||
if (ArgumentTypeResolver.isFunctionLiteralArgument(baseExpression, context)) {
|
||||
context.trace.report(NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION.on(operationSign));
|
||||
boolean isFunctionLiteral = ArgumentTypeResolver.isFunctionLiteralArgument(baseExpression, context);
|
||||
boolean isCallableReference = ArgumentTypeResolver.isCallableReferenceArgument(baseExpression, context);
|
||||
if (isFunctionLiteral || isCallableReference) {
|
||||
DiagnosticFactory0<PsiElement> diagnosticFactory =
|
||||
isFunctionLiteral ? NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION : NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE;
|
||||
context.trace.report(diagnosticFactory.on(operationSign));
|
||||
if (baseTypeInfo == null) {
|
||||
return TypeInfoFactoryKt.createTypeInfo(ErrorUtils.createErrorType("Unresolved lambda expression"), context);
|
||||
}
|
||||
@@ -1218,9 +1223,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
call, ResolveConstruct.ELVIS, Lists.newArrayList("left", "right"),
|
||||
Lists.newArrayList(true, false), contextWithExpectedType, null);
|
||||
KotlinTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
|
||||
if (ArgumentTypeResolver.isFunctionLiteralArgument(left, context)) {
|
||||
context.trace.report(USELESS_ELVIS_ON_LAMBDA_EXPRESSION.on(expression.getOperationReference()));
|
||||
if (leftTypeInfo == null) return TypeInfoFactoryKt.noTypeInfo(context);
|
||||
boolean isLeftFunctionLiteral = ArgumentTypeResolver.isFunctionLiteralArgument(left, context);
|
||||
boolean isLeftCallableReference = ArgumentTypeResolver.isCallableReferenceArgument(left, context);
|
||||
if (leftTypeInfo == null && (isLeftFunctionLiteral || isLeftCallableReference)) {
|
||||
DiagnosticFactory0<PsiElement> diagnosticFactory =
|
||||
isLeftFunctionLiteral ? USELESS_ELVIS_ON_LAMBDA_EXPRESSION : USELESS_ELVIS_ON_CALLABLE_REFERENCE;
|
||||
context.trace.report(diagnosticFactory.on(expression.getOperationReference()));
|
||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||
}
|
||||
assert leftTypeInfo != null : "Left expression was not processed: " + expression;
|
||||
KotlinType leftType = leftTypeInfo.getType();
|
||||
@@ -1231,7 +1240,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
context.trace.report(USELESS_ELVIS_RIGHT_IS_NULL.on(expression));
|
||||
}
|
||||
KotlinTypeInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext());
|
||||
if (rightTypeInfo == null && ArgumentTypeResolver.isFunctionLiteralArgument(right, context)) {
|
||||
if (rightTypeInfo == null && ArgumentTypeResolver.isFunctionLiteralOrCallableReference(right, context)) {
|
||||
// the type is computed later in call completer according to the '?:' semantics as a function
|
||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||
}
|
||||
|
||||
+28
-1
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.ModifierCheckerCore;
|
||||
import org.jetbrains.kotlin.resolve.ModifiersChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
@@ -132,10 +133,35 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
Lists.newArrayList(false, false),
|
||||
contextWithExpectedType, dataFlowInfoForArguments);
|
||||
|
||||
return processBranches(
|
||||
ifExpression, contextWithExpectedType, context, conditionDataFlowInfo,
|
||||
loopBreakContinuePossibleInCondition, elseBranch, thenBranch, resolvedCall);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinTypeInfo processBranches(
|
||||
KtIfExpression ifExpression,
|
||||
ExpressionTypingContext contextWithExpectedType,
|
||||
ExpressionTypingContext context,
|
||||
DataFlowInfo conditionDataFlowInfo,
|
||||
boolean loopBreakContinuePossibleInCondition,
|
||||
KtExpression elseBranch,
|
||||
KtExpression thenBranch,
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall
|
||||
) {
|
||||
BindingContext bindingContext = context.trace.getBindingContext();
|
||||
KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
|
||||
KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
|
||||
assert thenTypeInfo != null || elseTypeInfo != null : "Both branches of if expression were not processed: " + ifExpression.getText();
|
||||
|
||||
boolean isThenPostponed = ArgumentTypeResolver.isFunctionLiteralOrCallableReference(thenBranch, context);
|
||||
boolean isElsePostponed = ArgumentTypeResolver.isFunctionLiteralOrCallableReference(thenBranch, context);
|
||||
|
||||
assert thenTypeInfo != null || elseTypeInfo != null ||
|
||||
isThenPostponed || isElsePostponed : "Both branches of if expression were not processed: " + ifExpression.getText();
|
||||
|
||||
if (thenTypeInfo == null && elseTypeInfo == null) {
|
||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||
}
|
||||
|
||||
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||
boolean loopBreakContinuePossible = loopBreakContinuePossibleInCondition;
|
||||
@@ -184,6 +210,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
return TypeInfoFactoryKt.noTypeInfo(resultDataFlowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// If break or continue was possible, take condition check info as the jump info
|
||||
return TypeInfoFactoryKt.createTypeInfo(
|
||||
components.dataFlowAnalyzer.checkType(resultType, ifExpression, contextWithExpectedType),
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ fun test() {
|
||||
else -> ::baz
|
||||
})
|
||||
|
||||
val x5: (Int) -> Int = bar(::baz<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
|
||||
val x5: (Int) -> Int = bar(::baz<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>)
|
||||
|
||||
(if (true) ::baz else ::baz)(1)
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// See KT-8277
|
||||
|
||||
val v = { true } <!USELESS_ELVIS!><!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> ( { true } <!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> null!! )<!>
|
||||
val v = { true } <!USELESS_ELVIS!>?: ( { true } <!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> null!! )<!>
|
||||
|
||||
val w = if (true) {
|
||||
{ true }
|
||||
@@ -32,6 +32,6 @@ val bbb = null ?: ( l() <!USELESS_ELVIS_RIGHT_IS_NULL!>?: null<!>)
|
||||
val bbbb = ( l() <!USELESS_ELVIS_RIGHT_IS_NULL!>?: null<!>) ?: ( l() <!USELESS_ELVIS_RIGHT_IS_NULL!>?: null<!>)
|
||||
|
||||
fun f(x : Long?): Long {
|
||||
var a = x ?: (<!TYPE_MISMATCH!>fun() {}<!> <!USELESS_ELVIS!><!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> <!TYPE_MISMATCH!>fun() {}<!><!>)
|
||||
var a = x ?: (<!TYPE_MISMATCH!>fun() {}<!> <!USELESS_ELVIS!>?: <!TYPE_MISMATCH!>fun() {}<!><!>)
|
||||
return <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ fun test() {
|
||||
use({ }<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>);
|
||||
|
||||
// KT-KT-9070
|
||||
<!TYPE_MISMATCH!>{ }<!> <!USELESS_ELVIS!><!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> 1<!>
|
||||
<!TYPE_MISMATCH!>{ }<!> <!USELESS_ELVIS!>?: 1<!>
|
||||
use({ 2 } <!USELESS_ELVIS_ON_LAMBDA_EXPRESSION!>?:<!> 1);
|
||||
|
||||
1 <!USELESS_ELVIS!>?: <!TYPE_MISMATCH, UNUSED_LAMBDA_EXPRESSION!>{ }<!><!>
|
||||
|
||||
Reference in New Issue
Block a user