org.jetbrains.jet.lang.resolve.lazy.LazyImportScope.java Source code

Java tutorial

Introduction

Here is the source code for org.jetbrains.jet.lang.resolve.lazy.LazyImportScope.java

Source

/*
 * 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.lazy;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import kotlin.Function0;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.Importer;
import org.jetbrains.jet.lang.resolve.ImportsResolver;
import org.jetbrains.jet.lang.resolve.JetModuleUtil;
import org.jetbrains.jet.lang.resolve.name.LabelName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.*;
import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
import org.jetbrains.jet.utils.Printer;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode;

public class LazyImportScope implements JetScope, LazyEntity {
    private final ResolveSession resolveSession;
    private final PackageViewDescriptor packageDescriptor;
    private final ImportsProvider importsProvider;
    private final JetScope rootScope;
    private final BindingTrace traceForImportResolve;
    private final String debugName;

    private static class ImportResolveStatus {
        private final LookupMode lookupMode;
        private final JetScope scope;

        ImportResolveStatus(LookupMode lookupMode, JetScope scope) {
            this.lookupMode = lookupMode;
            this.scope = scope;
        }
    }

    private class ImportDirectiveResolveCache {
        private final JetImportDirective directive;

        @Nullable
        private volatile ImportResolveStatus importResolveStatus;

        private ImportDirectiveResolveCache(JetImportDirective directive) {
            this.directive = directive;
        }

        private JetScope scopeForMode(final LookupMode mode) {
            ImportResolveStatus status = importResolveStatus;
            if (status != null && (status.lookupMode == mode || status.lookupMode == LookupMode.EVERYTHING)) {
                return status.scope;
            }

            return resolveSession.getStorageManager().compute(new Function0<JetScope>() {
                @Override
                public JetScope invoke() {
                    ImportResolveStatus cachedStatus = importResolveStatus;
                    if (cachedStatus != null && (cachedStatus.lookupMode == mode
                            || cachedStatus.lookupMode == LookupMode.EVERYTHING)) {
                        return cachedStatus.scope;
                    }

                    WritableScope directiveImportScope = new WritableScopeImpl(JetScope.EMPTY, packageDescriptor,
                            RedeclarationHandler.DO_NOTHING,
                            "Scope for import '" + directive.getText() + "' resolve in " + toString());
                    directiveImportScope.changeLockLevel(WritableScope.LockLevel.BOTH);

                    Importer.StandardImporter importer = new Importer.StandardImporter(directiveImportScope);
                    directiveUnderResolve = directive;

                    try {
                        resolveSession.getQualifiedExpressionResolver().processImportReference(directive, rootScope,
                                packageDescriptor.getMemberScope(), importer, traceForImportResolve,
                                resolveSession.getModuleDescriptor(), mode);
                    } finally {
                        directiveUnderResolve = null;
                        directiveImportScope.changeLockLevel(WritableScope.LockLevel.READING);
                    }

                    importResolveStatus = new ImportResolveStatus(mode, directiveImportScope);
                    return directiveImportScope;
                }
            });
        }
    }

    private final MemoizedFunctionToNotNull<JetImportDirective, ImportDirectiveResolveCache> importedScopesProvider;

    private JetImportDirective directiveUnderResolve = null;

    public LazyImportScope(@NotNull ResolveSession resolveSession, @NotNull PackageViewDescriptor packageDescriptor,
            @NotNull List<JetImportDirective> imports, @NotNull BindingTrace traceForImportResolve,
            @NotNull String debugName, boolean inRootPackage) {
        this.resolveSession = resolveSession;
        this.packageDescriptor = packageDescriptor;
        this.importsProvider = new ImportsProvider(resolveSession.getStorageManager(), imports);
        this.traceForImportResolve = traceForImportResolve;
        this.debugName = debugName;

        this.importedScopesProvider = resolveSession.getStorageManager()
                .createMemoizedFunction(new Function1<JetImportDirective, ImportDirectiveResolveCache>() {
                    @Override
                    public ImportDirectiveResolveCache invoke(JetImportDirective directive) {
                        return new ImportDirectiveResolveCache(directive);
                    }
                });

        this.rootScope = JetModuleUtil.getImportsResolutionScope(resolveSession.getModuleDescriptor(),
                inRootPackage);
    }

    public static LazyImportScope createImportScopeForFile(@NotNull ResolveSession resolveSession,
            @NotNull PackageViewDescriptor packageDescriptor, @NotNull JetFile jetFile,
            @NotNull BindingTrace traceForImportResolve, @NotNull String debugName) {
        return new LazyImportScope(resolveSession, packageDescriptor, Lists.reverse(jetFile.getImportDirectives()),
                traceForImportResolve, debugName, packageDescriptor.getFqName().isRoot());
    }

    @Override
    public void forceResolveAllContents() {
        for (JetImportDirective importDirective : importsProvider.getAllImports()) {
            getImportScope(importDirective, LookupMode.EVERYTHING);
        }
    }

    @Nullable
    private <D extends DeclarationDescriptor> D selectFirstFromImports(final Name name, final LookupMode lookupMode,
            final JetScopeSelectorUtil.ScopeByNameSelector<D> descriptorSelector) {
        return resolveSession.getStorageManager().compute(new Function0<D>() {
            @Override
            public D invoke() {
                for (JetImportDirective directive : importsProvider.getImports(name)) {
                    if (directive == directiveUnderResolve) {
                        // This is the recursion in imports analysis
                        return null;
                    }

                    D foundDescriptor = descriptorSelector.get(getImportScope(directive, lookupMode), name);
                    if (foundDescriptor != null) {
                        return foundDescriptor;
                    }
                }

                return null;
            }
        });
    }

    @NotNull
    private <D extends DeclarationDescriptor> Collection<D> collectFromImports(final Name name,
            final LookupMode lookupMode,
            final JetScopeSelectorUtil.ScopeByNameMultiSelector<D> descriptorsSelector) {
        return resolveSession.getStorageManager().compute(new Function0<Collection<D>>() {
            @Override
            public Collection<D> invoke() {
                Set<D> descriptors = Sets.newHashSet();
                for (JetImportDirective directive : importsProvider.getImports(name)) {
                    if (directive == directiveUnderResolve) {
                        // This is the recursion in imports analysis
                        throw new IllegalStateException(
                                "Recursion while resolving many imports: " + directive.getText());
                    }

                    descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode), name));
                }

                return descriptors;
            }
        });
    }

    @NotNull
    private <D extends DeclarationDescriptor> Collection<D> collectFromImports(final LookupMode lookupMode,
            final JetScopeSelectorUtil.ScopeDescriptorSelector<D> descriptorsSelector) {
        return resolveSession.getStorageManager().compute(new Function0<Collection<D>>() {
            @Override
            public Collection<D> invoke() {
                Set<D> descriptors = Sets.newHashSet();
                for (JetImportDirective directive : importsProvider.getAllImports()) {
                    if (directive == directiveUnderResolve) {
                        // This is the recursion in imports analysis
                        throw new IllegalStateException(
                                "Recursion while resolving many imports: " + directive.getText());
                    }

                    descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode)));
                }

                return descriptors;
            }
        });
    }

    @NotNull
    private JetScope getImportScope(JetImportDirective directive, LookupMode lookupMode) {
        return importedScopesProvider.invoke(directive).scopeForMode(lookupMode);
    }

    @Nullable
    @Override
    public ClassifierDescriptor getClassifier(@NotNull Name name) {
        return selectFirstFromImports(name, LookupMode.ONLY_CLASSES,
                JetScopeSelectorUtil.CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR);
    }

    @Nullable
    @Override
    public PackageViewDescriptor getPackage(@NotNull Name name) {
        return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.PACKAGE_SCOPE_SELECTOR);
    }

    @NotNull
    @Override
    public Collection<VariableDescriptor> getProperties(@NotNull Name name) {
        return collectFromImports(name, LookupMode.EVERYTHING,
                JetScopeSelectorUtil.NAMED_PROPERTIES_SCOPE_SELECTOR);
    }

    @Nullable
    @Override
    public VariableDescriptor getLocalVariable(@NotNull Name name) {
        return null;
    }

    @NotNull
    @Override
    public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
        return collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_FUNCTION_SCOPE_SELECTOR);
    }

    @NotNull
    @Override
    public DeclarationDescriptor getContainingDeclaration() {
        return packageDescriptor;
    }

    @NotNull
    @Override
    public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
        return Collections.emptyList();
    }

    @NotNull
    @Override
    public Collection<DeclarationDescriptor> getAllDescriptors() {
        return collectFromImports(LookupMode.EVERYTHING, JetScopeSelectorUtil.ALL_DESCRIPTORS_SCOPE_SELECTOR);
    }

    @NotNull
    @Override
    public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
        return Collections.emptyList();
    }

    @NotNull
    @Override
    public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
        return Collections.emptyList();
    }

    @Override
    public String toString() {
        return "LazyImportScope: " + debugName;
    }

    @TestOnly
    @Override
    public void printScopeStructure(@NotNull Printer p) {
        p.println(getClass().getSimpleName(), ": ", debugName, " {");
        p.pushIndent();

        p.println("packageDescriptor = ", packageDescriptor);

        p.print("rootScope = ");
        rootScope.printScopeStructure(p.withholdIndentOnce());

        p.popIndent();
        p.println("}");
    }
}