001 /*
002 * Copyright 2010-2014 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.jet.lang.resolve.lazy;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.util.PsiTreeUtil;
022 import kotlin.Function0;
023 import kotlin.Function1;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.ImportPath;
028 import org.jetbrains.jet.lang.resolve.JetModuleUtil;
029 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
030 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
031 import org.jetbrains.jet.lang.resolve.name.FqName;
032 import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
033 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034 import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
035 import org.jetbrains.jet.storage.NotNullLazyValue;
036
037 import java.util.Collection;
038 import java.util.List;
039
040 public class ScopeProvider {
041 private final ResolveSession resolveSession;
042
043 private final MemoizedFunctionToNotNull<JetFile, LazyImportScope> explicitImportScopes;
044
045 private final NotNullLazyValue<JetScope> defaultImportsScope;
046
047 public ScopeProvider(@NotNull ResolveSession resolveSession) {
048 this.resolveSession = resolveSession;
049
050 this.explicitImportScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function1<JetFile, LazyImportScope>() {
051 @Override
052 public LazyImportScope invoke(@NotNull JetFile file) {
053 return createExplicitImportScope(file);
054 }
055 });
056
057 this.defaultImportsScope = resolveSession.getStorageManager().createLazyValue(new Function0<JetScope>() {
058 @Override
059 public JetScope invoke() {
060 return createScopeWithDefaultImports();
061 }
062 });
063 }
064
065 private LazyImportScope createExplicitImportScope(@NotNull JetFile file) {
066 return LazyImportScope.createImportScopeForFile(
067 resolveSession,
068 getFilePackageDescriptor(file),
069 file,
070 resolveSession.getTrace(),
071 "Lazy Imports Scope for file " + file.getName());
072 }
073
074 @NotNull
075 public JetScope getFileScope(@NotNull JetFile file) {
076 return new ChainedScope(resolveSession.getPackageFragment(JetPsiUtil.getFQName(file)),
077 "File scope: " + file.getName(),
078 getFilePackageDescriptor(file).getMemberScope(),
079 JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor()),
080 explicitImportScopes.invoke(file),
081 defaultImportsScope.invoke());
082 }
083
084 @NotNull
085 public LazyImportScope getExplicitImportsScopeForFile(@NotNull JetFile file) {
086 return explicitImportScopes.invoke(file);
087 }
088
089 private JetScope createScopeWithDefaultImports() {
090 PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT);
091 if (rootPackage == null) {
092 throw new IllegalStateException("Root package not found");
093 }
094
095 JetImportsFactory importsFactory = resolveSession.getJetImportsFactory();
096 List<ImportPath> defaultImports = resolveSession.getModuleDescriptor().getDefaultImports();
097
098 Collection<JetImportDirective> defaultImportDirectives = importsFactory.createImportDirectives(defaultImports);
099
100 return new LazyImportScope(
101 resolveSession,
102 rootPackage,
103 Lists.reverse(Lists.newArrayList(defaultImportDirectives)),
104 TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"),
105 "Lazy default imports scope",
106 false);
107 }
108
109 @NotNull
110 private PackageViewDescriptor getFilePackageDescriptor(JetFile file) {
111 JetPackageDirective directive = file.getPackageDirective();
112 if (directive == null) {
113 throw new IllegalArgumentException("Scripts are not supported: " + file.getName());
114 }
115
116 FqName fqName = new FqName(directive.getQualifiedName());
117 PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName);
118
119 if (packageDescriptor == null) {
120 throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName());
121 }
122
123 return packageDescriptor;
124 }
125
126 @NotNull
127 public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) {
128 JetDeclaration jetDeclaration = PsiTreeUtil.getParentOfType(elementOfDeclaration, JetDeclaration.class, false);
129
130 assert !(elementOfDeclaration instanceof JetDeclaration) || jetDeclaration == elementOfDeclaration :
131 "For JetDeclaration element getParentOfType() should return itself.";
132
133 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class);
134 if (parentDeclaration == null) {
135 return getFileScope((JetFile) elementOfDeclaration.getContainingFile());
136 }
137
138 if (parentDeclaration instanceof JetClassOrObject) {
139 JetClassOrObject classOrObject = (JetClassOrObject) parentDeclaration;
140 LazyClassDescriptor classDescriptor = (LazyClassDescriptor) resolveSession.getClassDescriptor(classOrObject);
141 if (jetDeclaration instanceof JetClassInitializer || jetDeclaration instanceof JetProperty) {
142 return classDescriptor.getScopeForInitializerResolution();
143 }
144 return classDescriptor.getScopeForMemberDeclarationResolution();
145 }
146
147 if (parentDeclaration instanceof JetClassObject) {
148 assert jetDeclaration instanceof JetObjectDeclaration : "Should be situation for getting scope for object in class [object {...}]";
149
150 JetClassObject classObject = (JetClassObject) parentDeclaration;
151 LazyClassDescriptor classObjectDescriptor =
152 (LazyClassDescriptor) resolveSession.getClassObjectDescriptor(classObject).getContainingDeclaration();
153
154 return classObjectDescriptor.getScopeForMemberDeclarationResolution();
155 }
156
157 throw new IllegalStateException("Don't call this method for local declarations: " + jetDeclaration + " " + jetDeclaration.getText());
158 }
159 }