diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java index 1895a74ccd0..9d30f2a8a5b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java @@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; @@ -42,10 +43,13 @@ public class InlineCallResolverExtension implements CallResolverExtension { private Set inlinableParameters = new HashSet(); + private final boolean isEffectivelyPublicApiFunction; + public InlineCallResolverExtension(@NotNull SimpleFunctionDescriptor descriptor) { assert descriptor.isInline() : "This extension should be created only for inline functions but not " + descriptor; - this.descriptor = descriptor; + this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor); + Iterator iterator = descriptor.getValueParameters().iterator(); while (iterator.hasNext()) { ValueParameterDescriptor next = iterator.next(); @@ -102,9 +106,10 @@ public class InlineCallResolverExtension implements CallResolverExtension { checkFunctionCall(context, targetDescriptor, jetExpression); } } - //TODO default and vararg } + + checkVisibility(targetDescriptor, expression, context); } private void checkCallWithReceiver( @@ -179,11 +184,20 @@ public class InlineCallResolverExtension implements CallResolverExtension { ((SimpleFunctionDescriptor) descriptor).isInline(); } - private void checkVisibility(){ - + private void checkVisibility(@NotNull CallableDescriptor declarationDescriptor, @NotNull JetElement expression, @NotNull BasicCallResolutionContext context){ + if (isEffectivelyPublicApiFunction && !isEffectivelyPublicApi(declarationDescriptor) && declarationDescriptor.getVisibility() != Visibilities.LOCAL) { + context.trace.report(Errors.INVISIBLE_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor)); + } } - interface FunctionParameter { - + private static boolean isEffectivelyPublicApi(DeclarationDescriptorWithVisibility descriptor) { + DeclarationDescriptorWithVisibility parent = descriptor; + while (parent != null) { + if (!parent.getVisibility().isPublicAPI()) { + return false; + } + parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class); + } + return true; } } diff --git a/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicClass.kt b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicClass.kt new file mode 100644 index 00000000000..d6684483699 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicClass.kt @@ -0,0 +1,47 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE +private class Z public (){ + public val publicProperty:Int = 12 + public fun publicFun() {} +} + +public inline fun test() { + Z().publicProperty + Z().publicFun() +} + +inline fun testInternal() { + Z().publicProperty + Z().publicFun() +} + +private class Z2 { + private val privateProperty = 11; + + public val publicProperty:Int = 12 + + private fun privateFun() {} + + public fun publicFun() {} + + public inline fun test() { + privateProperty + privateFun() + publicProperty + publicFun() + Z2().publicProperty + Z2().publicFun() + Z2().privateProperty + Z2().privateFun() + } + + inline fun testInternal() { + privateProperty + privateFun() + publicProperty + publicFun() + Z2().publicProperty + Z2().publicFun() + Z2().privateProperty + Z2().privateFun() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicInnerClass.kt b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicInnerClass.kt new file mode 100644 index 00000000000..31c1667d985 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicInnerClass.kt @@ -0,0 +1,36 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE +private class Z2 { + private val privateProperty = 11; + + public val publicProperty:Int = 12 + + private fun privateFun() {} + + public fun publicFun() {} + + private inner class ZInner { + public inline fun test() { + privateProperty + privateFun() + publicFun() + publicProperty + + Z2().publicProperty + Z2().publicFun() + Z2().privateProperty + Z2().privateFun() + } + + inline fun testInternal() { + privateProperty + privateFun() + publicFun() + publicProperty + + Z2().publicProperty + Z2().publicFun() + Z2().privateProperty + Z2().privateFun() + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPackage.kt b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPackage.kt new file mode 100644 index 00000000000..dae313f5c1a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPackage.kt @@ -0,0 +1,27 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +private val privateProperty = 11; +private fun privateFun() {} + +val internalProperty = 11; +fun internalFun() {} + +public inline fun test() { + privateFun() + privateProperty +} + +public inline fun test2() { + internalFun() + internalProperty +} + +inline fun testInternal() { + privateFun() + privateProperty +} + +inline fun test2Internal() { + internalFun() + internalProperty +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPublicClass.kt b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPublicClass.kt new file mode 100644 index 00000000000..0b1932fc6a9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nonPublicMember/inPublicClass.kt @@ -0,0 +1,37 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE +public class Z { + val privateProperty = 11; + + fun privateFun() { + + } +} + +public inline fun test() { + Z().privateProperty + Z().privateFun() +} + +inline fun testInternal() { + Z().privateProperty + Z().privateFun() +} + + +public class Z2 { + private val privateProperty = 11; + + private fun privateFun() { + + } + + public inline fun test() { + privateProperty + privateFun() + } + + inline fun testInternal() { + privateProperty + privateFun() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/nonPublicMember/localClass.kt b/compiler/testData/diagnostics/tests/inline/nonPublicMember/localClass.kt new file mode 100644 index 00000000000..bb947595277 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nonPublicMember/localClass.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -NOTHING_TO_INLINE + +public class Z { + private val privateProperty = 11; + + public fun privateFun() { + + class Local { + public inline fun a() { + privateProperty + } + } + + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 2cf65bf7d8a..ee7f3801aa5 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3751,6 +3751,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @TestMetadata("compiler/testData/diagnostics/tests/inline") + @InnerTestClasses({Inline.NonPublicMember.class}) public static class Inline extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInInline() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inline"), Pattern.compile("^(.+)\\.kt$"), true); @@ -3806,6 +3807,45 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/inline/wrongUsage2.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/inline/nonPublicMember") + public static class NonPublicMember extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInNonPublicMember() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inline/nonPublicMember"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("inNonPublicClass.kt") + public void testInNonPublicClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicClass.kt"); + } + + @TestMetadata("inNonPublicInnerClass.kt") + public void testInNonPublicInnerClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nonPublicMember/inNonPublicInnerClass.kt"); + } + + @TestMetadata("inPackage.kt") + public void testInPackage() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nonPublicMember/inPackage.kt"); + } + + @TestMetadata("inPublicClass.kt") + public void testInPublicClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nonPublicMember/inPublicClass.kt"); + } + + @TestMetadata("localClass.kt") + public void testLocalClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nonPublicMember/localClass.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("Inline"); + suite.addTestSuite(Inline.class); + suite.addTestSuite(NonPublicMember.class); + return suite; + } } @TestMetadata("compiler/testData/diagnostics/tests/inner") @@ -6313,7 +6353,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTest(IncompleteCode.innerSuite()); suite.addTest(Inference.innerSuite()); suite.addTestSuite(Infos.class); - suite.addTestSuite(Inline.class); + suite.addTest(Inline.innerSuite()); suite.addTest(Inner.innerSuite()); suite.addTestSuite(J_k.class); suite.addTest(Jdk_annotations.innerSuite());