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.diagnostics.Diagnostic;
027 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
028 import org.jetbrains.kotlin.diagnostics.Errors;
029 import org.jetbrains.kotlin.lexer.JetTokens;
030 import org.jetbrains.kotlin.psi.*;
031 import org.jetbrains.kotlin.resolve.*;
032 import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
033 import org.jetbrains.kotlin.resolve.scopes.WritableScope;
034 import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver;
035 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
036 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
037 import org.jetbrains.kotlin.types.JetType;
038 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
039
040 import java.util.ArrayList;
041 import java.util.List;
042
043 import static org.jetbrains.kotlin.diagnostics.Errors.*;
044 import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
045 import static org.jetbrains.kotlin.resolve.BindingContext.PROCESSED;
046
047 public class ExpressionTypingUtils {
048
049 @NotNull
050 public static ReceiverValue normalizeReceiverValueForVisibility(@NotNull ReceiverValue receiverValue, @NotNull BindingContext trace) {
051 if (receiverValue instanceof ExpressionReceiver) {
052 JetExpression expression = ((ExpressionReceiver) receiverValue).getExpression();
053 JetReferenceExpression referenceExpression = null;
054 if (expression instanceof JetThisExpression) {
055 referenceExpression = ((JetThisExpression) expression).getInstanceReference();
056 }
057 else if (expression instanceof JetConstructorDelegationReferenceExpression) {
058 referenceExpression = (JetReferenceExpression) expression;
059 }
060
061 if (referenceExpression != null) {
062 DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, referenceExpression);
063 if (descriptor instanceof ClassDescriptor) {
064 return new ClassReceiver((ClassDescriptor) descriptor.getOriginal());
065 }
066 }
067 }
068 return receiverValue;
069 }
070
071 @Nullable
072 public static ExpressionReceiver getExpressionReceiver(@NotNull JetExpression expression, @Nullable JetType type) {
073 if (type == null) return null;
074 return new ExpressionReceiver(expression, type);
075 }
076
077 @Nullable
078 public static ExpressionReceiver getExpressionReceiver(
079 @NotNull ExpressionTypingFacade facade,
080 @NotNull JetExpression expression,
081 ExpressionTypingContext context
082 ) {
083 return getExpressionReceiver(expression, facade.getTypeInfo(expression, context).getType());
084 }
085
086 @NotNull
087 public static ExpressionReceiver safeGetExpressionReceiver(
088 @NotNull ExpressionTypingFacade facade,
089 @NotNull JetExpression expression,
090 ExpressionTypingContext context
091 ) {
092 JetType type = safeGetType(facade.safeGetTypeInfo(expression, context));
093 return new ExpressionReceiver(expression, type);
094 }
095
096 @NotNull
097 public static JetType safeGetType(@NotNull JetTypeInfo typeInfo) {
098 JetType type = typeInfo.getType();
099 assert type != null : "safeGetType should be invoked on safe JetTypeInfo; safeGetTypeInfo should return @NotNull type";
100 return type;
101 }
102
103 @NotNull
104 public static LexicalWritableScope newWritableScopeImpl(ExpressionTypingContext context, @NotNull String scopeDebugName) {
105 LexicalWritableScope scope = new LexicalWritableScope(
106 context.scope, context.scope.getOwnerDescriptor(), false, null, new TraceBasedRedeclarationHandler(context.trace), scopeDebugName);
107 scope.changeLockLevel(WritableScope.LockLevel.BOTH);
108 return scope;
109 }
110
111 public static JetExpression createFakeExpressionOfType(
112 @NotNull Project project,
113 @NotNull BindingTrace trace,
114 @NotNull String argumentName,
115 @NotNull JetType argumentType
116 ) {
117 JetExpression fakeExpression = JetPsiFactory(project).createExpression(argumentName);
118 trace.recordType(fakeExpression, argumentType);
119 trace.record(PROCESSED, fakeExpression);
120 return fakeExpression;
121 }
122
123 public static void checkVariableShadowing(
124 @NotNull ExpressionTypingContext context,
125 @NotNull VariableDescriptor variableDescriptor,
126 @Nullable VariableDescriptor oldDescriptor
127 ) {
128 if (oldDescriptor != null && isLocal(variableDescriptor.getContainingDeclaration(), oldDescriptor)) {
129 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor);
130 if (declaration != null) {
131 context.trace.report(Errors.NAME_SHADOWING.on(declaration, variableDescriptor.getName().asString()));
132 }
133 }
134 }
135
136 public static ObservableBindingTrace makeTraceInterceptingTypeMismatch(
137 @NotNull BindingTrace trace,
138 @NotNull final JetElement expressionToWatch,
139 @NotNull final boolean[] mismatchFound
140 ) {
141 return new ObservableBindingTrace(trace) {
142
143 @Override
144 public void report(@NotNull Diagnostic diagnostic) {
145 DiagnosticFactory<?> factory = diagnostic.getFactory();
146 if ((factory == TYPE_MISMATCH || factory == CONSTANT_EXPECTED_TYPE_MISMATCH || factory == NULL_FOR_NONNULL_TYPE)
147 && diagnostic.getPsiElement() == expressionToWatch) {
148 mismatchFound[0] = true;
149 }
150 if (TYPE_INFERENCE_ERRORS.contains(factory) &&
151 PsiTreeUtil.isAncestor(expressionToWatch, diagnostic.getPsiElement(), false)) {
152 mismatchFound[0] = true;
153 }
154 super.report(diagnostic);
155 }
156 };
157 }
158
159 @NotNull
160 public static JetTypeInfo getTypeInfoOrNullType(
161 @Nullable JetExpression expression,
162 @NotNull ExpressionTypingContext context,
163 @NotNull ExpressionTypingInternals facade
164 ) {
165 return expression != null
166 ? facade.getTypeInfo(expression, context)
167 : TypeInfoFactoryPackage.noTypeInfo(context);
168 }
169
170 @SuppressWarnings("SuspiciousMethodCalls")
171 public static boolean isBinaryExpressionDependentOnExpectedType(@NotNull JetBinaryExpression expression) {
172 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
173 return (operationType == JetTokens.IDENTIFIER || OperatorConventions.BINARY_OPERATION_NAMES.containsKey(operationType)
174 || operationType == JetTokens.ELVIS);
175 }
176
177 public static boolean isUnaryExpressionDependentOnExpectedType(@NotNull JetUnaryExpression expression) {
178 return expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL;
179 }
180
181 public static boolean isExclExclExpression(@Nullable JetExpression expression) {
182 return expression instanceof JetUnaryExpression
183 && ((JetUnaryExpression) 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 }