Switch to use FakeCallResolver in DelegatedPropertyResolver

This commit is contained in:
Zalim Bashorov
2015-09-16 18:45:19 +03:00
parent 760571c2a3
commit f7e2c127b7
6 changed files with 66 additions and 33 deletions
+1
View File
@@ -3,6 +3,7 @@
<words> <words>
<w>ctor</w> <w>ctor</w>
<w>lookups</w> <w>lookups</w>
<w>unescape</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>
@@ -77,7 +77,8 @@ public class CheckerTestUtil {
}; };
private static final String IGNORE_DIAGNOSTIC_PARAMETER = "IGNORE"; private static final String IGNORE_DIAGNOSTIC_PARAMETER = "IGNORE";
private static final String DIAGNOSTIC_PARAMETER = "[^\\)\\(;]+"; private static final String SHOULD_BE_ESCAPED = "\\)\\(;";
private static final String DIAGNOSTIC_PARAMETER = "(?:(?:\\\\[" + SHOULD_BE_ESCAPED + "])|[^" + SHOULD_BE_ESCAPED + "])+";
private static final String INDIVIDUAL_DIAGNOSTIC = "(\\w+)(\\(" + DIAGNOSTIC_PARAMETER + "(;\\s*" + DIAGNOSTIC_PARAMETER + ")*\\))?"; private static final String INDIVIDUAL_DIAGNOSTIC = "(\\w+)(\\(" + DIAGNOSTIC_PARAMETER + "(;\\s*" + DIAGNOSTIC_PARAMETER + ")*\\))?";
private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!"+ private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!"+
INDIVIDUAL_DIAGNOSTIC +"(,\\s*"+ INDIVIDUAL_DIAGNOSTIC +"(,\\s*"+
@@ -613,10 +614,18 @@ public class CheckerTestUtil {
List<String> parsedParameters = new SmartList<String>(); List<String> parsedParameters = new SmartList<String>();
Matcher parametersMatcher = INDIVIDUAL_PARAMETER_PATTERN.matcher(parameters); Matcher parametersMatcher = INDIVIDUAL_PARAMETER_PATTERN.matcher(parameters);
while (parametersMatcher.find()) while (parametersMatcher.find())
parsedParameters.add(parametersMatcher.group().trim()); parsedParameters.add(unescape(parametersMatcher.group().trim()));
return new TextDiagnostic(name, parsedParameters); return new TextDiagnostic(name, parsedParameters);
} }
private static @NotNull String escape(@NotNull String s) {
return s.replaceAll("([" + SHOULD_BE_ESCAPED + "])", "\\\\$1");
}
private static @NotNull String unescape(@NotNull String s) {
return s.replaceAll("\\\\([" + SHOULD_BE_ESCAPED + "])", "$1");
}
@NotNull @NotNull
public static TextDiagnostic asTextDiagnostic(@NotNull Diagnostic diagnostic) { public static TextDiagnostic asTextDiagnostic(@NotNull Diagnostic diagnostic) {
DiagnosticRenderer renderer = DefaultErrorMessages.getRendererForDiagnostic(diagnostic); DiagnosticRenderer renderer = DefaultErrorMessages.getRendererForDiagnostic(diagnostic);
@@ -679,7 +688,12 @@ public class CheckerTestUtil {
public String asString() { public String asString() {
if (parameters == null) if (parameters == null)
return name; return name;
return name + '(' + StringUtil.join(parameters, "; ") + ')'; return name + '(' + StringUtil.join(parameters, new Function<String, String>() {
@Override
public String fun(String s) {
return escape(s);
}
}, "; ") + ')';
} }
} }
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -25,13 +26,11 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.rendering.Renderers; import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.CallResolver;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
@@ -41,8 +40,10 @@ import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.JetTypeChecker; import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext; import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.FakeCallResolver;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice; import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.diagnostics.Errors.*;
@@ -57,21 +58,23 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.creat
public class DelegatedPropertyResolver { public class DelegatedPropertyResolver {
public static final Name PROPERTY_DELEGATED_FUNCTION_NAME = Name.identifier("propertyDelegated"); public static final Name PROPERTY_DELEGATED_FUNCTION_NAME = Name.identifier("propertyDelegated");
public static final Name GETTER_NAME = Name.identifier("get");
public static final Name SETTER_NAME = Name.identifier("set");
@NotNull private final ExpressionTypingServices expressionTypingServices; @NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final CallResolver callResolver; @NotNull private final FakeCallResolver fakeCallResolver;
@NotNull private final KotlinBuiltIns builtIns; @NotNull private final KotlinBuiltIns builtIns;
@NotNull private final SymbolUsageValidator symbolUsageValidator; @NotNull private final SymbolUsageValidator symbolUsageValidator;
public DelegatedPropertyResolver( public DelegatedPropertyResolver(
@NotNull SymbolUsageValidator symbolUsageValidator, @NotNull SymbolUsageValidator symbolUsageValidator,
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull CallResolver callResolver, @NotNull FakeCallResolver fakeCallResolver,
@NotNull ExpressionTypingServices expressionTypingServices @NotNull ExpressionTypingServices expressionTypingServices
) { ) {
this.symbolUsageValidator = symbolUsageValidator; this.symbolUsageValidator = symbolUsageValidator;
this.builtIns = builtIns; this.builtIns = builtIns;
this.callResolver = callResolver; this.fakeCallResolver = fakeCallResolver;
this.expressionTypingServices = expressionTypingServices; this.expressionTypingServices = expressionTypingServices;
} }
@@ -143,15 +146,15 @@ public class DelegatedPropertyResolver {
traceToResolvePDMethod, scope, traceToResolvePDMethod, scope,
DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE); DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
List<JetExpression> arguments = Lists.newArrayList();
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression); JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor)); List<JetExpression> arguments = Collections.singletonList(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(PROPERTY_DELEGATED_FUNCTION_NAME.asString());
ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType); ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
Call call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT);
OverloadResolutionResults<FunctionDescriptor> functionResults = Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, PROPERTY_DELEGATED_FUNCTION_NAME); fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, PROPERTY_DELEGATED_FUNCTION_NAME, delegateExpression);
Call call = resolutionResult.getFirst();
OverloadResolutionResults<FunctionDescriptor> functionResults = resolutionResult.getSecond();
if (!functionResults.isSuccess()) { if (!functionResults.isSuccess()) {
String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext()); String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext());
@@ -245,7 +248,6 @@ public class DelegatedPropertyResolver {
List<JetExpression> arguments = Lists.newArrayList(); List<JetExpression> arguments = Lists.newArrayList();
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression); JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
arguments.add(psiFactory.createExpression(hasThis ? "this" : "null")); arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor)); arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
if (!isGet) { if (!isGet) {
@@ -257,17 +259,17 @@ public class DelegatedPropertyResolver {
trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0)); trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0));
} }
Name functionName = Name.identifier(isGet ? "get" : "set"); Name functionName = isGet ? GETTER_NAME : SETTER_NAME;
JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(functionName.asString());
ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType); ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
Call call = CallMaker.makeCallWithExpressions(delegateExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT);
trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, call);
return callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, functionName); Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression);
trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.getFirst());
return resolutionResult.getSecond();
} }
private String renderCall(@NotNull Call call, @NotNull BindingContext context) { private static String renderCall(@NotNull Call call, @NotNull BindingContext context) {
JetExpression calleeExpression = call.getCalleeExpression(); JetExpression calleeExpression = call.getCalleeExpression();
assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method"; assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method";
StringBuilder builder = new StringBuilder(calleeExpression.getText()); StringBuilder builder = new StringBuilder(calleeExpression.getText());
@@ -16,21 +16,20 @@
package org.jetbrains.kotlin.types.expressions package org.jetbrains.kotlin.types.expressions
import com.google.common.collect.Lists
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.TraceEntryFilter
import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.util.slicedMap.WritableSlice import org.jetbrains.kotlin.utils.doNothing
import java.util.* import java.util.*
public class FakeCallResolver( public class FakeCallResolver(
@@ -78,17 +77,34 @@ public class FakeCallResolver(
name: Name, name: Name,
callElement: JetExpression? callElement: JetExpression?
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> { ): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fake = JetPsiFactory(project).createSimpleName("fake")
val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name) val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name)
val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments) val fakeBindingTrace = context.replaceBindingTrace(fakeTrace)
val results = callResolver.resolveCallWithGivenName(context.replaceBindingTrace(fakeTrace), call, fake, name)
if (results.isSuccess()) { return makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake ->
fakeTrace.commit({ _, key -> fakeTrace.commit({ _, key ->
// excluding all entries related to fake expression // excluding all entries related to fake expression
key != fake key != fake
}, true) }, true)
} }
return Pair(call, results)
} }
} @JvmOverloads
public fun makeAndResolveFakeCallInContext(
receiver: ReceiverValue,
context: ExpressionTypingContext,
valueArguments: List<JetExpression>,
name: Name,
callElement: JetExpression?,
onSuccess: (JetSimpleNameExpression) -> Unit = doNothing()
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fake = JetPsiFactory(project).createSimpleName(name.asString())
val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments)
val results = callResolver.resolveCallWithGivenName(context, call, fake, name)
if (results.isSuccess) {
onSuccess(fake)
}
return Pair(call, results)
}
}
@@ -1,3 +1,3 @@
val a: Int by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>A()<!> val a: Int by <!DELEGATE_SPECIAL_FUNCTION_MISSING(get\(kotlin.Nothing?, kotlin.PropertyMetadata\); A)!>A()<!>
class A class A
@@ -1,6 +1,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER // !DIAGNOSTICS: -UNUSED_PARAMETER
var a: Int by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>A()<!> var a: Int by <!DELEGATE_SPECIAL_FUNCTION_MISSING(set\(kotlin.Nothing?, kotlin.PropertyMetadata, kotlin.Int\); A)!>A()<!>
class A { class A {
fun get(t: Any?, p: PropertyMetadata): Int { fun get(t: Any?, p: PropertyMetadata): Int {