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.isSingleResult() || functionResults.isIncomplete() ||
193                         functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
194                    trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE
195                                         .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
196                }
197                else if (functionResults.isAmbiguity()) {
198                    trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
199                                                 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
200                }
201                else {
202                    trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType));
203                }
204                return;
205            }
206    
207            FunctionDescriptor resultingDescriptor = functionResults.getResultingDescriptor();
208    
209            ResolvedCall<FunctionDescriptor> resultingCall = functionResults.getResultingCall();
210            PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
211            if (declaration instanceof KtProperty) {
212                KtProperty property = (KtProperty) declaration;
213                KtPropertyDelegate delegate = property.getDelegate();
214                if (delegate != null) {
215                    PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
216    
217                    if (!resultingDescriptor.isOperator()) {
218                        OperatorValidator.Companion.report(byKeyword, resultingDescriptor, trace);
219                    }
220    
221                    symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword);
222                }
223            }
224            trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall);
225        }
226    
227        /* Resolve getValue() or setValue() methods from delegate */
228        public OverloadResolutionResults<FunctionDescriptor> getDelegatedPropertyConventionMethod(
229                @NotNull PropertyDescriptor propertyDescriptor,
230                @NotNull KtExpression delegateExpression,
231                @NotNull KotlinType delegateType,
232                @NotNull BindingTrace trace,
233                @NotNull LexicalScope scope,
234                boolean isGet,
235                boolean isComplete
236        ) {
237            PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
238            assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
239    
240            KotlinType expectedType = isComplete && isGet && !(propertyDescriptor.getType() instanceof DeferredType)
241                                   ? propertyDescriptor.getType() : TypeUtils.NO_EXPECTED_TYPE;
242    
243            ExpressionTypingContext context = ExpressionTypingContext.newContext(
244                    trace, scope,
245                    DataFlowInfo.EMPTY, expectedType);
246    
247            boolean hasThis = propertyDescriptor.getExtensionReceiverParameter() != null || propertyDescriptor.getDispatchReceiverParameter() != null;
248    
249            List<KtExpression> arguments = Lists.newArrayList();
250            KtPsiFactory psiFactory = KtPsiFactory(delegateExpression);
251            arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
252            arguments.add(createExpressionForProperty(psiFactory));
253    
254            if (!isGet) {
255                KtReferenceExpression fakeArgument = (KtReferenceExpression) createFakeExpressionOfType(delegateExpression.getProject(), trace,
256                                                                                                          "fakeArgument" + arguments.size(),
257                                                                                                        propertyDescriptor.getType());
258                arguments.add(fakeArgument);
259                List<ValueParameterDescriptor> valueParameters = accessor.getValueParameters();
260                trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0));
261            }
262    
263            Name functionName = isGet ? GETTER_NAME : SETTER_NAME;
264            ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
265    
266            Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
267                    fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression);
268    
269            OverloadResolutionResults<FunctionDescriptor> resolutionResults = resolutionResult.getSecond();
270    
271            // Resolve get/set is getValue/setValue was not found. Temporary, for code migration
272            if (!resolutionResults.isSuccess() && !resolutionResults.isAmbiguity()) {
273                Name oldFunctionName = isGet ? OLD_GETTER_NAME : OLD_SETTER_NAME;
274                Pair<Call, OverloadResolutionResults<FunctionDescriptor>> additionalResolutionResult =
275                        fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, oldFunctionName, delegateExpression);
276                if (additionalResolutionResult.getSecond().isSuccess()) {
277                    FunctionDescriptor resultingDescriptor = additionalResolutionResult.getSecond().getResultingDescriptor();
278    
279                    PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
280                    if (declaration instanceof KtProperty) {
281                        KtProperty property = (KtProperty) declaration;
282                        KtPropertyDelegate delegate = property.getDelegate();
283                        if (delegate != null) {
284                            PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
285    
286                            trace.report(DELEGATE_RESOLVED_TO_DEPRECATED_CONVENTION.on(
287                                    byKeyword, resultingDescriptor, delegateType, functionName.asString()));
288                        }
289                    }
290    
291                    trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, additionalResolutionResult.getFirst());
292                    return additionalResolutionResult.getSecond();
293                }
294            }
295    
296            trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.getFirst());
297            return resolutionResults;
298        }
299    
300        private static String renderCall(@NotNull Call call, @NotNull BindingContext context) {
301            KtExpression calleeExpression = call.getCalleeExpression();
302            assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method";
303            StringBuilder builder = new StringBuilder(calleeExpression.getText());
304            builder.append("(");
305            List<KotlinType> argumentTypes = Lists.newArrayList();
306            for (ValueArgument argument : call.getValueArguments()) {
307                argumentTypes.add(context.getType(argument.getArgumentExpression()));
308    
309            }
310            builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes));
311            builder.append(")");
312            return builder.toString();
313        }
314    
315        @Nullable
316        public KotlinType resolveDelegateExpression(
317                @NotNull KtExpression delegateExpression,
318                @NotNull KtProperty jetProperty,
319                @NotNull PropertyDescriptor propertyDescriptor,
320                @NotNull LexicalScope propertyDeclarationInnerScope,
321                @NotNull LexicalScope accessorScope,
322                @NotNull BindingTrace trace,
323                @NotNull DataFlowInfo dataFlowInfo
324        ) {
325            TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property");
326            KtExpression calleeExpression = CallUtilKt.getCalleeExpressionIfAny(delegateExpression);
327            ConstraintSystemCompleter completer = createConstraintSystemCompleter(
328                    jetProperty, propertyDescriptor, delegateExpression, accessorScope, trace);
329            if (calleeExpression != null) {
330                traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer);
331            }
332            KotlinType delegateType = expressionTypingServices.safeGetType(propertyDeclarationInnerScope, delegateExpression, NO_EXPECTED_TYPE,
333                                                                           dataFlowInfo, traceToResolveDelegatedProperty);
334            traceToResolveDelegatedProperty.commit(new TraceEntryFilter() {
335                @Override
336                public boolean accept(@Nullable WritableSlice<?, ?> slice, Object key) {
337                    return slice != CONSTRAINT_SYSTEM_COMPLETER;
338                }
339            }, true);
340            return delegateType;
341        }
342    
343        @NotNull
344        private ConstraintSystemCompleter createConstraintSystemCompleter(
345                @NotNull KtProperty property,
346                @NotNull final PropertyDescriptor propertyDescriptor,
347                @NotNull final KtExpression delegateExpression,
348                @NotNull final LexicalScope accessorScope,
349                @NotNull final BindingTrace trace
350        ) {
351            final KotlinType expectedType = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
352            return new ConstraintSystemCompleter() {
353                @Override
354                public void completeConstraintSystem(
355                        @NotNull ConstraintSystem constraintSystem, @NotNull ResolvedCall<?> resolvedCall
356                ) {
357                    KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
358                    if (returnType == null) return;
359    
360                    TemporaryBindingTrace traceToResolveConventionMethods =
361                            TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods");
362                    OverloadResolutionResults<FunctionDescriptor>
363                            getMethodResults = getDelegatedPropertyConventionMethod(
364                                    propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, accessorScope,
365                                    true, false
366                            );
367    
368                    if (conventionMethodFound(getMethodResults)) {
369                        FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor();
370                        KotlinType returnTypeOfGetMethod = descriptor.getReturnType();
371                        if (returnTypeOfGetMethod != null) {
372                            constraintSystem.addSupertypeConstraint(expectedType, returnTypeOfGetMethod, FROM_COMPLETER.position());
373                        }
374                        addConstraintForThisValue(constraintSystem, descriptor);
375                    }
376                    if (!propertyDescriptor.isVar()) return;
377    
378                    // For the case: 'val v by d' (no declared type).
379                    // When we add a constraint for 'set' method for delegated expression 'd' we use a type of the declared variable 'v'.
380                    // 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).
381                    if (propertyDescriptor.getReturnType() instanceof DeferredType) return;
382    
383                    OverloadResolutionResults<FunctionDescriptor>
384                            setMethodResults = getDelegatedPropertyConventionMethod(
385                                    propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, accessorScope,
386                                    false, false
387                            );
388    
389                    if (conventionMethodFound(setMethodResults)) {
390                        FunctionDescriptor descriptor = setMethodResults.getResultingDescriptor();
391                        List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
392                        if (valueParameters.size() == 3) {
393                            ValueParameterDescriptor valueParameterForThis = valueParameters.get(2);
394    
395                            if (!noExpectedType(expectedType)) {
396                                constraintSystem.addSubtypeConstraint(
397                                        expectedType, valueParameterForThis.getType(), FROM_COMPLETER.position());
398                            }
399                            addConstraintForThisValue(constraintSystem, descriptor);
400                        }
401                    }
402                }
403    
404                private boolean conventionMethodFound(@NotNull OverloadResolutionResults<FunctionDescriptor> results) {
405                    return results.isSuccess() ||
406                           (results.isSingleResult() &&
407                            results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
408                }
409    
410                private void addConstraintForThisValue(ConstraintSystem constraintSystem, FunctionDescriptor resultingDescriptor) {
411                    ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
412                    ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
413                    KotlinType typeOfThis =
414                            extensionReceiver != null ? extensionReceiver.getType() :
415                            dispatchReceiver != null ? dispatchReceiver.getType() :
416                            builtIns.getNullableNothingType();
417    
418                    List<ValueParameterDescriptor> valueParameters = resultingDescriptor.getValueParameters();
419                    if (valueParameters.isEmpty()) return;
420                    ValueParameterDescriptor valueParameterForThis = valueParameters.get(0);
421    
422                    constraintSystem.addSubtypeConstraint(typeOfThis, valueParameterForThis.getType(), FROM_COMPLETER.position());
423                }
424            };
425        }
426    }