Fix class run configuration applicability (KT-33787)

The bug appeared when we turned “ultra light classes” on by default.
  The difference with the old implementation is that
  PsiClass.getTextRange() returns the correct non-null value.
  This triggers JavaExecutionUtil#stepIntoSingleClass() to return
  a light class instead of the original location (of a PsiIdentifier).
  So AbstractJavaTestConfigurationProducer#isConfigurationFromContext()
  returns true, and the wrong configuration is reused instead of
  creating the new one.

By the way, for Java it also returns an identifier because of the
  PsiTreeUtil.getParentOfType(element, PsiClass.class) != null check.

The proper fix should land in the newer versions of IDEA, however this
  (hopefully, temporary) hack will fix test method gutters for
  all platform versions.
This commit is contained in:
Yan Zhulanow
2020-02-14 17:51:42 +09:00
parent b360fb5119
commit 390d062721
6 changed files with 33 additions and 18 deletions
@@ -81,7 +81,7 @@ abstract class KtLightClassForSourceDeclaration(
override fun getText() = kotlinOrigin.text ?: "" override fun getText() = kotlinOrigin.text ?: ""
override fun getTextRange(): TextRange = kotlinOrigin.textRange ?: TextRange.EMPTY_RANGE override fun getTextRange(): TextRange? = kotlinOrigin.textRange ?: TextRange.EMPTY_RANGE
override fun getTextOffset() = kotlinOrigin.textOffset override fun getTextOffset() = kotlinOrigin.textOffset
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.asJava.classes package org.jetbrains.kotlin.asJava.classes
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.impl.InheritanceImplUtil import com.intellij.psi.impl.InheritanceImplUtil
import com.intellij.psi.impl.PsiClassImplUtil import com.intellij.psi.impl.PsiClassImplUtil
@@ -475,4 +477,12 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
override fun isDeprecated(): Boolean = _deprecated override fun isDeprecated(): Boolean = _deprecated
override fun copy(): KtLightClassImpl = KtUltraLightClass(classOrObject.copy() as KtClassOrObject, support) override fun copy(): KtLightClassImpl = KtUltraLightClass(classOrObject.copy() as KtClassOrObject, support)
override fun getTextRange(): TextRange? {
if (Registry.`is`("kotlin.ultra.light.classes.empty.text.range", true)) {
return null
}
return super.getTextRange()
}
} }
@@ -34,20 +34,20 @@ class GradleTestRunConfigurationCustomTest : GradleImportingTestCase() {
val kotlinFile = files.first { it.name == "MyKotlinTest.kt" } val kotlinFile = files.first { it.name == "MyKotlinTest.kt" }
val javaClassConfiguration = getConfiguration(javaFile, myProject, "MyTest") val javaClassConfiguration = getConfiguration(javaFile, myProject, "MyTest")
javaClassConfiguration.isProducedBy(TestClassGradleConfigurationProducer::class.java) assert(javaClassConfiguration.isProducedBy(TestClassGradleConfigurationProducer::class.java))
assert(javaClassConfiguration.configuration !is KotlinGradleRunConfiguration) assert(javaClassConfiguration.configuration.name == "MyTest")
val javaMethodConfiguration = getConfiguration(javaFile, myProject, "testA") val javaMethodConfiguration = getConfiguration(javaFile, myProject, "testA")
javaMethodConfiguration.isProducedBy(TestMethodGradleConfigurationProducer::class.java) assert(javaMethodConfiguration.isProducedBy(TestMethodGradleConfigurationProducer::class.java))
assert(javaMethodConfiguration.configuration !is KotlinGradleRunConfiguration) assert(javaMethodConfiguration.configuration.name == "MyTest.testA")
val kotlinClassConfiguration = getConfiguration(kotlinFile, myProject, "MyKotlinTest") val kotlinClassConfiguration = getConfiguration(kotlinFile, myProject, "MyKotlinTest")
kotlinClassConfiguration.isProducedBy(KotlinJvmTestClassGradleConfigurationProducer::class.java) assert(kotlinClassConfiguration.isProducedBy(KotlinJvmTestClassGradleConfigurationProducer::class.java))
assert(kotlinClassConfiguration.configuration is KotlinGradleRunConfiguration) assert(kotlinClassConfiguration.configuration.name == "MyKotlinTest")
val kotlinFunctionConfiguration = getConfiguration(kotlinFile, myProject, "testA") val kotlinFunctionConfiguration = getConfiguration(kotlinFile, myProject, "testA")
kotlinFunctionConfiguration.isProducedBy(KotlinJvmTestMethodGradleConfigurationProducer::class.java) assert(kotlinFunctionConfiguration.isProducedBy(KotlinJvmTestMethodGradleConfigurationProducer::class.java))
assert(kotlinFunctionConfiguration.configuration is KotlinGradleRunConfiguration) assert(kotlinFunctionConfiguration.configuration.name == "MyKotlinTest.testA")
} }
} }
} }
+5
View File
@@ -175,6 +175,11 @@
defaultValue="true" defaultValue="true"
restartRequired="false"/> restartRequired="false"/>
<registryKey key="kotlin.ultra.light.classes.empty.text.range"
description="Return 'null' text range as in old light class implementation"
defaultValue="true"
restartRequired="false"/>
<registryKey key="kotlin.uast.force.uinjectionhost" <registryKey key="kotlin.uast.force.uinjectionhost"
description="Whether to convert `KtStringTemplateExpression` to `KotlinStringTemplateUPolyadicExpression` in all cases" description="Whether to convert `KtStringTemplateExpression` to `KotlinStringTemplateUPolyadicExpression` in all cases"
defaultValue="true" defaultValue="true"
@@ -43,7 +43,7 @@ class LightClassFromTextTest : KotlinLightCodeInsightFixtureTestCase() {
val classC = classes[0] val classC = classes[0]
assertEquals("C", classC.qualifiedName) assertEquals("C", classC.qualifiedName)
assertEquals("class C", classC.text) assertEquals("class C", classC.text)
assertEquals(TextRange(17, 24), classC.textRange) assertEquals(null, classC.textRange)
assertEquals(23, classC.textOffset) assertEquals(23, classC.textOffset)
assertEquals(17, classC.startOffsetInParent) assertEquals(17, classC.startOffsetInParent)
assertTrue(classC.isWritable) assertTrue(classC.isWritable)
@@ -44,20 +44,20 @@ class KotlinJUnitRunConfigurationTest : AbstractRunConfigurationTest() {
val kotlinFile = testDir.findChild("MyKotlinTest.kt")!! val kotlinFile = testDir.findChild("MyKotlinTest.kt")!!
val javaClassConfiguration = getConfiguration(javaFile, project, "MyTest") val javaClassConfiguration = getConfiguration(javaFile, project, "MyTest")
javaClassConfiguration.isProducedBy(TestInClassConfigurationProducer::class.java) assert(javaClassConfiguration.isProducedBy(TestInClassConfigurationProducer::class.java))
assert(javaClassConfiguration.configuration !is KotlinJUnitConfiguration) assert(javaClassConfiguration.configuration.name == "MyJavaTest")
val javaMethodConfiguration = getConfiguration(javaFile, project, "testA") val javaMethodConfiguration = getConfiguration(javaFile, project, "testA")
javaMethodConfiguration.isProducedBy(TestInClassConfigurationProducer::class.java) assert(javaMethodConfiguration.isProducedBy(TestInClassConfigurationProducer::class.java))
assert(javaMethodConfiguration.configuration !is KotlinJUnitConfiguration) assert(javaMethodConfiguration.configuration.name == "MyJavaTest.testA")
val kotlinClassConfiguration = getConfiguration(kotlinFile, project, "MyKotlinTest") val kotlinClassConfiguration = getConfiguration(kotlinFile, project, "MyKotlinTest")
kotlinClassConfiguration.isProducedBy(KotlinJUnitRunConfigurationProducer::class.java) assert(kotlinClassConfiguration.isProducedBy(KotlinJUnitRunConfigurationProducer::class.java))
assert(kotlinClassConfiguration.configuration is KotlinJUnitConfiguration) assert(kotlinClassConfiguration.configuration.name == "MyKotlinTest")
val kotlinFunctionConfiguration = getConfiguration(kotlinFile, project, "testA") val kotlinFunctionConfiguration = getConfiguration(kotlinFile, project, "testA")
kotlinFunctionConfiguration.isProducedBy(KotlinJUnitRunConfigurationProducer::class.java) assert(kotlinFunctionConfiguration.isProducedBy(KotlinJUnitRunConfigurationProducer::class.java))
assert(kotlinFunctionConfiguration.configuration is KotlinJUnitConfiguration) assert(kotlinFunctionConfiguration.configuration.name == "MyKotlinTest.testA")
} finally { } finally {
detachJUnitLibrary() detachJUnitLibrary()
} }