diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/moduleVisibilityUtils.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/moduleVisibilityUtils.kt index fde0786082d..1d953dd44ed 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/moduleVisibilityUtils.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/moduleVisibilityUtils.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeAliasDescriptor import java.io.File +import java.nio.file.Paths interface ModuleVisibilityManager { val chunk: Collection @@ -66,10 +67,12 @@ fun isContainedByCompiledPartOfOurModule(descriptor: DeclarationDescriptor, outD if (binaryClass is VirtualFileKotlinClass) { val file = binaryClass.file - if (file.fileSystem.protocol == StandardFileSystems.FILE_PROTOCOL) { - val ioFile = VfsUtilCore.virtualToIoFile(file) - return ioFile.absolutePath.startsWith(outDirectory.absolutePath + File.separator) + val ioFile = when (file.fileSystem.protocol) { + StandardFileSystems.FILE_PROTOCOL -> VfsUtilCore.virtualToIoFile(file) + StandardFileSystems.JAR_PROTOCOL -> VfsUtilCore.getVirtualFileForJar(file)?.let(VfsUtilCore::virtualToIoFile) + else -> null } + return ioFile != null && Paths.get(ioFile.toURI()).startsWith(Paths.get(outDirectory.toURI())) } return false diff --git a/compiler/testData/friendPaths/lib.kt b/compiler/testData/friendPaths/lib.kt new file mode 100644 index 00000000000..6ea78c185ff --- /dev/null +++ b/compiler/testData/friendPaths/lib.kt @@ -0,0 +1,10 @@ +package lib + +fun publicFun() {} +internal fun internalFun() {} + +val publicVal = "" +internal val internalVal = "" + +class PublicClass +internal class InternalClass diff --git a/compiler/testData/friendPaths/usage.kt b/compiler/testData/friendPaths/usage.kt new file mode 100644 index 00000000000..d6775cef658 --- /dev/null +++ b/compiler/testData/friendPaths/usage.kt @@ -0,0 +1,10 @@ +import lib.* + +fun usage() { + publicFun() + internalFun() + publicVal + internalVal + PublicClass() + InternalClass() +} diff --git a/compiler/tests/org/jetbrains/kotlin/cli/FriendPathsTest.kt b/compiler/tests/org/jetbrains/kotlin/cli/FriendPathsTest.kt new file mode 100644 index 00000000000..4f501b55bd4 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/cli/FriendPathsTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli + +import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.config.Services +import org.jetbrains.kotlin.test.TestCaseWithTmpdir +import org.junit.Assert +import java.io.File + +/** + * This test checks that [org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments.friendPaths] works by invoking the compiler's + * "exec" method directly. Once there's a CLI argument for friend paths, it can be simplified to use that CLI argument instead. + */ +class FriendPathsTest : TestCaseWithTmpdir() { + private fun getTestDataDirectory(): File = File("compiler/testData/friendPaths/") + + fun testArchive() { + val libSrc = File(getTestDataDirectory(), "lib.kt") + val libDest = File(tmpdir, "lib.jar") + val (output, libExitCode) = AbstractCliTest.executeCompilerGrabOutput(K2JVMCompiler(), listOf("-d", libDest.path, libSrc.path)) + Assert.assertEquals(output, ExitCode.OK, libExitCode) + + Assert.assertEquals(ExitCode.OK, invokeCompiler(libDest.path)) + } + + fun testDirectory() { + val libSrc = File(getTestDataDirectory(), "lib.kt") + val libDest = File(tmpdir, "lib") + val (output, libExitCode) = AbstractCliTest.executeCompilerGrabOutput(K2JVMCompiler(), listOf("-d", libDest.path, libSrc.path)) + Assert.assertEquals(output, ExitCode.OK, libExitCode) + + Assert.assertEquals(ExitCode.OK, invokeCompiler(libDest.path)) + } + + private fun invokeCompiler(libraryPath: String): ExitCode { + return K2JVMCompiler().exec(ThrowingMessageCollector(), Services.EMPTY, K2JVMCompilerArguments().apply { + destination = tmpdir.path + classpath = libraryPath + freeArgs = listOf(File(getTestDataDirectory(), "usage.kt").path) + + friendPaths = arrayOf(libraryPath) + }) + } + + private class ThrowingMessageCollector : MessageCollector { + override fun clear() {} + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) { + if (severity.isError) { + Assert.fail("${severity.presentableName}: $message at $location") + } + } + + override fun hasErrors(): Boolean = false + } +}