From f2e78d9064585dce7aa7c003aa23d214913c2c59 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 25 Dec 2012 21:34:02 +0400 Subject: [PATCH] Create scope with lazy import resolve --- .../jetbrains/jet/lang/psi/JetPsiBuilder.java | 17 ++ .../jetbrains/jet/lang/resolve/Importer.java | 3 +- .../lang/resolve/lazy/ImportsProvider.java | 95 +++++++ .../lang/resolve/lazy/LazyImportScope.java | 268 ++++++++++++++++++ .../resolve/lazy/LazyPackageMemberScope.java | 3 +- .../resolve/lazy/ResolveSessionUtils.java | 10 +- .../jet/lang/resolve/lazy/ScopeProvider.java | 127 ++++----- .../resolve/scopes/JetScopeSelectorUtil.java | 131 +++++++++ .../diagnostics/tests/scopes/kt1080.kt | 6 +- .../lazyResolve/diagnostics/scopes/kt1080.txt | 6 + ...ctionWithAllUnderImportAfterNamedImport.kt | 22 ++ ...tionWithAllUnderImportAfterNamedImport.txt | 3 + ...esolveNamespaceComparingTestGenerated.java | 5 + 13 files changed, 616 insertions(+), 80 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ImportsProvider.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyImportScope.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/JetScopeSelectorUtil.java create mode 100644 compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.kt create mode 100644 compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiBuilder.java index 3b189edc4c0..5f09d3a7829 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiBuilder.java @@ -16,12 +16,16 @@ package org.jetbrains.jet.lang.psi; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.ImportPath; import javax.inject.Inject; +import java.util.Collection; import java.util.Map; public class JetPsiBuilder { @@ -36,6 +40,7 @@ public class JetPsiBuilder { this.project = project; } + @NotNull public JetImportDirective createImportDirective(@NotNull ImportPath importPath) { JetImportDirective directive = importsCache.get(importPath); if (directive != null) { @@ -47,4 +52,16 @@ public class JetPsiBuilder { return createdDirective; } + + @NotNull + public Collection createImportDirectives(@NotNull Collection importPaths) { + return Collections2.transform(importPaths, + new Function() { + @Override + public JetImportDirective apply(@Nullable ImportPath path) { + assert path != null; + return createImportDirective(path); + } + }); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/Importer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/Importer.java index e04683baee2..02519abe607 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/Importer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/Importer.java @@ -31,8 +31,7 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import java.util.Collection; import java.util.List; -/*package*/ interface Importer { - +public interface Importer { void addAllUnderImport(@NotNull DeclarationDescriptor descriptor, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap); void addAliasImport(@NotNull DeclarationDescriptor descriptor, @NotNull Name aliasName); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ImportsProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ImportsProvider.java new file mode 100644 index 00000000000..bb122c6ab15 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ImportsProvider.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.lazy; + +import com.google.common.collect.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetImportDirective; +import org.jetbrains.jet.lang.psi.JetPsiUtil; +import org.jetbrains.jet.lang.resolve.ImportPath; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.*; + +class ImportsProvider { + private final List importDirectives; + + private ListMultimap nameToDirectives = null; + private List allUnderImports = null; + private boolean indexed; + + public ImportsProvider(List importDirectives) { + this.importDirectives = importDirectives; + } + + @NotNull + public List getImports(@NotNull Name name) { + createIndex(); + return nameToDirectives.containsKey(name) ? nameToDirectives.get(name) : allUnderImports; + } + + @NotNull + public List getAllImports() { + return importDirectives; + } + + private void createIndex() { + if (indexed) { + return; + } + + ImmutableListMultimap.Builder namesToRelativeImportsBuilder = ImmutableListMultimap.builder(); + + Set processedAliases = Sets.newHashSet(); + List processedAllUnderImports = Lists.newArrayList(); + + for (JetImportDirective anImport : importDirectives) { + ImportPath path = JetPsiUtil.getImportPath(anImport); + if (path == null) { + // Could be some parse errors + continue; + } + + if (path.isAllUnder()) { + processedAllUnderImports.add(anImport); + + // All-Under import is relevant to all names found so far + for (Name aliasName : processedAliases) { + namesToRelativeImportsBuilder.put(aliasName, anImport); + } + } + else { + Name aliasName = path.getImportedName(); + assert aliasName != null; + + if (!processedAliases.contains(aliasName)) { + processedAliases.add(aliasName); + + // Add to relevant imports all all-under imports found by this moment + namesToRelativeImportsBuilder.putAll(aliasName, processedAllUnderImports); + } + + namesToRelativeImportsBuilder.put(aliasName, anImport); + } + } + + allUnderImports = ImmutableList.copyOf(processedAllUnderImports); + nameToDirectives = namesToRelativeImportsBuilder.build(); + + indexed = true; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyImportScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyImportScope.java new file mode 100644 index 00000000000..3f00a4a9415 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyImportScope.java @@ -0,0 +1,268 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.lazy; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetImportDirective; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.Importer; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.LabelName; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.*; + +import java.util.*; + +import static org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver.LookupMode; + +public class LazyImportScope implements JetScope { + private static class ImportResolveStatus { + private final LookupMode lookupMode; + private final JetScope scope; + + ImportResolveStatus(LookupMode lookupMode, JetScope scope) { + this.lookupMode = lookupMode; + this.scope = scope; + } + } + + private final ResolveSession resolveSession; + private final NamespaceDescriptor packageDescriptor; + private final ImportsProvider importsProvider; + private final JetScope rootScope; + private final BindingTrace traceForImportResolve; + private final String debugName; + + private final Map importedScopes = Maps.newHashMap(); + private JetImportDirective directiveUnderResolve = null; + + public LazyImportScope( + @NotNull ResolveSession resolveSession, + @NotNull NamespaceDescriptor packageDescriptor, + @NotNull List imports, + @NotNull BindingTrace traceForImportResolve, + @NotNull String debugName + ) { + this.resolveSession = resolveSession; + this.packageDescriptor = packageDescriptor; + this.importsProvider = new ImportsProvider(imports); + this.traceForImportResolve = traceForImportResolve; + this.debugName = debugName; + + NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); + if (rootPackageDescriptor == null) { + throw new IllegalStateException("Root package not found"); + } + rootScope = rootPackageDescriptor.getMemberScope(); + } + + public static LazyImportScope createImportScopeForFile( + @NotNull ResolveSession resolveSession, + @NotNull NamespaceDescriptor packageDescriptor, + @NotNull JetFile jetFile, + @NotNull BindingTrace traceForImportResolve, + @NotNull String debugName + ) { + return new LazyImportScope( + resolveSession, + packageDescriptor, + Lists.reverse(jetFile.getImportDirectives()), + traceForImportResolve, + debugName); + } + + @Nullable + private D selectFirstFromImports( + Name name, + LookupMode lookupMode, + JetScopeSelectorUtil.ScopeByNameSelector descriptorSelector + ) { + for (JetImportDirective directive : importsProvider.getImports(name)) { + if (directive == directiveUnderResolve) { + // This is the recursion in imports analysis + return null; + } + + D foundDescriptor = descriptorSelector.get(getImportScope(directive, lookupMode), name); + if (foundDescriptor != null) { + return foundDescriptor; + } + } + + return null; + } + + @NotNull + private Collection collectFromImports( + Name name, + LookupMode lookupMode, + JetScopeSelectorUtil.ScopeByNameMultiSelector descriptorsSelector + ) { + Set descriptors = Sets.newHashSet(); + for (JetImportDirective directive : importsProvider.getImports(name)) { + if (directive == directiveUnderResolve) { + // This is the recursion in imports analysis + throw new IllegalStateException("Recursion while resolving many imports: " + directive.getText()); + } + + descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode), name)); + } + + return descriptors; + } + + @NotNull + private Collection collectFromImports( + LookupMode lookupMode, + JetScopeSelectorUtil.ScopeDescriptorSelector descriptorsSelector + ) { + Set descriptors = Sets.newHashSet(); + for (JetImportDirective directive : importsProvider.getAllImports()) { + if (directive == directiveUnderResolve) { + // This is the recursion in imports analysis + throw new IllegalStateException("Recursion while resolving many imports: " + directive.getText()); + } + + descriptors.addAll(descriptorsSelector.get(getImportScope(directive, lookupMode))); + } + + return descriptors; + } + + @NotNull + private JetScope getImportScope(JetImportDirective directive, LookupMode lookupMode) { + ImportResolveStatus status = importedScopes.get(directive); + if (status != null && (lookupMode == status.lookupMode || status.lookupMode == LookupMode.EVERYTHING)) { + return status.scope; + } + + WritableScope directiveImportScope = new WritableScopeImpl( + JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, + "Scope for import '" + directive.getText() + "' resolve in " + toString()); + directiveImportScope.changeLockLevel(WritableScope.LockLevel.BOTH); + + Importer.StandardImporter importer = new Importer.StandardImporter(directiveImportScope); + directiveUnderResolve = directive; + + try { + resolveSession.getInjector().getQualifiedExpressionResolver().processImportReference( + directive, + rootScope, + packageDescriptor.getMemberScope(), + importer, + traceForImportResolve, + resolveSession.getModuleConfiguration(), + lookupMode); + } + finally { + directiveUnderResolve = null; + directiveImportScope.changeLockLevel(WritableScope.LockLevel.READING); + importedScopes.put(directive, new ImportResolveStatus(lookupMode, directiveImportScope)); + } + + return directiveImportScope; + } + + @Nullable + @Override + public ClassifierDescriptor getClassifier(@NotNull Name name) { + return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR); + } + + @Nullable + @Override + public ClassDescriptor getObjectDescriptor(@NotNull Name name) { + return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.NAMED_OBJECT_SCOPE_SELECTOR); + } + + @NotNull + @Override + public Collection getObjectDescriptors() { + return collectFromImports(LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.OBJECTS_SCOPE_SELECTOR); + } + + @Nullable + @Override + public NamespaceDescriptor getNamespace(@NotNull Name name) { + return selectFirstFromImports(name, LookupMode.ONLY_CLASSES, JetScopeSelectorUtil.NAMESPACE_SCOPE_SELECTOR); + } + + @NotNull + @Override + public Collection getProperties(@NotNull Name name) { + return collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_PROPERTIES_SCOPE_SELECTOR); + } + + @Nullable + @Override + public VariableDescriptor getLocalVariable(@NotNull Name name) { + return null; + } + + @NotNull + @Override + public Collection getFunctions(@NotNull Name name) { + return collectFromImports(name, LookupMode.EVERYTHING, JetScopeSelectorUtil.NAMED_FUNCTION_SCOPE_SELECTOR); + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return packageDescriptor; + } + + @NotNull + @Override + public Collection getDeclarationsByLabel(@NotNull LabelName labelName) { + return Collections.emptyList(); + } + + @Nullable + @Override + public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) { + return null; + } + + @NotNull + @Override + public Collection getAllDescriptors() { + return collectFromImports(LookupMode.EVERYTHING, JetScopeSelectorUtil.ALL_DESCRIPTORS_SCOPE_SELECTOR); + } + + @NotNull + @Override + public List getImplicitReceiversHierarchy() { + return Collections.emptyList(); + } + + @NotNull + @Override + public Collection getOwnDeclaredDescriptors() { + return Collections.emptyList(); + } + + @Override + public String toString() { + return "LazyImportScope: " + debugName; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java index 3507cd94c4e..4edbbb5067f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyPackageMemberScope.java @@ -68,8 +68,7 @@ public class LazyPackageMemberScope extends AbstractLazyMemberScope fileScopes = new WeakHashMap(); + + private final NotNullLazyValue defaultImportsScope = new NotNullLazyValue() { + @NotNull + @Override + protected JetScope compute() { + return createScopeWithDefaultImports(); + } + }; + public ScopeProvider(@NotNull ResolveSession resolveSession) { this.resolveSession = resolveSession; } - private final Map fileScopeWithImportedClassesCache = new WeakHashMap(); - private final Map fileScopeWithAllImportedCache = new WeakHashMap(); - @NotNull - public JetScope getFileScopeWithImportedClasses(JetFile file) { - JetScope scope = fileScopeWithImportedClassesCache.get(file); + public JetScope getFileScope(JetFile file) { + JetScope scope = fileScopes.get(file); if (scope == null) { - scope = createFileScopeWithImportedClasses(file); - fileScopeWithImportedClassesCache.put(file, scope); + scope = createFileScope(file); + fileScopes.put(file, scope); } return scope; } - @NotNull - public JetScope getFileScopeWithAllImported(JetFile file) { - JetScope scope = fileScopeWithAllImportedCache.get(file); - if (scope == null) { - scope = createFileScopeWithAllImported(file); - fileScopeWithAllImportedCache.put(file, scope); - } - return scope; - } - - private JetScope createFileScopeWithImportedClasses(JetFile file) { - NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file); - - WritableScope fileScope = new WritableScopeImpl( - JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for declaration resolution with only classes imported"); - - fileScope.changeLockLevel(WritableScope.LockLevel.BOTH); - + private JetScope createFileScope(JetFile file) { NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); if (rootPackageDescriptor == null) { throw new IllegalStateException("Root package not found"); } - // Don't import twice - if (!packageDescriptor.getQualifiedName().equals(FqName.ROOT)) { - fileScope.importScope(rootPackageDescriptor.getMemberScope()); - } + NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file); - ImportsResolver.processImportsInFile(QualifiedExpressionResolver.LookupMode.ONLY_CLASSES, fileScope, Lists.newArrayList(file.getImportDirectives()), - rootPackageDescriptor.getMemberScope(), - resolveSession.getModuleConfiguration(), resolveSession.getTrace(), - resolveSession.getInjector().getQualifiedExpressionResolver(), - resolveSession.getInjector().getJetPsiBuilder()); + JetScope importsScope = LazyImportScope.createImportScopeForFile( + resolveSession, + packageDescriptor, + file, + resolveSession.getTrace(), + "Lazy Imports Scope for file " + file.getName()); - fileScope.changeLockLevel(WritableScope.LockLevel.READING); - - return new ChainedScope(packageDescriptor, packageDescriptor.getMemberScope(), fileScope); + return new ChainedScope(packageDescriptor, + "File scope: " + file.getName(), + rootPackageDescriptor.getMemberScope(), + packageDescriptor.getMemberScope(), + importsScope, + defaultImportsScope.getValue()); } + private JetScope createScopeWithDefaultImports() { + NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); + if (rootPackageDescriptor == null) { + throw new IllegalStateException("Root package not found"); + } + + JetPsiBuilder jetPsiBuilder = resolveSession.getInjector().getJetPsiBuilder(); + List defaultImports = resolveSession.getModuleConfiguration().getDefaultImports(); + + Collection defaultImportDirectives = jetPsiBuilder.createImportDirectives(defaultImports); + + return new LazyImportScope( + resolveSession, + rootPackageDescriptor, + Lists.reverse(Lists.newArrayList(defaultImportDirectives)), + TemporaryBindingTrace.create(resolveSession.getTrace(), "Transient trace for default imports lazy resolve"), + "Lazy default imports scope"); + } + + @NotNull private NamespaceDescriptor getFilePackageDescriptor(JetFile file) { - // package JetNamespaceHeader header = file.getNamespaceHeader(); if (header == null) { throw new IllegalArgumentException("Scripts are not supported: " + file.getName()); @@ -103,34 +114,10 @@ public class ScopeProvider { if (packageDescriptor == null) { throw new IllegalStateException("Package not found: " + fqName + " maybe the file is not in scope of this resolve session: " + file.getName()); } + return packageDescriptor; } - private JetScope createFileScopeWithAllImported(JetFile file) { - JetScope scopeWithImportedClasses = getFileScopeWithImportedClasses(file); - NamespaceDescriptor packageDescriptor = getFilePackageDescriptor(file); - - NamespaceDescriptor rootPackageDescriptor = resolveSession.getPackageDescriptorByFqName(FqName.ROOT); - if (rootPackageDescriptor == null) { - throw new IllegalStateException("Root package not found"); - } - - WritableScope fileMemberScope = new WritableScopeImpl( - JetScope.EMPTY, packageDescriptor, RedeclarationHandler.DO_NOTHING, "File scope for members declaration resolution with non-class imports"); - - fileMemberScope.changeLockLevel(WritableScope.LockLevel.BOTH); - - ImportsResolver.processImportsInFile(QualifiedExpressionResolver.LookupMode.EVERYTHING, fileMemberScope, Lists.newArrayList(file.getImportDirectives()), - rootPackageDescriptor.getMemberScope(), - resolveSession.getModuleConfiguration(), resolveSession.getTrace(), - resolveSession.getInjector().getQualifiedExpressionResolver(), - resolveSession.getInjector().getJetPsiBuilder()); - - fileMemberScope.changeLockLevel(WritableScope.LockLevel.READING); - - return new ChainedScope(packageDescriptor, scopeWithImportedClasses, fileMemberScope); - } - @NotNull public JetScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) { JetDeclaration jetDeclaration = PsiTreeUtil.getParentOfType(elementOfDeclaration, JetDeclaration.class, false); @@ -140,7 +127,7 @@ public class ScopeProvider { JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(jetDeclaration, JetDeclaration.class); if (parentDeclaration == null) { - return getFileScopeWithAllImported((JetFile) elementOfDeclaration.getContainingFile()); + return getFileScope((JetFile) elementOfDeclaration.getContainingFile()); } assert jetDeclaration != null : "Can't happen because of getParentOfType(null, ?) == null"; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/JetScopeSelectorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/JetScopeSelectorUtil.java new file mode 100644 index 00000000000..309034be3e0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/JetScopeSelectorUtil.java @@ -0,0 +1,131 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.scopes; + +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.Collection; +import java.util.Set; + +public class JetScopeSelectorUtil { + private JetScopeSelectorUtil() { + } + + public interface ScopeByNameSelector { + @Nullable + D get(@NotNull JetScope scope, @NotNull Name name); + } + + public interface ScopeByNameMultiSelector { + @NotNull + Collection get(JetScope scope, Name name); + } + + public interface ScopeDescriptorSelector { + @NotNull + Collection get(JetScope scope); + } + + @NotNull + public static Collection collect(Collection scopes, ScopeByNameMultiSelector selector, Name name) { + Set descriptors = Sets.newHashSet(); + + for (JetScope scope : scopes) { + descriptors.addAll(selector.get(scope, name)); + } + + return descriptors; + } + + @NotNull + public static Collection collect(Collection scopes, ScopeDescriptorSelector selector) { + Set descriptors = Sets.newHashSet(); + + for (JetScope scope : scopes) { + descriptors.addAll(selector.get(scope)); + } + + return descriptors; + } + + public static final ScopeByNameSelector CLASSIFIER_DESCRIPTOR_SCOPE_SELECTOR = + new ScopeByNameSelector() { + @Nullable + @Override + public ClassifierDescriptor get(@NotNull JetScope scope, @NotNull Name name) { + return scope.getClassifier(name); + } + }; + + public static final ScopeByNameSelector NAMED_OBJECT_SCOPE_SELECTOR = + new ScopeByNameSelector() { + @Nullable + @Override + public ClassDescriptor get(@NotNull JetScope scope, @NotNull Name name) { + return scope.getObjectDescriptor(name); + } + }; + + public static final ScopeByNameSelector NAMESPACE_SCOPE_SELECTOR = + new ScopeByNameSelector() { + @Nullable + @Override + public NamespaceDescriptor get(@NotNull JetScope scope, @NotNull Name name) { + return scope.getNamespace(name); + } + }; + + public static final ScopeByNameMultiSelector NAMED_FUNCTION_SCOPE_SELECTOR = + new ScopeByNameMultiSelector() { + @NotNull + @Override + public Collection get(@NotNull JetScope scope, @NotNull Name name) { + return scope.getFunctions(name); + } + }; + + public static final ScopeByNameMultiSelector NAMED_PROPERTIES_SCOPE_SELECTOR = + new ScopeByNameMultiSelector() { + @NotNull + @Override + public Collection get(@NotNull JetScope scope, @NotNull Name name) { + return scope.getProperties(name); + } + }; + + public static final ScopeDescriptorSelector OBJECTS_SCOPE_SELECTOR = + new ScopeDescriptorSelector() { + @NotNull + @Override + public Collection get(@NotNull JetScope scope) { + return scope.getObjectDescriptors(); + } + }; + + public static final ScopeDescriptorSelector ALL_DESCRIPTORS_SCOPE_SELECTOR = + new ScopeDescriptorSelector() { + @NotNull + @Override + public Collection get(@NotNull JetScope scope) { + return scope.getAllDescriptors(); + } + }; +} diff --git a/compiler/testData/diagnostics/tests/scopes/kt1080.kt b/compiler/testData/diagnostics/tests/scopes/kt1080.kt index 23d40f8fbe7..fde50739bc8 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt1080.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt1080.kt @@ -7,9 +7,13 @@ import reflect.Const import b.* import d +import d.Test import b.d +class Some: Test() //FILE:b.kt -package b.d \ No newline at end of file +package b.d + +public open class Test \ No newline at end of file diff --git a/compiler/testData/lazyResolve/diagnostics/scopes/kt1080.txt b/compiler/testData/lazyResolve/diagnostics/scopes/kt1080.txt index 72425dfddb2..1df452aff48 100644 --- a/compiler/testData/lazyResolve/diagnostics/scopes/kt1080.txt +++ b/compiler/testData/lazyResolve/diagnostics/scopes/kt1080.txt @@ -3,6 +3,9 @@ namespace // namespace kt1080 +internal final class kt1080.Some : jet.Any { + public final /*constructor*/ fun (): kt1080.Some +} // // namespace b @@ -10,5 +13,8 @@ namespace b // namespace d +public open class b.d.Test : jet.Any { + public final /*constructor*/ fun (): b.d.Test +} // // diff --git a/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.kt b/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.kt new file mode 100644 index 00000000000..cf512690411 --- /dev/null +++ b/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.kt @@ -0,0 +1,22 @@ +//FILE:mainFile.kt +//---------------------------------------------------------------------------------- +package test + +import testing.other.* +import testing.TestFun + +// Resolve should be ambiguous +val a = TestFun() + + +//FILE:testing.kt +//---------------------------------------------------------------------------------- +package testing + +class TestFun + +//FILE:testingOther.kt +//---------------------------------------------------------------------------------- +package testing.other + +fun TestFun() = 12 diff --git a/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.txt b/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.txt new file mode 100644 index 00000000000..5ce403563e0 --- /dev/null +++ b/compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.txt @@ -0,0 +1,3 @@ +package test + +internal val a : [ERROR : Type for TestFun()] diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index a43ff7e5b9d..c62f7876825 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -1952,6 +1952,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructors("compiler/testData/lazyResolve/namespaceComparator/genericFunction.kt"); } + @TestMetadata("importFunctionWithAllUnderImportAfterNamedImport.kt") + public void testImportFunctionWithAllUnderImportAfterNamedImport() throws Exception { + doTestCheckingPrimaryConstructors("compiler/testData/lazyResolve/namespaceComparator/importFunctionWithAllUnderImportAfterNamedImport.kt"); + } + @TestMetadata("InnerClassNameClash.kt") public void testInnerClassNameClash() throws Exception { doTestCheckingPrimaryConstructors("compiler/testData/lazyResolve/namespaceComparator/InnerClassNameClash.kt");