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