Avoid creating synthetic safe-call nodes when resolving == calls
Each of them leads to a separate synthetic file retained in the memory
This commit is contained in:
@@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
|
||||
@@ -31,6 +32,10 @@ public interface Call {
|
||||
@Nullable
|
||||
ASTNode getCallOperationNode();
|
||||
|
||||
default boolean isSemanticallyEquivalentToSafeCall() {
|
||||
return getCallOperationNode() != null && getCallOperationNode().getElementType() == KtTokens.SAFE_ACCESS;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Receiver getExplicitReceiver();
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiComment
|
||||
@@ -65,10 +64,6 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
return property.valOrVarKeyword
|
||||
}
|
||||
|
||||
fun createSafeCallNode(): ASTNode {
|
||||
return (createExpression("a?.b") as KtSafeQualifiedExpression).operationTokenNode
|
||||
}
|
||||
|
||||
private fun doCreateExpression(text: String): KtExpression? {
|
||||
//NOTE: '\n' below is important - some strange code indenting problems appear without it
|
||||
return createProperty("val x =\n$text").initializer
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getErasedReceiverType
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnExpressionWithBothReceivers
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isExplicitSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||
@@ -508,7 +507,7 @@ class CandidateResolver(
|
||||
// Here we know that receiver is OK ignoring nullability and check that nullability is OK too
|
||||
// Doing it simply as full subtyping check (receiverValueType <: receiverParameterType)
|
||||
val call = candidateCall.call
|
||||
val safeAccess = isExplicitReceiver && !implicitInvokeCheck && call.isExplicitSafeCall()
|
||||
val safeAccess = isExplicitReceiver && !implicitInvokeCheck && call.isSemanticallyEquivalentToSafeCall
|
||||
val expectedReceiverParameterType = if (safeAccess) TypeUtils.makeNullable(receiverParameter.type) else receiverParameter.type
|
||||
|
||||
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
|
||||
|
||||
@@ -108,19 +108,34 @@ public class CallMaker {
|
||||
private final KtExpression calleeExpression;
|
||||
private final List<? extends ValueArgument> valueArguments;
|
||||
private final Call.CallType callType;
|
||||
private final boolean isSemanticallyEquivalentToSafeCall;
|
||||
|
||||
protected CallImpl(@NotNull KtElement callElement, @NotNull Receiver explicitReceiver, @Nullable ASTNode callOperationNode, @Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
|
||||
this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT);
|
||||
protected CallImpl(
|
||||
@NotNull KtElement callElement,
|
||||
@NotNull Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode,
|
||||
@Nullable KtExpression calleeExpression,
|
||||
@NotNull List<? extends ValueArgument> valueArguments
|
||||
) {
|
||||
this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT, false);
|
||||
}
|
||||
|
||||
protected CallImpl(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode,
|
||||
@Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments, @NotNull CallType callType) {
|
||||
protected CallImpl(
|
||||
@NotNull KtElement callElement,
|
||||
@Nullable Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode,
|
||||
@Nullable KtExpression calleeExpression,
|
||||
@NotNull List<? extends ValueArgument> valueArguments,
|
||||
@NotNull CallType callType,
|
||||
boolean isSemanticallyEquivalentToSafeCall
|
||||
) {
|
||||
this.callElement = callElement;
|
||||
this.explicitReceiver = explicitReceiver;
|
||||
this.callOperationNode = callOperationNode;
|
||||
this.calleeExpression = calleeExpression;
|
||||
this.valueArguments = valueArguments;
|
||||
this.callType = callType;
|
||||
this.isSemanticallyEquivalentToSafeCall = isSemanticallyEquivalentToSafeCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,6 +143,11 @@ public class CallMaker {
|
||||
return callOperationNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSemanticallyEquivalentToSafeCall() {
|
||||
return isSemanticallyEquivalentToSafeCall || Call.super.isSemanticallyEquivalentToSafeCall();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Receiver getExplicitReceiver() {
|
||||
@@ -194,13 +214,26 @@ public class CallMaker {
|
||||
public static Call makeCallWithExpressions(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
|
||||
@NotNull List<KtExpression> argumentExpressions) {
|
||||
return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT);
|
||||
return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT,
|
||||
false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Call makeCallWithExpressions(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
|
||||
@NotNull List<KtExpression> argumentExpressions, @NotNull CallType callType) {
|
||||
@Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
|
||||
@NotNull List<KtExpression> argumentExpressions, @NotNull CallType callType) {
|
||||
return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, callType,
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static Call makeCallWithExpressions(
|
||||
@NotNull KtElement callElement, @Nullable Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
|
||||
@NotNull List<KtExpression> argumentExpressions, @NotNull CallType callType,
|
||||
boolean isSemanticallyEquivalentToSafeCall
|
||||
) {
|
||||
List<ValueArgument> arguments;
|
||||
if (argumentExpressions.isEmpty()) {
|
||||
arguments = Collections.emptyList();
|
||||
@@ -211,7 +244,9 @@ public class CallMaker {
|
||||
arguments.add(makeValueArgument(argumentExpression, calleeExpression));
|
||||
}
|
||||
}
|
||||
return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
|
||||
return makeCall(
|
||||
callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType, isSemanticallyEquivalentToSafeCall
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -222,8 +257,22 @@ public class CallMaker {
|
||||
@NotNull
|
||||
public static Call makeCall(
|
||||
KtElement callElement, @Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode,
|
||||
KtExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType) {
|
||||
return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
|
||||
KtExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType
|
||||
) {
|
||||
return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Call makeCall(
|
||||
KtElement callElement,
|
||||
@Nullable Receiver explicitReceiver,
|
||||
@Nullable ASTNode callOperationNode,
|
||||
KtExpression calleeExpression,
|
||||
List<? extends ValueArgument> arguments,
|
||||
CallType callType,
|
||||
boolean isSemanticallyEquivalentToSafeCall
|
||||
) {
|
||||
return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType, isSemanticallyEquivalentToSafeCall);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.resolve.calls.callUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getTextWithLocation
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -237,15 +236,13 @@ val KtElement.isFakeElement: Boolean
|
||||
fun Call.isSafeCall(): Boolean {
|
||||
if (this is CallTransformer.CallForImplicitInvoke) {
|
||||
//implicit safe 'invoke'
|
||||
if (outerCall.isExplicitSafeCall()) {
|
||||
if (outerCall.isSemanticallyEquivalentToSafeCall) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return isExplicitSafeCall()
|
||||
return isSemanticallyEquivalentToSafeCall
|
||||
}
|
||||
|
||||
fun Call.isExplicitSafeCall(): Boolean = callOperationNode?.elementType == KtTokens.SAFE_ACCESS
|
||||
|
||||
fun Call.isCallableReference(): Boolean {
|
||||
val callElement = callElement
|
||||
return callElement is KtNameReferenceExpression &&
|
||||
|
||||
+5
-3
@@ -1129,10 +1129,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
Call call = CallMaker.makeCallWithExpressions(
|
||||
expression,
|
||||
receiver,
|
||||
// semantically, a call to `==` is a safe call
|
||||
new KtPsiFactory(expression.getProject(), false).createSafeCallNode(),
|
||||
null,
|
||||
operationSign,
|
||||
Collections.singletonList(right)
|
||||
Collections.singletonList(right),
|
||||
Call.CallType.DEFAULT,
|
||||
// semantically, a call to `==` is a safe call
|
||||
true
|
||||
);
|
||||
|
||||
OverloadResolutionResults<FunctionDescriptor> resolutionResults =
|
||||
|
||||
Reference in New Issue
Block a user