From 4f0f81155a69beaeb3ec51bfe9dfb44d9fd55bfd Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Thu, 11 Feb 2016 17:41:03 +0300 Subject: [PATCH] Weaken PRIVATE_CLASS_MEMBER_FROM_INLINE diagnostic --- .../resolve/calls/checkers/InlineChecker.java | 5 +++-- .../boxInline/private/effectivePrivate.1.kt | 5 +++++ .../boxInline/private/effectivePrivate.2.kt | 21 +++++++++++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 6 ++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 6 ++++++ .../kotlin/resolve/DescriptorUtils.kt | 14 +++++++++++++ .../kotlin/generators/tests/GenerateTests.kt | 2 +- 7 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt create mode 100644 compiler/testData/codegen/boxInline/private/effectivePrivate.2.kt 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 2815c3000cf..d92ae2ee73b 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 @@ -52,12 +52,13 @@ class InlineChecker implements CallChecker { private final SimpleFunctionDescriptor descriptor; private final Set inlinableParameters = new LinkedHashSet(); private final boolean isEffectivelyPublicApiFunction; + private final boolean isEffectivelyPrivateApiFunction; public InlineChecker(@NotNull SimpleFunctionDescriptor descriptor) { assert InlineUtil.isInline(descriptor) : "This extension should be created only for inline functions: " + descriptor; this.descriptor = descriptor; this.isEffectivelyPublicApiFunction = DescriptorUtilsKt.isEffectivelyPublicApi(descriptor); - + this.isEffectivelyPrivateApiFunction = DescriptorUtilsKt.isEffectivelyPrivateApi(descriptor); for (ValueParameterDescriptor param : descriptor.getValueParameters()) { if (isInlinableParameter(param)) { inlinableParameters.add(param); @@ -253,7 +254,7 @@ class InlineChecker implements CallChecker { @NotNull KtElement expression, @NotNull BasicCallResolutionContext context ) { - if (!Visibilities.isPrivate(descriptor.getVisibility())) { + if (!isEffectivelyPrivateApiFunction) { if (DescriptorUtilsKt.isInsidePrivateClass(declarationDescriptor)) { context.trace.report(Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor)); } diff --git a/compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt b/compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt new file mode 100644 index 00000000000..548a14e01c6 --- /dev/null +++ b/compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt @@ -0,0 +1,5 @@ +import test.* + +fun box() : String { + return Test().run() +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/private/effectivePrivate.2.kt b/compiler/testData/codegen/boxInline/private/effectivePrivate.2.kt new file mode 100644 index 00000000000..57c676fff88 --- /dev/null +++ b/compiler/testData/codegen/boxInline/private/effectivePrivate.2.kt @@ -0,0 +1,21 @@ +package test + +class Test { + private abstract class Base { + protected fun duplicate(s: String) = s + "K" + + protected inline fun doInline(block: () -> String): String { + return duplicate(block()) + } + } + + private class Extender: Base() { + fun doSomething(): String { + return doInline { "O" } + } + } + + fun run(): String { + return Extender().doSomething(); + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 00e260d9908..7f900951170 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -1381,6 +1381,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/private"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("effectivePrivate.1.kt") + public void testEffectivePrivate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("kt6453.1.kt") public void testKt6453() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/private/kt6453.1.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 290b87587c7..241ef709295 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1381,6 +1381,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/private"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("effectivePrivate.1.kt") + public void testEffectivePrivate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/private/effectivePrivate.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("kt6453.1.kt") public void testKt6453() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/private/kt6453.1.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 2ea15247fec..c750726bc5f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -106,6 +106,20 @@ val DeclarationDescriptorWithVisibility.isEffectivelyPublicApi: Boolean return true } +val DeclarationDescriptorWithVisibility.isEffectivelyPrivateApi: Boolean + get() { + var parent: DeclarationDescriptorWithVisibility? = this + + while (parent != null) { + if (Visibilities.isPrivate(parent.visibility)) return true + + parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility::class.java) + } + + return false + } + + val DeclarationDescriptor.isInsidePrivateClass: Boolean get() { var parent = containingDeclaration as? ClassDescriptor diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index bde4f1e5932..48d301ea53c 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -1066,7 +1066,7 @@ fun main(args: Array) { } } -internal class TestGroup(val testsRoot: String, val testDataRoot: String) { +private class TestGroup(val testsRoot: String, val testDataRoot: String) { inline fun testClass( suiteTestClass: String = getDefaultSuiteTestClass(T::class.java), noinline init: TestClass.() -> Unit