
org.jetbrains.jet.lang.resolve.BindingContextUtils Maven / Gradle / Ivy
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInfo;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.Slices;
import java.util.*;
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
import static org.jetbrains.jet.lang.diagnostics.Errors.AMBIGUOUS_LABEL;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
public class BindingContextUtils {
private BindingContextUtils() {
}
private static final Slices.KeyNormalizer DECLARATION_DESCRIPTOR_NORMALIZER = new Slices.KeyNormalizer() {
@Override
public DeclarationDescriptor normalize(DeclarationDescriptor declarationDescriptor) {
if (declarationDescriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor callable = (CallableMemberDescriptor) declarationDescriptor;
if (callable.getKind() != DECLARATION) {
throw new IllegalStateException("non-declaration descriptors should be filtered out earlier: " + callable);
}
}
//if (declarationDescriptor instanceof VariableAsFunctionDescriptor) {
// VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor;
// if (descriptor.getOriginal() != descriptor) {
// throw new IllegalStateException("original should be resolved earlier: " + descriptor);
// }
//}
return declarationDescriptor.getOriginal();
}
};
/*package*/ static final ReadOnlySlice DESCRIPTOR_TO_DECLARATION =
Slices.sliceBuilder().setKeyNormalizer(DECLARATION_DESCRIPTOR_NORMALIZER).setDebugName("DESCRIPTOR_TO_DECLARATION").build();
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
DeclarationDescriptor descriptor = null;
if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
}
else if (element instanceof JetSimpleNameExpression) {
descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
}
else if (element instanceof JetQualifiedExpression) {
descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
}
if (descriptor instanceof VariableDescriptor) {
return (VariableDescriptor) descriptor;
}
return null;
}
@Nullable
public static JetFile getContainingFile(@NotNull BindingContext context, @NotNull DeclarationDescriptor declarationDescriptor) {
// declarationDescriptor may describe a synthesized element which doesn't have PSI
// To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
DeclarationDescriptor descriptor = DescriptorUtils.findTopLevelParent(declarationDescriptor);
if (descriptor == null) return null;
PsiElement declaration = descriptorToDeclaration(context, descriptor);
if (declaration == null) return null;
PsiFile containingFile = declaration.getContainingFile();
if (!(containingFile instanceof JetFile)) return null;
return (JetFile) containingFile;
}
@Nullable
private static PsiElement doGetDescriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
return context.get(DESCRIPTOR_TO_DECLARATION, descriptor);
}
// NOTE this is also used by KDoc
@Nullable
public static PsiElement descriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableMemberDescriptor) {
return callableDescriptorToDeclaration(context, (CallableMemberDescriptor) descriptor);
}
else if (descriptor instanceof ClassDescriptor) {
return classDescriptorToDeclaration(context, (ClassDescriptor) descriptor);
}
else {
return doGetDescriptorToDeclaration(context, descriptor);
}
}
@NotNull
public static List descriptorToDeclarations(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableMemberDescriptor) {
return callableDescriptorToDeclarations(context, (CallableMemberDescriptor) descriptor);
}
else {
PsiElement psiElement = descriptorToDeclaration(context, descriptor);
if (psiElement != null) {
return Lists.newArrayList(psiElement);
} else {
return Lists.newArrayList();
}
}
}
@Nullable
public static PsiElement callableDescriptorToDeclaration(@NotNull BindingContext context, @NotNull CallableMemberDescriptor callable) {
if (callable.getKind() == SYNTHESIZED) {
CallableMemberDescriptor original = callable.getOriginal();
if (original instanceof SynthesizedCallableMemberDescriptor>) {
DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor>) original).getBaseForSynthesized();
return descriptorToDeclaration(context, base);
}
return null;
}
if (callable.getKind() == DECLARATION) {
return doGetDescriptorToDeclaration(context, callable.getOriginal());
}
Set extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
if (overriddenDescriptors.size() != 1) {
throw new IllegalStateException(
"Cannot find declaration: fake descriptor " + callable + " has more than one overridden descriptor:\n" +
StringUtil.join(overriddenDescriptors, ",\n"));
}
return callableDescriptorToDeclaration(context, overriddenDescriptors.iterator().next());
}
@NotNull
public static List callableDescriptorToDeclarations(
@NotNull BindingContext context,
@NotNull CallableMemberDescriptor callable
) {
if (callable.getKind() == SYNTHESIZED) {
CallableMemberDescriptor original = callable.getOriginal();
if (original instanceof SynthesizedCallableMemberDescriptor>) {
DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor>) original).getBaseForSynthesized();
return descriptorToDeclarations(context, base);
}
return Collections.emptyList();
}
if (callable.getKind() == DECLARATION) {
PsiElement psiElement = doGetDescriptorToDeclaration(context, callable);
return psiElement != null ? Lists.newArrayList(psiElement) : Lists.newArrayList();
}
List r = new ArrayList();
Set extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
r.addAll(callableDescriptorToDeclarations(context, overridden));
}
return r;
}
@Nullable
public static PsiElement classDescriptorToDeclaration(@NotNull BindingContext context, @NotNull ClassDescriptor clazz) {
return doGetDescriptorToDeclaration(context, clazz);
}
public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
@NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
if (function.getKind() != DECLARATION) {
throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
}
trace.record(BindingContext.FUNCTION, psiElement, function);
}
@NotNull
public static V getNotNull(
@NotNull BindingContext bindingContext,
@NotNull ReadOnlySlice slice,
@NotNull K key
) {
return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
}
@NotNull
public static V getNotNull(
@NotNull BindingContext bindingContext,
@NotNull ReadOnlySlice slice,
@NotNull K key,
@NotNull String messageIfNull
) {
V value = bindingContext.get(slice, key);
if (value == null) {
throw new IllegalStateException(messageIfNull);
}
return value;
}
@NotNull
public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
if (declaration instanceof JetFunctionLiteral) {
return getEnclosingDescriptor(context, declaration);
}
DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
return descriptor;
}
public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
}
public static void reportAmbiguousLabel(
@NotNull BindingTrace trace,
@NotNull JetSimpleNameExpression targetLabel,
@NotNull Collection declarationsByLabel
) {
Collection targets = Lists.newArrayList();
for (DeclarationDescriptor descriptor : declarationsByLabel) {
PsiElement element = descriptorToDeclaration(trace.getBindingContext(), descriptor);
assert element != null : "Label can only point to something in the same lexical scope";
targets.add(element);
}
if (!targets.isEmpty()) {
trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
}
trace.report(AMBIGUOUS_LABEL.on(targetLabel));
}
@Nullable
public static JetType updateRecordedType(
@Nullable JetType type,
@NotNull JetExpression expression,
@NotNull BindingTrace trace,
boolean shouldBeMadeNullable
) {
if (type == null) return null;
if (shouldBeMadeNullable) {
type = TypeUtils.makeNullable(type);
}
trace.record(BindingContext.EXPRESSION_TYPE, expression, type);
return type;
}
@Nullable
public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
if (!context.get(BindingContext.PROCESSED, expression)) return null;
DataFlowInfo dataFlowInfo = context.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
if (dataFlowInfo == null) {
dataFlowInfo = DataFlowInfo.EMPTY;
}
JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
return JetTypeInfo.create(type, dataFlowInfo);
}
public static boolean isExpressionWithValidReference(
@NotNull JetExpression expression,
@NotNull BindingContext context
) {
if (expression instanceof JetCallExpression) {
return isCallExpressionWithValidReference(expression, context);
}
return expression instanceof JetReferenceExpression;
}
public static boolean isCallExpressionWithValidReference(
@NotNull JetExpression expression,
@NotNull BindingContext context
) {
if (expression instanceof JetCallExpression) {
JetExpression calleeExpression = ((JetCallExpression) expression).getCalleeExpression();
ResolvedCall> resolvedCall = context.get(BindingContext.RESOLVED_CALL, calleeExpression);
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return true;
}
}
return false;
}
public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy