From 3a2d93f73eb5abde8851999033b9cf685a4c7e80 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 21 Jul 2017 15:47:57 +0300 Subject: [PATCH] Do not report "header with no impl" on incorrect header Descriptor for a 'header' member in a non-'header' class now has isHeader = false #KT-18442 Fixed --- .../kotlin/resolve/DescriptorResolver.java | 23 +++++++++---------- .../resolve/FunctionDescriptorResolver.kt | 14 +++++------ .../checkers/HeaderImplDeclarationChecker.kt | 3 +++ .../headerClass/extraHeaderOnMembers.kt | 14 +++++++++++ .../headerClass/extraHeaderOnMembers.txt | 22 ++++++++++++++++++ .../headerFunInNonHeaderClass.kt | 10 ++++++++ .../headerFunInNonHeaderClass.txt | 22 ++++++++++++++++++ .../multiplatform/modifierApplicability.kt | 4 ++-- .../multiplatform/modifierApplicability.txt | 4 ++-- .../checkers/DiagnosticsTestGenerated.java | 12 ++++++++++ 10 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.txt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.kt create mode 100644 compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index a95edda3a84..911e92cf700 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -836,7 +836,7 @@ public class DescriptorResolver { @NotNull private PropertyDescriptor resolveAsPropertyDescriptor( - @NotNull DeclarationDescriptor containingDeclaration, + @NotNull DeclarationDescriptor container, @NotNull LexicalScope scopeForDeclarationResolution, @NotNull LexicalScope scopeForInitializerResolution, @NotNull KtVariableDeclaration variableDeclaration, @@ -847,11 +847,11 @@ public class DescriptorResolver { KtModifierList modifierList = variableDeclaration.getModifierList(); boolean isVar = variableDeclaration.isVar(); - Visibility visibility = resolveVisibilityFromModifiers(variableDeclaration, getDefaultVisibility(variableDeclaration, containingDeclaration)); - Modality modality = containingDeclaration instanceof ClassDescriptor + Visibility visibility = resolveVisibilityFromModifiers(variableDeclaration, getDefaultVisibility(variableDeclaration, container)); + Modality modality = container instanceof ClassDescriptor ? resolveMemberModalityFromModifiers(variableDeclaration, - getDefaultModality(containingDeclaration, visibility, propertyInfo.getHasBody()), - trace.getBindingContext(), containingDeclaration) + getDefaultModality(container, visibility, propertyInfo.getHasBody()), + trace.getBindingContext(), container) : Modality.FINAL; AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(variableDeclaration); @@ -866,7 +866,7 @@ public class DescriptorResolver { annotationSplitter.getOtherAnnotations())); PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create( - containingDeclaration, + container, propertyAnnotations, modality, visibility, @@ -876,8 +876,8 @@ public class DescriptorResolver { KotlinSourceElementKt.toSourceElement(variableDeclaration), modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD), - modifierList != null && modifierList.hasModifier(KtTokens.HEADER_KEYWORD) || - containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isHeader(), + modifierList != null && modifierList.hasModifier(KtTokens.HEADER_KEYWORD) && container instanceof PackageFragmentDescriptor || + container instanceof ClassDescriptor && ((ClassDescriptor) container).isHeader(), modifierList != null && modifierList.hasModifier(KtTokens.IMPL_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.EXTERNAL_KEYWORD), propertyInfo.getHasDelegate() @@ -898,10 +898,10 @@ public class DescriptorResolver { } else { LexicalWritableScope writableScopeForDeclarationResolution = new LexicalWritableScope( - scopeForDeclarationResolution, containingDeclaration, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker), + scopeForDeclarationResolution, container, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker), LexicalScopeKind.PROPERTY_HEADER); LexicalWritableScope writableScopeForInitializerResolution = new LexicalWritableScope( - scopeForInitializerResolution, containingDeclaration, false, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, + scopeForInitializerResolution, container, false, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, LexicalScopeKind.PROPERTY_HEADER); typeParameterDescriptors = resolveTypeParametersForDescriptor( propertyDescriptor, @@ -951,8 +951,7 @@ public class DescriptorResolver { propertyDescriptor, scopeForInitializer, variableDeclaration, dataFlowInfo, type, trace ); - propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(containingDeclaration), - receiverDescriptor); + propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(container), receiverDescriptor); PropertySetterDescriptor setter = resolvePropertySetterDescriptor( scopeForDeclarationResolutionWithTypeParameters, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt index 8ea81eef0d9..a2395adcc39 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt @@ -134,7 +134,7 @@ class FunctionDescriptorResolver( } fun initializeFunctionDescriptorAndExplicitReturnType( - containingDescriptor: DeclarationDescriptor, + container: DeclarationDescriptor, scope: LexicalScope, function: KtFunction, functionDescriptor: SimpleFunctionDescriptorImpl, @@ -164,12 +164,12 @@ class FunctionDescriptorResolver( val returnType = function.typeReference?.let { typeResolver.resolveType(headerScope, it, trace, true) } - val visibility = resolveVisibilityFromModifiers(function, getDefaultVisibility(function, containingDescriptor)) - val modality = resolveMemberModalityFromModifiers(function, getDefaultModality(containingDescriptor, visibility, function.hasBody()), - trace.bindingContext, containingDescriptor) + val visibility = resolveVisibilityFromModifiers(function, getDefaultVisibility(function, container)) + val modality = resolveMemberModalityFromModifiers(function, getDefaultModality(container, visibility, function.hasBody()), + trace.bindingContext, container) functionDescriptor.initialize( receiverType, - getDispatchReceiverParameterIfNeeded(containingDescriptor), + getDispatchReceiverParameterIfNeeded(container), typeParameterDescriptors, valueParameterDescriptors, returnType, @@ -182,8 +182,8 @@ class FunctionDescriptorResolver( functionDescriptor.isInline = function.hasModifier(KtTokens.INLINE_KEYWORD) functionDescriptor.isTailrec = function.hasModifier(KtTokens.TAILREC_KEYWORD) functionDescriptor.isSuspend = function.hasModifier(KtTokens.SUSPEND_KEYWORD) - functionDescriptor.isHeader = function.hasModifier(KtTokens.HEADER_KEYWORD) || - containingDescriptor is ClassDescriptor && containingDescriptor.isHeader + functionDescriptor.isHeader = container is PackageFragmentDescriptor && function.hasModifier(KtTokens.HEADER_KEYWORD) || + container is ClassDescriptor && container.isHeader functionDescriptor.isImpl = function.hasModifier(KtTokens.IMPL_KEYWORD) receiverType?.let { ForceResolveUtil.forceResolveAllContents(it.annotations) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt index f4f7e0213a8..ce8893cae81 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt @@ -80,6 +80,9 @@ object HeaderImplDeclarationChecker : DeclarationChecker { platformModule: ModuleDescriptor, checkImpl: Boolean ) { + // Only look for implementations of top level members; class members will be handled as a part of that header class + if (descriptor is CallableMemberDescriptor && descriptor.containingDeclaration !is PackageFragmentDescriptor) return + val compatibility = findImplForHeader(descriptor, platformModule, checkImpl) ?: return val shouldReportError = diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.kt new file mode 100644 index 00000000000..5beb9a254b1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.kt @@ -0,0 +1,14 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +header class H { + header fun foo() +} + +// MODULE: m1-jvm(m1-common) +// FILE: jvm.kt + +impl class H { + impl fun foo() {} +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.txt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.txt new file mode 100644 index 00000000000..fef594f44f9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.txt @@ -0,0 +1,22 @@ +// -- Module: -- +package + +public final header class H { + public constructor H() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final header fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + + +// -- Module: -- +package + +public final impl class H { + public constructor H() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final impl fun foo(): kotlin.Unit + 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/multiplatform/headerFunInNonHeaderClass.kt b/compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.kt new file mode 100644 index 00000000000..3f0f1a99da1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.kt @@ -0,0 +1,10 @@ +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +class Foo { + header fun bar(): String +} + +// MODULE: m1-jvm(m1-common) +// FILE: jvm.kt diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.txt b/compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.txt new file mode 100644 index 00000000000..5367b2d1d7c --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.txt @@ -0,0 +1,22 @@ +// -- Module: -- +package + +public final class Foo { + public constructor Foo() + public final fun bar(): kotlin.String + 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 +} + + +// -- Module: -- +package + +public final class Foo { + public constructor Foo() + public final fun bar(): kotlin.String + 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/multiplatform/modifierApplicability.kt b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.kt index 44e864355bf..1ccb53f3f8b 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.kt @@ -10,11 +10,11 @@ class Outer header constructor() { header init {} header fun foo() - header val bar: Int + header val bar: Int } fun foo() { - header fun localFun() + header fun localFun() header var x = 42 header class Bar } diff --git a/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.txt b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.txt index d7db811a784..836039dcb3a 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.txt +++ b/compiler/testData/diagnostics/tests/multiplatform/modifierApplicability.txt @@ -5,9 +5,9 @@ public fun foo(): kotlin.Unit public final class Outer { public constructor Outer() - public header final val bar: kotlin.Int + public final val bar: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final header fun foo(): kotlin.Unit + public final fun foo(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 85fe7885351..8a89959ecad 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13630,6 +13630,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("headerFunInNonHeaderClass.kt") + public void testHeaderFunInNonHeaderClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/headerFunInNonHeaderClass.kt"); + doTest(fileName); + } + @TestMetadata("implDelegatedMember.kt") public void testImplDelegatedMember() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/implDelegatedMember.kt"); @@ -13734,6 +13740,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("extraHeaderOnMembers.kt") + public void testExtraHeaderOnMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/headerClass/extraHeaderOnMembers.kt"); + doTest(fileName); + } + @TestMetadata("genericClassImplTypeAlias.kt") public void testGenericClassImplTypeAlias() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/headerClass/genericClassImplTypeAlias.kt");