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 kotlin.Function0;
022 import kotlin.Function1;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
025 import org.jetbrains.jet.lang.psi.*;
026 import org.jetbrains.jet.lang.resolve.ImportPath;
027 import org.jetbrains.jet.lang.resolve.JetModuleUtil;
028 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
029 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
030 import org.jetbrains.jet.lang.resolve.name.FqName;
031 import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
032 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033 import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
034 import org.jetbrains.jet.storage.NotNullLazyValue;
035
036 import java.util.Collection;
037 import java.util.List;
038
039 public class ScopeProvider {
040 private final ResolveSession resolveSession;
041
042 private final MemoizedFunctionToNotNull<JetFile, LazyImportScope> explicitImportScopes;
043
044 private final NotNullLazyValue<JetScope> defaultImportsScope;
045
046 public ScopeProvider(@NotNull ResolveSession resolveSession) {
047 this.resolveSession = resolveSession;
048
049 this.explicitImportScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function1<JetFile, LazyImportScope>() {
050 @Override
051 public LazyImportScope invoke(@NotNull JetFile file) {
052 return createExplicitImportScope(file);
053 }
054 });
055
056 this.defaultImportsScope = resolveSession.getStorageManager().createLazyValue(new Function0<JetScope>() {
057 @Override
058 public JetScope invoke() {
059 return createScopeWithDefaultImports();
060 }
061 });
062 }
063
064 private LazyImportScope createExplicitImportScope(@NotNull JetFile file) {
065 return LazyImportScope.createImportScopeForFile(
066 resolveSession,
067 getFilePackageDescriptor(file),
068 file,
069 resolveSession.getTrace(),
070 "Lazy Imports Scope for file " + file.getName());
071 }
072
073 @NotNull
074 public JetScope getFileScope(@NotNull JetFile file) {
075 return new ChainedScope(resolveSession.getPackageFragment(file.getPackageFqName()),
076 "File scope: " + file.getName(),
077 getFilePackageDescriptor(file).getMemberScope(),
078 JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor()),
079 explicitImportScopes.invoke(file),
080 defaultImportsScope.invoke());
081 }
082
083 @NotNull
084 public LazyImportScope getExplicitImportsScopeForFile(@NotNull JetFile file) {
085 return explicitImportScopes.invoke(file);
086 }
087
088 private JetScope createScopeWithDefaultImports() {
089 PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT);
090 if (rootPackage == null) {
091 throw new IllegalStateException("Root package not found");
092 }
093
094 JetImportsFactory importsFactory = resolveSession.getJetImportsFactory();
095 List<ImportPath> defaultImports = resolveSession.getModuleDescriptor().getDefaultImports();
096
097 Collection<JetImportDirective> defaultImportDirectives = importsFactory.createImportDirectives(defaultImports);
098
099 return new LazyImportScope(
100 resolveSession,
101 rootPackage,
102 Lists.reverse(Lists.newArrayList(defaultImportDirectives)),
103 TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"),
104 "Lazy default imports scope",
105 false);
106 }
107
108 @NotNull
109 private PackageViewDescriptor getFilePackageDescriptor(JetFile file) {
110 FqName fqName = file.getPackageFqName();
111 PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName);
112
113 if (packageDescriptor == null) {
114 throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName());
115 }
116
117 return packageDescriptor;
118 }
119
120 @NotNull
121 public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) {
122 JetDeclaration jetDeclaration = JetStubbedPsiUtil.getPsiOrStubParent(elementOfDeclaration, JetDeclaration.class, false);
123
124 assert !(elementOfDeclaration instanceof JetDeclaration) || jetDeclaration == elementOfDeclaration :
125 "For JetDeclaration element getParentOfType() should return itself.";
126 assert jetDeclaration != null : "Should be contained inside declaration.";
127
128 JetDeclaration parentDeclaration = JetStubbedPsiUtil.getContainingDeclaration(jetDeclaration);
129
130 if (jetDeclaration instanceof JetPropertyAccessor) {
131 parentDeclaration = JetStubbedPsiUtil.getContainingDeclaration(parentDeclaration, JetDeclaration.class);
132 }
133
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 + "\n" +
158 JetPsiUtil.getElementTextWithContext(jetDeclaration));
159 }
160 }