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 javax.inject.Inject; 037 import java.util.ArrayList; 038 import java.util.Collection; 039 import java.util.Collections; 040 import java.util.List; 041 042 public class ScopeProvider { 043 public static class AdditionalFileScopeProvider { 044 @NotNull 045 public List<JetScope> scopes(@NotNull JetFile file) { 046 return Collections.emptyList(); 047 } 048 } 049 050 private final ResolveSession resolveSession; 051 052 private final MemoizedFunctionToNotNull<JetFile, LazyImportScope> explicitImportScopes; 053 054 private final NotNullLazyValue<JetScope> defaultImportsScope; 055 056 @SuppressWarnings("ConstantConditions") @NotNull 057 private AdditionalFileScopeProvider additionalFileScopeProvider = null; 058 059 @Inject 060 public void setAdditionalFileScopesProvider(@NotNull AdditionalFileScopeProvider additionalFileScopeProvider) { 061 this.additionalFileScopeProvider = additionalFileScopeProvider; 062 } 063 064 public ScopeProvider(@NotNull ResolveSession resolveSession) { 065 this.resolveSession = resolveSession; 066 067 this.explicitImportScopes = resolveSession.getStorageManager().createMemoizedFunction(new Function1<JetFile, LazyImportScope>() { 068 @Override 069 public LazyImportScope invoke(@NotNull JetFile file) { 070 return createExplicitImportScope(file); 071 } 072 }); 073 074 this.defaultImportsScope = resolveSession.getStorageManager().createLazyValue(new Function0<JetScope>() { 075 @Override 076 public JetScope invoke() { 077 return createScopeWithDefaultImports(); 078 } 079 }); 080 } 081 082 private LazyImportScope createExplicitImportScope(@NotNull JetFile file) { 083 return LazyImportScope.OBJECT$.createImportScopeForFile( 084 resolveSession, 085 getFilePackageDescriptor(file), 086 file, 087 resolveSession.getTrace(), 088 "Lazy Imports Scope for file " + file.getName()); 089 } 090 091 @NotNull 092 public JetScope getFileScope(@NotNull JetFile file) { 093 return new ChainedScope(resolveSession.getPackageFragment(file.getPackageFqName()), 094 "File scope: " + file.getName(), 095 collectFileScopes(file)); 096 } 097 098 public JetScope[] collectFileScopes(@NotNull JetFile file) { 099 List<JetScope> list = new ArrayList<JetScope>(); 100 list.add(getFilePackageDescriptor(file).getMemberScope()); 101 list.add(JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor())); 102 list.add(explicitImportScopes.invoke(file)); 103 list.addAll(additionalFileScopeProvider.scopes(file)); 104 list.add(defaultImportsScope.invoke()); 105 106 return list.toArray(new JetScope[list.size()]); 107 } 108 109 @NotNull 110 public LazyImportScope getExplicitImportsScopeForFile(@NotNull JetFile file) { 111 return explicitImportScopes.invoke(file); 112 } 113 114 private JetScope createScopeWithDefaultImports() { 115 PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT); 116 if (rootPackage == null) { 117 throw new IllegalStateException("Root package not found"); 118 } 119 120 JetImportsFactory importsFactory = resolveSession.getJetImportsFactory(); 121 List<ImportPath> defaultImports = resolveSession.getModuleDescriptor().getDefaultImports(); 122 123 Collection<JetImportDirective> defaultImportDirectives = importsFactory.createImportDirectives(defaultImports); 124 125 return new LazyImportScope( 126 resolveSession, 127 rootPackage, 128 Lists.reverse(Lists.newArrayList(defaultImportDirectives)), 129 TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"), 130 "Lazy default imports scope", 131 false); 132 } 133 134 @NotNull 135 private PackageViewDescriptor getFilePackageDescriptor(JetFile file) { 136 FqName fqName = file.getPackageFqName(); 137 PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName); 138 139 if (packageDescriptor == null) { 140 throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName()); 141 } 142 143 return packageDescriptor; 144 } 145 146 @NotNull 147 public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) { 148 JetDeclaration jetDeclaration = JetStubbedPsiUtil.getPsiOrStubParent(elementOfDeclaration, JetDeclaration.class, false); 149 150 assert !(elementOfDeclaration instanceof JetDeclaration) || jetDeclaration == elementOfDeclaration : 151 "For JetDeclaration element getParentOfType() should return itself."; 152 assert jetDeclaration != null : "Should be contained inside declaration."; 153 154 JetDeclaration parentDeclaration = JetStubbedPsiUtil.getContainingDeclaration(jetDeclaration); 155 156 if (jetDeclaration instanceof JetPropertyAccessor) { 157 parentDeclaration = JetStubbedPsiUtil.getContainingDeclaration(parentDeclaration, JetDeclaration.class); 158 } 159 160 if (parentDeclaration == null) { 161 return getFileScope((JetFile) elementOfDeclaration.getContainingFile()); 162 } 163 164 if (parentDeclaration instanceof JetClassOrObject) { 165 JetClassOrObject classOrObject = (JetClassOrObject) parentDeclaration; 166 LazyClassDescriptor classDescriptor = (LazyClassDescriptor) resolveSession.getClassDescriptor(classOrObject); 167 if (jetDeclaration instanceof JetClassInitializer || jetDeclaration instanceof JetProperty) { 168 return classDescriptor.getScopeForInitializerResolution(); 169 } 170 return classDescriptor.getScopeForMemberDeclarationResolution(); 171 } 172 173 if (parentDeclaration instanceof JetClassObject) { 174 assert jetDeclaration instanceof JetObjectDeclaration : "Should be situation for getting scope for object in class [object {...}]"; 175 176 JetClassObject classObject = (JetClassObject) parentDeclaration; 177 LazyClassDescriptor classObjectDescriptor = 178 (LazyClassDescriptor) resolveSession.getClassObjectDescriptor(classObject).getContainingDeclaration(); 179 180 return classObjectDescriptor.getScopeForMemberDeclarationResolution(); 181 } 182 183 throw new IllegalStateException("Don't call this method for local declarations: " + jetDeclaration + "\n" + 184 JetPsiUtil.getElementTextWithContext(jetDeclaration)); 185 } 186 }