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