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.psi.PsiElement;
021 import com.intellij.psi.util.PsiTreeUtil;
022 import jet.Function0;
023 import jet.Function1;
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.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, JetScope> fileScopes;
043
044 private final NotNullLazyValue<JetScope> defaultImportsScope;
045
046 public ScopeProvider(@NotNull ResolveSession resolveSession) {
047 this.resolveSession = resolveSession;
048
049 this.fileScopes = resolveSession.getStorageManager().createWeaklyRetainedMemoizedFunction(new Function1<JetFile, JetScope>() {
050 @Override
051 public JetScope invoke(@NotNull JetFile file) {
052 return createFileScope(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 @NotNull
065 public JetScope getFileScope(JetFile file) {
066 return fileScopes.invoke(file);
067 }
068
069 private JetScope createFileScope(JetFile file) {
070 NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
071 if (rootPackageDescriptor == null) {
072 throw new IllegalStateException("Root package not found");
073 }
074
075 NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file);
076
077 JetScope importsScope = LazyImportScope.createImportScopeForFile(
078 resolveSession,
079 packageDescriptor,
080 file,
081 resolveSession.getTrace(),
082 "Lazy Imports Scope for file " + file.getName());
083
084 return new ChainedScope(packageDescriptor,
085 "File scope: " + file.getName(),
086 packageDescriptor.getMemberScope(),
087 rootPackageDescriptor.getMemberScope(),
088 importsScope,
089 defaultImportsScope.invoke());
090 }
091
092 private JetScope createScopeWithDefaultImports() {
093 NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
094 if (rootPackageDescriptor == null) {
095 throw new IllegalStateException("Root package not found");
096 }
097
098 JetImportsFactory importsFactory = resolveSession.getInjector().getJetImportsFactory();
099 List<ImportPath> defaultImports = resolveSession.getRootModuleDescriptor().getDefaultImports();
100
101 Collection<JetImportDirective> defaultImportDirectives = importsFactory.createImportDirectives(defaultImports);
102
103 return new LazyImportScope(
104 resolveSession,
105 rootPackageDescriptor,
106 Lists.reverse(Lists.newArrayList(defaultImportDirectives)),
107 TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"),
108 "Lazy default imports scope");
109 }
110
111 @NotNull
112 private NamespaceDescriptor getFilePackageDescriptor(JetFile file) {
113 JetNamespaceHeader header = file.getNamespaceHeader();
114 if (header == null) {
115 throw new IllegalArgumentException("Scripts are not supported: " + file.getName());
116 }
117
118 FqName fqName = new FqName(header.getQualifiedName());
119 NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(fqName);
120
121 if (packageDescriptor == null) {
122 throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName());
123 }
124
125 return packageDescriptor;
126 }
127
128 @NotNull
129 public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) {
130 JetDeclaration jetDeclaration = PsiTreeUtil.getParentOfType(elementOfDeclaration, JetDeclaration.class, false);
131
132 assert !(elementOfDeclaration instanceof JetDeclaration) || jetDeclaration == elementOfDeclaration :
133 "For JetDeclaration element getParentOfType() should return itself.";
134
135 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class);
136 if (parentDeclaration == null) {
137 return getFileScope((JetFile) elementOfDeclaration.getContainingFile());
138 }
139
140 if (parentDeclaration instanceof JetClassOrObject) {
141 JetClassOrObject classOrObject = (JetClassOrObject) parentDeclaration;
142 LazyClassDescriptor classDescriptor = (LazyClassDescriptor) resolveSession.getClassDescriptor(classOrObject);
143 if (jetDeclaration instanceof JetClassInitializer || jetDeclaration instanceof JetProperty) {
144 return classDescriptor.getScopeForPropertyInitializerResolution();
145 }
146 return classDescriptor.getScopeForMemberDeclarationResolution();
147 }
148
149 if (parentDeclaration instanceof JetClassObject) {
150 assert jetDeclaration instanceof JetObjectDeclaration : "Should be situation for getting scope for object in class [object {...}]";
151
152 JetClassObject classObject = (JetClassObject) parentDeclaration;
153 LazyClassDescriptor classObjectDescriptor =
154 (LazyClassDescriptor) resolveSession.getClassObjectDescriptor(classObject).getContainingDeclaration();
155
156 return classObjectDescriptor.getScopeForMemberDeclarationResolution();
157 }
158
159 throw new IllegalStateException("Don't call this method for local declarations: " + jetDeclaration + " " + jetDeclaration.getText());
160 }
161 }