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>
<w>ctor</w>
<w>lookups</w>
<w>unescape</w>
</words>
</dictionary>
</component>
@@ -77,7 +77,8 @@ public class CheckerTestUtil {
};
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 Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!"+
INDIVIDUAL_DIAGNOSTIC +"(,\\s*"+
@@ -613,10 +614,18 @@ public class CheckerTestUtil {
List<String> parsedParameters = new SmartList<String>();
Matcher parametersMatcher = INDIVIDUAL_PARAMETER_PATTERN.matcher(parameters);
while (parametersMatcher.find())
parsedParameters.add(parametersMatcher.group().trim());
parsedParameters.add(unescape(parametersMatcher.group().trim()));
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
public static TextDiagnostic asTextDiagnostic(@NotNull Diagnostic diagnostic) {
DiagnosticRenderer renderer = DefaultErrorMessages.getRendererForDiagnostic(diagnostic);
@@ -679,7 +688,12 @@ public class CheckerTestUtil {
public String asString() {
if (parameters == null)
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.intellij.psi.PsiElement;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.name.Name;
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.ConstraintSystemCompleter;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
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.receivers.ExpressionReceiver;
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.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.FakeCallResolver;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
@@ -57,21 +58,23 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.creat
public class DelegatedPropertyResolver {
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 CallResolver callResolver;
@NotNull private final FakeCallResolver fakeCallResolver;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final SymbolUsageValidator symbolUsageValidator;
public DelegatedPropertyResolver(
@NotNull SymbolUsageValidator symbolUsageValidator,
@NotNull KotlinBuiltIns builtIns,
@NotNull CallResolver callResolver,
@NotNull FakeCallResolver fakeCallResolver,
@NotNull ExpressionTypingServices expressionTypingServices
) {
this.symbolUsageValidator = symbolUsageValidator;
this.builtIns = builtIns;
this.callResolver = callResolver;
this.fakeCallResolver = fakeCallResolver;
this.expressionTypingServices = expressionTypingServices;
}
@@ -143,15 +146,15 @@ public class DelegatedPropertyResolver {
traceToResolvePDMethod, scope,
DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
List<JetExpression> arguments = Lists.newArrayList();
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(PROPERTY_DELEGATED_FUNCTION_NAME.asString());
List<JetExpression> arguments = Collections.singletonList(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
Call call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT);
OverloadResolutionResults<FunctionDescriptor> functionResults =
callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, PROPERTY_DELEGATED_FUNCTION_NAME);
Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, PROPERTY_DELEGATED_FUNCTION_NAME, delegateExpression);
Call call = resolutionResult.getFirst();
OverloadResolutionResults<FunctionDescriptor> functionResults = resolutionResult.getSecond();
if (!functionResults.isSuccess()) {
String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext());
@@ -245,7 +248,6 @@ public class DelegatedPropertyResolver {
List<JetExpression> arguments = Lists.newArrayList();
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
if (!isGet) {
@@ -257,17 +259,17 @@ public class DelegatedPropertyResolver {
trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0));
}
Name functionName = Name.identifier(isGet ? "get" : "set");
JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(functionName.asString());
Name functionName = isGet ? GETTER_NAME : SETTER_NAME;
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();
assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method";
StringBuilder builder = new StringBuilder(calleeExpression.getText());
@@ -16,21 +16,20 @@
package org.jetbrains.kotlin.types.expressions
import com.google.common.collect.Lists
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
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.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlin.utils.doNothing
import java.util.*
public class FakeCallResolver(
@@ -78,17 +77,34 @@ public class FakeCallResolver(
name: Name,
callElement: JetExpression?
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fake = JetPsiFactory(project).createSimpleName("fake")
val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name)
val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments)
val results = callResolver.resolveCallWithGivenName(context.replaceBindingTrace(fakeTrace), call, fake, name)
if (results.isSuccess()) {
val fakeBindingTrace = context.replaceBindingTrace(fakeTrace)
return makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake ->
fakeTrace.commit({ _, key ->
// excluding all entries related to fake expression
key != fake
}, 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
@@ -1,6 +1,6 @@
// !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 {
fun get(t: Any?, p: PropertyMetadata): Int {