Create KotlinCoreEnvironment a bit later in tests

Before this change, diagnostic tests with Java source files failed
because KotlinCoreEnvironment was being created in the test's setUp,
even before the test data file has been split into .java/.kt and the
resulting .java files have been copied to a temporary directory. In
KotlinCoreEnvironment's constructor, we now inspect all roots for
module-info files, which involves calling VirtualFile.getChildren on all
roots in the configuration. CoreLocalVirtualFile.getChildren is
cached on the first access, and so because the temporary directory with
.java files was empty at this point, the VirtualFile for that directory
returned empty array in getChildren later in the test, resulting in
unresolved reference errors.

This is fixed by creating the environment _after_ the .java files have
been copied to a temporary directory. Note that slow assertions for
flexible types are now enabled in KtUsefulTestCase instead of
KotlinTestWithEnvironmentManagement, because BaseDiagnosticsTest no
longer inherits from the latter
This commit is contained in:
Alexander Udalov
2017-06-22 16:22:34 +03:00
parent 03d83db660
commit 9274d963aa
9 changed files with 70 additions and 57 deletions
@@ -16,11 +16,10 @@
package org.jetbrains.kotlin.checkers package org.jetbrains.kotlin.checkers
import com.intellij.lang.java.JavaLanguage import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.Conditions import com.intellij.openapi.util.Conditions
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
@@ -28,6 +27,7 @@ import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestFile import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestFile
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestModule import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest.TestModule
import org.jetbrains.kotlin.checkers.CheckerTestUtil.ActualDiagnostic import org.jetbrains.kotlin.checkers.CheckerTestUtil.ActualDiagnostic
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.* import org.jetbrains.kotlin.diagnostics.*
@@ -42,8 +42,19 @@ import org.junit.Assert
import java.io.File import java.io.File
import java.util.* import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.reflect.jvm.javaField
abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, TestFile>() { abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, TestFile>() {
protected lateinit var environment: KotlinCoreEnvironment
protected val project: Project
get() = environment.project
override fun tearDown() {
this::environment.javaField!![this] = null
super.tearDown()
}
override fun createTestModule(name: String): TestModule = override fun createTestModule(name: String): TestModule =
TestModule(name) TestModule(name)
@@ -61,6 +72,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
}) })
} }
environment = createEnvironment()
analyzeAndCheck(file, testFiles) analyzeAndCheck(file, testFiles)
} }
@@ -120,7 +133,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
private val diagnosedRanges: List<CheckerTestUtil.DiagnosedRange> = ArrayList() private val diagnosedRanges: List<CheckerTestUtil.DiagnosedRange> = ArrayList()
val expectedText: String val expectedText: String
private val clearText: String private val clearText: String
val ktFile: KtFile? private val createKtFile: Lazy<KtFile?>
private val whatDiagnosticsToConsider: Condition<Diagnostic> private val whatDiagnosticsToConsider: Condition<Diagnostic>
val customLanguageVersionSettings: LanguageVersionSettings? val customLanguageVersionSettings: LanguageVersionSettings?
val declareCheckType: Boolean val declareCheckType: Boolean
@@ -137,19 +150,20 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
this.declareFlexibleType = EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE in directives this.declareFlexibleType = EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE in directives
this.markDynamicCalls = MARK_DYNAMIC_CALLS_DIRECTIVE in directives this.markDynamicCalls = MARK_DYNAMIC_CALLS_DIRECTIVE in directives
if (fileName.endsWith(".java")) { if (fileName.endsWith(".java")) {
PsiFileFactory.getInstance(project).createFileFromText(fileName, JavaLanguage.INSTANCE, textWithMarkers) // TODO: check there are no syntax errors in .java sources
// TODO: check there's not syntax errors this.createKtFile = lazyOf(null)
this.ktFile = null
this.clearText = textWithMarkers this.clearText = textWithMarkers
this.expectedText = this.clearText this.expectedText = this.clearText
} }
else { else {
this.expectedText = textWithMarkers this.expectedText = textWithMarkers
this.clearText = CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges) this.clearText = CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges)
this.ktFile = TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project) this.createKtFile = lazy { TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project) }
} }
} }
val ktFile: KtFile? by createKtFile
private val imports: String private val imports: String
get() = buildString { get() = buildString {
// Line separator is "\n" intentionally here (see DocumentImpl.assertValidSeparators) // Line separator is "\n" intentionally here (see DocumentImpl.assertValidSeparators)
@@ -196,7 +210,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
actualText: StringBuilder, actualText: StringBuilder,
skipJvmSignatureDiagnostics: Boolean skipJvmSignatureDiagnostics: Boolean
): Boolean { ): Boolean {
if (this.ktFile == null) { val ktFile = this.ktFile
if (ktFile == null) {
// TODO: check java files too // TODO: check java files too
actualText.append(this.clearText) actualText.append(this.clearText)
return true return true
@@ -30,8 +30,8 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.script.StandardScriptDefinition; import org.jetbrains.kotlin.script.StandardScriptDefinition;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment;
import org.jetbrains.kotlin.test.TestJdkKind; import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
import java.io.File; import java.io.File;
import java.util.Collections; import java.util.Collections;
@@ -39,10 +39,27 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEnvironment { public abstract class KotlinMultiFileTestWithJava<M, F> extends KtUsefulTestCase {
private File javaFilesDir; private File javaFilesDir;
private File kotlinSourceRoot; private File kotlinSourceRoot;
@Override
public void setUp() throws Exception {
super.setUp();
// TODO: do not create temporary directory for tests without Java sources
javaFilesDir = KotlinTestUtils.tmpDir("java-files");
if (isKotlinSourceRootNeeded()) {
kotlinSourceRoot = KotlinTestUtils.tmpDir("kotlin-src");
}
}
@Override
protected void tearDown() throws Exception {
if (javaFilesDir != null) FileUtil.delete(javaFilesDir);
if (kotlinSourceRoot != null) FileUtil.delete(kotlinSourceRoot);
super.tearDown();
}
public class ModuleAndDependencies { public class ModuleAndDependencies {
final M module; final M module;
final List<String> dependencies; final List<String> dependencies;
@@ -55,10 +72,8 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
} }
} }
@Override @NotNull
protected KotlinCoreEnvironment createEnvironment() throws Exception { protected KotlinCoreEnvironment createEnvironment() {
// TODO: do not create temporary directory for tests without Java sources
javaFilesDir = KotlinTestUtils.tmpDir("java-files");
CompilerConfiguration configuration = KotlinTestUtils.newConfiguration( CompilerConfiguration configuration = KotlinTestUtils.newConfiguration(
getConfigurationKind(), getConfigurationKind(),
getTestJdkKind(), getTestJdkKind(),
@@ -67,18 +82,11 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
); );
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE); configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE);
if (isKotlinSourceRootNeeded()) { if (isKotlinSourceRootNeeded()) {
kotlinSourceRoot = KotlinTestUtils.tmpDir("kotlin-src");
ContentRootsKt.addKotlinSourceRoot(configuration, kotlinSourceRoot.getPath()); ContentRootsKt.addKotlinSourceRoot(configuration, kotlinSourceRoot.getPath());
} }
return KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, getEnvironmentConfigFiles()); return KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, getEnvironmentConfigFiles());
} }
@Override
protected void removeEnvironment() throws Exception {
if (javaFilesDir != null) FileUtil.delete(javaFilesDir);
if (kotlinSourceRoot != null) FileUtil.delete(kotlinSourceRoot);
}
@NotNull @NotNull
protected ConfigurationKind getConfigurationKind() { protected ConfigurationKind getConfigurationKind() {
return ConfigurationKind.JDK_ONLY; return ConfigurationKind.JDK_ONLY;
@@ -31,13 +31,11 @@ public abstract class KotlinTestWithEnvironment extends KotlinTestWithEnvironmen
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
removeEnvironment();
environment = null; environment = null;
super.tearDown(); super.tearDown();
} }
protected abstract KotlinCoreEnvironment createEnvironment() throws Exception; protected abstract KotlinCoreEnvironment createEnvironment() throws Exception;
protected void removeEnvironment() throws Exception {}
@NotNull @NotNull
public KotlinCoreEnvironment getEnvironment() { public KotlinCoreEnvironment getEnvironment() {
@@ -19,12 +19,10 @@ package org.jetbrains.kotlin.test;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase; import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
public abstract class KotlinTestWithEnvironmentManagement extends KtUsefulTestCase { public abstract class KotlinTestWithEnvironmentManagement extends KtUsefulTestCase {
static { static {
System.setProperty("java.awt.headless", "true"); System.setProperty("java.awt.headless", "true");
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
} }
@NotNull @NotNull
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.junit.Assert; import org.junit.Assert;
@@ -80,6 +81,8 @@ public abstract class KtUsefulTestCase extends TestCase {
static { static {
// Radar #5755208: Command line Java applications need a way to launch without a Dock icon. // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
System.setProperty("apple.awt.UIElement", "true"); System.setProperty("apple.awt.UIElement", "true");
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
} }
private boolean oldDisposerDebug; private boolean oldDisposerDebug;
+1
View File
@@ -31,5 +31,6 @@
<orderEntry type="library" name="intellij-core" level="project" /> <orderEntry type="library" name="intellij-core" level="project" />
<orderEntry type="library" name="idea-full" level="project" /> <orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="module" module-name="backend.jvm" /> <orderEntry type="module" module-name="backend.jvm" />
<orderEntry type="library" name="kotlin-reflect" level="project" />
</component> </component>
</module> </module>
@@ -52,10 +52,11 @@ public abstract class AbstractCompilerLightClassTest extends KotlinMultiFileTest
@Override @Override
protected void doMultiFileTest(File file, Map<String, ModuleAndDependencies> modules, List<Void> files) throws IOException { protected void doMultiFileTest(File file, Map<String, ModuleAndDependencies> modules, List<Void> files) throws IOException {
KotlinCoreEnvironment environment = createEnvironment();
File expectedFile = KotlinTestUtils.replaceExtension(file, "java"); File expectedFile = KotlinTestUtils.replaceExtension(file, "java");
LightClassTestCommon.INSTANCE.testLightClass(expectedFile, file, s -> { LightClassTestCommon.INSTANCE.testLightClass(expectedFile, file, s -> {
try { try {
return createFinder(getEnvironment()).findClass(s, GlobalSearchScope.allScope(getEnvironment().getProject())); return createFinder(environment).findClass(s, GlobalSearchScope.allScope(environment.getProject()));
} }
catch (IOException e) { catch (IOException e) {
throw ExceptionUtilsKt.rethrow(e); throw ExceptionUtilsKt.rethrow(e);
@@ -36,22 +36,19 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import java.util.* import java.util.*
import kotlin.reflect.jvm.javaField
abstract class AbstractDiagnosticsTestWithJsStdLib : AbstractDiagnosticsTest() { abstract class AbstractDiagnosticsTestWithJsStdLib : AbstractDiagnosticsTest() {
protected lateinit var config: JsConfig private var lazyConfig: Lazy<JsConfig>? = lazy(LazyThreadSafetyMode.NONE) {
private set JsConfig(project, environment.configuration.copy().apply {
override fun setUp() {
super.setUp()
config = JsConfig(project, environment.configuration.copy().apply {
put(CommonConfigurationKeys.MODULE_NAME, KotlinTestUtils.TEST_MODULE_NAME) put(CommonConfigurationKeys.MODULE_NAME, KotlinTestUtils.TEST_MODULE_NAME)
put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB) put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB)
}) })
} }
protected val config: JsConfig get() = lazyConfig!!.value
override fun tearDown() { override fun tearDown() {
(AbstractDiagnosticsTestWithJsStdLib::config).javaField!!.set(this, null) lazyConfig = null
super.tearDown() super.tearDown()
} }
@@ -24,22 +24,11 @@ import org.jetbrains.kotlin.codegen.CodegenTestUtil
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
import java.io.StringWriter import java.io.StringWriter
import kotlin.properties.Delegates
abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment() {
private var javaSourceRoot: File by Delegates.notNull()
override fun setUp() {
javaSourceRoot = KotlinTestUtils.tmpDir("java-files")
super.setUp()
}
abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironmentManagement() {
fun doTest(path: String) { fun doTest(path: String) {
val testDir = File(path) val testDir = File(path)
@@ -53,9 +42,19 @@ abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment()
val supportStubs = testName.contains("stubs", ignoreCase = true) val supportStubs = testName.contains("stubs", ignoreCase = true)
val javaFiles = filesByExtension("java") val javaFiles = filesByExtension("java")
if (javaFiles.isNotEmpty()) { val javaSourceRoot =
javaFiles.forEach { it.copyTo(File(javaSourceRoot, it.name)) } if (javaFiles.isNotEmpty()) {
} KotlinTestUtils.tmpDir("java-files").also { javaSourceRoot ->
javaFiles.forEach { javaFile -> javaFile.copyTo(File(javaSourceRoot, javaFile.name)) }
}
}
else null
val configuration = KotlinTestUtils.newConfiguration(
ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, listOf(KotlinTestUtils.getAnnotationsJar()), listOfNotNull(javaSourceRoot)
)
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val project = environment.project
val collectorExtension = AnnotationCollectorExtensionForTests(supportInheritedAnnotations) val collectorExtension = AnnotationCollectorExtensionForTests(supportInheritedAnnotations)
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension) ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
@@ -76,13 +75,6 @@ abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment()
KotlinTestUtils.assertEqualsToFile(expectedAnnotationsFile, actualAnnotations) KotlinTestUtils.assertEqualsToFile(expectedAnnotationsFile, actualAnnotations)
} }
override fun createEnvironment(): KotlinCoreEnvironment {
val configuration = KotlinTestUtils.newConfiguration(
ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, listOf(KotlinTestUtils.getAnnotationsJar()), listOf(javaSourceRoot)
)
return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
}
private class AnnotationCollectorExtensionForTests( private class AnnotationCollectorExtensionForTests(
supportInheritedAnnotations: Boolean supportInheritedAnnotations: Boolean
) : AnnotationCollectorExtensionBase(supportInheritedAnnotations) { ) : AnnotationCollectorExtensionBase(supportInheritedAnnotations) {