[Tests] Check for duplicate file names in FIR diagnostic tests with IR

The relative path of a test file is just its name, even if it's in a
module.
Diagnostics in IR are mapped to the file path and so it's reported on
all files with the same path, i.e. name.
This doesn't happen in production code because no two files can have
the same path.

The proper fix would be to prefix the test files' paths with the module
name.
Unfortunately, this breaks a bunch of test runners that rely on the
current behavior.
Especially, some JS runners turned out to be hard to fix.
The linked YouTrack issue contains a WIP, incomplete patch of fixing
some runners.

#KT-61592 Fixed
#KT-63252
This commit is contained in:
Kirill Rakhman
2023-10-30 16:58:59 +01:00
committed by Space Team
parent 159d89b7af
commit eba1fdec1d
5 changed files with 46 additions and 9 deletions
@@ -11,10 +11,10 @@
// MODULE: commonJS()()(common)
// TARGET_PLATFORM: JS
// FILE: StringValue.kt
actual class Strin<!NO_ACTUAL_FOR_EXPECT{JS}!>gValue(val value: String<!>)
<!NO_ACTUAL_FOR_EXPECT{JS}!>
actual fun StringValue.plus(other: String) = StringVal<!>ue(this.value + other)
// FILE: StringValueJs.kt
actual class StringValue(val value: String)
actual fun StringValue.plus(other: String) = StringValue(this.value + other)
// MODULE: intermediate()()(common)
// TARGET_PLATFORM: Common
@@ -31,10 +31,10 @@ interface KotlinXStringDemoInterface {
// MODULE: js()()(common, intermediate)
// TARGET_PLATFORM: JS
// FILE: StringDemoInterface.kt
// FILE: StringDemoInterfaceJs.kt
actual typealias StringDemoInterface = KotlinXStringDemoInterface
actual fun StringDemoIn<!EXPECT_ACTUAL_INCOMPATIBILITY!>terface.<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible because return type is different: expect fun StringDemoInterface.plusK(): String")!>plusK<!>() = <!EXPECT_CLASS_AS_FUNCTION!>StringValue<!>(value).plus("K")<!>.<!UNRESOLVED_REFERENCE!>value<!>
actual fun StringDemoInterface.<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible because return type is different: expect fun StringDemoInterface.plusK(): String")!>plusK<!>() = <!EXPECT_CLASS_AS_FUNCTION!>StringValue<!>(value).plus("K").<!UNRESOLVED_REFERENCE!>value<!>
// FILE: main.kt
class StringDemo(override val value: String) : StringDemoInterface
@@ -11,7 +11,7 @@ expect fun StringValue.<!NO_ACTUAL_FOR_EXPECT{JS}!>plus<!>(other: String): Strin
// MODULE: commonJS()()(common)
// TARGET_PLATFORM: JS
// FILE: StringValue.kt
// FILE: StringValueJs.kt
actual class StringValue(val value: String)
actual fun StringValue.plus(other: String) = StringValue(this.value + other)
@@ -31,7 +31,7 @@ expect fun StringDemoInterface.plusK(): <!NO_ACTUAL_FOR_EXPECT{JS}!>String<!>
// MODULE: js()()(common, intermediate)
// TARGET_PLATFORM: JS
// FILE: StringDemoInterface.kt
// FILE: StringDemoInterfaceJs.kt
actual typealias StringDemoInterface = KotlinXStringDemoInterface
actual fun StringDemoInterface.<!ACTUAL_WITHOUT_EXPECT("Actual function 'plusK'; The following declaration is incompatible because return type is different: public expect fun StringDemoInterface /* = KotlinXStringDemoInterface */.plusK(): String")!>plusK<!>() = <!RESOLUTION_TO_CLASSIFIER!>StringValue<!>(value).<!DEBUG_INFO_MISSING_UNRESOLVED!>plus<!>("K").<!DEBUG_INFO_MISSING_UNRESOLVED!>value<!>
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners
import org.jetbrains.kotlin.config.ExplicitApiMode
import org.jetbrains.kotlin.diagnostics.impl.SimpleDiagnosticsCollector
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.*
@@ -110,6 +111,9 @@ abstract class AbstractFirWithActualizerDiagnosticsTest(val parser: FirParser) :
}
useAdditionalService(::LibraryProvider)
@OptIn(TestInfrastructureInternals::class)
useModuleStructureTransformers(DuplicateFileNameChecker)
}
}
@@ -238,7 +242,7 @@ fun TestConfigurationBuilder.baseFirDiagnosticTestConfiguration(
class FirLazyDeclarationResolverWithPhaseCheckingSessionComponentRegistrar : FirSessionComponentRegistrar() {
private val lazyResolver = FirCompilerLazyDeclarationResolverWithPhaseChecking()
@OptIn(org.jetbrains.kotlin.fir.SessionConfiguration::class)
@OptIn(SessionConfiguration::class)
override fun registerAdditionalComponent(session: FirSession) {
session.register(FirLazyDeclarationResolver::class, lazyResolver)
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.test.runners
import org.jetbrains.kotlin.test.TestInfrastructureInternals
import org.jetbrains.kotlin.test.services.ModuleStructureTransformer
import org.jetbrains.kotlin.test.services.TestModuleStructure
// TODO remove when duplicate files names are supported by prefix their path with the module name KT-63252
@OptIn(TestInfrastructureInternals::class)
object DuplicateFileNameChecker : ModuleStructureTransformer() {
override fun transformModuleStructure(moduleStructure: TestModuleStructure): TestModuleStructure {
val files = mutableSetOf<String>()
for (module in moduleStructure.modules) {
for (file in module.files) {
if (!files.add(file.name)) {
throw IllegalStateException("Duplicate file name: ${file.name}")
}
}
}
return moduleStructure
}
}
@@ -7,12 +7,14 @@ package org.jetbrains.kotlin.test.runners.ir
import org.jetbrains.kotlin.test.FirParser
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.TestInfrastructureInternals
import org.jetbrains.kotlin.test.backend.ir.IrDiagnosticsHandler
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.directives.configureFirParser
import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.runners.DuplicateFileNameChecker
import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration
abstract class AbstractFirWithInterpreterDiagnosticsTest(val parser: FirParser) : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
@@ -26,6 +28,9 @@ abstract class AbstractFirWithInterpreterDiagnosticsTest(val parser: FirParser)
::IrDiagnosticsHandler
)
}
@OptIn(TestInfrastructureInternals::class)
useModuleStructureTransformers(DuplicateFileNameChecker)
}
}