Implement Java 9 module visibility checks
In this commit, only IDE tests are added, because we look for module declarations in the IDE across the whole project, whereas in the compiler we should do this on the module path only and that requires separate work (KT-18599) which is done in the following commits. (The change in Cache.kt is needed so that JvmModuleAccessibilityChecker.ClassifierUsage, which is an inner class, would be injected properly.) #KT-18598 In Progress #KT-18599 In Progress
This commit is contained in:
@@ -44,9 +44,11 @@ internal class ClasspathRootsResolver(
|
||||
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?
|
||||
) {
|
||||
private val javaModuleFinder = CliJavaModuleFinder(VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL))
|
||||
private val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||
|
||||
fun convertClasspathRoots(contentRoots: Iterable<ContentRoot>): List<JavaRoot> {
|
||||
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
||||
|
||||
fun convertClasspathRoots(contentRoots: Iterable<ContentRoot>): RootsAndModules {
|
||||
val result = mutableListOf<JavaRoot>()
|
||||
|
||||
val modules = ArrayList<JavaModule>()
|
||||
@@ -79,7 +81,7 @@ internal class ClasspathRootsResolver(
|
||||
|
||||
addModularRoots(modules, result)
|
||||
|
||||
return result
|
||||
return RootsAndModules(result, modules)
|
||||
}
|
||||
|
||||
private fun modularSourceRoot(root: VirtualFile): JavaModule.Explicit? {
|
||||
|
||||
@@ -78,6 +78,7 @@ import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
|
||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||
import org.jetbrains.kotlin.cli.jvm.index.*
|
||||
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
@@ -98,6 +99,7 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
@@ -194,7 +196,9 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
classpathRootsResolver = ClasspathRootsResolver(PsiManager.getInstance(project), messageCollector, this::contentRootToVirtualFile)
|
||||
|
||||
initialRoots = classpathRootsResolver.convertClasspathRoots(configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS))
|
||||
val (initialRoots, javaModules) =
|
||||
classpathRootsResolver.convertClasspathRoots(configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS))
|
||||
this.initialRoots = initialRoots
|
||||
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
|
||||
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
|
||||
@@ -219,6 +223,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
configuration.getBoolean(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING)
|
||||
)
|
||||
|
||||
project.registerService(
|
||||
JavaModuleResolver::class.java,
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules)
|
||||
)
|
||||
|
||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
||||
project.registerService(MetadataFinderFactory::class.java, finderFactory)
|
||||
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
||||
@@ -277,8 +286,9 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun updateClasspath(contentRoots: List<ContentRoot>): List<File>? {
|
||||
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots)
|
||||
fun updateClasspath(contentRoots: List<ContentRoot>): List<File>? {
|
||||
// TODO: add new Java modules to CliJavaModuleResolver
|
||||
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
|
||||
|
||||
for (packagePartProvider in packagePartProviders) {
|
||||
packagePartProvider.addRoots(newRoots)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.jvm.modules
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleGraph
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
|
||||
class CliJavaModuleResolver(
|
||||
override val moduleGraph: JavaModuleGraph,
|
||||
private val javaModules: List<JavaModule>
|
||||
) : JavaModuleResolver {
|
||||
override fun findJavaModule(file: VirtualFile): JavaModule? {
|
||||
val isBinary = file.fileType == JavaClassFileType.INSTANCE
|
||||
return javaModules.firstOrNull { module ->
|
||||
module.isBinary == isBinary && VfsUtilCore.isAncestor(module.moduleRoot, file, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,7 @@ package org.jetbrains.kotlin.container
|
||||
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import java.lang.reflect.*
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedHashSet
|
||||
import java.util.*
|
||||
|
||||
private object ClassTraversalCache {
|
||||
private val cache = ContainerUtil.createConcurrentWeakKeySoftValueMap<Class<*>, ClassInfo>()
|
||||
@@ -82,7 +81,11 @@ private fun getConstructorInfo(c: Class<*>): ConstructorInfo? {
|
||||
return null
|
||||
|
||||
val constructor = constructors.single()
|
||||
return ConstructorInfo(constructor, constructor.genericParameterTypes.toList())
|
||||
val parameterTypes =
|
||||
if (c.declaringClass != null && !Modifier.isStatic(c.modifiers))
|
||||
listOf(c.declaringClass, *constructor.genericParameterTypes)
|
||||
else constructor.genericParameterTypes.toList()
|
||||
return ConstructorInfo(constructor, parameterTypes)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.resolve.jvm.checkers
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
|
||||
class JvmModuleAccessibilityChecker(project: Project) : CallChecker {
|
||||
private val moduleResolver = JavaModuleResolver.getInstance(project)
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.resultingDescriptor
|
||||
|
||||
// javac seems to check only the containing class of the member being called. Note that it's fine to call, for example,
|
||||
// members with parameter types or return type from an unexported package
|
||||
val targetDescriptor = DescriptorUtils.getParentOfType(descriptor, ClassOrPackageFragmentDescriptor::class.java) ?: return
|
||||
|
||||
val fileFromOurModule = DescriptorToSourceUtils.getContainingFile(context.scope.ownerDescriptor)?.virtualFile
|
||||
diagnosticFor(targetDescriptor, descriptor, fileFromOurModule, reportOn)?.let(context.trace::report)
|
||||
}
|
||||
|
||||
private fun diagnosticFor(
|
||||
targetClassOrPackage: ClassOrPackageFragmentDescriptor,
|
||||
originalDescriptor: DeclarationDescriptorWithSource?,
|
||||
fileFromOurModule: VirtualFile?,
|
||||
reportOn: PsiElement
|
||||
): Diagnostic? {
|
||||
val referencedFile = findVirtualFile(targetClassOrPackage, originalDescriptor) ?: return null
|
||||
|
||||
// TODO: do not resolve our JavaModule every time, invent a way to obtain it from ModuleDescriptor and do it once in constructor
|
||||
val ourModule = fileFromOurModule?.let(moduleResolver::findJavaModule)
|
||||
val theirModule = moduleResolver.findJavaModule(referencedFile)
|
||||
|
||||
// If we're both in the unnamed module, it's OK, no error should be reported
|
||||
if (ourModule == null && theirModule == null) return null
|
||||
|
||||
if (theirModule == null) {
|
||||
// We should probably prohibit this usage according to JPMS (named module cannot use types from unnamed module),
|
||||
// but we cannot be sure that a module without module-info.java is going to be actually used as an unnamed module.
|
||||
// It could also be an automatic module, in which case it would be read by every module.
|
||||
return null
|
||||
}
|
||||
|
||||
val containingPackage = DescriptorUtils.getParentOfType(targetClassOrPackage, PackageFragmentDescriptor::class.java, false)
|
||||
val fqName = containingPackage?.fqNameUnsafe?.toSafe() ?: return null
|
||||
if (theirModule.exports(fqName)) return null
|
||||
|
||||
if (ourModule != null) {
|
||||
if (ourModule.name == theirModule.name) return null
|
||||
|
||||
if (!moduleResolver.moduleGraph.reads(ourModule.name, theirModule.name)) {
|
||||
return ErrorsJvm.JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE.on(reportOn, theirModule.name)
|
||||
}
|
||||
|
||||
if (theirModule.exportsTo(fqName, ourModule.name)) return null
|
||||
}
|
||||
|
||||
return ErrorsJvm.JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE.on(reportOn, theirModule.name, fqName.asString())
|
||||
}
|
||||
|
||||
private fun findVirtualFile(
|
||||
descriptor: ClassOrPackageFragmentDescriptor,
|
||||
originalDescriptor: DeclarationDescriptorWithSource?
|
||||
): VirtualFile? {
|
||||
val source = descriptor.source
|
||||
when (source) {
|
||||
is KotlinJvmBinarySourceElement -> (source.binaryClass as? VirtualFileKotlinClass)?.file?.let { return it }
|
||||
is JavaSourceElement -> (source.javaElement as? VirtualFileBoundJavaClass)?.virtualFile?.let { return it }
|
||||
is KotlinJvmBinaryPackageSourceElement -> {
|
||||
if (originalDescriptor is DeserializedMemberDescriptor) {
|
||||
(source.getContainingBinaryClass(originalDescriptor) as? VirtualFileKotlinClass)?.file?.let { return it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source.getPsi()?.containingFile?.virtualFile?.let { return it }
|
||||
|
||||
return originalDescriptor?.source?.getPsi()?.containingFile?.virtualFile
|
||||
}
|
||||
|
||||
inner class ClassifierUsage : ClassifierUsageChecker {
|
||||
override fun check(
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
val targetClassOrPackage = when (targetDescriptor) {
|
||||
is ClassDescriptor -> targetDescriptor
|
||||
is TypeAliasDescriptor -> {
|
||||
DescriptorUtils.getParentOfType(targetDescriptor, ClassOrPackageFragmentDescriptor::class.java) ?: return
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
|
||||
diagnosticFor(targetClassOrPackage, targetDescriptor, element.containingFile.virtualFile, element)?.let(trace::report)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -112,7 +112,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET, "Calls to static methods in Java interfaces are deprecated in JVM target 1.6. Recompile with '-jvm-target 1.8'");
|
||||
|
||||
MAP.put(INLINE_FROM_HIGHER_PLATFORM, "Cannot inline bytecode built with {0} into bytecode that is being built with {1}. Please specify proper ''-jvm-target'' option", STRING, STRING);
|
||||
MAP.put(ErrorsJvm.OBSOLETE_SUSPEND_INLINE_FUNCTIONS_ABI, "Cannot inline suspend function built with compiler version less than 1.1.4/1.2-M1");
|
||||
MAP.put(OBSOLETE_SUSPEND_INLINE_FUNCTIONS_ABI, "Cannot inline suspend function built with compiler version less than 1.1.4/1.2-M1");
|
||||
|
||||
MAP.put(JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE, "Symbol is declared in module ''{0}'' which current module does not depend on", STRING);
|
||||
MAP.put(JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE, "Symbol is declared in module ''{0}'' which does not export package ''{1}''", STRING, STRING);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -95,6 +95,9 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory2<PsiElement, String, String> INLINE_FROM_HIGHER_PLATFORM = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> OBSOLETE_SUSPEND_INLINE_FUNCTIONS_ABI = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, String> JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
+27
@@ -29,6 +29,7 @@ class JavaModuleGraph(finder: JavaModuleFinder) {
|
||||
visited += "java.base"
|
||||
|
||||
fun dfs(moduleName: String) {
|
||||
// Automatic modules have no transitive exports, so we only consider explicit modules here
|
||||
val moduleInfo = (module(moduleName) as? JavaModule.Explicit)?.moduleInfo ?: return
|
||||
for ((dependencyModuleName, isTransitive) in moduleInfo.requires) {
|
||||
if (!visited.add(dependencyModuleName) && isTransitive) {
|
||||
@@ -40,4 +41,30 @@ class JavaModuleGraph(finder: JavaModuleFinder) {
|
||||
moduleNames.forEach(::dfs)
|
||||
return visited.toList()
|
||||
}
|
||||
|
||||
fun reads(moduleName: String, dependencyName: String): Boolean {
|
||||
if (moduleName == dependencyName || dependencyName == "java.base") return true
|
||||
|
||||
val visited = linkedSetOf<String>()
|
||||
|
||||
fun dfs(name: String): Boolean {
|
||||
if (!visited.add(name)) return false
|
||||
|
||||
val module = module(name)
|
||||
when (module) {
|
||||
is JavaModule.Automatic -> return true
|
||||
is JavaModule.Explicit -> {
|
||||
for ((dependencyModuleName, isTransitive) in module.moduleInfo.requires) {
|
||||
if (dependencyModuleName == dependencyName) return true
|
||||
if (isTransitive && dfs(dependencyName)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
null -> return false
|
||||
else -> error("Unsupported module type: $module")
|
||||
}
|
||||
}
|
||||
|
||||
return dfs(moduleName)
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.resolve.jvm.modules
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
|
||||
interface JavaModuleResolver {
|
||||
val moduleGraph: JavaModuleGraph
|
||||
|
||||
// For any .java, .kt or .class file in the project, returns the corresponding module or null if there's none
|
||||
fun findJavaModule(file: VirtualFile): JavaModule?
|
||||
|
||||
companion object SERVICE {
|
||||
fun getInstance(project: Project): JavaModuleResolver =
|
||||
ServiceManager.getService(project, JavaModuleResolver::class.java)
|
||||
}
|
||||
}
|
||||
+2
@@ -86,6 +86,8 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
container.useImpl<JavaSyntheticScopes>()
|
||||
container.useImpl<InterfaceDefaultMethodCallChecker>()
|
||||
container.useImpl<InlinePlatformCompatibilityChecker>()
|
||||
container.useImpl<JvmModuleAccessibilityChecker>()
|
||||
container.useImpl<JvmModuleAccessibilityChecker.ClassifierUsage>()
|
||||
container.useInstance(JvmTypeSpecificityComparator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ public class KotlinTestUtils {
|
||||
JvmContentRootsKt.addJvmClasspathRoots(configuration, PathUtil.getJdkClassesRootsFromJre(getJreHome(jdk6)));
|
||||
}
|
||||
else if (jdkKind == TestJdkKind.FULL_JDK_9) {
|
||||
File home = getJre9HomeIfPossible();
|
||||
File home = getJdk9HomeIfPossible();
|
||||
if (home != null) {
|
||||
configuration.put(JVMConfigurationKeys.JDK_HOME, home);
|
||||
}
|
||||
@@ -529,8 +529,11 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getJre9HomeIfPossible() {
|
||||
public static File getJdk9HomeIfPossible() {
|
||||
String jdk9 = System.getenv("JDK_19");
|
||||
if (jdk9 == null) {
|
||||
jdk9 = System.getenv("JDK_9");
|
||||
}
|
||||
if (jdk9 == null) {
|
||||
// TODO: replace this with a failure as soon as Java 9 is installed on all TeamCity agents
|
||||
System.err.println("Environment variable JDK_19 is not set, the test will be skipped");
|
||||
|
||||
@@ -46,11 +46,11 @@ object MockLibraryUtil {
|
||||
jarName: String,
|
||||
addSources: Boolean = false,
|
||||
extraOptions: List<String> = emptyList(),
|
||||
extraClasspath: List<String> = emptyList()
|
||||
extraClasspath: List<String> = emptyList(),
|
||||
useJava9: Boolean = false
|
||||
): File {
|
||||
return compileLibraryToJar(
|
||||
sourcesPath, KotlinTestUtils.tmpDir("testLibrary-" + jarName), jarName, addSources, extraOptions, extraClasspath
|
||||
)
|
||||
return compileLibraryToJar(sourcesPath, KotlinTestUtils.tmpDir("testLibrary-" + jarName), jarName, addSources,
|
||||
extraOptions, extraClasspath, useJava9)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -61,7 +61,8 @@ object MockLibraryUtil {
|
||||
jarName: String,
|
||||
addSources: Boolean = false,
|
||||
extraOptions: List<String> = emptyList(),
|
||||
extraClasspath: List<String> = emptyList()
|
||||
extraClasspath: List<String> = emptyList(),
|
||||
useJava9: Boolean = false
|
||||
): File {
|
||||
val classesDir = File(contentDir, "classes")
|
||||
|
||||
@@ -91,7 +92,14 @@ object MockLibraryUtil {
|
||||
"-d", classesDir.path
|
||||
)
|
||||
|
||||
KotlinTestUtils.compileJavaFiles(javaFiles, options)
|
||||
val compile =
|
||||
if (useJava9) KotlinTestUtils::compileJavaFilesExternallyWithJava9
|
||||
else KotlinTestUtils::compileJavaFiles
|
||||
|
||||
val success = compile(javaFiles, options)
|
||||
if (!success) {
|
||||
throw AssertionError("Java files are not compiled successfully")
|
||||
}
|
||||
}
|
||||
|
||||
return createJarFile(contentDir, classesDir, jarName, sourcesPath.takeIf { addSources })
|
||||
|
||||
@@ -44,7 +44,7 @@ public abstract class AbstractDiagnosticsWithJdk9Test extends AbstractDiagnostic
|
||||
@NotNull Map<String, ModuleAndDependencies> modules,
|
||||
@NotNull List<TestFile> testFiles
|
||||
) {
|
||||
if (KotlinTestUtils.getJre9HomeIfPossible() == null) {
|
||||
if (KotlinTestUtils.getJdk9HomeIfPossible() == null) {
|
||||
// Skip this test if no Java 9 is found
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user