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 }