001    /*
002     * Copyright 2010-2016 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.descriptors.*;
026    import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
027    import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor;
028    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
029    import org.jetbrains.kotlin.diagnostics.Diagnostic;
030    import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
031    import org.jetbrains.kotlin.diagnostics.Errors;
032    import org.jetbrains.kotlin.lexer.KtTokens;
033    import org.jetbrains.kotlin.psi.*;
034    import org.jetbrains.kotlin.resolve.BindingTrace;
035    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
036    import org.jetbrains.kotlin.resolve.ObservableBindingTrace;
037    import org.jetbrains.kotlin.resolve.OverloadChecker;
038    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
039    import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
040    import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
041    import org.jetbrains.kotlin.resolve.scopes.TraceBasedLocalRedeclarationChecker;
042    import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
043    import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
044    import org.jetbrains.kotlin.types.KotlinType;
045    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
046    
047    import java.util.ArrayList;
048    import java.util.List;
049    
050    import static org.jetbrains.kotlin.diagnostics.Errors.TYPE_INFERENCE_ERRORS;
051    import static org.jetbrains.kotlin.resolve.BindingContext.PROCESSED;
052    
053    public class ExpressionTypingUtils {
054    
055        @Nullable
056        public static ExpressionReceiver getExpressionReceiver(
057                @NotNull ExpressionTypingFacade facade,
058                @NotNull KtExpression expression,
059                ExpressionTypingContext context
060        ) {
061            KotlinType type = facade.getTypeInfo(expression, context).getType();
062            if (type == null) return null;
063            return ExpressionReceiver.Companion.create(expression, type, context.trace.getBindingContext());
064        }
065    
066        @NotNull
067        public static ExpressionReceiver safeGetExpressionReceiver(
068                @NotNull ExpressionTypingFacade facade,
069                @NotNull KtExpression expression,
070                ExpressionTypingContext context
071        ) {
072            KotlinType type = safeGetType(facade.safeGetTypeInfo(expression, context));
073            return ExpressionReceiver.Companion.create(expression, type, context.trace.getBindingContext());
074        }
075    
076        @NotNull
077        public static KotlinType safeGetType(@NotNull KotlinTypeInfo typeInfo) {
078            KotlinType type = typeInfo.getType();
079            assert type != null : "safeGetType should be invoked on safe KotlinTypeInfo; safeGetTypeInfo should return @NotNull type";
080            return type;
081        }
082    
083        @NotNull
084        public static LexicalWritableScope newWritableScopeImpl(
085                @NotNull ExpressionTypingContext context,
086                @NotNull LexicalScopeKind scopeKind,
087                @NotNull OverloadChecker overloadChecker
088        ) {
089            return new LexicalWritableScope(context.scope, context.scope.getOwnerDescriptor(), false,
090                                            new TraceBasedLocalRedeclarationChecker(context.trace, overloadChecker), scopeKind);
091        }
092    
093        public static KtExpression createFakeExpressionOfType(
094                @NotNull Project project,
095                @NotNull BindingTrace trace,
096                @NotNull String argumentName,
097                @NotNull KotlinType argumentType
098        ) {
099            KtExpression fakeExpression = KtPsiFactoryKt.KtPsiFactory(project).createExpression(argumentName);
100            trace.recordType(fakeExpression, argumentType);
101            trace.record(PROCESSED, fakeExpression);
102            return fakeExpression;
103        }
104    
105        public static void checkVariableShadowing(
106                @NotNull LexicalScope scope,
107                @NotNull BindingTrace trace,
108                @NotNull VariableDescriptor variableDescriptor
109        ) {
110            VariableDescriptor oldDescriptor = ScopeUtilsKt.findLocalVariable(scope, variableDescriptor.getName());
111    
112            if (oldDescriptor != null && isLocal(variableDescriptor.getContainingDeclaration(), oldDescriptor)) {
113                PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor);
114                if (declaration != null) {
115                    if (declaration instanceof KtDestructuringDeclarationEntry && declaration.getParent().getParent() instanceof KtParameter) {
116                        // foo { a, (a, b) -> } -- do not report NAME_SHADOWING on the second 'a', because REDECLARATION must be reported here
117                        PsiElement oldElement = DescriptorToSourceUtils.descriptorToDeclaration(oldDescriptor);
118    
119                        if (oldElement != null && oldElement.getParent().equals(declaration.getParent().getParent().getParent())) return;
120                    }
121                    trace.report(Errors.NAME_SHADOWING.on(declaration, variableDescriptor.getName().asString()));
122                }
123            }
124        }
125    
126        public static ObservableBindingTrace makeTraceInterceptingTypeMismatch(
127                @NotNull BindingTrace trace,
128                @NotNull final KtElement expressionToWatch,
129                @NotNull final boolean[] mismatchFound
130        ) {
131            return new ObservableBindingTrace(trace) {
132    
133                @Override
134                public void report(@NotNull Diagnostic diagnostic) {
135                    DiagnosticFactory<?> factory = diagnostic.getFactory();
136                    if (Errors.TYPE_MISMATCH_ERRORS.contains(factory) && diagnostic.getPsiElement() == expressionToWatch) {
137                        mismatchFound[0] = true;
138                    }
139                    if (TYPE_INFERENCE_ERRORS.contains(factory) &&
140                        PsiTreeUtil.isAncestor(expressionToWatch, diagnostic.getPsiElement(), false)) {
141                        mismatchFound[0] = true;
142                    }
143                    super.report(diagnostic);
144                }
145            };
146        }
147    
148        @NotNull
149        public static KotlinTypeInfo getTypeInfoOrNullType(
150                @Nullable KtExpression expression,
151                @NotNull ExpressionTypingContext context,
152                @NotNull ExpressionTypingInternals facade
153        ) {
154            return expression != null
155                   ? facade.getTypeInfo(expression, context)
156                   : TypeInfoFactoryKt.noTypeInfo(context);
157        }
158    
159        @SuppressWarnings("SuspiciousMethodCalls")
160        public static boolean isBinaryExpressionDependentOnExpectedType(@NotNull KtBinaryExpression expression) {
161            IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
162            return (operationType == KtTokens.IDENTIFIER || OperatorConventions.BINARY_OPERATION_NAMES.containsKey(operationType)
163                    || operationType == KtTokens.ELVIS);
164        }
165    
166        public static boolean isUnaryExpressionDependentOnExpectedType(@NotNull KtUnaryExpression expression) {
167            return expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL;
168        }
169    
170        public static boolean isExclExclExpression(@Nullable KtExpression expression) {
171            return expression instanceof KtUnaryExpression
172                   && ((KtUnaryExpression) expression).getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL;
173        }
174    
175        @NotNull
176        public static List<KotlinType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
177            List<KotlinType> parameterTypes = new ArrayList<KotlinType>(valueParameters.size());
178            for (ValueParameterDescriptor parameter : valueParameters) {
179                parameterTypes.add(parameter.getType());
180            }
181            return parameterTypes;
182        }
183    
184        /**
185         * The primary case for local extensions is the following:
186         *
187         * I had a locally declared extension function or a local variable of function type called foo
188         * And I called it on my x
189         * Now, someone added function foo() to the class of x
190         * My code should not change
191         *
192         * thus
193         *
194         * local extension prevail over members (and members prevail over all non-local extensions)
195         */
196        public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
197            if (candidate instanceof ValueParameterDescriptor) {
198                return true;
199            }
200            DeclarationDescriptor parent = candidate.getContainingDeclaration();
201            if (!(parent instanceof FunctionDescriptor)) {
202                return false;
203            }
204            FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
205            DeclarationDescriptor current = containerOfTheCurrentLocality;
206            while (current != null) {
207                if (current == functionDescriptor) {
208                    return true;
209                }
210                current = current.getContainingDeclaration();
211            }
212            return false;
213        }
214    
215        public static boolean dependsOnExpectedType(@Nullable KtExpression expression) {
216            KtExpression expr = KtPsiUtil.deparenthesize(expression);
217            if (expr == null) return false;
218    
219            if (expr instanceof KtBinaryExpressionWithTypeRHS) {
220                return false;
221            }
222            if (expr instanceof KtBinaryExpression) {
223                return isBinaryExpressionDependentOnExpectedType((KtBinaryExpression) expr);
224            }
225            if (expr instanceof KtUnaryExpression) {
226                return isUnaryExpressionDependentOnExpectedType((KtUnaryExpression) expr);
227            }
228            return true;
229        }
230    
231        private ExpressionTypingUtils() {
232        }
233    
234        public static boolean isFunctionLiteral(@Nullable DeclarationDescriptor descriptor) {
235            return descriptor instanceof AnonymousFunctionDescriptor;
236        }
237    
238        public static boolean isLocalFunction(@Nullable DeclarationDescriptor descriptor) {
239            if (descriptor != null && descriptor.getClass() == SimpleFunctionDescriptorImpl.class) {
240                return ((SimpleFunctionDescriptorImpl) descriptor).getVisibility() == Visibilities.LOCAL;
241            }
242            return false;
243        }
244    
245        public static boolean isFunctionExpression(@Nullable DeclarationDescriptor descriptor) {
246            return descriptor instanceof FunctionExpressionDescriptor;
247        }
248    }