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