JVM IR: fix ::class reference and type mapping for scripts
#KT-46284 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
d10f734594
commit
276ffd5a4b
@@ -18,6 +18,7 @@ interface TypeMappingContext<Writer : JvmDescriptorTypeWriter<Type>> {
|
|||||||
val typeContext: TypeSystemCommonBackendContextForTypeMapping
|
val typeContext: TypeSystemCommonBackendContextForTypeMapping
|
||||||
|
|
||||||
fun getClassInternalName(typeConstructor: TypeConstructorMarker): String
|
fun getClassInternalName(typeConstructor: TypeConstructorMarker): String
|
||||||
|
fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String
|
||||||
fun Writer.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode)
|
fun Writer.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,9 +118,7 @@ object AbstractTypeMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typeConstructor.isScript() -> {
|
typeConstructor.isScript() -> {
|
||||||
val asmType = AsmTypes.JAVA_CLASS_TYPE
|
return Type.getObjectType(context.getScriptInternalName(typeConstructor))
|
||||||
with(context) { sw?.writeGenericType(type, asmType, mode) }
|
|
||||||
return asmType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typeConstructor.isTypeParameter() -> {
|
typeConstructor.isTypeParameter() -> {
|
||||||
|
|||||||
+5
-2
@@ -13,19 +13,19 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
import org.jetbrains.kotlin.fir.resolve.inference.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeMapper
|
import org.jetbrains.kotlin.types.AbstractTypeMapper
|
||||||
import org.jetbrains.kotlin.types.TypeMappingContext
|
import org.jetbrains.kotlin.types.TypeMappingContext
|
||||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||||
@@ -50,6 +50,9 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatur
|
|||||||
return typeConstructor.classId.asString().replace(".", "$").replace("/", ".")
|
return typeConstructor.classId.asString().replace(".", "$").replace("/", ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String =
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
|
||||||
override fun JvmSignatureWriter.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode) {
|
override fun JvmSignatureWriter.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode) {
|
||||||
if (type !is ConeClassLikeType) return
|
if (type !is ConeClassLikeType) return
|
||||||
if (skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.typeArguments.isEmpty()) {
|
if (skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.typeArguments.isEmpty()) {
|
||||||
|
|||||||
+16
@@ -38615,6 +38615,22 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Script {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("classReference.kt")
|
||||||
|
public void testClassReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
@@ -101,6 +101,12 @@ class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBas
|
|||||||
override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String =
|
override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String =
|
||||||
classInternalName((typeConstructor as IrClassSymbol).owner)
|
classInternalName((typeConstructor as IrClassSymbol).owner)
|
||||||
|
|
||||||
|
override fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String {
|
||||||
|
val script = (typeConstructor as IrScriptSymbol).owner
|
||||||
|
val targetClass = script.targetClass ?: error("No target class computed for script: ${script.render()}")
|
||||||
|
return classInternalName(targetClass.owner)
|
||||||
|
}
|
||||||
|
|
||||||
fun writeFormalTypeParameters(irParameters: List<IrTypeParameter>, sw: JvmSignatureWriter) {
|
fun writeFormalTypeParameters(irParameters: List<IrTypeParameter>, sw: JvmSignatureWriter) {
|
||||||
if (sw.skipGenericSignature()) return
|
if (sw.skipGenericSignature()) return
|
||||||
with(KotlinTypeMapper) {
|
with(KotlinTypeMapper) {
|
||||||
|
|||||||
@@ -66,12 +66,11 @@ fun IrType.eraseTypeParameters() = when (this) {
|
|||||||
is IrErrorType -> this
|
is IrErrorType -> this
|
||||||
is IrSimpleType ->
|
is IrSimpleType ->
|
||||||
when (val owner = classifier.owner) {
|
when (val owner = classifier.owner) {
|
||||||
is IrClass -> IrSimpleTypeImpl(
|
is IrScript -> {
|
||||||
classifier,
|
assert(arguments.isEmpty()) { "Script can't be generic: " + owner.render() }
|
||||||
hasQuestionMark,
|
IrSimpleTypeImpl(classifier, hasQuestionMark, emptyList(), annotations)
|
||||||
arguments.map { it.eraseTypeParameters() },
|
}
|
||||||
annotations
|
is IrClass -> IrSimpleTypeImpl(classifier, hasQuestionMark, arguments.map { it.eraseTypeParameters() }, annotations)
|
||||||
)
|
|
||||||
is IrTypeParameter -> {
|
is IrTypeParameter -> {
|
||||||
val upperBound = owner.erasedUpperBound
|
val upperBound = owner.erasedUpperBound
|
||||||
IrSimpleTypeImpl(
|
IrSimpleTypeImpl(
|
||||||
|
|||||||
@@ -338,6 +338,8 @@ fun ReferenceSymbolTable.referenceClassifier(classifier: ClassifierDescriptor):
|
|||||||
when (classifier) {
|
when (classifier) {
|
||||||
is TypeParameterDescriptor ->
|
is TypeParameterDescriptor ->
|
||||||
referenceTypeParameter(classifier)
|
referenceTypeParameter(classifier)
|
||||||
|
is ScriptDescriptor ->
|
||||||
|
referenceScript(classifier)
|
||||||
is ClassDescriptor ->
|
is ClassDescriptor ->
|
||||||
referenceClass(classifier)
|
referenceClass(classifier)
|
||||||
else ->
|
else ->
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// IGNORE_LIGHT_ANALYSIS
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
fun box(): String =
|
||||||
|
OK::class.java.simpleName
|
||||||
|
|
||||||
|
// FILE: OK.kts
|
||||||
+16
@@ -38591,6 +38591,22 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Script {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("classReference.kt")
|
||||||
|
public void testClassReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+16
@@ -38615,6 +38615,22 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Script {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("classReference.kt")
|
||||||
|
public void testClassReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+3
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.RUN_DEX_CHECKE
|
|||||||
import org.jetbrains.kotlin.test.model.*
|
import org.jetbrains.kotlin.test.model.*
|
||||||
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
|
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
|
||||||
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
|
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
|
||||||
|
import org.jetbrains.kotlin.test.services.configuration.ScriptingEnvironmentConfigurator
|
||||||
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
|
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
|
||||||
import org.jetbrains.kotlin.test.services.sourceProviders.CodegenHelpersSourceFilesProvider
|
import org.jetbrains.kotlin.test.services.sourceProviders.CodegenHelpersSourceFilesProvider
|
||||||
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
|
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
|
||||||
@@ -36,7 +37,8 @@ fun <R : ResultingArtifact.FrontendOutput<R>> TestConfigurationBuilder.commonCon
|
|||||||
|
|
||||||
useConfigurators(
|
useConfigurators(
|
||||||
::CommonEnvironmentConfigurator,
|
::CommonEnvironmentConfigurator,
|
||||||
::JvmEnvironmentConfigurator
|
::JvmEnvironmentConfigurator,
|
||||||
|
::ScriptingEnvironmentConfigurator,
|
||||||
)
|
)
|
||||||
|
|
||||||
useAdditionalSourceProviders(
|
useAdditionalSourceProviders(
|
||||||
|
|||||||
+18
@@ -30838,6 +30838,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Script extends AbstractLightAnalysisModeTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classReference.kt")
|
||||||
|
public void testClassReference() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+13
@@ -25978,6 +25978,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Script extends AbstractIrJsCodegenBoxES6Test {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+13
@@ -25389,6 +25389,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Script extends AbstractIrJsCodegenBoxTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Generated
+13
@@ -25349,6 +25349,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Script extends AbstractJsCodegenBoxTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+13
@@ -13810,6 +13810,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/script")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Script extends AbstractIrCodegenBoxWasmTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInScript() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/script"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user