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