From d749f85a6011e86e082b0dce455a16105ec50697 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 18 Jan 2016 17:17:58 +0300 Subject: [PATCH] Inaccessible classes from the current package to not conflict with visible classes from somewhere else --- .../resolve/lazy/FileScopeProviderImpl.kt | 62 ++++++++++++++++--- .../tests/imports/InaccessiblePrivateClass.kt | 18 ++++++ .../imports/InaccessiblePrivateClass.txt | 30 +++++++++ .../InaccessibleInternalClass.kt | 15 +++++ .../checkers/DiagnosticsTestGenerated.java | 8 ++- .../DiagnosticsTestWithStdLibGenerated.java | 6 ++ 6 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt create mode 100644 compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.kt 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 66436216b4e..7faca36db6b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.lazy import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -29,9 +30,12 @@ import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.bindingContextUtil.recordScope import org.jetbrains.kotlin.resolve.scopes.* import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue +import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.kotlin.utils.addToStdlib.check open class FileScopeProviderImpl( private val topLevelDescriptorProvider: TopLevelDescriptorProvider, @@ -81,6 +85,8 @@ open class FileScopeProviderImpl( val defaultExplicitImportResolver = createImportResolver(ExplicitImportsIndexed(defaultImportsFiltered), tempTrace) val defaultAllUnderImportResolver = createImportResolver(AllUnderImportsIndexed(defaultImportsFiltered), tempTrace) + val dummyContainerDescriptor = DummyContainerDescriptor(file, packageFragment) + var scope: ImportingScope scope = LazyImportScope(null, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, @@ -89,6 +95,9 @@ open class FileScopeProviderImpl( scope = LazyImportScope(scope, allUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, "All under imports in $debugName (invisible classes only)") + scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.INVISIBLE_CLASSES) + .memberScopeAsImportingScope(scope) + scope = LazyImportScope(scope, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "Default all under imports in $debugName (visible classes)") @@ -100,7 +109,8 @@ open class FileScopeProviderImpl( scope = SubpackagesImportingScope(scope, moduleDescriptor, FqName.ROOT) - scope = packageMemberScopeWithAliasedNamesExcluded(packageView, aliasImportNames).memberScopeAsImportingScope(scope) //TODO: problems with visibility too + scope = currentPackageScope(packageView, aliasImportNames, dummyContainerDescriptor, FilteringKind.VISIBLE_CLASSES) + .memberScopeAsImportingScope(scope) scope = LazyImportScope(scope, explicitImportResolver, LazyImportScope.FilteringKind.ALL, "Explicit imports in $debugName") @@ -127,36 +137,74 @@ open class FileScopeProviderImpl( return FileData(lexicalScope, importResolver) } - private fun packageMemberScopeWithAliasedNamesExcluded(packageView: PackageViewDescriptor, aliasImportNames: Collection): MemberScope { - val scope = packageView.memberScope - if (aliasImportNames.isEmpty()) return scope + // we use this dummy implementation of DeclarationDescriptor to check accessibility of symbols from the current package + private class DummyContainerDescriptor(private val file: KtFile, private val packageFragment: PackageFragmentDescriptor) : DeclarationDescriptorNonRoot { + private val sourceElement = KotlinSourceElement(file) + override fun getContainingDeclaration() = packageFragment + + override fun getSource() = sourceElement + + override fun getOriginal() = this + override fun getAnnotations() = Annotations.EMPTY + override fun substitute(substitutor: TypeSubstitutor) = this + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R { + throw UnsupportedOperationException() + } + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) { + throw UnsupportedOperationException() + } + + override fun getName(): Name { + throw UnsupportedOperationException() + } + } + + private enum class FilteringKind { + VISIBLE_CLASSES, INVISIBLE_CLASSES + } + + private fun currentPackageScope( + packageView: PackageViewDescriptor, + aliasImportNames: Collection, + fromDescriptor: DummyContainerDescriptor, + filteringKind: FilteringKind + ): MemberScope { + val scope = packageView.memberScope val packageName = packageView.fqName val excludedNames = aliasImportNames.mapNotNull { if (it.parent() == packageName) it.shortName() else null } - if (excludedNames.isEmpty()) return scope return object: MemberScope { override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { if (name in excludedNames) return null - return scope.getContributedClassifier(name, location) + val classifier = scope.getContributedClassifier(name, location) ?: return null + val visible = Visibilities.isVisibleWithIrrelevantReceiver(classifier as ClassDescriptor, fromDescriptor) + return classifier.check { filteringKind == if (visible) FilteringKind.VISIBLE_CLASSES else FilteringKind.INVISIBLE_CLASSES } } override fun getContributedVariables(name: Name, location: LookupLocation): Collection { + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() if (name in excludedNames) return emptyList() return scope.getContributedVariables(name, location) } override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() if (name in excludedNames) return emptyList() return scope.getContributedFunctions(name, location) } override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() return scope.getContributedDescriptors(kindFilter, { name -> name !in excludedNames && nameFilter(name) }) } + override fun toString() = "Scope for current package (${filteringKind.name})" + override fun printScopeStructure(p: Printer) { - return scope.printScopeStructure(p) + p.println(this.toString()) } } } diff --git a/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt b/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt new file mode 100644 index 00000000000..f8ac999bb3a --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt @@ -0,0 +1,18 @@ +// FILE: a.kt +package p1 + +private class X +private class Y + +// FILE: b.kt +package p2 + +class X + +// FILE: c.kt +package p1 + +import p2.* + +val x: X = X() +val y: Y = Y() diff --git a/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.txt b/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.txt new file mode 100644 index 00000000000..669f72da11d --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.txt @@ -0,0 +1,30 @@ +package + +package p1 { + public val x: p2.X + public val y: p1.Y + + private final class X { + public constructor X() + 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 + } + + private final class Y { + public constructor Y() + 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 + } +} + +package p2 { + + public final class X { + public constructor X() + 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/testsWithStdLib/InaccessibleInternalClass.kt b/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.kt new file mode 100644 index 00000000000..1574d35641e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.kt @@ -0,0 +1,15 @@ +// FILE: a.kt +package p + +class FilteringSequence + +// FILE: b.kt +// SKIP_TXT +package kotlin.sequences + +import p.* + +interface I { + val v1: FilteringSequence + val v2: IndexingSequence +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 242872d3053..2bb974f401a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7653,6 +7653,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("InaccessiblePrivateClass.kt") + public void testInaccessiblePrivateClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/InaccessiblePrivateClass.kt"); + doTest(fileName); + } + @TestMetadata("JavaPackageLocalClassNotImported.kt") public void testJavaPackageLocalClassNotImported() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/JavaPackageLocalClassNotImported.kt"); @@ -19003,7 +19009,7 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { @TestMetadata("compiler/testData/codegen/box/diagnostics/vararg") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class IIImpoiVararg extends AbstractDiagnosticsTest { + public static class Vararg extends AbstractDiagnosticsTest { public void testAllFilesPresentInVararg() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/diagnostics/vararg"), Pattern.compile("^(.+)\\.kt$"), true); } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 4619caee51f..71f0237cfc9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -77,6 +77,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("InaccessibleInternalClass.kt") + public void testInaccessibleInternalClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.kt"); + doTest(fileName); + } + @TestMetadata("instar.kt") public void testInstar() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/instar.kt");