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