diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java index f2d74a1f204..74710a50d2e 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java @@ -52,7 +52,6 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments { public String moduleName; // Advanced options - @Argument(value = "Xno-call-assertions", description = "Don't generate not-null assertion after each invocation of method returning not-null") public boolean noCallAssertions; @@ -65,6 +64,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments { @Argument(value = "Xreport-perf", description = "Report detailed performance statistics") public boolean reportPerf; + // Paths to output directories for friend modules. + public String[] friendPaths; + @Override @NotNull public String executableScriptFileName() { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/moduleVisibilityImpl.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/moduleVisibilityImpl.kt index aac73f1e149..2000ecc8421 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/moduleVisibilityImpl.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/moduleVisibilityImpl.kt @@ -47,7 +47,12 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper { val whatSource = getSourceElement(what) if (whatSource is KotlinSourceElement) return true - val modules = moduleVisibilityManager.chunk.toList() + moduleVisibilityManager.friendPaths.forEach { + if (isContainedByCompiledPartOfOurModule(what, File(it))) return true + } + + val modules = moduleVisibilityManager.chunk + val outputDirectories = modules.map { File(it.getOutputDirectory()) } if (outputDirectories.isEmpty()) return isContainedByCompiledPartOfOurModule(what, null) @@ -56,7 +61,7 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper { } // Hack in order to allow access to internal elements in production code from tests - if (modules.size() == 1 && modules[0].getModuleType() == ModuleXmlParser.TYPE_TEST) return true + if (modules.singleOrNull()?.getModuleType() == ModuleXmlParser.TYPE_TEST) return true return false } @@ -68,11 +73,16 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper { */ class CliModuleVisibilityManagerImpl() : ModuleVisibilityManager, Disposable { override val chunk: MutableList = arrayListOf() + override val friendPaths: MutableList = arrayListOf() override fun addModule(module: Module) { chunk.add(module) } + override fun addFriendPath(path: String) { + friendPaths.add(path) + } + override fun dispose() { chunk.clear() } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 43b8daa0486..f44d08184d9 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -21,9 +21,7 @@ import com.intellij.openapi.Disposable import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.ExitCode -import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR -import org.jetbrains.kotlin.cli.common.ExitCode.INTERNAL_ERROR -import org.jetbrains.kotlin.cli.common.ExitCode.OK +import org.jetbrains.kotlin.cli.common.ExitCode.* import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.jvm.compiler.* @@ -154,6 +152,8 @@ public open class K2JVMCompiler : CLICompiler() { } val environment: KotlinCoreEnvironment + val friendPaths = arguments.friendPaths?.toList() ?: emptyList() + if (arguments.module != null) { val sanitizedCollector = FilteringMessageCollector(messageSeverityCollector, `in`(CompilerMessageSeverity.VERBOSE)) val moduleScript = CompileEnvironmentUtil.loadModuleDescriptions(arguments.module, sanitizedCollector) @@ -169,7 +169,7 @@ public open class K2JVMCompiler : CLICompiler() { if (messageSeverityCollector.anyReported(CompilerMessageSeverity.ERROR)) return COMPILATION_ERROR - KotlinToJVMBytecodeCompiler.compileModules(environment, configuration, moduleScript.getModules(), directory, jar, arguments.includeRuntime) + KotlinToJVMBytecodeCompiler.compileModules(environment, configuration, moduleScript.getModules(), directory, jar, friendPaths, arguments.includeRuntime) } else if (arguments.script) { val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size()) @@ -189,7 +189,7 @@ public open class K2JVMCompiler : CLICompiler() { return COMPILATION_ERROR } - KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime) + KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, friendPaths, arguments.includeRuntime) } if (arguments.reportPerf) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 8e495f0145a..173c2b98bcb 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -114,14 +114,21 @@ public class KotlinToJVMBytecodeCompiler { @NotNull List chunk, @NotNull File directory, @Nullable File jarPath, + @NotNull List friendPaths, boolean jarRuntime ) { Map outputFiles = Maps.newHashMap(); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); + ModuleVisibilityManager moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.getProject()); + for (Module module: chunk) { - ModuleVisibilityManager.SERVICE.getInstance(environment.getProject()).addModule(module); + moduleVisibilityManager.addModule(module); + } + + for (String path : friendPaths) { + moduleVisibilityManager.addFriendPath(path); } String targetDescription = "in targets [" + Joiner.on(", ").join(Collections2.transform(chunk, new Function() { @@ -215,9 +222,16 @@ public class KotlinToJVMBytecodeCompiler { @NotNull KotlinCoreEnvironment environment, @Nullable File jar, @Nullable File outputDir, + @NotNull List friendPaths, boolean includeRuntime ) { + ModuleVisibilityManager moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.getProject()); + + for (String path : friendPaths) { + moduleVisibilityManager.addFriendPath(path); + } + GenerationState generationState = analyzeAndGenerate(environment); if (generationState == null) { return false; 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 b87b87f250a..7aa10a4c78a 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 @@ -29,7 +29,9 @@ import java.io.File interface ModuleVisibilityManager { val chunk: Collection + val friendPaths: Collection fun addModule(module: Module) + fun addFriendPath(path: String) public object SERVICE { @JvmStatic diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/IdeModuleVisibilityManagerImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/IdeModuleVisibilityManagerImpl.kt index 861fb90e3a1..144d028dadc 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/IdeModuleVisibilityManagerImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/IdeModuleVisibilityManagerImpl.kt @@ -21,5 +21,7 @@ import org.jetbrains.kotlin.modules.Module class IdeModuleVisibilityManagerImpl() : ModuleVisibilityManager { override val chunk: Collection = emptyList() + override val friendPaths: Collection = emptyList() override fun addModule(module: Module) {} + override fun addFriendPath(path: String) {} } diff --git a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index f464e2d86cb..ae8f98c9247 100644 --- a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -134,6 +134,21 @@ public open class KotlinCompile() : AbstractKotlinCompile("defaultModuleName") + + if (this.name == "compileTestKotlin") { + getLogger().kotlinDebug("try to determine the output directory of corresponding compileKotlin task") + val tasks = project.getTasksByName("compileKotlin", false) + getLogger().kotlinDebug("tasks for compileKotlin: ${tasks}") + if (tasks.size == 1) { + val task = tasks.firstOrNull() as? KotlinCompile + if (task != null) { + getLogger().kotlinDebug("destinantion directory for production = ${task.destinationDir}") + args.friendPaths = arrayOf(task.destinationDir.absolutePath) + args.moduleName = task.kotlinOptions.moduleName ?: task.extensions.extraProperties.getOrNull("defaultModuleName") + } + } + } + getLogger().kotlinDebug("args.moduleName = ${args.moduleName}") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt index 7db4c7b0562..e8416ca6ac4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt @@ -90,6 +90,15 @@ class KotlinGradleIT: BaseGradleIT() { } } + @Test + fun testInternalTest() { + Project("internalTest", "1.6").build("build") { + assertSuccessful() + assertReportExists() + assertContains(":compileKotlin", ":compileTestKotlin") + } + } + @Test fun testMultiprojectPluginClasspath() { Project("multiprojectClassPathTest", "1.6").build("build") { diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/build.gradle b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/build.gradle new file mode 100644 index 00000000000..9d3bc30c7f9 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/build.gradle @@ -0,0 +1,34 @@ +buildscript { + repositories { + mavenCentral() + maven { + url 'file://' + pathToKotlinPlugin + } + } + dependencies { + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.1-SNAPSHOT' + } +} + +apply plugin: "kotlin" + + +repositories { + maven { + url 'file://' + pathToKotlinPlugin + } + mavenCentral() +} + +dependencies { + testCompile 'org.testng:testng:6.8' + compile 'org.jetbrains.kotlin:kotlin-stdlib:0.1-SNAPSHOT' +} + +test { + useTestNG() +} + +task wrapper(type: Wrapper) { + gradleVersion="1.4" +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/main/kotlin/helloWorld.kt b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/main/kotlin/helloWorld.kt new file mode 100644 index 00000000000..5ef0d729fd2 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/main/kotlin/helloWorld.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2015 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 demo + +internal val CONST = "CONST" + +class PublicClass { + internal fun foo(): String = "foo" + internal val bar: String = "bar" +} + +internal data class InternalDataClass(val x: Int, val y: Int) + +internal fun box(): String { + return "OK" +} + + + + diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/test/kotlin/tests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/test/kotlin/tests.kt new file mode 100644 index 00000000000..181586b502a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/internalTest/src/test/kotlin/tests.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2015 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 demo + +import org.testng.Assert.* +import org.testng.annotations.Test as test + +class TestSource() { + @test fun f() { + assertEquals("CONST", CONST) + + assertEquals("foo", PublicClass().foo()) + assertEquals("bar", PublicClass().bar) + + val data = InternalDataClass(10, 20) + assertEquals(10, data.x) + assertEquals(20, data.y) + + assertEquals(box(), "OK") + } +} + diff --git a/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/pom.xml b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/pom.xml new file mode 100644 index 00000000000..d9cbb514093 --- /dev/null +++ b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + + org.jetbrains.kotlin + kotlin-project + 0.1-SNAPSHOT + ../../pom.xml + + + test-accessToInternal + + + + junit + junit + 4.9 + + + org.jetbrains.kotlin + kotlin-runtime + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + + + ${project.basedir}/src/main/kotlin + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${project.version} + + + compile + process-sources + + compile + + + + test-compile + process-test-sources + + test-compile + + + + + + + + \ No newline at end of file diff --git a/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/main/kotlin/org/jetbrains/HelloWorld.kt b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/main/kotlin/org/jetbrains/HelloWorld.kt new file mode 100644 index 00000000000..9e2e4121450 --- /dev/null +++ b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/main/kotlin/org/jetbrains/HelloWorld.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2015 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 + +fun main(args : Array) { + System.out?.println(getGreeting()) +} + +internal fun getGreeting() : String { + return "Hello, World!" +} + +internal val CONST = "CONST" + +class PublicClass { + internal fun foo(): String = "foo" + internal val bar: String = "bar" +} + +internal data class InternalDataClass(val x: Int, val y: Int) + diff --git a/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/test/java/org/jetbrains/HelloWorldTest.kt b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/test/java/org/jetbrains/HelloWorldTest.kt new file mode 100644 index 00000000000..ca4a2fd1807 --- /dev/null +++ b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/src/test/java/org/jetbrains/HelloWorldTest.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2015 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 + +import org.junit.Test + +import junit.framework.Assert.assertEquals + +class HelloWorldTest { + + @Test + fun greeting() { + assertEquals("Hello, World!", getGreeting()) + } + + @Test + fun accessToInternal() { + assertEquals("CONST", CONST) + + assertEquals("foo", PublicClass().foo()) + assertEquals("bar", PublicClass().bar) + + val data = InternalDataClass(10, 20) + assertEquals(10, data.x) + assertEquals(20, data.y) + } +} diff --git a/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/verify.bsh b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/verify.bsh new file mode 100644 index 00000000000..038f618025f --- /dev/null +++ b/libraries/tools/kotlin-maven-plugin-test/src/it/test-accessToInternal/verify.bsh @@ -0,0 +1,6 @@ +import java.io.*; + +File file = new File(basedir, "target/test-accessToInternal-0.1-SNAPSHOT.jar"); +if (!file.exists() || !file.isFile()) { + throw new FileNotFoundException("Could not find generated JAR: " + file); +} diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java index fb63feb09c2..0dae790d532 100644 --- a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java +++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/KotlinTestCompileMojo.java @@ -24,7 +24,6 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; -import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler; import java.util.List; @@ -86,9 +85,8 @@ public class KotlinTestCompileMojo extends K2JVMCompileMojo { protected void configureSpecificCompilerArguments(@NotNull K2JVMCompilerArguments arguments) throws MojoExecutionException { module = testModule; classpath = testClasspath; + arguments.friendPaths = new String[] { output }; output = testOutput; - moduleName = testModuleName; - super.configureSpecificCompilerArguments(arguments); } }