All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 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