From 94d7bd7a6b6fbb26b15d67a756327fca42e621e5 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 9 Nov 2016 11:57:26 +0300 Subject: [PATCH] KT-14641: Nested type alias reference via an instance is an error. --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 +- .../rendering/DiagnosticRendererUtil.kt | 5 +-- .../kotlin/diagnostics/rendering/Renderers.kt | 7 ++-- .../resolve/calls/CallExpressionResolver.kt | 7 ++-- .../diagnostics/tests/typealias/kt14641.kt | 9 ++++++ .../diagnostics/tests/typealias/kt14641.txt | 18 +++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++ .../kotlin/renderer/DescriptorRenderer.kt | 32 +++++++++++-------- .../kotlin/renderer/DescriptorRendererImpl.kt | 2 +- .../pullUp/pullUpConflictsUtils.kt | 2 +- .../nestedClassAcessedViaInstanceReference.kt | 4 ++- ...estedClassAcessedViaInstanceReference4.txt | 2 +- ...estedClassAcessedViaInstanceReference5.txt | 2 ++ 13 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/typealias/kt14641.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/kt14641.txt create mode 100644 idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference5.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 91f42df0a73..7504304d5e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -813,7 +813,7 @@ public interface Errors { DiagnosticFactory1 NO_COMPANION_OBJECT = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_PARAMETER_IS_NOT_AN_EXPRESSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_PARAMETER_ON_LHS_OF_DOT = DiagnosticFactory1.create(ERROR); - DiagnosticFactory1 NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 NESTED_CLASS_SHOULD_BE_QUALIFIED = DiagnosticFactory2.create(ERROR); DiagnosticFactory1 INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticRendererUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticRendererUtil.kt index 34a20f8d8eb..8548d67c023 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticRendererUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticRendererUtil.kt @@ -17,12 +17,13 @@ package org.jetbrains.kotlin.diagnostics.rendering import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.renderer.DescriptorRenderer fun

renderParameter(parameter: P, renderer: DiagnosticParameterRenderer

?, context: RenderingContext): Any = renderer?.render(parameter, context) ?: parameter -fun ClassDescriptor.renderKindWithName(): String = DescriptorRenderer.getClassKindPrefix(this) + " '" + name + "'" +fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String = DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'" -fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassKindPrefix(this) +fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 44a116545e4..835a8e3ef12 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -38,10 +38,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_BOUND -import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind -import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.* +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.getValidityConstraintForConstituentType import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.types.KotlinType @@ -53,7 +53,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.PrintWriter import java.io.StringWriter import java.lang.AssertionError -import java.util.* object Renderers { @@ -119,7 +118,7 @@ object Renderers { if (classOrObject is KtClass) "Class" + name else "Object" + name } - @JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer { it.renderKindWithName() } + @JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer { it.renderKindWithName() } @JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false }) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt index 4be0637f72c..1449d62c3f8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt @@ -501,10 +501,9 @@ class CallExpressionResolver( val receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.receiverExpression) if (receiverQualifier == null && expressionQualifier != null) { - assert(expressionQualifier is ClassQualifier) { "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier } - context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on( - selectorExpression, - (expressionQualifier as ClassQualifier).descriptor)) + assert(expressionQualifier is ClassifierQualifier) { "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier } + val descriptor = (expressionQualifier as ClassifierQualifier).descriptor + context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, descriptor)) } } } diff --git a/compiler/testData/diagnostics/tests/typealias/kt14641.kt b/compiler/testData/diagnostics/tests/typealias/kt14641.kt new file mode 100644 index 00000000000..d9a1dfa847e --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/kt14641.kt @@ -0,0 +1,9 @@ +class A { + public inner class B { } + public typealias BAlias = B +} + +fun f() { + val a = A() + a.BAlias +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/kt14641.txt b/compiler/testData/diagnostics/tests/typealias/kt14641.txt new file mode 100644 index 00000000000..75f82bb8cc1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/kt14641.txt @@ -0,0 +1,18 @@ +package + +public fun f(): kotlin.Unit + +public final class A { + public constructor 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 + + public final inner class B { + public constructor B() + 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 + } + public typealias BAlias = A.B +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 347921c305b..dd3d3cd6d7f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -20878,6 +20878,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt14641.kt") + public void testKt14641() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/kt14641.kt"); + doTest(fileName); + } + @TestMetadata("localTypeAlias.kt") public void testLocalTypeAlias() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/localTypeAlias.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index 4c027bf8f8b..c3b70154b93 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -144,19 +144,25 @@ abstract class DescriptorRenderer { modifiers = DescriptorRendererModifier.ALL } - fun getClassKindPrefix(klass: ClassDescriptor): String { - if (klass.isCompanionObject) { - return "companion object" - } - return when (klass.kind) { - ClassKind.CLASS -> "class" - ClassKind.INTERFACE -> "interface" - ClassKind.ENUM_CLASS -> "enum class" - ClassKind.OBJECT -> "object" - ClassKind.ANNOTATION_CLASS -> "annotation class" - ClassKind.ENUM_ENTRY -> "enum entry" - } - } + fun getClassifierKindPrefix(classifier: ClassifierDescriptorWithTypeParameters): String = + when (classifier) { + is TypeAliasDescriptor -> + "typealias" + is ClassDescriptor -> + if (classifier.isCompanionObject) { + "companion object" + } + else when (classifier.kind) { + ClassKind.CLASS -> "class" + ClassKind.INTERFACE -> "interface" + ClassKind.ENUM_CLASS -> "enum class" + ClassKind.OBJECT -> "object" + ClassKind.ANNOTATION_CLASS -> "annotation class" + ClassKind.ENUM_ENTRY -> "enum entry" + } + else -> + throw AssertionError("Unexpected classifier: $classifier") + } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 0bc605b228a..c9f7f66ed79 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -931,7 +931,7 @@ internal class DescriptorRendererImpl( } private fun renderClassKindPrefix(klass: ClassDescriptor, builder: StringBuilder) { - builder.append(renderKeyword(DescriptorRenderer.getClassKindPrefix(klass))) + builder.append(renderKeyword(DescriptorRenderer.getClassifierKindPrefix(klass))) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt index f585321037a..4d074fc5850 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt @@ -78,7 +78,7 @@ private val CALLABLE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_I fun DeclarationDescriptor.renderForConflicts(): String { return when (this) { - is ClassDescriptor -> "${DescriptorRenderer.getClassKindPrefix(this)} ${IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(this)}" + is ClassDescriptor -> "${DescriptorRenderer.getClassifierKindPrefix(this)} ${IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(this)}" is FunctionDescriptor -> "function '${CALLABLE_RENDERER.render(this)}'" is PropertyDescriptor -> "property '${CALLABLE_RENDERER.render(this)}'" else -> "" diff --git a/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt index a827a784897..98c4705884d 100644 --- a/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt +++ b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt @@ -1,4 +1,4 @@ -// !DIAGNOSTICS_NUMBER: 3 +// !DIAGNOSTICS_NUMBER: 4 // !DIAGNOSTICS: NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE class A { @@ -6,11 +6,13 @@ class A { class NestedWithClassObject { companion object } enum class NestedEnum { A } object NestedObj { fun invoke() = 1 } + typealias NestedAlias = Nested } fun test(a: A) { a.NestedWithClassObject a.NestedEnum a.NestedObj + a.NestedAlias a.Nested() // TODO: report "nested class accessed via instance reference" here as well } diff --git a/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference4.txt b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference4.txt index 5c7807ba8ed..b49c5cb8433 100644 --- a/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference4.txt +++ b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference4.txt @@ -1,2 +1,2 @@ -Nested class 'Nested' accessed via instance reference \ No newline at end of file +Nested typealias 'NestedAlias' accessed via instance reference \ No newline at end of file diff --git a/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference5.txt b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference5.txt new file mode 100644 index 00000000000..2ddc8944596 --- /dev/null +++ b/idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference5.txt @@ -0,0 +1,2 @@ + +Nested class 'Nested' accessed via instance reference \ No newline at end of file