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
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.Conditions
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
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.TestModule
import org.jetbrains.kotlin.checkers.CheckerTestUtil.ActualDiagnostic
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.*
@@ -42,8 +42,19 @@ import org.junit.Assert
import java.io.File
import java.util.*
import java.util.regex.Pattern
import kotlin.reflect.jvm.javaField
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 =
TestModule(name)
@@ -61,6 +72,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
})
}
environment = createEnvironment()
analyzeAndCheck(file, testFiles)
}
@@ -120,7 +133,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
private val diagnosedRanges: List<CheckerTestUtil.DiagnosedRange> = ArrayList()
val expectedText: String
private val clearText: String
val ktFile: KtFile?
private val createKtFile: Lazy<KtFile?>
private val whatDiagnosticsToConsider: Condition<Diagnostic>
val customLanguageVersionSettings: LanguageVersionSettings?
val declareCheckType: Boolean
@@ -137,19 +150,20 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
this.declareFlexibleType = EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE in directives
this.markDynamicCalls = MARK_DYNAMIC_CALLS_DIRECTIVE in directives
if (fileName.endsWith(".java")) {
PsiFileFactory.getInstance(project).createFileFromText(fileName, JavaLanguage.INSTANCE, textWithMarkers)
// TODO: check there's not syntax errors
this.ktFile = null
// TODO: check there are no syntax errors in .java sources
this.createKtFile = lazyOf(null)
this.clearText = textWithMarkers
this.expectedText = this.clearText
}
else {
this.expectedText = textWithMarkers
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
get() = buildString {
// Line separator is "\n" intentionally here (see DocumentImpl.assertValidSeparators)
@@ -196,7 +210,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
actualText: StringBuilder,
skipJvmSignatureDiagnostics: Boolean
): Boolean {
if (this.ktFile == null) {
val ktFile = this.ktFile
if (ktFile == null) {
// TODO: check java files too
actualText.append(this.clearText)
return true
@@ -30,8 +30,8 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.script.StandardScriptDefinition;
import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment;
import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
import java.io.File;
import java.util.Collections;
@@ -39,10 +39,27 @@ import java.util.HashMap;
import java.util.List;
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 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 {
final M module;
final List<String> dependencies;
@@ -55,10 +72,8 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
}
}
@Override
protected KotlinCoreEnvironment createEnvironment() throws Exception {
// TODO: do not create temporary directory for tests without Java sources
javaFilesDir = KotlinTestUtils.tmpDir("java-files");
@NotNull
protected KotlinCoreEnvironment createEnvironment() {
CompilerConfiguration configuration = KotlinTestUtils.newConfiguration(
getConfigurationKind(),
getTestJdkKind(),
@@ -67,18 +82,11 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
);
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE);
if (isKotlinSourceRootNeeded()) {
kotlinSourceRoot = KotlinTestUtils.tmpDir("kotlin-src");
ContentRootsKt.addKotlinSourceRoot(configuration, kotlinSourceRoot.getPath());
}
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
protected ConfigurationKind getConfigurationKind() {
return ConfigurationKind.JDK_ONLY;
@@ -31,13 +31,11 @@ public abstract class KotlinTestWithEnvironment extends KotlinTestWithEnvironmen
@Override
protected void tearDown() throws Exception {
removeEnvironment();
environment = null;
super.tearDown();
}
protected abstract KotlinCoreEnvironment createEnvironment() throws Exception;
protected void removeEnvironment() throws Exception {}
@NotNull
public KotlinCoreEnvironment getEnvironment() {
@@ -19,12 +19,10 @@ package org.jetbrains.kotlin.test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
public abstract class KotlinTestWithEnvironmentManagement extends KtUsefulTestCase {
static {
System.setProperty("java.awt.headless", "true");
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
}
@NotNull
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.junit.Assert;
@@ -80,6 +81,8 @@ public abstract class KtUsefulTestCase extends TestCase {
static {
// Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
System.setProperty("apple.awt.UIElement", "true");
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
}
private boolean oldDisposerDebug;
+1
View File
@@ -31,5 +31,6 @@
<orderEntry type="library" name="intellij-core" level="project" />
<orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="module" module-name="backend.jvm" />
<orderEntry type="library" name="kotlin-reflect" level="project" />
</component>
</module>
@@ -52,10 +52,11 @@ public abstract class AbstractCompilerLightClassTest extends KotlinMultiFileTest
@Override
protected void doMultiFileTest(File file, Map<String, ModuleAndDependencies> modules, List<Void> files) throws IOException {
KotlinCoreEnvironment environment = createEnvironment();
File expectedFile = KotlinTestUtils.replaceExtension(file, "java");
LightClassTestCommon.INSTANCE.testLightClass(expectedFile, file, s -> {
try {
return createFinder(getEnvironment()).findClass(s, GlobalSearchScope.allScope(getEnvironment().getProject()));
return createFinder(environment).findClass(s, GlobalSearchScope.allScope(environment.getProject()));
}
catch (IOException 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.test.KotlinTestUtils
import java.util.*
import kotlin.reflect.jvm.javaField
abstract class AbstractDiagnosticsTestWithJsStdLib : AbstractDiagnosticsTest() {
protected lateinit var config: JsConfig
private set
override fun setUp() {
super.setUp()
config = JsConfig(project, environment.configuration.copy().apply {
private var lazyConfig: Lazy<JsConfig>? = lazy(LazyThreadSafetyMode.NONE) {
JsConfig(project, environment.configuration.copy().apply {
put(CommonConfigurationKeys.MODULE_NAME, KotlinTestUtils.TEST_MODULE_NAME)
put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB)
})
}
protected val config: JsConfig get() = lazyConfig!!.value
override fun tearDown() {
(AbstractDiagnosticsTestWithJsStdLib::config).javaField!!.set(this, null)
lazyConfig = null
super.tearDown()
}
@@ -24,22 +24,11 @@ import org.jetbrains.kotlin.codegen.CodegenTestUtil
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.*
import java.io.File
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) {
val testDir = File(path)
@@ -53,9 +42,19 @@ abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment()
val supportStubs = testName.contains("stubs", ignoreCase = true)
val javaFiles = filesByExtension("java")
if (javaFiles.isNotEmpty()) {
javaFiles.forEach { it.copyTo(File(javaSourceRoot, it.name)) }
}
val javaSourceRoot =
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)
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
@@ -76,13 +75,6 @@ abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment()
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(
supportInheritedAnnotations: Boolean
) : AnnotationCollectorExtensionBase(supportInheritedAnnotations) {