diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt index 29c17d76a57..4939ccddd2d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportScope.kt @@ -16,17 +16,20 @@ package org.jetbrains.kotlin.resolve -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PackageViewDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.BaseImportingScope import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.ResolutionScope import org.jetbrains.kotlin.utils.Printer -class AllUnderImportScope(descriptor: DeclarationDescriptor) : BaseImportingScope(null) { +class AllUnderImportScope( + descriptor: DeclarationDescriptor, + aliasImportNames: Collection +) : BaseImportingScope(null) { + private val scopes: List = if (descriptor is ClassDescriptor) { listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope) } @@ -37,17 +40,39 @@ class AllUnderImportScope(descriptor: DeclarationDescriptor) : BaseImportingScop listOf((descriptor as PackageViewDescriptor).memberScope) } - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) - = scopes.flatMap { it.getContributedDescriptors(kindFilter, nameFilter) } + private val excludedNames = if (aliasImportNames.isEmpty()) { // optimization + emptyList() + } + else { + val fqName = DescriptorUtils.getFqNameSafe(descriptor) + aliasImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null } + } - override fun getContributedClassifier(name: Name, location: LookupLocation) - = scopes.asSequence().mapNotNull { it.getContributedClassifier(name, location) }.singleOrNull() + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List { + val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization + nameFilter + } + else { + { it !in excludedNames && nameFilter(it) } + } - override fun getContributedVariables(name: Name, location: LookupLocation) - = scopes.flatMap { it.getContributedVariables(name, location) } + return scopes.flatMap { it.getContributedDescriptors(kindFilter, nameFilterToUse) } + } - override fun getContributedFunctions(name: Name, location: LookupLocation) - = scopes.flatMap { it.getContributedFunctions(name, location) } + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { + if (name in excludedNames) return null + return scopes.asSequence().mapNotNull { it.getContributedClassifier(name, location) }.singleOrNull() + } + + override fun getContributedVariables(name: Name, location: LookupLocation): List { + if (name in excludedNames) return emptyList() + return scopes.flatMap { it.getContributedVariables(name, location) } + } + + override fun getContributedFunctions(name: Name, location: LookupLocation): List { + if (name in excludedNames) return emptyList() + return scopes.flatMap { it.getContributedFunctions(name, location) } + } override fun printStructure(p: Printer) { p.println(javaClass.simpleName) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index c43085cba0b..ec7b89447df 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -134,6 +134,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator importDirective: KtImportDirective, moduleDescriptor: ModuleDescriptor, trace: BindingTrace, + aliasImportNames: Collection, packageFragmentForVisibilityCheck: PackageFragmentDescriptor? ): ImportingScope? { // null if some error happened val importedReference = importDirective.importedReference ?: return null @@ -156,7 +157,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator return null } - return AllUnderImportScope(packageOrClassDescriptor) + return AllUnderImportScope(packageOrClassDescriptor, aliasImportNames) } else { return processSingleImport(moduleDescriptor, trace, importDirective, path, lastPart, packageFragmentForCheck) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt index 15b2b333d73..70fbde6af40 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt @@ -60,17 +60,26 @@ open class FileScopeProviderImpl( val imports = file.importDirectives + val aliasImportNames = imports.mapNotNull { if (it.aliasName != null) it.importedFqName else null } + val packageView = moduleDescriptor.getPackage(file.packageFqName) val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName) .sure { "Could not find fragment ${file.packageFqName} for file ${file.name}" } fun createImportResolver(indexedImports: IndexedImports, trace: BindingTrace) - = LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, trace, packageFragment) + = LazyImportResolver(storageManager, qualifiedExpressionResolver, moduleDescriptor, indexedImports, aliasImportNames, trace, packageFragment) - val aliasImportResolver = createImportResolver(AliasImportsIndexed(imports), bindingTrace) + val explicitImportResolver = createImportResolver(ExplicitImportsIndexed(imports), bindingTrace) val allUnderImportResolver = createImportResolver(AllUnderImportsIndexed(imports), bindingTrace) - val defaultAliasImportResolver = createImportResolver(AliasImportsIndexed(defaultImports), tempTrace) - val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImports), tempTrace) + + val defaultImportsFiltered = if (aliasImportNames.isEmpty()) { // optimization + defaultImports + } + else { + defaultImports.filter { it.isAllUnder || it.importedFqName !in aliasImportNames } + } + val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace) + val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace) var scope: ImportingScope @@ -86,14 +95,14 @@ open class FileScopeProviderImpl( scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "All under imports in $debugName (visible classes)") - scope = LazyImportScope(scope, defaultAliasImportResolver, LazyImportScope.FilteringKind.ALL, - "Default alias imports in $debugName") + scope = LazyImportScope(scope, defaultExplicitImportResolver, LazyImportScope.FilteringKind.ALL, + "Default explicit imports in $debugName") scope = SubpackagesImportingScope(scope, moduleDescriptor, FqName.ROOT) scope = packageView.memberScope.memberScopeAsImportingScope(scope) //TODO: problems with visibility too - scope = LazyImportScope(scope, aliasImportResolver, LazyImportScope.FilteringKind.ALL, "Alias imports in $debugName") + scope = LazyImportScope(scope, explicitImportResolver, LazyImportScope.FilteringKind.ALL, "Explicit imports in $debugName") val lexicalScope = LexicalScope.empty(scope, packageFragment) @@ -101,7 +110,7 @@ open class FileScopeProviderImpl( val importResolver = object : ImportResolver { override fun forceResolveAllImports() { - aliasImportResolver.forceResolveAllImports() + explicitImportResolver.forceResolveAllImports() allUnderImportResolver.forceResolveAllImports() } @@ -110,7 +119,7 @@ open class FileScopeProviderImpl( allUnderImportResolver.forceResolveImport(importDirective) } else { - aliasImportResolver.forceResolveImport(importDirective) + explicitImportResolver.forceResolveImport(importDirective) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 6579a9edd5f..a5e557fb7ae 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtPsiUtil @@ -46,7 +47,7 @@ class AllUnderImportsIndexed(allImports: Collection) : Indexe override fun importsForName(name: Name) = imports } -class AliasImportsIndexed(allImports: Collection) : IndexedImports { +class ExplicitImportsIndexed(allImports: Collection) : IndexedImports { override val imports = allImports.filter { !it.isAllUnder() } private val nameToDirectives: ListMultimap by lazy { @@ -74,13 +75,14 @@ class LazyImportResolver( val qualifiedExpressionResolver: QualifiedExpressionResolver, val moduleDescriptor: ModuleDescriptor, val indexedImports: IndexedImports, + aliasImportNames: Collection, private val traceForImportResolve: BindingTrace, private val packageFragment: PackageFragmentDescriptor ) : ImportResolver { private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues { directive: KtImportDirective -> val directiveImportScope = qualifiedExpressionResolver.processImportReference( - directive, moduleDescriptor, traceForImportResolve, packageFragment) ?: return@createMemoizedFunctionWithNullableValues null + directive, moduleDescriptor, traceForImportResolve, aliasImportNames, packageFragment) ?: return@createMemoizedFunctionWithNullableValues null if (!directive.isAllUnder) { PlatformTypesMappedToKotlinChecker.checkPlatformTypesMappedToKotlin( diff --git a/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.kt b/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.kt index d531078860e..08d4242283a 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.kt +++ b/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.kt @@ -2,4 +2,7 @@ package a import a.A as ER -class A() +interface A { + val a: A + val b: ER +} diff --git a/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.txt b/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.txt index 85d5d888651..37b79e25bc2 100644 --- a/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.txt +++ b/compiler/testData/diagnostics/tests/imports/ImportFromCurrentWithDifferentName.txt @@ -2,8 +2,9 @@ package package a { - public final class A { - public constructor A() + public interface A { + public abstract val a: a.A + public abstract val b: a.A public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/testData/diagnostics/tests/imports/RenameOnImport.kt b/compiler/testData/diagnostics/tests/imports/RenameOnImport.kt index a642f9ef13c..04e4e4f091e 100644 --- a/compiler/testData/diagnostics/tests/imports/RenameOnImport.kt +++ b/compiler/testData/diagnostics/tests/imports/RenameOnImport.kt @@ -2,10 +2,21 @@ package a val x = 1 +val y = 1 // FILE: b.kt package b -import a.x as AX +val x = "" -val y = AX \ No newline at end of file +// FILE: c.kt +package c + +import a.x as AX +import a.* +import b.* +import a.y as AY + +val v1: Int = AX +val v2: String = x +val v3 = y diff --git a/compiler/testData/diagnostics/tests/imports/RenameOnImport.txt b/compiler/testData/diagnostics/tests/imports/RenameOnImport.txt index 3bcd7b2d8d0..caf1b5076f7 100644 --- a/compiler/testData/diagnostics/tests/imports/RenameOnImport.txt +++ b/compiler/testData/diagnostics/tests/imports/RenameOnImport.txt @@ -2,8 +2,15 @@ package package a { public val x: kotlin.Int = 1 + public val y: kotlin.Int = 1 } package b { - public val y: kotlin.Int = 1 + public val x: kotlin.String = "" +} + +package c { + public val v1: kotlin.Int = 1 + public val v2: kotlin.String = "" + public val v3: [ERROR : Type for y] } diff --git a/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.kt b/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.kt new file mode 100644 index 00000000000..9f7173f0fc3 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.kt @@ -0,0 +1,9 @@ +import kotlin.collections.map as map1 +import kotlin.Array as KotlinArray + +fun f() { + listOf(1).map1 { it.hashCode() } + listOf(1).map { it.hashCode() } +} + +fun g(a1: KotlinArray, a2: Array){} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.txt b/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.txt new file mode 100644 index 00000000000..dde5b3e6d6f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.txt @@ -0,0 +1,4 @@ +package + +public fun f(): kotlin.Unit +public fun g(/*0*/ a1: kotlin.Array, /*1*/ a2: [ERROR : Array]): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 1607be5252a..9b15fc3467e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -125,6 +125,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("RenameOnImportHidesDefaultImport.kt") + public void testRenameOnImportHidesDefaultImport() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/RenameOnImportHidesDefaultImport.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt index 8ebc12c6226..f0baf7c3d01 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt @@ -85,5 +85,5 @@ fun ResolutionFacade.resolveImportReference( val importDirective = KtPsiFactory(project).createImportDirective(ImportPath(fqName, false)) val qualifiedExpressionResolver = this.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java) return qualifiedExpressionResolver.processImportReference( - importDirective, moduleDescriptor, BindingTraceContext(), packageFragmentForVisibilityCheck = null)?.getContributedDescriptors() ?: emptyList() + importDirective, moduleDescriptor, BindingTraceContext(), aliasImportNames = emptyList(), packageFragmentForVisibilityCheck = null)?.getContributedDescriptors() ?: emptyList() } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt index 7750e927ac1..430b5a599c0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt @@ -146,7 +146,8 @@ class CodeFragmentAnalyzer( } val importScopes = importList.imports.mapNotNull { - qualifierResolver.processImportReference(it, resolveSession.moduleDescriptor, resolveSession.trace, null) + qualifierResolver.processImportReference(it, resolveSession.moduleDescriptor, resolveSession.trace, + aliasImportNames = emptyList(), packageFragmentForVisibilityCheck = null) } return scopeForContextElement.addImportingScopes(importScopes) to dataFlowInfo