From fcfabb70d57c90d0aee9560e7307fc522c0a771c Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Mon, 21 Sep 2020 23:53:13 +0300 Subject: [PATCH] Report invisible setter error if it's resolved to synthetic property of base class with public getter and protected setter ^KT-11713 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 15 +++++++ .../ProtectedSyntheticExtensionCallChecker.kt | 45 ++++++++++++++----- .../jetbrains/kotlin/diagnostics/Errors.java | 2 +- .../kotlin/diagnostics/diagnosticUtils.kt | 24 +++++----- .../resolve/calls/context/CallPosition.kt | 2 +- .../ExpressionTypingVisitorForStatements.java | 15 +++++-- .../syntheticPropertyExtensions.kt | 6 +-- .../syntheticSAMExtensions.kt | 2 +- .../javaProperties/OnlyPublic.kt | 2 +- .../invisibleSetterOfJavaClass.fir.kt | 29 ++++++++++++ .../visibility/invisibleSetterOfJavaClass.kt | 29 ++++++++++++ .../visibility/invisibleSetterOfJavaClass.txt | 35 +++++++++++++++ ...etterOfJavaClassWithDisabledFeature.fir.kt | 29 ++++++++++++ ...bleSetterOfJavaClassWithDisabledFeature.kt | 29 ++++++++++++ ...leSetterOfJavaClassWithDisabledFeature.txt | 35 +++++++++++++++ ...sibleSetterOfJavaClassInSamePackage.fir.kt | 23 ++++++++++ ...InvisibleSetterOfJavaClassInSamePackage.kt | 23 ++++++++++ ...nvisibleSetterOfJavaClassInSamePackage.txt | 32 +++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 15 +++++++ .../DiagnosticsUsingJavacTestGenerated.java | 15 +++++++ .../kotlin/config/LanguageVersionSettings.kt | 1 + 21 files changed, 372 insertions(+), 36 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.fir.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.txt create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.fir.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.txt create mode 100644 compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.fir.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt create mode 100644 compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 6d23a13afe1..f7712001e92 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -25203,6 +25203,21 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte public void testAllFilesPresentInVisibility() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + + @TestMetadata("invisibleSetterOfJavaClass.kt") + public void testInvisibleSetterOfJavaClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt"); + } + + @TestMetadata("invisibleSetterOfJavaClassWithDisabledFeature.kt") + public void testInvisibleSetterOfJavaClassWithDisabledFeature() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt"); + } + + @TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt") + public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/when") diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt index 38134cefc59..51da0a11dcf 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt @@ -17,28 +17,47 @@ package org.jetbrains.kotlin.resolve.jvm.checkers import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3 import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor object ProtectedSyntheticExtensionCallChecker : CallChecker { + fun computeSuitableDescriptorAndError( + descriptor: SyntheticJavaPropertyDescriptor, + reportOn: PsiElement, + context: CallCheckerContext + ): Pair> { + val callPosition = context.resolutionContext.callPosition + val isLeftSide = callPosition is CallPosition.PropertyAssignment + && (callPosition.leftPart as? KtDotQualifiedExpression)?.selectorExpression == reportOn + val getMethod = descriptor.getMethod + val setMethod = descriptor.setMethod + val isImprovingDiagnosticsEnabled = + context.languageVersionSettings.supportsFeature(LanguageFeature.ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass) + val needToTakeSetter = isImprovingDiagnosticsEnabled && isLeftSide + val suitableDescriptor = if (needToTakeSetter && setMethod != null) setMethod else getMethod + + return suitableDescriptor to if (needToTakeSetter && setMethod != null) Errors.INVISIBLE_SETTER else Errors.INVISIBLE_MEMBER + } + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { val descriptor = resolvedCall.resultingDescriptor - val sourceFunction = when (descriptor) { - is SyntheticJavaPropertyDescriptor -> descriptor.getMethod - // TODO: this branch becomes unnecessary, because common checks are applied to SAM adapters being resolved as common members - // But this part may be still useful when we enable backward compatibility mode and SAM adapters become extensions again - is SamAdapterExtensionFunctionDescriptor -> descriptor.baseDescriptorForSynthetic - else -> return - } + if (descriptor !is SyntheticJavaPropertyDescriptor) return + + val (sourceFunction, error) = computeSuitableDescriptorAndError(descriptor, reportOn, context) val from = context.scope.ownerDescriptor @@ -49,12 +68,14 @@ object ProtectedSyntheticExtensionCallChecker : CallChecker { val receiverValue = resolvedCall.extensionReceiver as ReceiverValue val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getStableTypes( - context.dataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor), - context.languageVersionSettings + context.dataFlowValueFactory.createDataFlowValue( + receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor + ), + context.languageVersionSettings ) if (receiverTypes.none { DescriptorVisibilities.isVisible(getReceiverValueWithSmartCast(null, it), sourceFunction, from) }) { - context.trace.report(Errors.INVISIBLE_MEMBER.on(reportOn, descriptor, descriptor.visibility, from)) + context.trace.report(error.on(reportOn, descriptor, descriptor.visibility, from)) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 62c992e8667..81ea542f41b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1033,7 +1033,7 @@ public interface Errors { DiagnosticFactory0 LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 LOCAL_VARIABLE_WITH_TYPE_PARAMETERS = DiagnosticFactory0.create(ERROR); - DiagnosticFactory3 INVISIBLE_SETTER = DiagnosticFactory3.create(ERROR); + DiagnosticFactory3 INVISIBLE_SETTER = DiagnosticFactory3.create(ERROR); DiagnosticFactory1 VAL_OR_VAR_ON_LOOP_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 VAL_OR_VAR_ON_FUN_PARAMETER = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt index 380ed05f746..02715a8d00b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt @@ -51,25 +51,23 @@ fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection( ): Boolean { if (!TypeUtils.contains(expectedType) { it.isAnyOrNullableAny() || it.isNothing() || it.isNullableNothing() }) return false - val callPosition = this.callPosition val (resolvedCall, correspondingNotApproximatedTypeByDescriptor: (CallableDescriptor) -> KotlinType?) = when (callPosition) { - is CallPosition.ValueArgumentPosition -> Pair( - callPosition.resolvedCall, { f: CallableDescriptor -> + is CallPosition.ValueArgumentPosition -> + callPosition.resolvedCall to { f: CallableDescriptor -> getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument, this) - }) - is CallPosition.ExtensionReceiverPosition -> Pair, (CallableDescriptor) -> KotlinType?>( - callPosition.resolvedCall, { f: CallableDescriptor -> - f.extensionReceiverParameter?.type - }) - is CallPosition.PropertyAssignment -> Pair, (CallableDescriptor) -> KotlinType?>( - callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false, { f: CallableDescriptor -> - (f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type - }) + } + is CallPosition.ExtensionReceiverPosition -> + callPosition.resolvedCall to { f: CallableDescriptor -> f.extensionReceiverParameter?.type } + is CallPosition.PropertyAssignment -> { + if (callPosition.isLeft) return false + val resolvedCall = callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false + resolvedCall to { f: CallableDescriptor -> (f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type } + } is CallPosition.Unknown -> return false } val receiverType = resolvedCall.smartCastDispatchReceiverType - ?: (resolvedCall.dispatchReceiver ?: return false).type + ?: (resolvedCall.dispatchReceiver ?: return false).type val callableDescriptor = resolvedCall.resultingDescriptor.original diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt index 1eefab915a8..27c9d96354a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt @@ -33,5 +33,5 @@ sealed class CallPosition { val valueArgument: ValueArgument ) : CallPosition() - class PropertyAssignment(val leftPart: KtExpression?) : CallPosition() + class PropertyAssignment(val leftPart: KtExpression?, val isLeft: Boolean) : CallPosition() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index 57197099865..63d891fd801 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -304,7 +304,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType); components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType) - .replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left))); + .replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left, false))); basic.checkLValue(context.trace, context, leftOperand, right, expression, false); } temporary.commit(); @@ -354,14 +354,21 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito basic.checkLValue(context.trace, context, arrayAccessExpression, right, expression, true); return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType)); } - KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade); + KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType( + left, + context.replaceCallPosition(new CallPosition.PropertyAssignment(left, true)), + facade + ); KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftInfo.getType()); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); KotlinTypeInfo resultInfo; if (right != null) { resultInfo = facade.getTypeInfo( - right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(expectedType).replaceCallPosition( - new CallPosition.PropertyAssignment(leftOperand))); + right, + context.replaceDataFlowInfo(dataFlowInfo) + .replaceExpectedType(expectedType) + .replaceCallPosition(new CallPosition.PropertyAssignment(leftOperand, false)) + ); dataFlowInfo = resultInfo.getDataFlowInfo(); KotlinType rightType = resultInfo.getType(); diff --git a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticPropertyExtensions.kt b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticPropertyExtensions.kt index f4701d86ecd..a26cafecede 100644 --- a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticPropertyExtensions.kt +++ b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticPropertyExtensions.kt @@ -23,7 +23,7 @@ class B : A() { a.foo // TODO: should be INVISIBLE_SETTER - a.bar = a.bar + "" + a.bar = a.bar + "" if (a is B) { a.foo @@ -34,12 +34,12 @@ class B : A() { d.x.abc // Ok d.x.foo // TODO: should be INVISIBLE_SETTER - d.x.bar = d.x.bar + "" + d.x.bar = d.x.bar + "" } } } fun baz(a: A) { a.foo - a.bar = a.bar + "" + a.bar = a.bar + "" } diff --git a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticSAMExtensions.kt b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticSAMExtensions.kt index 308acfa0c82..cb88bbac2d8 100644 --- a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticSAMExtensions.kt +++ b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/syntheticSAMExtensions.kt @@ -17,7 +17,7 @@ class B : A() { b.foo { } if (a is B) { - a.foo {} + a.foo {} } if (d.x is B) { diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/OnlyPublic.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/OnlyPublic.kt index 6a5ac7818fb..7164afb1eb6 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/OnlyPublic.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/OnlyPublic.kt @@ -8,7 +8,7 @@ fun foo(javaClass: JavaClass) { javaClass.somethingProtected javaClass.somethingPrivate javaClass.somethingPackage - javaClass.somethingPublic = 1 + javaClass.somethingPublic = 1 } // FILE: JavaClass.java diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.fir.kt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.fir.kt new file mode 100644 index 00000000000..bd3fbbf6a49 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.fir.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: +ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass + +// FILE: abc/Foo.java +package abc; + +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +import abc.Foo + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt new file mode 100644 index 00000000000..3402a85d40d --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: +ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass + +// FILE: abc/Foo.java +package abc; + +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +import abc.Foo + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.txt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.txt new file mode 100644 index 00000000000..bbcb4e8bd71 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.txt @@ -0,0 +1,35 @@ +package + +public final class B : abc.Foo { + public constructor B() + public final fun baz(/*0*/ a: abc.Foo, /*1*/ t: abc.Foo, /*2*/ d: Data): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getBar(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + invisible_fake open override /*1*/ /*fake_override*/ fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Data { + public constructor Data(/*0*/ x: abc.Foo) + public final var x: abc.Foo + 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 abc { + + public open class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getBar(): kotlin.String! + public open fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + private open fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.fir.kt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.fir.kt new file mode 100644 index 00000000000..9ee3b7b757d --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.fir.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: -ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass + +// FILE: abc/Foo.java +package abc; + +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +import abc.Foo + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt new file mode 100644 index 00000000000..bdca9ce04a7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: -ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass + +// FILE: abc/Foo.java +package abc; + +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +import abc.Foo + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.txt b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.txt new file mode 100644 index 00000000000..bbcb4e8bd71 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.txt @@ -0,0 +1,35 @@ +package + +public final class B : abc.Foo { + public constructor B() + public final fun baz(/*0*/ a: abc.Foo, /*1*/ t: abc.Foo, /*2*/ d: Data): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getBar(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + invisible_fake open override /*1*/ /*fake_override*/ fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Data { + public constructor Data(/*0*/ x: abc.Foo) + public final var x: abc.Foo + 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 abc { + + public open class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getBar(): kotlin.String! + public open fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + private open fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.fir.kt b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.fir.kt new file mode 100644 index 00000000000..7c542493194 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.fir.kt @@ -0,0 +1,23 @@ +// FILE: Foo.java +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt new file mode 100644 index 00000000000..5242ac50303 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt @@ -0,0 +1,23 @@ +// FILE: Foo.java +public class Foo { + public String getBar() { return ""; } + protected void setBar(String x) { } + public String getFoo() { return ""; } + private void setFoo(String x) { } +} + +// FILE: main.kt + +class Data(var x: Foo) + +class B : Foo() { + fun baz(a: Foo, t: Foo, d: Data) { + a.bar = t.bar + a.foo = t.foo + + if (d.x is B) { + d.x.bar = d.x.bar + "" + d.x.foo = d.x.foo + "" + } + } +} diff --git a/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.txt b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.txt new file mode 100644 index 00000000000..1c265c9597e --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.txt @@ -0,0 +1,32 @@ +package + +public final class B : Foo { + public constructor B() + public final fun baz(/*0*/ a: Foo, /*1*/ t: Foo, /*2*/ d: Data): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun getBar(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + invisible_fake open override /*1*/ /*fake_override*/ fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Data { + public constructor Data(/*0*/ x: Foo) + public final var x: Foo + 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 open class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getBar(): kotlin.String! + public open fun getFoo(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected/*protected and package*/ open fun setBar(/*0*/ x: kotlin.String!): kotlin.Unit + private open fun setFoo(/*0*/ x: kotlin.String!): kotlin.Unit + 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 d68ceea647c..3f50d272804 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -25285,6 +25285,21 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali public void testAllFilesPresentInVisibility() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + + @TestMetadata("invisibleSetterOfJavaClass.kt") + public void testInvisibleSetterOfJavaClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt"); + } + + @TestMetadata("invisibleSetterOfJavaClassWithDisabledFeature.kt") + public void testInvisibleSetterOfJavaClassWithDisabledFeature() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt"); + } + + @TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt") + public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/when") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 43b6b935b0c..9c0559d1093 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -25205,6 +25205,21 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing public void testAllFilesPresentInVisibility() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + + @TestMetadata("invisibleSetterOfJavaClass.kt") + public void testInvisibleSetterOfJavaClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClass.kt"); + } + + @TestMetadata("invisibleSetterOfJavaClassWithDisabledFeature.kt") + public void testInvisibleSetterOfJavaClassWithDisabledFeature() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisibleSetterOfJavaClassWithDisabledFeature.kt"); + } + + @TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt") + public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/when") diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index eb78fea16c5..83b12a93a69 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -125,6 +125,7 @@ enum class LanguageFeature( FunctionalInterfaceConversion(KOTLIN_1_4, kind = UNSTABLE_FEATURE), GenerateJvmOverloadsAsFinal(KOTLIN_1_4), MangleClassMembersReturningInlineClasses(KOTLIN_1_4), + ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass(KOTLIN_1_4, kind = BUG_FIX, defaultState = State.ENABLED), ProhibitSpreadOnSignaturePolymorphicCall(KOTLIN_1_5, kind = BUG_FIX), ProhibitInvisibleAbstractMethodsInSuperclasses(KOTLIN_1_5, kind = BUG_FIX),