[analysis api] allow generating test with for with more possible parameters

This commit is contained in:
Ilya Kirillov
2022-03-24 20:55:19 +01:00
parent 12e0254918
commit 443ee4c860
24 changed files with 495 additions and 309 deletions
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2022 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.analysis.api.fe10
import org.jetbrains.kotlin.analysis.test.framework.*
object AnalysisApiFe10TestConfiguratorFactory : AnalysisApiTestConfiguratorFactory() {
override fun createConfigurator(data: AnalysisApiTestConfiguratorFactoryData): AnalysisApiTestConfiguratorService {
require(supportMode(data))
return when (data.moduleKind) {
TestModuleKind.Source -> when (data.analysisSessionMode) {
AnalysisSessionMode.Normal -> KtFe10AnalysisApiTestConfiguratorService
AnalysisSessionMode.Dependent -> error("Unsupported AnalysisSessionMode.Dependent for fe10")
}
else -> {
error("Unsupported non-source module for fe10")
}
}
}
override fun supportMode(data: AnalysisApiTestConfiguratorFactoryData): Boolean {
return when {
data.frontend != FrontendKind.Fe10 -> false
data.analysisSessionMode != AnalysisSessionMode.Normal -> false
data.analysisApiMode != AnalysisApiMode.Ide -> false
else -> when (data.moduleKind) {
TestModuleKind.Source -> true
TestModuleKind.LibraryBinary,
TestModuleKind.LibrarySource -> false
}
}
}
}
@@ -3,7 +3,7 @@
* 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.analysis.api.descriptors.test
package org.jetbrains.kotlin.analysis.api.fe10
import com.intellij.mock.MockApplication
import com.intellij.mock.MockProject
@@ -3,7 +3,7 @@
* 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.analysis.api.descriptors.test
package org.jetbrains.kotlin.analysis.api.fe10
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2022 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.analysis.api.fir
import org.jetbrains.kotlin.analysis.api.fir.utils.libraries.binary.LibraryAnalysisApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.fir.utils.libraries.source.LibrarySourceAnalysisApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.test.framework.*
object AnalysisApiFirTestConfiguratorFactory : AnalysisApiTestConfiguratorFactory() {
override fun createConfigurator(data: AnalysisApiTestConfiguratorFactoryData): AnalysisApiTestConfiguratorService {
require(supportMode(data))
return when (data.moduleKind) {
TestModuleKind.Source -> when (data.analysisSessionMode) {
AnalysisSessionMode.Normal -> FirAnalysisApiNormalModeTestConfiguratorService
AnalysisSessionMode.Dependent -> FirAnalysisApiDependentModeTestConfiguratorService
}
TestModuleKind.LibraryBinary -> {
require(data.analysisSessionMode == AnalysisSessionMode.Normal)
LibraryAnalysisApiTestConfiguratorService
}
TestModuleKind.LibrarySource -> {
require(data.analysisSessionMode == AnalysisSessionMode.Normal)
LibrarySourceAnalysisApiTestConfiguratorService
}
}
}
override fun supportMode(data: AnalysisApiTestConfiguratorFactoryData): Boolean {
return when {
data.frontend != FrontendKind.Fir -> false
data.analysisApiMode != AnalysisApiMode.Ide -> false
else -> when (data.moduleKind) {
TestModuleKind.Source -> true
TestModuleKind.LibraryBinary,
TestModuleKind.LibrarySource ->
data.analysisSessionMode == AnalysisSessionMode.Normal
}
}
}
}
@@ -29,14 +29,6 @@ open class FirAnalysisApiTestConfiguratorService(override val analyseInDependent
configureOptionalTestCompilerPlugin()
}
override fun processTestFiles(files: List<KtFile>): List<KtFile> {
return FirLowLevelAnalysisApiTestConfiguratorService.processTestFiles(files)
}
override fun getOriginalFile(file: KtFile): KtFile {
return FirLowLevelAnalysisApiTestConfiguratorService.getOriginalFile(file)
}
override fun registerProjectServices(
project: MockProject,
compilerConfig: CompilerConfiguration,
@@ -44,9 +44,7 @@ abstract class AbstractReferenceResolveTest : AbstractAnalysisApiBasedSingleModu
}
val resolvedTo =
analyseForTest(
PsiTreeUtil.findElementOfClassAtOffset(mainKtFile, caretPosition, KtDeclaration::class.java, false) ?: mainKtFile
) {
analyseForTest(ktReferences.first().element) {
val symbols = ktReferences.flatMap { it.resolveToSymbols() }
checkReferenceResultForValidity(ktReferences, module, testServices, symbols)
renderResolvedTo(symbols, renderingOptions)
@@ -19,7 +19,7 @@ abstract class AbstractAnalysisApiAnnotationsOnDeclarationsTest : AbstractAnalys
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val ktDeclaration = testServices.expressionMarkerProvider
.getElementOfTypAtCaret<KtDeclaration>(ktFile)
val actual = analyseForTest(ktFile) {
val actual = analyseForTest(ktDeclaration) {
val declarationSymbol = ktDeclaration.getSymbol() as KtAnnotatedSymbol
buildString {
appendLine("KtDeclaration: ${ktDeclaration::class.simpleName} ${ktDeclaration.name}")
@@ -21,7 +21,7 @@ abstract class AbstractAnalysisApiAnnotationsOnTypesTest : AbstractAnalysisApiSi
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val ktTypeReference = testServices.expressionMarkerProvider
.getElementOfTypAtCaret<KtTypeReference>(ktFile)
val actual = analyseForTest(ktFile) {
val actual = analyseForTest(ktTypeReference) {
val ktType = ktTypeReference.getKtType()
val annotations = ktType.annotations
buildString {
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2022 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.analysis.api.standalone
import org.jetbrains.kotlin.analysis.test.framework.*
object AnalysisApiFirStandaloneModeTestConfiguratorFactory : AnalysisApiTestConfiguratorFactory() {
override fun createConfigurator(data: AnalysisApiTestConfiguratorFactoryData): AnalysisApiTestConfiguratorService {
requireSupported(data)
return when (data.moduleKind) {
TestModuleKind.Source -> when (data.analysisSessionMode) {
AnalysisSessionMode.Normal -> StandaloneModeConfiguratorService
AnalysisSessionMode.Dependent -> unsupportedModeError(data)
}
else -> {
unsupportedModeError(data)
}
}
}
override fun supportMode(data: AnalysisApiTestConfiguratorFactoryData): Boolean {
return when {
data.frontend != FrontendKind.Fir -> false
data.analysisSessionMode != AnalysisSessionMode.Normal -> false
data.analysisApiMode != AnalysisApiMode.Standalone -> false
else -> when (data.moduleKind) {
TestModuleKind.Source -> true
TestModuleKind.LibraryBinary,
TestModuleKind.LibrarySource -> false
}
}
}
}
@@ -1,3 +1,5 @@
// DISABLE_DEPENDED_MODE
class Generic<T> {
inner class Nested
}
@@ -8,3 +10,4 @@ class C {
class Foo
@@ -24,9 +24,7 @@ interface AnalysisApiTestConfiguratorService {
val analyseInDependentSession: Boolean
fun TestConfigurationBuilder.configureTest(disposable: Disposable)
fun processTestFiles(files: List<KtFile>): List<KtFile> = files
fun getOriginalFile(file: KtFile): KtFile = file
fun registerProjectServices(
project: MockProject,
compilerConfig: CompilerConfiguration,
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2022 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.analysis.test.framework
abstract class AnalysisApiTestConfiguratorFactory {
abstract fun createConfigurator(data: AnalysisApiTestConfiguratorFactoryData): AnalysisApiTestConfiguratorService
abstract fun supportMode(data: AnalysisApiTestConfiguratorFactoryData): Boolean
protected fun requireSupported(data: AnalysisApiTestConfiguratorFactoryData) {
if (!supportMode(data)) {
unsupportedModeError(data)
}
}
protected fun unsupportedModeError(data: AnalysisApiTestConfiguratorFactoryData): Nothing {
error("${this::class} is does not support $data")
}
}
data class AnalysisApiTestConfiguratorFactoryData(
val frontend: FrontendKind,
val moduleKind: TestModuleKind,
val analysisSessionMode: AnalysisSessionMode,
val analysisApiMode: AnalysisApiMode,
)
enum class AnalysisSessionMode(val suffix: String) {
Normal("Normal"),
Dependent("Dependent");
}
enum class AnalysisApiMode(val suffix: String) {
Ide("Ide"),
Standalone("Standalone");
}
enum class FrontendKind(val suffix: String) {
Fir("Fir"),
Fe10("Fe10"),
}
enum class TestModuleKind(val suffix: String) {
Source("Source"),
LibraryBinary("LibraryBinary"),
LibrarySource("LibrarySource");
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2022 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.analysis.test.framework
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
object AnalysisApiTestDirectives : SimpleDirectivesContainer() {
val DISABLE_DEPENDED_MODE by directive("Analysis in dependent mode should not be run in this test")
}
@@ -9,12 +9,14 @@ import com.intellij.mock.MockApplication
import com.intellij.mock.MockProject
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Disposer
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.TestDataFile
import junit.framework.ComparisonFailure
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.analyseInDependedAnalysisSession
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
import org.jetbrains.kotlin.analysis.test.framework.TestWithDisposable
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KotlinProjectStructureProviderTestImpl
import org.jetbrains.kotlin.analysis.test.framework.project.structure.TestKtModuleProvider
@@ -58,6 +60,9 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
protected lateinit var testDataPath: Path
private set
private lateinit var moduleStructure: TestModuleStructure
private set
protected open fun configureTest(builder: TestConfigurationBuilder) {
with(configurator) {
builder.configureTest(disposable)
@@ -122,6 +127,7 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
useAdditionalService(::TestKtModuleProvider)
useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
useDirectives(AnalysisApiTestDirectives)
configureTest(this)
startingArtifactFactory = { ResultingArtifact.Source() }
@@ -144,6 +150,7 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
path,
testConfiguration.directives,
)
this.moduleStructure = moduleStructure
val singleModule = moduleStructure.modules.single()
val project = try {
testServices.compilerConfigurationProvider.getProject(singleModule)
@@ -193,10 +200,12 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
}
protected fun <R> analyseForTest(contextElement: KtElement, action: KtAnalysisSession.() -> R): R {
return if (configurator.analyseInDependentSession) {
require(!contextElement.isPhysical)
val originalFile = configurator.getOriginalFile(contextElement.containingKtFile)
analyseInDependedAnalysisSession(originalFile, contextElement, action)
return if (configurator.analyseInDependentSession
&& AnalysisApiTestDirectives.DISABLE_DEPENDED_MODE !in this.moduleStructure.allDirectives
) {
val originalContainingFile = contextElement.containingKtFile
val fileCopy = originalContainingFile.copy() as KtFile
analyseInDependedAnalysisSession(originalContainingFile, PsiTreeUtil.findSameElementInCopy(contextElement, fileCopy), action)
} else {
analyse(contextElement, action)
}
@@ -217,8 +226,4 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
tags = testInfo.tags
)
}
companion object {
val DISABLE_DEPENDED_MODE_DIRECTIVE = "DISABLE_DEPENDED_MODE"
}
}
@@ -30,18 +30,6 @@ object FirLowLevelAnalysisApiTestConfiguratorService : AnalysisApiTestConfigurat
usePreAnalysisHandlers(::ModuleRegistrarPreAnalysisHandler.bind(disposable, false))
}
override fun processTestFiles(files: List<KtFile>): List<KtFile> {
return files.map {
val fakeFile = it.copy() as KtFile
fakeFile.originalKtFile = it
fakeFile
}
}
override fun getOriginalFile(file: KtFile): KtFile {
return file.originalKtFile!!
}
override fun registerProjectServices(
project: MockProject,
compilerConfig: CompilerConfiguration,