diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java index eee41141faa..6cf13bcf0be 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/InlineChecker.java @@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.FunctionTypesKt; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.lexer.KtToken; @@ -51,13 +50,13 @@ import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturn class InlineChecker implements CallChecker { private final FunctionDescriptor descriptor; private final Set inlinableParameters = new LinkedHashSet(); - private final boolean isEffectivelyPublicOrPublishedApiFunction; + private final EffectiveVisibility inlineFunEffectiveVisibility; private final boolean isEffectivelyPrivateApiFunction; public InlineChecker(@NotNull FunctionDescriptor descriptor) { assert InlineUtil.isInline(descriptor) : "This extension should be created only for inline functions: " + descriptor; this.descriptor = descriptor; - this.isEffectivelyPublicOrPublishedApiFunction = isEffectivelyPublicOrPublishedApi(descriptor); + this.inlineFunEffectiveVisibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true); this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor); for (ValueParameterDescriptor param : descriptor.getValueParameters()) { if (isInlinableParameter(param)) { @@ -239,31 +238,33 @@ class InlineChecker implements CallChecker { } private void checkVisibilityAndAccess( - @NotNull CallableDescriptor declarationDescriptor, + @NotNull CallableDescriptor calledDescriptor, @NotNull KtElement expression, @NotNull CallCheckerContext context ) { - boolean declarationDescriptorIsPublicOrPublishedApi = isEffectivelyPublicOrPublishedApi(declarationDescriptor) || - isDefinedInInlineFunction(declarationDescriptor); - if (isEffectivelyPublicOrPublishedApiFunction && - !declarationDescriptorIsPublicOrPublishedApi && - declarationDescriptor.getVisibility() != Visibilities.LOCAL) { - context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor, descriptor)); + EffectiveVisibility calledFunEffectiveVisibility = + isDefinedInInlineFunction(calledDescriptor) ? + EffectiveVisibility.Public.INSTANCE : + EffectiveVisibilityKt.effectiveVisibility(calledDescriptor, calledDescriptor.getVisibility(), true); + + boolean isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.getPublicApi(); + boolean isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.getPublicApi(); + if (isInlineFunPublicOrPublishedApi && + !isCalledFunPublicOrPublishedApi && + calledDescriptor.getVisibility() != Visibilities.LOCAL) { + context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor, descriptor)); } else { - checkPrivateClassMemberAccess(declarationDescriptor, expression, context); + checkPrivateClassMemberAccess(calledDescriptor, expression, context); } - if (isEffectivelyPublicOrPublishedApiFunction && declarationDescriptor.getVisibility() == Visibilities.PROTECTED) { - context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor)); + if (isInlineFunPublicOrPublishedApi && + inlineFunEffectiveVisibility.toVisibility() != Visibilities.PROTECTED && + calledFunEffectiveVisibility.toVisibility() == Visibilities.PROTECTED) { + context.getTrace().report(Errors.PROTECTED_CALL_FROM_PUBLIC_INLINE.on(expression, calledDescriptor)); } } - private static boolean isEffectivelyPublicOrPublishedApi(@NotNull CallableDescriptor descriptor) { - EffectiveVisibility visibility = EffectiveVisibilityKt.effectiveVisibility(descriptor, descriptor.getVisibility(), true); - return visibility.getPublicApi(); - } - private void checkPrivateClassMemberAccess( @NotNull DeclarationDescriptor declarationDescriptor, @NotNull KtElement expression, diff --git a/compiler/testData/diagnostics/tests/inline/protectedDepecation.kt b/compiler/testData/diagnostics/tests/inline/protectedDepecation.kt index 8c9f031ffc2..36e6ffd21d9 100644 --- a/compiler/testData/diagnostics/tests/inline/protectedDepecation.kt +++ b/compiler/testData/diagnostics/tests/inline/protectedDepecation.kt @@ -1,5 +1,13 @@ // !DIAGNOSTICS: -EXPOSED_PARAMETER_TYPE -NOTHING_TO_INLINE +// FILE: JavaClass.java + + +public abstract class JavaClass { + protected void bind() {} +} + +// FILE: main.kt open class A { protected fun test() {} @@ -28,6 +36,13 @@ open class A { zVar zVar = "123" } + + protected inline fun callFromProtected() { + test() + zVar + zVar = "123" + } + } class B : A() { @@ -36,6 +51,25 @@ class B : A() { } } +class C : JavaClass() { + inline fun call() { + bind() + } + + internal inline fun callFromInternal() { + bind() + } + + protected inline fun callFromProtected() { + bind() + } + + @PublishedApi + internal inline fun callFromPublished() { + bind() + } +} + internal class AInternal { protected fun test() {} @@ -54,4 +88,14 @@ internal class AInternal { internal inline fun call2() { test() } +} + +private class X { + + public class Z : A() { + public inline fun effictivelyNonPublic() { + test() + } + } + } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/protectedDepecation.txt b/compiler/testData/diagnostics/tests/inline/protectedDepecation.txt index 8a3b53cf962..ad8c5f09fd5 100644 --- a/compiler/testData/diagnostics/tests/inline/protectedDepecation.txt +++ b/compiler/testData/diagnostics/tests/inline/protectedDepecation.txt @@ -6,6 +6,7 @@ public open class A { public final var zVar: kotlin.String public final inline fun call(): kotlin.Unit internal final inline fun callFromInternal(): kotlin.Unit + protected final inline fun callFromProtected(): kotlin.Unit @kotlin.PublishedApi internal final inline fun callFromPublished(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -31,6 +32,7 @@ public final class B : A { public final override /*1*/ /*fake_override*/ var zVar: kotlin.String public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit internal final inline override /*1*/ /*fake_override*/ fun callFromInternal(): kotlin.Unit + protected final inline override /*1*/ /*fake_override*/ fun callFromProtected(): kotlin.Unit @kotlin.PublishedApi internal final inline override /*1*/ /*fake_override*/ fun callFromPublished(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -38,3 +40,45 @@ public final class B : A { public final inline fun testB(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + +public final class C : JavaClass { + public constructor C() + protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun bind(): kotlin.Unit + public final inline fun call(): kotlin.Unit + internal final inline fun callFromInternal(): kotlin.Unit + protected final inline fun callFromProtected(): kotlin.Unit + @kotlin.PublishedApi internal final inline fun callFromPublished(): kotlin.Unit + 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 abstract class JavaClass { + public constructor JavaClass() + protected/*protected and package*/ open fun bind(): kotlin.Unit + 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 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 + + public final class Z : A { + public constructor Z() + protected final override /*1*/ /*fake_override*/ val z: kotlin.String + public final override /*1*/ /*fake_override*/ var zVar: kotlin.String + public final inline override /*1*/ /*fake_override*/ fun call(): kotlin.Unit + internal final inline override /*1*/ /*fake_override*/ fun callFromInternal(): kotlin.Unit + protected final inline override /*1*/ /*fake_override*/ fun callFromProtected(): kotlin.Unit + @kotlin.PublishedApi internal final inline override /*1*/ /*fake_override*/ fun callFromPublished(): kotlin.Unit + public final inline fun effictivelyNonPublic(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + protected final override /*1*/ /*fake_override*/ fun test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/kt7971.kt b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/kt7971.kt index 3025b9081f9..96ca9e92256 100644 --- a/compiler/testData/diagnostics/tests/scopes/protectedVisibility/kt7971.kt +++ b/compiler/testData/diagnostics/tests/scopes/protectedVisibility/kt7971.kt @@ -15,7 +15,7 @@ fun javaClass(): Class = null!! public class AppServiceModule : AbstractModule() { inline fun AbstractModule.bind() { - val x = bind(javaClass()) + val x = bind(javaClass()) x checkType { _() } // check that Class receiver is used instead of extension one }