001/*
002 * Copyright 2010-2013 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
017package org.jetbrains.jet.lang.resolve.calls.tasks;
018
019import com.google.common.collect.Sets;
020import com.intellij.lang.ASTNode;
021import com.intellij.psi.PsiElement;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.jet.lang.descriptors.*;
024import org.jetbrains.jet.lang.diagnostics.Errors;
025import org.jetbrains.jet.lang.psi.*;
026import org.jetbrains.jet.lang.resolve.BindingTrace;
027import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
028import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData;
029import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
030import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
031import org.jetbrains.jet.lang.resolve.name.Name;
032import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
033import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
034import org.jetbrains.jet.lang.types.ErrorUtils;
035import org.jetbrains.jet.lang.types.JetType;
036import org.jetbrains.jet.lang.types.TypeUtils;
037import org.jetbrains.jet.lang.types.Variance;
038import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
039import org.jetbrains.jet.lexer.JetToken;
040import org.jetbrains.jet.lexer.JetTokens;
041
042import java.util.Collection;
043import java.util.List;
044
045import static org.jetbrains.jet.lang.diagnostics.Errors.*;
046import static org.jetbrains.jet.lang.resolve.BindingContext.*;
047
048public class TracingStrategyImpl implements TracingStrategy {
049    private final JetReferenceExpression reference;
050    private final Call call;
051
052    private TracingStrategyImpl(@NotNull JetReferenceExpression reference, @NotNull Call call) {
053        this.reference = reference;
054        this.call = call;
055    }
056
057    @NotNull
058    public static TracingStrategy create(@NotNull JetReferenceExpression reference, @NotNull Call call) {
059        return new TracingStrategyImpl(reference, call);
060    }
061
062    @Override
063    public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall) {
064        CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
065        if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
066            descriptor = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getResultingDescriptor();
067        }
068        DeclarationDescriptor storedReference = trace.get(REFERENCE_TARGET, reference);
069        if (storedReference == null || !ErrorUtils.isError(descriptor)) {
070            trace.record(REFERENCE_TARGET, reference, descriptor);
071        }
072    }
073
074    @Override
075    public <D extends CallableDescriptor> void bindResolvedCall(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall) {
076        trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
077        trace.record(CALL, call.getCalleeExpression(), call);
078    }
079
080    @Override
081    public <D extends CallableDescriptor> void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
082        Collection<D> descriptors = Sets.newHashSet();
083        for (ResolvedCallWithTrace<D> candidate : candidates) {
084            descriptors.add(candidate.getCandidateDescriptor());
085        }
086        trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors);
087    }
088
089    @Override
090    public void unresolvedReference(@NotNull BindingTrace trace) {
091        trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
092    }
093
094    @Override
095    public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
096        trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates));
097    }
098
099    @Override
100    public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) {
101        JetElement reportOn;
102        JetValueArgumentList valueArgumentList = call.getValueArgumentList();
103        if (valueArgumentList != null) {
104            reportOn = valueArgumentList;
105        }
106        else {
107            reportOn = reference;
108        }
109        trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter));
110    }
111
112    @Override
113    public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {
114        trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType()));
115    }
116
117    @Override
118    public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument) {
119        if (receiverArgument instanceof ExpressionReceiver) {
120            ExpressionReceiver expressionReceiver = (ExpressionReceiver)receiverArgument;
121            trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType()));
122        }
123        else {
124            trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType()));
125        }
126    }
127
128    @Override
129    public void noReceiverAllowed(@NotNull BindingTrace trace) {
130        trace.report(NO_RECEIVER_ADMITTED.on(reference));
131    }
132
133    @Override
134    public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
135        JetTypeArgumentList typeArgumentList = call.getTypeArgumentList();
136        if (typeArgumentList != null) {
137            trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount));
138        }
139        else {
140            trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount));
141        }
142    }
143
144    @Override
145    public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors) {
146        trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(call.getCallElement(), descriptors));
147    }
148
149    @Override
150    public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors) {
151        trace.report(NONE_APPLICABLE.on(reference, descriptors));
152    }
153
154    @Override
155    public <D extends CallableDescriptor> void cannotCompleteResolve(
156            @NotNull BindingTrace trace,
157            @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
158    ) {
159        trace.report(CANNOT_COMPLETE_RESOLVE.on(reference, descriptors));
160    }
161
162    @Override
163    public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
164        trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallElement()));
165    }
166
167    @Override
168    public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {
169        ASTNode callOperationNode = call.getCallOperationNode();
170        if (callOperationNode != null && !isCallForImplicitInvoke) {
171            trace.report(UNSAFE_CALL.on(callOperationNode.getPsi(), type));
172        }
173        else {
174            PsiElement callElement = call.getCallElement();
175            if (callElement instanceof JetBinaryExpression) {
176                JetBinaryExpression binaryExpression = (JetBinaryExpression)callElement;
177                JetSimpleNameExpression operationReference = binaryExpression.getOperationReference();
178
179                Name operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ?
180                        Name.identifier(operationReference.getText()) :
181                        OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType());
182
183                JetExpression left = binaryExpression.getLeft();
184                JetExpression right = binaryExpression.getRight();
185                if (left != null && right != null) {
186                    trace.report(UNSAFE_INFIX_CALL.on(reference, left.getText(), operationString.asString(), right.getText()));
187                }
188            }
189            else {
190                trace.report(UNSAFE_CALL.on(reference, type));
191            }
192        }
193    }
194
195    @Override
196    public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {
197        ASTNode callOperationNode = call.getCallOperationNode();
198        assert callOperationNode != null;
199        trace.report(UNNECESSARY_SAFE_CALL.on(callOperationNode.getPsi(), type));
200    }
201
202    @Override
203    public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments) {
204        for (JetExpression functionLiteralArgument : functionLiteralArguments) {
205            trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument));
206        }
207    }
208
209    @Override
210    public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {
211        trace.report(INVISIBLE_MEMBER.on(call.getCallElement(), descriptor, descriptor.getVisibility(), descriptor.getContainingDeclaration()));
212    }
213
214    @Override
215    public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data) {
216        ConstraintSystem constraintSystem = data.constraintSystem;
217        assert !constraintSystem.isSuccessful() : "Report error only for not successful constraint system";
218
219        if (constraintSystem.hasErrorInConstrainingTypes()) {
220            // Do not report type inference errors if there is one in the arguments
221            // (it's useful, when the arguments, e.g. lambdas or calls are incomplete)
222            return;
223        }
224        if (constraintSystem.hasOnlyExpectedTypeMismatch()) {
225            JetType declaredReturnType = data.descriptor.getReturnType();
226            if (declaredReturnType == null) return;
227
228            JetType substitutedReturnType = constraintSystem.getResultingSubstitutor().substitute(declaredReturnType, Variance.INVARIANT);
229            assert substitutedReturnType != null; //todo
230
231            assert data.expectedType != TypeUtils.NO_EXPECTED_TYPE : "Expected type doesn't exist, but there is an expected type mismatch error";
232            trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, substitutedReturnType, data.expectedType));
233        }
234        else if (constraintSystem.hasTypeConstructorMismatch()) {
235            trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
236        }
237        else if (constraintSystem.hasConflictingConstraints()) {
238            trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
239        }
240        else {
241            assert constraintSystem.hasUnknownParameters();
242            trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
243        }
244    }
245
246    @Override
247    public void upperBoundViolated(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {
248        trace.report(Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, inferenceErrorData));
249    }
250}