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