001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.PsiElement;
021 import kotlin.Pair;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
027 import org.jetbrains.kotlin.name.Name;
028 import org.jetbrains.kotlin.psi.*;
029 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
030 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
031 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
032 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
033 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
034 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
035 import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
036 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
037 import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
038 import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
039 import org.jetbrains.kotlin.types.DeferredType;
040 import org.jetbrains.kotlin.types.KotlinType;
041 import org.jetbrains.kotlin.types.TypeUtils;
042 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
043 import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
044 import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
045 import org.jetbrains.kotlin.types.expressions.FakeCallResolver;
046 import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
047
048 import java.util.Collections;
049 import java.util.List;
050
051 import static org.jetbrains.kotlin.diagnostics.Errors.*;
052 import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
053 import static org.jetbrains.kotlin.resolve.BindingContext.*;
054 import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER;
055 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
056 import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
057 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType;
058
059 public class DelegatedPropertyResolver {
060
061 public static final Name PROPERTY_DELEGATED_FUNCTION_NAME = Name.identifier("propertyDelegated");
062 public static final Name GETTER_NAME = Name.identifier("getValue");
063 public static final Name SETTER_NAME = Name.identifier("setValue");
064
065 public static final Name OLD_GETTER_NAME = Name.identifier("get");
066 public static final Name OLD_SETTER_NAME = Name.identifier("set");
067
068 @NotNull private final ExpressionTypingServices expressionTypingServices;
069 @NotNull private final FakeCallResolver fakeCallResolver;
070 @NotNull private final KotlinBuiltIns builtIns;
071 @NotNull private final SymbolUsageValidator symbolUsageValidator;
072
073 public DelegatedPropertyResolver(
074 @NotNull SymbolUsageValidator symbolUsageValidator,
075 @NotNull KotlinBuiltIns builtIns,
076 @NotNull FakeCallResolver fakeCallResolver,
077 @NotNull ExpressionTypingServices expressionTypingServices
078 ) {
079 this.symbolUsageValidator = symbolUsageValidator;
080 this.builtIns = builtIns;
081 this.fakeCallResolver = fakeCallResolver;
082 this.expressionTypingServices = expressionTypingServices;
083 }
084
085 @Nullable
086 public KotlinType getDelegatedPropertyGetMethodReturnType(
087 @NotNull PropertyDescriptor propertyDescriptor,
088 @NotNull KtExpression delegateExpression,
089 @NotNull KotlinType delegateType,
090 @NotNull BindingTrace trace,
091 @NotNull LexicalScope scope
092 ) {
093 resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, scope, true);
094 ResolvedCall<FunctionDescriptor> resolvedCall =
095 trace.getBindingContext().get(DELEGATED_PROPERTY_RESOLVED_CALL, propertyDescriptor.getGetter());
096 return resolvedCall != null ? resolvedCall.getResultingDescriptor().getReturnType() : null;
097 }
098
099 public void resolveDelegatedPropertyGetMethod(
100 @NotNull PropertyDescriptor propertyDescriptor,
101 @NotNull KtExpression delegateExpression,
102 @NotNull KotlinType delegateType,
103 @NotNull BindingTrace trace,
104 @NotNull LexicalScope scope
105 ) {
106 KotlinType returnType = getDelegatedPropertyGetMethodReturnType(
107 propertyDescriptor, delegateExpression, delegateType, trace, scope);
108 KotlinType propertyType = propertyDescriptor.getType();
109
110 /* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */
111 if (!(propertyType instanceof DeferredType) && returnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) {
112 Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, propertyDescriptor.getGetter());
113 assert call != null : "Call should exists for " + propertyDescriptor.getGetter();
114 trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH
115 .on(delegateExpression, renderCall(call, trace.getBindingContext()), propertyDescriptor.getType(), returnType));
116 }
117 }
118
119 public void resolveDelegatedPropertySetMethod(
120 @NotNull PropertyDescriptor propertyDescriptor,
121 @NotNull KtExpression delegateExpression,
122 @NotNull KotlinType delegateType,
123 @NotNull BindingTrace trace,
124 @NotNull LexicalScope scope
125 ) {
126 resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, scope, false);
127 }
128
129 @NotNull
130 private static KtExpression createExpressionForProperty(@NotNull KtPsiFactory psiFactory) {
131 return psiFactory.createExpression("null as " + KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString() + "<*>");
132 }
133
134 public void resolveDelegatedPropertyPDMethod(
135 @NotNull PropertyDescriptor propertyDescriptor,
136 @NotNull KtExpression delegateExpression,
137 @NotNull KotlinType delegateType,
138 @NotNull BindingTrace trace,
139 @NotNull LexicalScope scope
140 ) {
141 TemporaryBindingTrace traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property");
142 ExpressionTypingContext context = ExpressionTypingContext.newContext(
143 traceToResolvePDMethod, scope,
144 DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
145
146 KtPsiFactory psiFactory = KtPsiFactory(delegateExpression);
147 List<KtExpression> arguments = Collections.singletonList(createExpressionForProperty(psiFactory));
148 ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
149
150 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
151 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, PROPERTY_DELEGATED_FUNCTION_NAME, delegateExpression);
152
153 Call call = resolutionResult.getFirst();
154 OverloadResolutionResults<FunctionDescriptor> functionResults = resolutionResult.getSecond();
155
156 if (!functionResults.isSuccess()) {
157 String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext());
158 if (functionResults.isIncomplete() || functionResults.isSingleResult() ||
159 functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
160 trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
161 } else if (functionResults.isAmbiguity()) {
162 trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
163 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
164 }
165 return;
166 }
167
168 trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor, functionResults.getResultingCall());
169 }
170
171 /* Resolve getValue() or setValue() methods from delegate */
172 private void resolveDelegatedPropertyConventionMethod(
173 @NotNull PropertyDescriptor propertyDescriptor,
174 @NotNull KtExpression delegateExpression,
175 @NotNull KotlinType delegateType,
176 @NotNull BindingTrace trace,
177 @NotNull LexicalScope scope,
178 boolean isGet
179 ) {
180 PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
181 assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
182
183 if (trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor) != null) return;
184
185 OverloadResolutionResults<FunctionDescriptor> functionResults = getDelegatedPropertyConventionMethod(
186 propertyDescriptor, delegateExpression, delegateType, trace, scope, isGet, true);
187 Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor);
188 assert call != null : "'getDelegatedPropertyConventionMethod' didn't record a call";
189
190 if (!functionResults.isSuccess()) {
191 String expectedFunction = renderCall(call, trace.getBindingContext());
192 if (functionResults.isIncomplete()) {
193 trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType));
194 }
195 else if (functionResults.isSingleResult() ||
196 functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
197 trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE
198 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
199 }
200 else if (functionResults.isAmbiguity()) {
201 trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
202 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
203 }
204 else {
205 trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType));
206 }
207 return;
208 }
209
210 FunctionDescriptor resultingDescriptor = functionResults.getResultingDescriptor();
211
212 ResolvedCall<FunctionDescriptor> resultingCall = functionResults.getResultingCall();
213 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
214 if (declaration instanceof KtProperty) {
215 KtProperty property = (KtProperty) declaration;
216 KtPropertyDelegate delegate = property.getDelegate();
217 if (delegate != null) {
218 PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
219
220 if (!resultingDescriptor.isOperator()) {
221 OperatorValidator.Companion.report(byKeyword, resultingDescriptor, trace);
222 }
223
224 symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword);
225 }
226 }
227 trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall);
228 }
229
230 /* Resolve getValue() or setValue() methods from delegate */
231 public OverloadResolutionResults<FunctionDescriptor> getDelegatedPropertyConventionMethod(
232 @NotNull PropertyDescriptor propertyDescriptor,
233 @NotNull KtExpression delegateExpression,
234 @NotNull KotlinType delegateType,
235 @NotNull BindingTrace trace,
236 @NotNull LexicalScope scope,
237 boolean isGet,
238 boolean isComplete
239 ) {
240 PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
241 assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
242
243 KotlinType expectedType = isComplete && isGet && !(propertyDescriptor.getType() instanceof DeferredType)
244 ? propertyDescriptor.getType() : TypeUtils.NO_EXPECTED_TYPE;
245
246 ExpressionTypingContext context = ExpressionTypingContext.newContext(
247 trace, scope,
248 DataFlowInfo.EMPTY, expectedType);
249
250 boolean hasThis = propertyDescriptor.getExtensionReceiverParameter() != null || propertyDescriptor.getDispatchReceiverParameter() != null;
251
252 List<KtExpression> arguments = Lists.newArrayList();
253 KtPsiFactory psiFactory = KtPsiFactory(delegateExpression);
254 arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
255 arguments.add(createExpressionForProperty(psiFactory));
256
257 if (!isGet) {
258 KtReferenceExpression fakeArgument = (KtReferenceExpression) createFakeExpressionOfType(delegateExpression.getProject(), trace,
259 "fakeArgument" + arguments.size(),
260 propertyDescriptor.getType());
261 arguments.add(fakeArgument);
262 List<ValueParameterDescriptor> valueParameters = accessor.getValueParameters();
263 trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0));
264 }
265
266 Name functionName = isGet ? GETTER_NAME : SETTER_NAME;
267 ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
268
269 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
270 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression);
271
272 OverloadResolutionResults<FunctionDescriptor> resolutionResults = resolutionResult.getSecond();
273
274 // Resolve get/set is getValue/setValue was not found. Temporary, for code migration
275 if (!resolutionResults.isSuccess() && !resolutionResults.isAmbiguity()) {
276 Name oldFunctionName = isGet ? OLD_GETTER_NAME : OLD_SETTER_NAME;
277 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> additionalResolutionResult =
278 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, oldFunctionName, delegateExpression);
279 if (additionalResolutionResult.getSecond().isSuccess()) {
280 FunctionDescriptor resultingDescriptor = additionalResolutionResult.getSecond().getResultingDescriptor();
281
282 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
283 if (declaration instanceof KtProperty) {
284 KtProperty property = (KtProperty) declaration;
285 KtPropertyDelegate delegate = property.getDelegate();
286 if (delegate != null) {
287 PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
288
289 trace.report(DELEGATE_RESOLVED_TO_DEPRECATED_CONVENTION.on(
290 byKeyword, resultingDescriptor, delegateType, functionName.asString()));
291 }
292 }
293
294 trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, additionalResolutionResult.getFirst());
295 return additionalResolutionResult.getSecond();
296 }
297 }
298
299 trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.getFirst());
300 return resolutionResults;
301 }
302
303 private static String renderCall(@NotNull Call call, @NotNull BindingContext context) {
304 KtExpression calleeExpression = call.getCalleeExpression();
305 assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method";
306 StringBuilder builder = new StringBuilder(calleeExpression.getText());
307 builder.append("(");
308 List<KotlinType> argumentTypes = Lists.newArrayList();
309 for (ValueArgument argument : call.getValueArguments()) {
310 argumentTypes.add(context.getType(argument.getArgumentExpression()));
311
312 }
313 builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes));
314 builder.append(")");
315 return builder.toString();
316 }
317
318 @Nullable
319 public KotlinType resolveDelegateExpression(
320 @NotNull KtExpression delegateExpression,
321 @NotNull KtProperty jetProperty,
322 @NotNull PropertyDescriptor propertyDescriptor,
323 @NotNull LexicalScope propertyDeclarationInnerScope,
324 @NotNull LexicalScope accessorScope,
325 @NotNull BindingTrace trace,
326 @NotNull DataFlowInfo dataFlowInfo
327 ) {
328 TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property");
329 KtExpression calleeExpression = CallUtilKt.getCalleeExpressionIfAny(delegateExpression);
330 ConstraintSystemCompleter completer = createConstraintSystemCompleter(
331 jetProperty, propertyDescriptor, delegateExpression, accessorScope, trace);
332 if (calleeExpression != null) {
333 traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer);
334 }
335 KotlinType delegateType = expressionTypingServices.safeGetType(propertyDeclarationInnerScope, delegateExpression, NO_EXPECTED_TYPE,
336 dataFlowInfo, traceToResolveDelegatedProperty);
337 traceToResolveDelegatedProperty.commit(new TraceEntryFilter() {
338 @Override
339 public boolean accept(@Nullable WritableSlice<?, ?> slice, Object key) {
340 return slice != CONSTRAINT_SYSTEM_COMPLETER;
341 }
342 }, true);
343 return delegateType;
344 }
345
346 @NotNull
347 private ConstraintSystemCompleter createConstraintSystemCompleter(
348 @NotNull KtProperty property,
349 @NotNull final PropertyDescriptor propertyDescriptor,
350 @NotNull final KtExpression delegateExpression,
351 @NotNull final LexicalScope accessorScope,
352 @NotNull final BindingTrace trace
353 ) {
354 final KotlinType expectedType = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
355 return new ConstraintSystemCompleter() {
356 @Override
357 public void completeConstraintSystem(
358 @NotNull ConstraintSystem constraintSystem, @NotNull ResolvedCall<?> resolvedCall
359 ) {
360 KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
361 if (returnType == null) return;
362
363 TemporaryBindingTrace traceToResolveConventionMethods =
364 TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods");
365 OverloadResolutionResults<FunctionDescriptor>
366 getMethodResults = getDelegatedPropertyConventionMethod(
367 propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, accessorScope,
368 true, false
369 );
370
371 if (conventionMethodFound(getMethodResults)) {
372 FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor();
373 KotlinType returnTypeOfGetMethod = descriptor.getReturnType();
374 if (returnTypeOfGetMethod != null) {
375 constraintSystem.addSupertypeConstraint(expectedType, returnTypeOfGetMethod, FROM_COMPLETER.position());
376 }
377 addConstraintForThisValue(constraintSystem, descriptor);
378 }
379 if (!propertyDescriptor.isVar()) return;
380
381 // For the case: 'val v by d' (no declared type).
382 // When we add a constraint for 'set' method for delegated expression 'd' we use a type of the declared variable 'v'.
383 // But if the type isn't known yet, the constraint shouldn't be added (we try to infer the type of 'v' here as well).
384 if (propertyDescriptor.getReturnType() instanceof DeferredType) return;
385
386 OverloadResolutionResults<FunctionDescriptor>
387 setMethodResults = getDelegatedPropertyConventionMethod(
388 propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, accessorScope,
389 false, false
390 );
391
392 if (conventionMethodFound(setMethodResults)) {
393 FunctionDescriptor descriptor = setMethodResults.getResultingDescriptor();
394 List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
395 if (valueParameters.size() == 3) {
396 ValueParameterDescriptor valueParameterForThis = valueParameters.get(2);
397
398 if (!noExpectedType(expectedType)) {
399 constraintSystem.addSubtypeConstraint(
400 expectedType, valueParameterForThis.getType(), FROM_COMPLETER.position());
401 }
402 addConstraintForThisValue(constraintSystem, descriptor);
403 }
404 }
405 }
406
407 private boolean conventionMethodFound(@NotNull OverloadResolutionResults<FunctionDescriptor> results) {
408 return results.isSuccess() ||
409 (results.isSingleResult() &&
410 results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
411 }
412
413 private void addConstraintForThisValue(ConstraintSystem constraintSystem, FunctionDescriptor resultingDescriptor) {
414 ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
415 ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
416 KotlinType typeOfThis =
417 extensionReceiver != null ? extensionReceiver.getType() :
418 dispatchReceiver != null ? dispatchReceiver.getType() :
419 builtIns.getNullableNothingType();
420
421 List<ValueParameterDescriptor> valueParameters = resultingDescriptor.getValueParameters();
422 if (valueParameters.isEmpty()) return;
423 ValueParameterDescriptor valueParameterForThis = valueParameters.get(0);
424
425 constraintSystem.addSubtypeConstraint(typeOfThis, valueParameterForThis.getType(), FROM_COMPLETER.position());
426 }
427 };
428 }
429 }