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.types.expressions;
018    
019    import com.intellij.openapi.project.Project;
020    import com.intellij.psi.PsiElement;
021    import com.intellij.psi.tree.IElementType;
022    import com.intellij.psi.util.PsiTreeUtil;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
026    import org.jetbrains.kotlin.descriptors.*;
027    import org.jetbrains.kotlin.diagnostics.Diagnostic;
028    import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
029    import org.jetbrains.kotlin.diagnostics.Errors;
030    import org.jetbrains.kotlin.lexer.JetTokens;
031    import org.jetbrains.kotlin.psi.*;
032    import org.jetbrains.kotlin.resolve.*;
033    import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
034    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
035    import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
036    import org.jetbrains.kotlin.resolve.scopes.WritableScope;
037    import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl;
038    import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver;
039    import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
040    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
041    import org.jetbrains.kotlin.types.JetType;
042    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
043    
044    import java.util.ArrayList;
045    import java.util.List;
046    
047    import static org.jetbrains.kotlin.diagnostics.Errors.*;
048    import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
049    import static org.jetbrains.kotlin.resolve.BindingContext.PROCESSED;
050    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
051    
052    public class ExpressionTypingUtils {
053    
054        @NotNull
055        public static ReceiverValue normalizeReceiverValueForVisibility(@NotNull ReceiverValue receiverValue, @NotNull BindingContext trace) {
056            if (receiverValue instanceof ExpressionReceiver) {
057                JetExpression expression = ((ExpressionReceiver) receiverValue).getExpression();
058                JetReferenceExpression referenceExpression = null;
059                if (expression instanceof JetThisExpression) {
060                    referenceExpression = ((JetThisExpression) expression).getInstanceReference();
061                }
062                else if (expression instanceof JetConstructorDelegationReferenceExpression) {
063                    referenceExpression = (JetReferenceExpression) expression;
064                }
065    
066                if (referenceExpression != null) {
067                    DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, referenceExpression);
068                    if (descriptor instanceof ClassDescriptor) {
069                        return new ClassReceiver((ClassDescriptor) descriptor.getOriginal());
070                    }
071                }
072            }
073            return receiverValue;
074        }
075    
076        @Nullable
077        public static ExpressionReceiver getExpressionReceiver(@NotNull JetExpression expression, @Nullable JetType type) {
078            if (type == null) return null;
079            return new ExpressionReceiver(expression, type);
080        }
081    
082        @Nullable
083        public static ExpressionReceiver getExpressionReceiver(
084                @NotNull ExpressionTypingFacade facade,
085                @NotNull JetExpression expression,
086                ExpressionTypingContext context
087        ) {
088            return getExpressionReceiver(expression, facade.getTypeInfo(expression, context).getType());
089        }
090    
091        @NotNull
092        public static ExpressionReceiver safeGetExpressionReceiver(
093                @NotNull ExpressionTypingFacade facade,
094                @NotNull JetExpression expression,
095                ExpressionTypingContext context
096        ) {
097            JetType type = safeGetType(facade.safeGetTypeInfo(expression, context));
098            return new ExpressionReceiver(expression, type);
099        }
100    
101        @NotNull
102        public static JetType safeGetType(@NotNull JetTypeInfo typeInfo) {
103            JetType type = typeInfo.getType();
104            assert type != null : "safeGetType should be invoked on safe JetTypeInfo; safeGetTypeInfo should return @NotNull type";
105            return type;
106        }
107    
108        @NotNull
109        public static WritableScopeImpl newWritableScopeImpl(ExpressionTypingContext context, @NotNull String scopeDebugName) {
110            WritableScopeImpl scope = new WritableScopeImpl(
111                    context.scope, context.scope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.trace), scopeDebugName);
112            scope.changeLockLevel(WritableScope.LockLevel.BOTH);
113            return scope;
114        }
115    
116        public static JetExpression createFakeExpressionOfType(
117                @NotNull Project project,
118                @NotNull BindingTrace trace,
119                @NotNull String argumentName,
120                @NotNull JetType argumentType
121        ) {
122            JetExpression fakeExpression = JetPsiFactory(project).createExpression(argumentName);
123            trace.recordType(fakeExpression, argumentType);
124            trace.record(PROCESSED, fakeExpression);
125            return fakeExpression;
126        }
127    
128        public static void checkVariableShadowing(
129                @NotNull ExpressionTypingContext context,
130                @NotNull VariableDescriptor variableDescriptor,
131                @Nullable VariableDescriptor oldDescriptor
132        ) {
133            if (oldDescriptor != null && isLocal(variableDescriptor.getContainingDeclaration(), oldDescriptor)) {
134                PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor);
135                if (declaration != null) {
136                    context.trace.report(Errors.NAME_SHADOWING.on(declaration, variableDescriptor.getName().asString()));
137                }
138            }
139        }
140    
141        public static ObservableBindingTrace makeTraceInterceptingTypeMismatch(
142                @NotNull BindingTrace trace,
143                @NotNull final JetElement expressionToWatch,
144                @NotNull final boolean[] mismatchFound
145        ) {
146            return new ObservableBindingTrace(trace) {
147    
148                @Override
149                public void report(@NotNull Diagnostic diagnostic) {
150                    DiagnosticFactory<?> factory = diagnostic.getFactory();
151                    if ((factory == TYPE_MISMATCH || factory == CONSTANT_EXPECTED_TYPE_MISMATCH || factory == NULL_FOR_NONNULL_TYPE)
152                        && diagnostic.getPsiElement() == expressionToWatch) {
153                        mismatchFound[0] = true;
154                    }
155                    if (TYPE_INFERENCE_ERRORS.contains(factory) &&
156                        PsiTreeUtil.isAncestor(expressionToWatch, diagnostic.getPsiElement(), false)) {
157                        mismatchFound[0] = true;
158                    }
159                    super.report(diagnostic);
160                }
161            };
162        }
163    
164        @NotNull
165        public static JetTypeInfo getTypeInfoOrNullType(
166                @Nullable JetExpression expression,
167                @NotNull ExpressionTypingContext context,
168                @NotNull ExpressionTypingInternals facade
169        ) {
170            return expression != null
171                   ? facade.getTypeInfo(expression, context)
172                   : TypeInfoFactoryPackage.noTypeInfo(context);
173        }
174    
175        @SuppressWarnings("SuspiciousMethodCalls")
176        public static boolean isBinaryExpressionDependentOnExpectedType(@NotNull JetBinaryExpression expression) {
177            IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
178            return (operationType == JetTokens.IDENTIFIER || OperatorConventions.BINARY_OPERATION_NAMES.containsKey(operationType)
179                    || operationType == JetTokens.ELVIS);
180        }
181    
182        public static boolean isUnaryExpressionDependentOnExpectedType(@NotNull JetUnaryExpression expression) {
183            return expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL;
184        }
185    
186        @NotNull
187        public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
188            List<JetType> parameterTypes = new ArrayList<JetType>(valueParameters.size());
189            for (ValueParameterDescriptor parameter : valueParameters) {
190                parameterTypes.add(parameter.getType());
191            }
192            return parameterTypes;
193        }
194    
195        /**
196         * The primary case for local extensions is the following:
197         *
198         * I had a locally declared extension function or a local variable of function type called foo
199         * And I called it on my x
200         * Now, someone added function foo() to the class of x
201         * My code should not change
202         *
203         * thus
204         *
205         * local extension prevail over members (and members prevail over all non-local extensions)
206         */
207        public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
208            if (candidate instanceof ValueParameterDescriptor) {
209                return true;
210            }
211            DeclarationDescriptor parent = candidate.getContainingDeclaration();
212            if (!(parent instanceof FunctionDescriptor)) {
213                return false;
214            }
215            FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
216            DeclarationDescriptor current = containerOfTheCurrentLocality;
217            while (current != null) {
218                if (current == functionDescriptor) {
219                    return true;
220                }
221                current = current.getContainingDeclaration();
222            }
223            return false;
224        }
225    
226        public static boolean dependsOnExpectedType(@Nullable JetExpression expression) {
227            JetExpression expr = JetPsiUtil.deparenthesize(expression, false);
228            if (expr == null) return false;
229    
230            if (expr instanceof JetBinaryExpressionWithTypeRHS) {
231                return false;
232            }
233            if (expr instanceof JetBinaryExpression) {
234                return isBinaryExpressionDependentOnExpectedType((JetBinaryExpression) expr);
235            }
236            if (expr instanceof JetUnaryExpression) {
237                return isUnaryExpressionDependentOnExpectedType((JetUnaryExpression) expr);
238            }
239            return true;
240        }
241    
242        private ExpressionTypingUtils() {
243        }
244    
245        @NotNull
246        public static JetTypeInfo createCompileTimeConstantTypeInfo(
247                @NotNull CompileTimeConstant<?> value,
248                @NotNull JetExpression expression,
249                @NotNull ExpressionTypingContext context,
250                @NotNull KotlinBuiltIns kotlinBuiltIns
251        ) {
252            JetType expressionType = value.getType(kotlinBuiltIns);
253            if (value instanceof IntegerValueTypeConstant && context.contextDependency == INDEPENDENT) {
254                expressionType = ((IntegerValueTypeConstant) value).getType(context.expectedType);
255                ArgumentTypeResolver.updateNumberType(expressionType, expression, context);
256            }
257    
258            return TypeInfoFactoryPackage.createCheckedTypeInfo(expressionType, context, expression);
259        }
260    }