FIR IDE: move analysis api fir generator to the analysis directory
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
application
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":compiler:resolution.common"))
|
||||
implementation(project(":compiler:fir:tree"))
|
||||
implementation(project(":compiler:fir:tree:tree-generator"))
|
||||
implementation(project(":compiler:fir:checkers:checkers-component-generator"))
|
||||
implementation(project(":analysis:analysis-api"))
|
||||
|
||||
implementation(project(":kotlin-reflect"))
|
||||
implementation(project(":kotlin-reflect-api"))
|
||||
|
||||
/*
|
||||
We do not need guava in the generator, but because of a bug in the IJ project importing, we need to have a dependency on intellijCoreDep
|
||||
the same as it is in `:fir:tree:tree-generator` module to the project be imported correctly
|
||||
*/
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
|
||||
|
||||
implementation(project(":compiler:psi"))
|
||||
}
|
||||
|
||||
val writeCopyright by task<tasks.WriteCopyrightToFile> {
|
||||
outputFile.set(file("$buildDir/copyright/notice.txt"))
|
||||
commented.set(true)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClassName = "org.jetbrains.kotlin.analysis.api.fir.generator.MainKt"
|
||||
}
|
||||
|
||||
val processResources by tasks
|
||||
processResources.dependsOn(writeCopyright)
|
||||
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("$buildDir/copyright")
|
||||
}
|
||||
"test" {}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.getGenerationPath
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.rendererrs.FirDiagnosticToKtDiagnosticConverterRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.rendererrs.KtDiagnosticClassImplementationRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.rendererrs.KtDiagnosticClassRenderer
|
||||
import java.nio.file.Path
|
||||
|
||||
object DiagnosticClassGenerator {
|
||||
fun generate(rootPath: Path, diagnosticList: DiagnosticList, packageName: String) {
|
||||
val path = getGenerationPath(rootPath.toFile(), packageName)
|
||||
KtDiagnosticClassRenderer.render(path.resolve("KtFirDiagnostics.kt"), diagnosticList, packageName)
|
||||
KtDiagnosticClassImplementationRenderer.render(path.resolve("KtFirDiagnosticsImpl.kt"), diagnosticList, packageName)
|
||||
FirDiagnosticToKtDiagnosticConverterRenderer.render(path.resolve("KtFirDataClassConverters.kt"), diagnosticList, packageName)
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticData
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter
|
||||
import kotlin.reflect.KType
|
||||
|
||||
data class HLDiagnostic(
|
||||
val original: DiagnosticData,
|
||||
val severity: Severity?,
|
||||
val className: String,
|
||||
val implClassName: String,
|
||||
val parameters: List<HLDiagnosticParameter>,
|
||||
)
|
||||
|
||||
data class HLDiagnosticList(val diagnostics: List<HLDiagnostic>)
|
||||
|
||||
data class HLDiagnosticParameter(
|
||||
val original: DiagnosticParameter,
|
||||
val name: String,
|
||||
val type: KType,
|
||||
val originalParameterName: String,
|
||||
val conversion: HLParameterConversion,
|
||||
val importsToAdd: List<String>
|
||||
)
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.createType
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
object HLDiagnosticConverter {
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun convert(diagnosticList: DiagnosticList): HLDiagnosticList {
|
||||
return HLDiagnosticList(diagnosticList.allDiagnostics.flatMap(::convertDiagnostic))
|
||||
}
|
||||
|
||||
private fun convertDiagnostic(diagnostic: DiagnosticData): List<HLDiagnostic> {
|
||||
return when (diagnostic){
|
||||
is RegularDiagnosticData -> listOf(
|
||||
HLDiagnostic(
|
||||
original = diagnostic,
|
||||
severity = null,
|
||||
className = diagnostic.getHLDiagnosticClassName(),
|
||||
implClassName = diagnostic.getHLDiagnosticImplClassName(),
|
||||
parameters = diagnostic.parameters.mapIndexed(::convertParameter)
|
||||
)
|
||||
)
|
||||
is DeprecationDiagnosticData -> listOf(Severity.ERROR, Severity.WARNING).map {
|
||||
HLDiagnostic(
|
||||
original = diagnostic,
|
||||
severity = it,
|
||||
className = diagnostic.getHLDiagnosticClassName(it),
|
||||
implClassName = diagnostic.getHLDiagnosticImplClassName(it),
|
||||
parameters = diagnostic.parameters.mapIndexed(::convertParameter)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertParameter(index: Int, diagnosticParameter: DiagnosticParameter): HLDiagnosticParameter {
|
||||
val conversion = FirToKtConversionCreator.createConversion(diagnosticParameter.type)
|
||||
val convertedType = conversion.convertType(diagnosticParameter.type)
|
||||
return HLDiagnosticParameter(
|
||||
name = diagnosticParameter.name,
|
||||
conversion = conversion,
|
||||
originalParameterName = ('a' + index).toString(),
|
||||
type = convertedType,
|
||||
original = diagnosticParameter,
|
||||
importsToAdd = conversion.importsToAdd
|
||||
)
|
||||
}
|
||||
|
||||
private fun RegularDiagnosticData.getHLDiagnosticClassName(): String = name.sanitizeName()
|
||||
|
||||
private fun RegularDiagnosticData.getHLDiagnosticImplClassName(): String =
|
||||
"${getHLDiagnosticClassName()}Impl"
|
||||
|
||||
private fun DeprecationDiagnosticData.getHLDiagnosticClassName(severity: Severity): String {
|
||||
val diagnosticName = "${name}_${severity.name}"
|
||||
return diagnosticName.sanitizeName()
|
||||
}
|
||||
|
||||
private fun DeprecationDiagnosticData.getHLDiagnosticImplClassName(severity: Severity): String {
|
||||
return "${getHLDiagnosticClassName(severity)}Impl"
|
||||
}
|
||||
|
||||
private fun String.sanitizeName(): String =
|
||||
lowercase()
|
||||
.split('_')
|
||||
.joinToString(separator = "") {
|
||||
it.replaceFirstChar(Char::uppercaseChar)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private object FirToKtConversionCreator {
|
||||
fun createConversion(type: KType): HLParameterConversion {
|
||||
val nullable = type.isMarkedNullable
|
||||
val kClass = type.classifier as KClass<*>
|
||||
return tryMapAllowedType(kClass)
|
||||
?: tryMapPsiElementType(kClass)
|
||||
?: tryMapFirTypeToKtType(kClass, nullable)
|
||||
?: tryMapPlatformType(type, kClass)
|
||||
?: error("Unsupported type $type, consider add corresponding mapping")
|
||||
}
|
||||
|
||||
private fun tryMapFirTypeToKtType(kClass: KClass<*>, nullable: Boolean): HLParameterConversion? {
|
||||
return if (nullable) {
|
||||
nullableTypeMapping[kClass] ?: typeMapping[kClass]
|
||||
} else {
|
||||
typeMapping[kClass]
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryMapAllowedType(kClass: KClass<*>): HLParameterConversion? {
|
||||
if (kClass in allowedTypesWithoutTypeParams) return HLIdParameterConversion
|
||||
return null
|
||||
}
|
||||
|
||||
private fun KType.toParameterName(): String {
|
||||
return kClass.simpleName!!.replaceFirstChar(Char::lowercaseChar)
|
||||
}
|
||||
|
||||
private fun tryMapPlatformType(type: KType, kClass: KClass<*>): HLParameterConversion? {
|
||||
if (kClass.isSubclassOf(Collection::class)) {
|
||||
val elementType = type.arguments.single().type ?: return HLIdParameterConversion
|
||||
return HLCollectionParameterConversion(
|
||||
parameterName = elementType.toParameterName(),
|
||||
mappingConversion = createConversion(elementType)
|
||||
)
|
||||
}
|
||||
if (kClass.isSubclassOf(Map::class)) {
|
||||
val keyType = type.arguments.getOrNull(0)?.type
|
||||
val valueType = type.arguments.getOrNull(1)?.type
|
||||
|
||||
val keyConversion = keyType?.let { createConversion(it) } ?: HLIdParameterConversion
|
||||
val valueConversion = valueType?.let { createConversion(it) } ?: HLIdParameterConversion
|
||||
if (keyConversion.isTrivial && valueConversion.isTrivial) return HLIdParameterConversion
|
||||
return HLMapParameterConversion(
|
||||
keyName = keyType?.toParameterName() ?: "key",
|
||||
valueName = valueType?.toParameterName() ?: "value",
|
||||
mappingConversionForKeys = keyConversion,
|
||||
mappingConversionForValues = valueConversion
|
||||
)
|
||||
}
|
||||
if (kClass.isSubclassOf(Pair::class)) {
|
||||
val first = type.arguments.getOrNull(0)?.type ?: return HLIdParameterConversion
|
||||
val second = type.arguments.getOrNull(1)?.type ?: return HLIdParameterConversion
|
||||
return HLPairParameterConversion(
|
||||
mappingConversionFirst = createConversion(first),
|
||||
mappingConversionSecond = createConversion(second)
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun tryMapPsiElementType(kClass: KClass<*>): HLParameterConversion? {
|
||||
if (kClass.isSubclassOf(PsiElement::class)) {
|
||||
return HLIdParameterConversion
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private val nullableTypeMapping: Map<KClass<*>, HLFunctionCallConversion> = mapOf(
|
||||
FirExpression::class to HLFunctionCallConversion(
|
||||
"{0}?.source?.psi as? KtExpression",
|
||||
KtExpression::class.createType(nullable = true),
|
||||
importsToAdd = listOf(
|
||||
"org.jetbrains.kotlin.psi.KtExpression",
|
||||
"org.jetbrains.kotlin.fir.psi"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
private val typeMapping: Map<KClass<*>, HLFunctionCallConversion> = mapOf(
|
||||
FirBasedSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0}.fir)",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration")
|
||||
),
|
||||
FirClass::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0})",
|
||||
KtClassLikeSymbol::class.createType()
|
||||
),
|
||||
FirClassSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}.fir)",
|
||||
KtClassLikeSymbol::class.createType()
|
||||
),
|
||||
FirRegularClass::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}) as KtNamedClassOrObjectSymbol",
|
||||
KtNamedClassOrObjectSymbol::class.createType(),
|
||||
importsToAdd = listOf(
|
||||
"org.jetbrains.kotlin.fir.declarations.FirRegularClass",
|
||||
"org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol"
|
||||
)
|
||||
),
|
||||
FirExpression::class to HLFunctionCallConversion(
|
||||
"{0}.source!!.psi as KtExpression",
|
||||
KtExpression::class.createType(),
|
||||
importsToAdd = listOf(
|
||||
"org.jetbrains.kotlin.psi.KtExpression",
|
||||
"org.jetbrains.kotlin.fir.psi"
|
||||
)
|
||||
),
|
||||
FirQualifiedAccess::class to HLFunctionCallConversion(
|
||||
"{0}.source!!.psi as KtExpression",
|
||||
KtExpression::class.createType(),
|
||||
importsToAdd = listOf(
|
||||
"org.jetbrains.kotlin.psi.KtExpression",
|
||||
"org.jetbrains.kotlin.fir.psi"
|
||||
)
|
||||
),
|
||||
FirValueParameter::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0})",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration")
|
||||
),
|
||||
FirValueParameterSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0}.fir)",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration")
|
||||
),
|
||||
FirEnumEntrySymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0}.fir)",
|
||||
KtSymbol::class.createType(),
|
||||
),
|
||||
FirClassLikeSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}.fir as FirClass)",
|
||||
KtClassLikeSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirClass")
|
||||
),
|
||||
FirRegularClassSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}.fir)",
|
||||
KtClassLikeSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirRegularClass")
|
||||
),
|
||||
FirMemberDeclaration::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0} as FirDeclaration)",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration")
|
||||
),
|
||||
FirCallableDeclaration::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.callableBuilder.buildCallableSymbol({0} as FirCallableDeclaration)",
|
||||
KtCallableSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration")
|
||||
),
|
||||
FirCallableSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.callableBuilder.buildCallableSymbol({0}.fir)",
|
||||
KtCallableSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration")
|
||||
),
|
||||
FirTypeParameterSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol({0}.fir)",
|
||||
KtTypeParameterSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirTypeParameter")
|
||||
),
|
||||
FirTypeParameter::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol({0}.fir)",
|
||||
KtTypeParameterSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirTypeParameter")
|
||||
),
|
||||
ConeKotlinType::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.typeBuilder.buildKtType({0})",
|
||||
KtType::class.createType()
|
||||
),
|
||||
FirTypeRef::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.typeBuilder.buildKtType({0})",
|
||||
KtType::class.createType()
|
||||
),
|
||||
FirPropertySymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.variableLikeBuilder.buildVariableSymbol({0}.fir)",
|
||||
KtVariableSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirProperty")
|
||||
),
|
||||
FirBackingFieldSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.variableLikeBuilder.buildVariableSymbol({0}.fir.propertySymbol.fir)",
|
||||
KtVariableSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirProperty")
|
||||
),
|
||||
FirVariableSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.variableLikeBuilder.buildVariableLikeSymbol({0}.fir)",
|
||||
KtVariableLikeSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirVariable")
|
||||
),
|
||||
FirDeclaration::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0})",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration")
|
||||
),
|
||||
FirSimpleFunction::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.buildSymbol({0})",
|
||||
KtSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirSimpleFunction")
|
||||
),
|
||||
FirNamedFunctionSymbol::class to HLFunctionCallConversion(
|
||||
"firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol({0}.fir)",
|
||||
KtFunctionLikeSymbol::class.createType(),
|
||||
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirSimpleFunction")
|
||||
),
|
||||
FirSourceElement::class to HLFunctionCallConversion(
|
||||
"({0} as FirPsiSourceElement).psi",
|
||||
PsiElement::class.createType(),
|
||||
importsToAdd = listOf(
|
||||
"org.jetbrains.kotlin.fir.psi",
|
||||
"org.jetbrains.kotlin.fir.FirPsiSourceElement"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private val allowedTypesWithoutTypeParams = setOf(
|
||||
Boolean::class,
|
||||
String::class,
|
||||
Int::class,
|
||||
Name::class,
|
||||
EventOccurrencesRange::class,
|
||||
KtKeywordToken::class,
|
||||
KtModifierKeywordToken::class,
|
||||
Visibility::class,
|
||||
EffectiveVisibility::class,
|
||||
WhenMissingCase::class,
|
||||
ForbiddenNamedArgumentsTarget::class,
|
||||
LanguageFeature::class,
|
||||
LanguageVersionSettings::class,
|
||||
Variance::class,
|
||||
FqName::class,
|
||||
ClassId::class,
|
||||
FirModuleData::class,
|
||||
ExpectActualCompatibility.Incompatible::class,
|
||||
DeprecationInfo::class,
|
||||
)
|
||||
|
||||
private val KType.kClass: KClass<*>
|
||||
get() = classifier as KClass<*>
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.KTypeProjection
|
||||
import kotlin.reflect.KVariance
|
||||
import kotlin.reflect.full.createType
|
||||
|
||||
sealed class HLParameterConversion {
|
||||
abstract fun convertExpression(expression: String, context: ConversionContext): String
|
||||
abstract fun convertType(type: KType): KType
|
||||
open val importsToAdd: List<String> get() = emptyList()
|
||||
}
|
||||
|
||||
object HLIdParameterConversion : HLParameterConversion() {
|
||||
override fun convertExpression(expression: String, context: ConversionContext) = expression
|
||||
override fun convertType(type: KType): KType = type
|
||||
}
|
||||
|
||||
class HLCollectionParameterConversion(
|
||||
private val parameterName: String,
|
||||
private val mappingConversion: HLParameterConversion,
|
||||
) : HLParameterConversion() {
|
||||
override fun convertExpression(expression: String, context: ConversionContext): String {
|
||||
val innerExpression = mappingConversion.convertExpression(parameterName, context.increaseIndent())
|
||||
return buildString {
|
||||
appendLine("$expression.map { $parameterName ->")
|
||||
appendLine(innerExpression.withIndent(context.increaseIndent()))
|
||||
append("}".withIndent(context))
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertType(type: KType): KType =
|
||||
List::class.createType(
|
||||
arguments = listOf(
|
||||
KTypeProjection(
|
||||
variance = KVariance.INVARIANT,
|
||||
type = type.arguments.single().type?.let(mappingConversion::convertType)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
override val importsToAdd get() = mappingConversion.importsToAdd
|
||||
}
|
||||
|
||||
class HLMapParameterConversion(
|
||||
private val keyName: String,
|
||||
private val valueName: String,
|
||||
private val mappingConversionForKeys: HLParameterConversion,
|
||||
private val mappingConversionForValues: HLParameterConversion,
|
||||
) : HLParameterConversion() {
|
||||
override fun convertExpression(expression: String, context: ConversionContext): String {
|
||||
val keyTransformation = mappingConversionForKeys.convertExpression(keyName, context.increaseIndent())
|
||||
val valueTransformation = mappingConversionForValues.convertExpression(valueName, context.increaseIndent())
|
||||
return buildString {
|
||||
appendLine("$expression.mapKeys { ($keyName, _) ->")
|
||||
appendLine(keyTransformation.withIndent(context.increaseIndent()))
|
||||
appendLine("}.mapValues { (_, $valueName) -> ".withIndent(context))
|
||||
appendLine(valueTransformation.withIndent(context.increaseIndent()))
|
||||
append("}".withIndent(context))
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertType(type: KType): KType {
|
||||
val keyArgument = type.arguments[0]
|
||||
val valueArgument = type.arguments[1]
|
||||
return Map::class.createType(
|
||||
arguments = listOf(
|
||||
KTypeProjection(
|
||||
variance = KVariance.INVARIANT,
|
||||
type = keyArgument.type?.let(mappingConversionForKeys::convertType)
|
||||
),
|
||||
KTypeProjection(
|
||||
variance = KVariance.INVARIANT,
|
||||
type = valueArgument.type?.let(mappingConversionForValues::convertType)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override val importsToAdd: List<String>
|
||||
get() = (mappingConversionForKeys.importsToAdd + mappingConversionForValues.importsToAdd).distinct()
|
||||
}
|
||||
|
||||
class HLPairParameterConversion(
|
||||
private val mappingConversionFirst: HLParameterConversion,
|
||||
private val mappingConversionSecond: HLParameterConversion,
|
||||
) : HLParameterConversion() {
|
||||
override fun convertExpression(expression: String, context: ConversionContext): String {
|
||||
if (mappingConversionFirst.isTrivial && mappingConversionSecond.isTrivial) {
|
||||
return expression
|
||||
}
|
||||
val first = mappingConversionFirst.convertExpression("$expression.first", context)
|
||||
val second = mappingConversionSecond.convertExpression("$expression.second", context)
|
||||
return "$first to $second"
|
||||
}
|
||||
|
||||
override fun convertType(type: KType): KType {
|
||||
val first = type.arguments.getOrNull(0)?.type ?: return type
|
||||
val second = type.arguments.getOrNull(1)?.type ?: return type
|
||||
return Pair::class.createType(
|
||||
arguments = listOf(
|
||||
KTypeProjection(
|
||||
variance = KVariance.INVARIANT,
|
||||
type = mappingConversionFirst.convertType(first)
|
||||
),
|
||||
KTypeProjection(
|
||||
variance = KVariance.INVARIANT,
|
||||
type = mappingConversionSecond.convertType(second)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override val importsToAdd
|
||||
get() = mappingConversionFirst.importsToAdd + mappingConversionSecond.importsToAdd
|
||||
}
|
||||
|
||||
class HLFunctionCallConversion(
|
||||
private val callTemplate: String,
|
||||
private val callType: KType,
|
||||
override val importsToAdd: List<String> = emptyList()
|
||||
) : HLParameterConversion() {
|
||||
override fun convertExpression(expression: String, context: ConversionContext) =
|
||||
callTemplate.replace("{0}", expression)
|
||||
|
||||
override fun convertType(type: KType): KType = callType
|
||||
}
|
||||
|
||||
data class ConversionContext(val currentIndent: Int, val indentUnitValue: Int) {
|
||||
fun increaseIndent() = copy(currentIndent = currentIndent + 1)
|
||||
}
|
||||
|
||||
private fun String.withIndent(context: ConversionContext): String {
|
||||
val newIndent = " ".repeat(context.currentIndent * context.indentUnitValue)
|
||||
return replaceIndent(newIndent)
|
||||
}
|
||||
|
||||
val HLParameterConversion.isTrivial: Boolean
|
||||
get() = this is HLIdParameterConversion
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.DIAGNOSTICS_LIST
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.JVM_DIAGNOSTICS_LIST
|
||||
import java.nio.file.Paths
|
||||
|
||||
fun main() {
|
||||
val rootPath = Paths.get("idea/idea-frontend-fir/src").toAbsolutePath()
|
||||
val packageName = "org.jetbrains.kotlin.analysis.api.fir.diagnostics"
|
||||
DiagnosticClassGenerator.generate(rootPath, DIAGNOSTICS_LIST + JVM_DIAGNOSTICS_LIST, packageName)
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator
|
||||
|
||||
import org.jetbrains.kotlin.util.SmartPrinter
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
internal fun SmartPrinter.printTypeWithShortNames(type: KType, shouldRenderFqName: (KType) -> Boolean = { false }) {
|
||||
fun typeConversion(type: KType): String {
|
||||
val nullableSuffix = if (type.isMarkedNullable) "?" else ""
|
||||
val simpleName = if (shouldRenderFqName(type)) {
|
||||
type.qualifiedName
|
||||
} else {
|
||||
type.simpleName
|
||||
}
|
||||
return if (type.arguments.isEmpty()) simpleName + nullableSuffix
|
||||
else simpleName + type.arguments.joinToString(separator = ", ", prefix = "<", postfix = ">") {
|
||||
when (val typeArgument = it.type) {
|
||||
null -> "*"
|
||||
else -> typeConversion(typeArgument)
|
||||
} + nullableSuffix
|
||||
}
|
||||
}
|
||||
print(typeConversion(type))
|
||||
}
|
||||
|
||||
val KType.simpleName: String
|
||||
get() = (classifier as KClass<*>).simpleName!!
|
||||
|
||||
val KType.qualifiedName: String
|
||||
get() = (classifier as KClass<*>).qualifiedName!!
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator.rendererrs
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.collectClassNamesTo
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticListRenderer
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.printImports
|
||||
import org.jetbrains.kotlin.fir.tree.generator.printer.printCopyright
|
||||
import org.jetbrains.kotlin.fir.tree.generator.printer.printGeneratedMessage
|
||||
import org.jetbrains.kotlin.fir.tree.generator.util.writeToFileUsingSmartPrinterIfFileContentChanged
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticConverter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticList
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticParameter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.simpleName
|
||||
import org.jetbrains.kotlin.util.SmartPrinter
|
||||
import java.io.File
|
||||
import kotlin.reflect.KType
|
||||
|
||||
abstract class AbstractDiagnosticsDataClassRenderer : DiagnosticListRenderer() {
|
||||
override fun render(file: File, diagnosticList: DiagnosticList, packageName: String) {
|
||||
val hlDiagnosticsList = HLDiagnosticConverter.convert(diagnosticList)
|
||||
file.writeToFileUsingSmartPrinterIfFileContentChanged { render(hlDiagnosticsList, packageName) }
|
||||
}
|
||||
|
||||
private fun SmartPrinter.collectAndPrintImports(diagnosticList: HLDiagnosticList) {
|
||||
val imports = collectImports(diagnosticList)
|
||||
printImports(imports)
|
||||
}
|
||||
|
||||
protected fun SmartPrinter.printHeader(packageName: String, diagnosticList: HLDiagnosticList) {
|
||||
printCopyright()
|
||||
println("package $packageName")
|
||||
println()
|
||||
collectAndPrintImports(diagnosticList)
|
||||
println()
|
||||
printGeneratedMessage()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
protected fun collectImports(diagnosticList: HLDiagnosticList): Collection<String> = buildSet {
|
||||
addAll(defaultImports)
|
||||
for (diagnostic in diagnosticList.diagnostics) {
|
||||
diagnostic.original.psiType.collectClassNamesTo(this)
|
||||
diagnostic.parameters.forEach { diagnosticParameter ->
|
||||
addAll(collectImportsForDiagnosticParameter(diagnosticParameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun HLDiagnosticList.containsClashingBySimpleNameType(type: KType): Boolean {
|
||||
return diagnostics.any { it.className == type.simpleName }
|
||||
}
|
||||
|
||||
protected abstract fun collectImportsForDiagnosticParameter(diagnosticParameter: HLDiagnosticParameter): Collection<String>
|
||||
|
||||
protected abstract fun SmartPrinter.render(diagnosticList: HLDiagnosticList, packageName: String)
|
||||
|
||||
protected abstract val defaultImports: Collection<String>
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator.rendererrs
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.inBracketsWithIndent
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.ConversionContext
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticList
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticParameter
|
||||
import org.jetbrains.kotlin.util.SmartPrinter
|
||||
import org.jetbrains.kotlin.util.withIndent
|
||||
|
||||
object FirDiagnosticToKtDiagnosticConverterRenderer : AbstractDiagnosticsDataClassRenderer() {
|
||||
override fun SmartPrinter.render(diagnosticList: HLDiagnosticList, packageName: String) {
|
||||
printHeader(packageName, diagnosticList)
|
||||
printDiagnosticConverter(diagnosticList)
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticConverter(diagnosticList: HLDiagnosticList) {
|
||||
inBracketsWithIndent("internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConverter") {
|
||||
for (diagnostic in diagnosticList.diagnostics) {
|
||||
printConverter(diagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printConverter(diagnostic: HLDiagnostic) {
|
||||
print("add(${diagnostic.original.containingObjectName}.${diagnostic.original.name}")
|
||||
if (diagnostic.severity != null) {
|
||||
print(".${diagnostic.severity.name.lowercase()}Factory")
|
||||
}
|
||||
println(") { firDiagnostic ->")
|
||||
withIndent {
|
||||
println("${diagnostic.implClassName}(")
|
||||
withIndent {
|
||||
printDiagnosticParameters(diagnostic)
|
||||
}
|
||||
println(")")
|
||||
}
|
||||
println("}")
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticParameters(diagnostic: HLDiagnostic) {
|
||||
printCustomParameters(diagnostic)
|
||||
println("firDiagnostic as FirPsiDiagnostic,")
|
||||
println("token,")
|
||||
}
|
||||
|
||||
|
||||
private fun SmartPrinter.printCustomParameters(diagnostic: HLDiagnostic) {
|
||||
diagnostic.parameters.forEach { parameter ->
|
||||
printParameter(parameter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printParameter(parameter: HLDiagnosticParameter) {
|
||||
val expression = parameter.conversion.convertExpression(
|
||||
"firDiagnostic.${parameter.originalParameterName}",
|
||||
ConversionContext(getCurrentIndentInUnits(), getIndentUnit())
|
||||
)
|
||||
println("$expression,")
|
||||
}
|
||||
|
||||
override fun collectImportsForDiagnosticParameter(diagnosticParameter: HLDiagnosticParameter): Collection<String> =
|
||||
diagnosticParameter.importsToAdd
|
||||
|
||||
override val defaultImports = listOf(
|
||||
"org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic",
|
||||
"org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors",
|
||||
"org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors",
|
||||
)
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator.rendererrs
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.collectClassNamesTo
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.inBracketsWithIndent
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticList
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.HLDiagnosticParameter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.printTypeWithShortNames
|
||||
import org.jetbrains.kotlin.util.SmartPrinter
|
||||
import org.jetbrains.kotlin.util.withIndent
|
||||
|
||||
object KtDiagnosticClassImplementationRenderer : AbstractDiagnosticsDataClassRenderer() {
|
||||
override fun SmartPrinter.render(diagnosticList: HLDiagnosticList, packageName: String) {
|
||||
printHeader(packageName, diagnosticList)
|
||||
printDiagnosticClassesImplementation(diagnosticList)
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticClassesImplementation(diagnosticList: HLDiagnosticList) {
|
||||
for (diagnostic in diagnosticList.diagnostics) {
|
||||
printDiagnosticImplementation(diagnostic, diagnosticList)
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticImplementation(diagnostic: HLDiagnostic, diagnosticList: HLDiagnosticList) {
|
||||
println("internal class ${diagnostic.implClassName}(")
|
||||
withIndent {
|
||||
printParameters(diagnostic, diagnosticList)
|
||||
}
|
||||
print(") : KtFirDiagnostic.${diagnostic.className}(), KtAbstractFirDiagnostic<")
|
||||
printTypeWithShortNames(diagnostic.original.psiType)
|
||||
print(">")
|
||||
inBracketsWithIndent {
|
||||
println("override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)")
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printParameters(diagnostic: HLDiagnostic, diagnosticList: HLDiagnosticList) {
|
||||
for (parameter in diagnostic.parameters) {
|
||||
printParameter(parameter, diagnosticList)
|
||||
}
|
||||
println("firDiagnostic: FirPsiDiagnostic,")
|
||||
println("override val token: ValidityToken,")
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printParameter(parameter: HLDiagnosticParameter, diagnosticList: HLDiagnosticList) {
|
||||
print("override val ${parameter.name}: ")
|
||||
printTypeWithShortNames(parameter.type) {
|
||||
diagnosticList.containsClashingBySimpleNameType(it)
|
||||
}
|
||||
println(",")
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun collectImportsForDiagnosticParameter(diagnosticParameter: HLDiagnosticParameter): Collection<String> = buildSet {
|
||||
diagnosticParameter.type.collectClassNamesTo(this)
|
||||
}
|
||||
|
||||
override val defaultImports = listOf(
|
||||
"org.jetbrains.kotlin.analysis.api.fir.utils.weakRef",
|
||||
"org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic",
|
||||
"org.jetbrains.kotlin.analysis.api.tokens.ValidityToken",
|
||||
)
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.generator.rendererrs
|
||||
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.collectClassNamesTo
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.inBracketsWithIndent
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.*
|
||||
import org.jetbrains.kotlin.analysis.api.fir.generator.printTypeWithShortNames
|
||||
import org.jetbrains.kotlin.util.SmartPrinter
|
||||
|
||||
object KtDiagnosticClassRenderer : AbstractDiagnosticsDataClassRenderer() {
|
||||
override fun SmartPrinter.render(diagnosticList: HLDiagnosticList, packageName: String) {
|
||||
printHeader(packageName, diagnosticList)
|
||||
printDiagnosticClasses(diagnosticList)
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticClasses(diagnosticList: HLDiagnosticList) {
|
||||
inBracketsWithIndent("sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI>") {
|
||||
for (diagnostic in diagnosticList.diagnostics) {
|
||||
printDiagnosticClass(diagnostic, diagnosticList)
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticClass(diagnostic: HLDiagnostic, diagnosticList: HLDiagnosticList) {
|
||||
print("abstract class ${diagnostic.className} : KtFirDiagnostic<")
|
||||
printTypeWithShortNames(diagnostic.original.psiType)
|
||||
print(">()")
|
||||
inBracketsWithIndent {
|
||||
println("override val diagnosticClass get() = ${diagnostic.className}::class")
|
||||
printDiagnosticParameters(diagnostic, diagnosticList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printDiagnosticParameters(diagnostic: HLDiagnostic, diagnosticList: HLDiagnosticList) {
|
||||
diagnostic.parameters.forEach { parameter ->
|
||||
print("abstract val ${parameter.name}: ")
|
||||
printTypeWithShortNames(parameter.type) { type ->
|
||||
diagnosticList.containsClashingBySimpleNameType(type)
|
||||
}
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun collectImportsForDiagnosticParameter(diagnosticParameter: HLDiagnosticParameter): Collection<String> = buildSet {
|
||||
diagnosticParameter.type.collectClassNamesTo(this)
|
||||
}
|
||||
|
||||
override val defaultImports = listOf(
|
||||
"org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi",
|
||||
"com.intellij.psi.PsiElement",
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user