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.resolve;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.openapi.util.Pair;
021 import com.intellij.psi.PsiElement;
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.psi.*;
027 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
028 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
029 import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
030 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
031 import org.jetbrains.kotlin.types.JetType;
032 import org.jetbrains.kotlin.types.TypeUtils;
033 import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
034 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
035 import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
036
037 import java.util.Collection;
038
039 import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
040 import static org.jetbrains.kotlin.diagnostics.Errors.AMBIGUOUS_LABEL;
041 import static org.jetbrains.kotlin.resolve.BindingContext.*;
042
043 public class BindingContextUtils {
044 private BindingContextUtils() {
045 }
046
047 @Nullable
048 public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
049 DeclarationDescriptor descriptor = null;
050 if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
051 descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
052 }
053 else if (element instanceof JetSimpleNameExpression) {
054 descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
055 }
056 else if (element instanceof JetQualifiedExpression) {
057 descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
058 }
059 if (descriptor instanceof VariableDescriptor) {
060 return (VariableDescriptor) descriptor;
061 }
062 return null;
063 }
064
065 public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
066 @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
067
068 if (function.getKind() != DECLARATION) {
069 throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
070 }
071
072 trace.record(BindingContext.FUNCTION, psiElement, function);
073 }
074
075 @NotNull
076 public static <K, V> V getNotNull(
077 @NotNull BindingContext bindingContext,
078 @NotNull ReadOnlySlice<K, V> slice,
079 @NotNull K key
080 ) {
081 return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
082 }
083
084 @NotNull
085 public static JetType getTypeNotNull(
086 @NotNull BindingContext bindingContext,
087 @NotNull JetExpression expression
088 ) {
089 JetType result = bindingContext.getType(expression);
090 if (result == null) {
091 throw new IllegalStateException("Type must be not null for " + expression);
092 }
093 return result;
094 }
095
096 @NotNull
097 public static <K, V> V getNotNull(
098 @NotNull BindingContext bindingContext,
099 @NotNull ReadOnlySlice<K, V> slice,
100 @NotNull K key,
101 @NotNull String messageIfNull
102 ) {
103 V value = bindingContext.get(slice, key);
104 if (value == null) {
105 throw new IllegalStateException(messageIfNull);
106 }
107 return value;
108 }
109
110 @NotNull
111 public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
112 JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
113 if (declaration instanceof JetFunctionLiteral) {
114 return getEnclosingDescriptor(context, declaration);
115 }
116 DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
117 assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
118 return descriptor;
119 }
120
121 public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
122 JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
123 return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
124 }
125
126 public static void reportAmbiguousLabel(
127 @NotNull BindingTrace trace,
128 @NotNull JetSimpleNameExpression targetLabel,
129 @NotNull Collection<DeclarationDescriptor> declarationsByLabel
130 ) {
131 Collection<PsiElement> targets = Lists.newArrayList();
132 for (DeclarationDescriptor descriptor : declarationsByLabel) {
133 PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
134 assert element != null : "Label can only point to something in the same lexical scope";
135 targets.add(element);
136 }
137 if (!targets.isEmpty()) {
138 trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
139 }
140 trace.report(AMBIGUOUS_LABEL.on(targetLabel));
141 }
142
143 @Nullable
144 public static JetType updateRecordedType(
145 @Nullable JetType type,
146 @NotNull JetExpression expression,
147 @NotNull BindingTrace trace,
148 boolean shouldBeMadeNullable
149 ) {
150 if (type == null) return null;
151 if (shouldBeMadeNullable) {
152 type = TypeUtils.makeNullable(type);
153 }
154 trace.recordType(expression, type);
155 return type;
156 }
157
158 @Nullable
159 public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
160 // noinspection ConstantConditions
161 if (!context.get(BindingContext.PROCESSED, expression)) return null;
162 // NB: should never return null if expression is already processed
163 JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
164 return result != null ? result : TypeInfoFactoryPackage.noTypeInfo(DataFlowInfo.EMPTY);
165 }
166
167 public static boolean isExpressionWithValidReference(
168 @NotNull JetExpression expression,
169 @NotNull BindingContext context
170 ) {
171 if (expression instanceof JetCallExpression) {
172 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
173 return resolvedCall instanceof VariableAsFunctionResolvedCall;
174 }
175 return expression instanceof JetReferenceExpression;
176 }
177
178 public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
179 if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
180 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
181 return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
182 }
183
184 @NotNull
185 public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
186 @Nullable DeclarationDescriptor startDescriptor,
187 boolean strict
188 ) {
189 FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
190 PsiElement containingFunction =
191 containingFunctionDescriptor != null ? DescriptorToSourceUtils.getSourceFromDescriptor(containingFunctionDescriptor) : null;
192 while (containingFunction instanceof JetFunctionLiteral) {
193 containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
194 containingFunction = containingFunctionDescriptor != null ? DescriptorToSourceUtils
195 .getSourceFromDescriptor(containingFunctionDescriptor) : null;
196 }
197
198 return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
199 }
200
201 @Nullable
202 public static ResolvedCall<ConstructorDescriptor> getDelegationConstructorCall(
203 @NotNull BindingContext bindingContext,
204 @NotNull ConstructorDescriptor constructorDescriptor
205 ) {
206 return bindingContext.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructorDescriptor);
207 }
208 }