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