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