001 /*
002 * Copyright 2010-2013 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.openapi.util.Computable;
021 import com.intellij.psi.PsiElement;
022 import com.intellij.psi.util.PsiTreeUtil;
023 import com.intellij.util.Function;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.ImportPath;
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.lazy.storage.MemoizedFunctionToNotNull;
031 import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
032 import org.jetbrains.jet.lang.resolve.name.FqName;
033 import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
034 import org.jetbrains.jet.lang.resolve.scopes.InnerClassesScopeWrapper;
035 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036
037 import java.util.Collection;
038 import java.util.List;
039
040 import static org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager.ReferenceKind.WEAK;
041
042 public class ScopeProvider {
043 private final ResolveSession resolveSession;
044
045 private final MemoizedFunctionToNotNull<JetFile, JetScope> fileScopes;
046
047 private final NotNullLazyValue<JetScope> defaultImportsScope;
048
049 public ScopeProvider(@NotNull ResolveSession resolveSession) {
050 this.resolveSession = resolveSession;
051
052 this.fileScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function<JetFile, JetScope>() {
053 @Override
054 public JetScope fun(@NotNull JetFile file) {
055 return createFileScope(file);
056 }
057 }, WEAK);
058
059 this.defaultImportsScope = resolveSession.getStorageManager().createLazyValue(new Computable<JetScope>() {
060 @Override
061 public JetScope compute() {
062 return createScopeWithDefaultImports();
063 }
064 });
065 }
066
067 @NotNull
068 public JetScope getFileScope(JetFile file) {
069 return fileScopes.fun(file);
070 }
071
072 private JetScope createFileScope(JetFile file) {
073 NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
074 if (rootPackageDescriptor == null) {
075 throw new IllegalStateException("Root package not found");
076 }
077
078 NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file);
079
080 JetScope importsScope = LazyImportScope.createImportScopeForFile(
081 resolveSession,
082 packageDescriptor,
083 file,
084 resolveSession.getTrace(),
085 "Lazy Imports Scope for file " + file.getName());
086
087 return new ChainedScope(packageDescriptor,
088 "File scope: " + file.getName(),
089 packageDescriptor.getMemberScope(),
090 rootPackageDescriptor.getMemberScope(),
091 importsScope,
092 defaultImportsScope.compute());
093 }
094
095 private JetScope createScopeWithDefaultImports() {
096 NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
097 if (rootPackageDescriptor == null) {
098 throw new IllegalStateException("Root package not found");
099 }
100
101 JetImportsFactory importsFactory = resolveSession.getInjector().getJetImportsFactory();
102 List<ImportPath> defaultImports = resolveSession.getRootModuleDescriptor().getDefaultImports();
103
104 Collection<JetImportDirective> defaultImportDirectives = importsFactory.createImportDirectives(defaultImports);
105
106 return new LazyImportScope(
107 resolveSession,
108 rootPackageDescriptor,
109 Lists.reverse(Lists.newArrayList(defaultImportDirectives)),
110 TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"),
111 "Lazy default imports scope");
112 }
113
114 @NotNull
115 private NamespaceDescriptor getFilePackageDescriptor(JetFile file) {
116 JetNamespaceHeader header = file.getNamespaceHeader();
117 if (header == null) {
118 throw new IllegalArgumentException("Scripts are not supported: " + file.getName());
119 }
120
121 FqName fqName = new FqName(header.getQualifiedName());
122 NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(fqName);
123
124 if (packageDescriptor == null) {
125 throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName());
126 }
127
128 return packageDescriptor;
129 }
130
131 @NotNull
132 public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) {
133 JetDeclaration jetDeclaration = PsiTreeUtil.getParentOfType(elementOfDeclaration, JetDeclaration.class, false);
134
135 assert !(elementOfDeclaration instanceof JetDeclaration) || jetDeclaration == elementOfDeclaration :
136 "For JetDeclaration element getParentOfType() should return itself.";
137
138 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class);
139 if (parentDeclaration == null) {
140 return getFileScope((JetFile) elementOfDeclaration.getContainingFile());
141 }
142
143 assert jetDeclaration != null : "Can't happen because of getParentOfType(null, ?) == null";
144
145 if (parentDeclaration instanceof JetClassOrObject) {
146 JetClassOrObject classOrObject = (JetClassOrObject) parentDeclaration;
147 LazyClassDescriptor classDescriptor = (LazyClassDescriptor) resolveSession.getClassDescriptor(classOrObject);
148 if (jetDeclaration instanceof JetClassInitializer || jetDeclaration instanceof JetProperty) {
149 return classDescriptor.getScopeForPropertyInitializerResolution();
150 }
151 if (jetDeclaration instanceof JetEnumEntry) {
152 LazyClassDescriptor descriptor = (LazyClassDescriptor) classDescriptor.getClassObjectDescriptor();
153 assert descriptor != null : "There should be class object descriptor for enum class " + parentDeclaration.getText() +
154 " on entry " + jetDeclaration.getText();
155
156 return descriptor.getScopeForMemberDeclarationResolution();
157 }
158 return classDescriptor.getScopeForMemberDeclarationResolution();
159 }
160
161 if (parentDeclaration instanceof JetClassObject) {
162 assert jetDeclaration instanceof JetObjectDeclaration : "Should be situation for getting scope for object in class [object {...}]";
163
164 JetClassObject classObject = (JetClassObject) parentDeclaration;
165 LazyClassDescriptor classObjectDescriptor =
166 (LazyClassDescriptor) resolveSession.getClassObjectDescriptor(classObject).getContainingDeclaration();
167
168 return classObjectDescriptor.getScopeForMemberDeclarationResolution();
169 }
170
171 throw new IllegalStateException("Don't call this method for local declarations: " + jetDeclaration + " " + jetDeclaration.getText());
172 }
173 }