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 }