Compare commits

..

1 Commits

Author SHA1 Message Date
Natalia Selezneva
3614bdce27 Do not show warning when multiple Gradle Definitions are loaded
This will happen when there are multiple gradle project linked to one IDEA project
andthey have different gradle versions
2020-07-23 17:06:05 +03:00
1367 changed files with 4741 additions and 48998 deletions

View File

@@ -74,7 +74,6 @@ benchmark {
param("size", 1000)
include("CommonCallsBenchmark")
include("ControlFlowAnalysisBenchmark")
//include("InferenceBaselineCallsBenchmark")
}
@@ -112,9 +111,8 @@ tasks.named("classes") {
}
}
tasks.register<JavaExec>("runBenchmark") {
// jmhArgs example: -PjmhArgs='CommonCalls -p size=500 -p isIR=true -p useNI=true -f 1'
val jmhArgs = if (project.hasProperty("jmhArgs")) project.property("jmhArgs").toString() else ""
/*tasks.register<JavaExec>("runBenchmark") {
val jmhArgs: String by project // example: -PjmhArgs='CommonCalls -p size=500 -p isIR=true -p useNI=true -f 1'
val resultFilePath = "$buildDir/benchmarks/jmh-result.json"
val ideaHome = intellijRootDir().canonicalPath
@@ -122,6 +120,7 @@ tasks.register<JavaExec>("runBenchmark") {
args = mutableListOf("-Didea.home.path=$ideaHome", benchmarkJarPath, "-rf", "json", "-rff", resultFilePath) + jmhArgs.split("\\s".toRegex())
main = "-jar"
doLast {
if (project.kotlinBuildProperties.isTeamcityBuild) {
val jsonArray = com.google.gson.JsonParser.parseString(File(resultFilePath).readText()).asJsonArray
@@ -145,4 +144,4 @@ tasks.register<JavaExec>("runBenchmark") {
}
}
}
}
}*/

View File

@@ -1,35 +0,0 @@
/*
* Copyright 2010-2020 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.benchmarks
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.TimeUnit
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
open class ControlFlowAnalysisBenchmark : AbstractSimpleFileBenchmark() {
@Param("1000")
private var size: Int = 0
@Benchmark
fun benchmark(bh: Blackhole) {
analyzeGreenFile(bh)
}
override fun buildText() =
buildString {
appendLine("fun test() {")
for (i in 0 until size) {
appendLine("for (i$i in 0..10) { ")
}
for (i in 0 until size) {
appendLine("}")
}
appendLine("}")
}
}

View File

@@ -229,8 +229,6 @@ extra["compilerModules"] = arrayOf(
":compiler:frontend.java",
":compiler:cli-common",
":compiler:ir.tree",
":compiler:ir.tree.impl",
":compiler:ir.tree.persistent",
":compiler:ir.psi2ir",
":compiler:ir.backend.common",
":compiler:backend.jvm",
@@ -723,6 +721,11 @@ tasks {
dependsOn(":jps-plugin:test")
}
register("idea-plugin-main-tests") {
dependsOn("dist")
dependsOn(":idea:test")
}
register("idea-plugin-additional-tests") {
dependsOn("dist")
dependsOn(
@@ -748,6 +751,17 @@ tasks {
}
}
register("idea-plugin-tests") {
dependsOn("dist")
dependsOn(
"idea-plugin-main-tests",
"idea-plugin-additional-tests"
)
if (Ide.IJ()) {
dependsOn("idea-new-project-wizard-tests")
}
}
register("idea-plugin-performance-tests") {
dependsOn("dist")
dependsOn(
@@ -764,21 +778,10 @@ tasks {
)
}
register("ideaPluginTest") {
dependsOn(
"mainIdeTests",
"gradleIdeTest",
"kaptIdeTest",
"miscIdeTests"
)
}
register("mainIdeTests") {
dependsOn(":idea:test")
}
register("miscIdeTests") {
register("plugins-tests") {
dependsOn("dist")
dependsOn(
":kotlin-annotation-processing:test",
":kotlin-allopen-compiler-plugin:test",
":kotlin-noarg-compiler-plugin:test",
":kotlin-sam-with-receiver-compiler-plugin:test",
@@ -786,18 +789,30 @@ tasks {
":kotlin-annotation-processing-gradle:test",
":kotlinx-serialization-compiler-plugin:test",
":kotlinx-serialization-ide-plugin:test",
":idea:jvm-debugger:jvm-debugger-test:test",
"idea-plugin-additional-tests",
"jps-tests",
":generators:test"
":idea:jvm-debugger:jvm-debugger-test:test"
)
if (Ide.IJ()) {
dependsOn("idea-new-project-wizard-tests")
}
}
register("kaptIdeTest") {
dependsOn(":kotlin-annotation-processing:test")
register("ideaPluginTest") {
dependsOn(
"gradleIdeTest",
"androidIdeTest",
"miscIdeTests"
)
}
register("miscIdeTests") {
dependsOn(
"idea-plugin-tests",
"jps-tests",
"plugins-tests",
":generators:test"
)
}
register("androidIdeTest") {
dependsOn("android-ide-tests")
}
register("gradleIdeTest") {
@@ -807,39 +822,6 @@ tasks {
)
}
register("kmmTest", AggregateTest::class) {
dependsOn(
":idea:idea-gradle:test",
":idea:test",
":compiler:test",
":js:js.tests:test"
)
if (Ide.IJ193.orHigher())
dependsOn(":kotlin-gradle-plugin-integration-tests:test")
if (Ide.AS40.orHigher())
dependsOn(":kotlin-ultimate:ide:android-studio-native:test")
testPatternFile = file("tests/mpp/kmm-patterns.csv")
}
register("test") {
doLast {
throw GradleException("Don't use directly, use aggregate tasks *-check instead")
}
}
named("check") {
dependsOn("test")
}
named("checkBuild") {
if (kotlinBuildProperties.isTeamcityBuild) {
doFirst {
println("##teamcity[setParameter name='bootstrap.kotlin.version' value='$bootstrapKotlinVersion']")
}
}
}
register("publishIdeArtifacts") {
idePluginDependency {
dependsOn(
@@ -873,6 +855,39 @@ tasks {
)
}
}
register("kmmTest", AggregateTest::class) {
dependsOn(
":idea:idea-gradle:test",
":idea:test",
":compiler:test",
":js:js.tests:test"
)
if (Ide.IJ193.orHigher())
dependsOn(":kotlin-gradle-plugin-integration-tests:test")
if (Ide.AS40.orHigher())
dependsOn(":kotlin-ultimate:ide:android-studio-native:test")
testPatternFile = file("tests/mpp/kmm-patterns.csv")
}
register("test") {
doLast {
throw GradleException("Don't use directly, use aggregate tasks *-check instead")
}
}
named("check") {
dependsOn("test")
}
named("checkBuild") {
if (kotlinBuildProperties.isTeamcityBuild) {
doFirst {
println("##teamcity[setParameter name='bootstrap.kotlin.version' value='$bootstrapKotlinVersion']")
}
}
}
}
fun CopySpec.setExecutablePermissions() {

View File

@@ -50,9 +50,6 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getA
public abstract class AnnotationCodegen {
private static final String ORG_JETBRAINS_ANNOTATIONS_NOTNULL = Type.getType(NotNull.class).getDescriptor();
private static final String ORG_JETBRAINS_ANNOTATIONS_NULLABLE = Type.getType(Nullable.class).getDescriptor();
public static final class JvmFlagAnnotation {
private final FqName fqName;
private final int jvmFlag;
@@ -123,7 +120,7 @@ public abstract class AnnotationCodegen {
@Nullable Type returnType,
@Nullable KotlinType typeForTypeAnnotations,
@Nullable DeclarationDescriptorWithVisibility parameterContainer,
@NotNull List<String> additionalVisibleAnnotations
@NotNull List<Class<?>> additionalAnnotations
) {
if (annotated == null) return;
@@ -158,9 +155,9 @@ public abstract class AnnotationCodegen {
}
}
for (String annotation : additionalVisibleAnnotations) {
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotation, true);
annotationDescriptorsAlreadyPresent.add(annotation);
for (Class<?> annotation : additionalAnnotations) {
String descriptor = generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotation);
annotationDescriptorsAlreadyPresent.add(descriptor);
}
generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent, parameterContainer);
@@ -251,15 +248,17 @@ public abstract class AnnotationCodegen {
if (!TypeUtils.isNullableType(flexibleType.getLowerBound()) && TypeUtils.isNullableType(flexibleType.getUpperBound())) {
AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
if (notNull != null) {
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, ORG_JETBRAINS_ANNOTATIONS_NOTNULL, false);
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class);
}
return;
}
}
String annotationDescriptor =
TypeUtils.isNullableType(type) ? ORG_JETBRAINS_ANNOTATIONS_NULLABLE : ORG_JETBRAINS_ANNOTATIONS_NOTNULL;
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationDescriptor, false);
boolean isNullableType = TypeUtils.isNullableType(type);
Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
}
private static final Map<JvmTarget, Map<KotlinTarget, ElementType>> annotationTargetMaps = new EnumMap<>(JvmTarget.class);
@@ -339,14 +338,13 @@ public abstract class AnnotationCodegen {
visitor.visitEnd();
}
private void generateAnnotationIfNotPresent(
Set<String> annotationDescriptorsAlreadyPresent,
String annotationDescriptor,
boolean visible
) {
if (!annotationDescriptorsAlreadyPresent.contains(annotationDescriptor)) {
visitAnnotation(annotationDescriptor, visible).visitEnd();
@NotNull
private String generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
String descriptor = Type.getType(annotationClass).getDescriptor();
if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
visitAnnotation(descriptor, false).visitEnd();
}
return descriptor;
}
private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull KotlinType type) {

View File

@@ -83,8 +83,6 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
public class FunctionCodegen {
private static final String JAVA_LANG_DEPRECATED = Type.getType(Deprecated.class).getDescriptor();
public final GenerationState state;
private final KotlinTypeMapper typeMapper;
private final BindingContext bindingContext;
@@ -223,7 +221,7 @@ public class FunctionCodegen {
InlineClassDescriptorResolver.isSpecializedEqualsMethod(functionDescriptor);
generateMethodAnnotationsIfRequired(
functionDescriptor, asmMethod, jvmSignature, mv,
isCompatibilityStubInDefaultImpls ? Collections.singletonList(JAVA_LANG_DEPRECATED) : Collections.emptyList(),
isCompatibilityStubInDefaultImpls ? Collections.singletonList(Deprecated.class) : Collections.emptyList(),
skipNullabilityAnnotations
);
GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0);
@@ -287,7 +285,7 @@ public class FunctionCodegen {
@NotNull Method asmMethod,
@NotNull JvmMethodGenericSignature jvmSignature,
@NotNull MethodVisitor mv,
@NotNull List<String> additionalVisibleAnnotations,
@NotNull List<Class<?>> additionalNoArgAnnotations,
boolean skipNullabilityAnnotations
) {
FunctionDescriptor annotationsOwner;
@@ -304,7 +302,7 @@ public class FunctionCodegen {
}
AnnotationCodegen.forMethod(mv, memberCodegen, state, skipNullabilityAnnotations)
.genAnnotations(annotationsOwner, asmMethod.getReturnType(), functionDescriptor.getReturnType(), null, additionalVisibleAnnotations);
.genAnnotations(annotationsOwner, asmMethod.getReturnType(), functionDescriptor.getReturnType(), null, additionalNoArgAnnotations);
generateParameterAnnotations(
annotationsOwner, mv, jvmSignature,

View File

@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
class JvmRuntimeTypes(
module: ModuleDescriptor,
@@ -98,14 +96,6 @@ class JvmRuntimeTypes(
else
descriptor
if (actualFunctionDescriptor.returnType == null)
throw KotlinExceptionWithAttachments(
"Return type for function description is null. Super type cannot be calculated." +
"initDesc=${descriptor}, actDesc=${actualFunctionDescriptor}, isReleaseCoroutines=${
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
}"
)
val functionType = createFunctionType(
descriptor.builtIns,
Annotations.EMPTY,

View File

@@ -726,7 +726,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
public SourceMapper getOrCreateSourceMapper() {
if (sourceMapper == null) {
// note: this is used in InlineCodegen and the element is always physical (KtElement) there
sourceMapper = new SourceMapper(SourceInfo.Companion.createFromPsi((KtElement)element, getClassName()));
sourceMapper = new SourceMapper(SourceInfo.Companion.createInfo((KtElement)element, getClassName()));
}
return sourceMapper;
}

View File

@@ -21,26 +21,28 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
data class SourceInfo(
val sourceFileName: String?,
val pathOrCleanFQN: String,
val linesInFile: Int
) {
data class SourceInfo(val source: String, val pathOrCleanFQN: String, val linesInFile: Int) {
companion object {
fun createFromPsi(element: KtElement?, internalClassName: String): SourceInfo {
fun createInfo(element: KtElement?, internalClassName: String): SourceInfo {
assert(element != null) { "Couldn't create source mapper for null element $internalClassName" }
val lineNumbers = CodegenUtil.getLineNumberForElement(element!!.containingFile, true)
?: error("Couldn't extract line count in ${element.containingFile}")
?: error("Couldn't extract line count in ${element.containingFile}")
//TODO hack condition for package parts cleaning
val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
val fileName = element.containingKtFile.name
return SourceInfo(fileName, cleanedClassFqName, lineNumbers)
return SourceInfo(element.containingKtFile.name, cleanedClassFqName, lineNumbers)
}
fun createInfoForIr(lineNumbers: Int, internalClassName: String, containingFileName: String): SourceInfo {
//TODO cut topLevel names
// val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
// val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
return SourceInfo(containingFileName, internalClassName, lineNumbers)
}
}
}

View File

@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -27,8 +28,10 @@ import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -230,7 +233,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
)
val sourceInfo = sourceMapper.sourceInfo!!
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.sourceFileName!!, sourceInfo.pathOrCleanFQN)
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.source, sourceInfo.pathOrCleanFQN)
val inliner = MethodInliner(
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
"Method inlining " + sourceCompiler.callElementText,

View File

@@ -85,14 +85,9 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
get() = fileMappings.values.toList()
init {
sourceInfo?.let { sourceInfo ->
// If 'sourceFileName' is null, this class doesn't have debug information
// (e.g., multi-file class facade with multiple parts).
sourceInfo.sourceFileName?.let { sourceFileName ->
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce fewer ranges.
getOrRegisterNewSource(sourceFileName, sourceInfo.pathOrCleanFQN)
.mapNewInterval(1, 1, sourceInfo.linesInFile)
}
sourceInfo?.let {
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce fewer ranges.
getOrRegisterNewSource(it.source, it.pathOrCleanFQN).mapNewInterval(1, 1, it.linesInFile)
}
}

View File

@@ -31,9 +31,6 @@ dependencies {
compile(project(":kotlin-util-io"))
compile(project(":compiler:ir.serialization.common"))
// TODO: as soon as cli-jvm is extracted out of this module, move this dependency there
compileOnly(project(":compiler:ir.tree.impl"))
compileOnly(toolsJarApi())
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) }

View File

@@ -6,7 +6,6 @@ plugins {
dependencies {
compile(project(":compiler:cli"))
compile(project(":compiler:ir.serialization.js"))
compileOnly(project(":compiler:ir.tree.persistent"))
runtimeOnly(project(":kotlin-reflect"))
if (Platform[193].orLower()) {
compile(intellijDep()) { includeJars("picocontainer", rootProject = rootProject) }

View File

@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.psi.KtFile
@@ -88,7 +87,6 @@ fun buildKLib(
configuration = configuration,
allDependencies = allDependencies,
friendDependencies = emptyList(),
irFactory = PersistentIrFactory,
outputKlibPath = outputPath,
nopack = true
)

View File

@@ -24,17 +24,13 @@ import org.jetbrains.kotlin.cli.common.messages.MessageUtil
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
@@ -197,7 +193,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configuration = config.configuration,
allDependencies = resolvedLibraries,
friendDependencies = friendDependencies,
irFactory = PersistentIrFactory,
outputKlibPath = outputKlibPath,
nopack = arguments.irProduceKlibDir
)

View File

@@ -71,7 +71,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveProcessor
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.ir.backend.jvm.jvmResolveLibraries
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.modules.Module
@@ -379,8 +378,9 @@ object KotlinToJVMBytecodeCompiler {
val (moduleFragment, symbolTable, sourceManager, components) =
Fir2IrConverter.createModuleFragment(
session, resolveTransformer.scopeSession, firFiles,
moduleConfiguration.languageVersionSettings, signaturer,
JvmGeneratorExtensions(), FirJvmKotlinMangler(session), IrFactoryImpl
moduleConfiguration.languageVersionSettings, signaturer = signaturer,
generatorExtensions = JvmGeneratorExtensions(),
mangler = FirJvmKotlinMangler(session)
)
performanceManager?.notifyIRTranslationFinished(ktFiles.size, codeLines, debugTargetDescription)

View File

@@ -52,7 +52,7 @@ fun foo() {
val piFloat: <!REDUNDANT_EXPLICIT_TYPE!>Float<!> = 3.14f
val piDouble: <!REDUNDANT_EXPLICIT_TYPE!>Double<!> = 3.14
val charZ: <!REDUNDANT_EXPLICIT_TYPE!>Char<!> = 'z'
<!CAN_BE_VAL!>var<!> alpha: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 0
var alpha: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 0
}
fun test(boolean: Boolean) {

View File

@@ -4,7 +4,7 @@ fun f() {
<!REDUNDANT_VISIBILITY_MODIFIER!>internal<!> var foo = 0
}
LocalClass().foo = 1
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> <!CAN_BE_VAL!>var<!> baz = 0
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> var baz = 0
}
internal inline fun internal() {

View File

@@ -1,187 +0,0 @@
// WITH_RUNTIME
import kotlin.reflect.KProperty
import kotlin.properties.Delegates
fun testDelegator() {
var x: Boolean by LocalFreezableVar(true)
var y by LocalFreezableVar("")
}
class LocalFreezableVar<T>(private var value: T) {
operator fun getValue(thisRef: Nothing?, property: KProperty<*>): T = value
operator fun setValue(thisRef: Nothing?, property: KProperty<*>, value: T) {
this.value = value
}
}
class C
operator fun C.plus(a: Any): C = this
operator fun C.plusAssign(a: Any) {}
fun testOperatorAssignment() {
val c = C()
c += ""
<!CAN_BE_VAL!>var<!> c1 = C()
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
var a = 1
a += 12
a -= 10
}
fun destructuringDeclaration() {
<!CAN_BE_VAL!>var<!> (v1, v2) = getPair()
print(v1)
var (v3, v4) = getPair()
print(v3)
v4 = ""
var (v5, v6) = getPair()
v5 = 1
var (v7, v8) = getPair()
v7 = 2
v8 = "42"
val (a, b, c) = Triple(1, 1, 1)
<!CAN_BE_VAL!>var<!> (x, y, z) = Triple(1, 1, 1)
}
fun stackOverflowBug() {
<!CAN_BE_VAL!>var<!> a: Int
a = 1
for (i in 1..10)
print(i)
}
fun smth(flag: Boolean) {
var a = 1
if (flag) {
while (a > 0) {
a--
}
}
}
fun withAnnotation(p: List<Any>) {
@Suppress("UNCHECKED_CAST")
<!CAN_BE_VAL!>var<!> v = p as List<String>
print(v)
}
fun withReadonlyDeligate() {
val s: String by lazy { "Hello!" }
s.hashCode()
}
fun getPair(): Pair<Int, String> = Pair(1, "1")
fun listReceiver(p: List<String>) {}
fun withInitializer() {
var v1 = 1
var v2 = 2
<!CAN_BE_VAL!>var<!> v3 = 3
v1 = 1
v2++
print(v3)
}
fun test() {
var a = 0
while (a>0) {
a++
}
}
fun foo() {
<!CAN_BE_VAL!>var<!> a: Int
val bool = true
val b: String
if (bool) a = 4 else a = 42
bool = false
}
fun cycles() {
var a = 10
while (a > 0) {
a--
}
val b: Int
while (a < 10) {
a++
b = a
}
}
fun assignedTwice(p: Int) {
var v: Int
v = 0
if (p > 0) v = 1
}
fun main(args: Array<String?>) {
<!CAN_BE_VAL!>var<!> a: String?
if (args.size == 1) {
a = args[0]
}
else {
a = args.toString()
}
if (a != null && a.equals("cde")) return
}
fun run(f: () -> Unit) = f()
fun lambda() {
var a: Int
a = 10
run {
a = 20
}
}
fun lambdaInitialization() {
<!CAN_BE_VAL!>var<!> a: Int
run {
a = 20
}
}
fun notAssignedWhenNotUsed(p: Int) {
<!CAN_BE_VAL!>var<!> v: Int
if (p > 0) {
v = 1
print(v)
}
}
var global = 1
class C {
var field = 2
fun foo() {
print(field)
print(global)
}
}
fun withDelegate() {
var s: String by Delegates.notNull()
s = ""
}

View File

@@ -1,240 +0,0 @@
FILE: VariableAssignmentChecker.kt
public final fun testDelegator(): R|kotlin/Unit| {
lvar x: R|kotlin/Boolean|by R|/LocalFreezableVar.LocalFreezableVar|<R|kotlin/Boolean|>(Boolean(true))
lvar y: R|kotlin/String|by R|/LocalFreezableVar.LocalFreezableVar|<R|kotlin/String|>(String())
}
public final class LocalFreezableVar<T> : R|kotlin/Any| {
public constructor<T>(value: R|T|): R|LocalFreezableVar<T>| {
super<R|kotlin/Any|>()
}
private final var value: R|T| = R|<local>/value|
private get(): R|T|
private set(value: R|T|): R|kotlin/Unit|
public final operator fun getValue(thisRef: R|kotlin/Nothing?|, property: R|kotlin/reflect/KProperty<*>|): R|T| {
^getValue this@R|/LocalFreezableVar|.R|/LocalFreezableVar.value|
}
public final operator fun setValue(thisRef: R|kotlin/Nothing?|, property: R|kotlin/reflect/KProperty<*>|, value: R|T|): R|kotlin/Unit| {
this@R|/LocalFreezableVar|.R|/LocalFreezableVar.value| = R|<local>/value|
}
}
public final class C : R|kotlin/Any| {
public constructor(): R|C| {
super<R|kotlin/Any|>()
}
}
public final operator fun R|C|.plus(a: R|kotlin/Any|): R|C| {
^plus this@R|/plus|
}
public final operator fun R|C|.plusAssign(a: R|kotlin/Any|): R|kotlin/Unit| {
}
public final fun testOperatorAssignment(): R|kotlin/Unit| {
lval c: R|C| = R|/C.C|()
R|<local>/c|.R|/plusAssign|(String())
lvar c1: R|C| = R|/C.C|()
ERROR_EXPR(Operator overload ambiguity. Compatible candidates: [/plus, /plusAssign])
lvar a: R|kotlin/Int| = Int(1)
R|<local>/a| = R|<local>/a|.R|kotlin/Int.plus|(Int(12))
R|<local>/a| = R|<local>/a|.R|kotlin/Int.minus|(Int(10))
}
public final fun destructuringDeclaration(): R|kotlin/Unit| {
lval <destruct>: R|kotlin/Pair<kotlin/Int, kotlin/String>| = R|/getPair|()
lvar v1: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component1: R|kotlin/Int|>|()
lvar v2: R|kotlin/String| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component2: R|kotlin/String|>|()
R|kotlin/io/print|(R|<local>/v1|)
lval <destruct>: R|kotlin/Pair<kotlin/Int, kotlin/String>| = R|/getPair|()
lvar v3: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component1: R|kotlin/Int|>|()
lvar v4: R|kotlin/String| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component2: R|kotlin/String|>|()
R|kotlin/io/print|(R|<local>/v3|)
R|<local>/v4| = String()
lval <destruct>: R|kotlin/Pair<kotlin/Int, kotlin/String>| = R|/getPair|()
lvar v5: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component1: R|kotlin/Int|>|()
lvar v6: R|kotlin/String| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component2: R|kotlin/String|>|()
R|<local>/v5| = Int(1)
lval <destruct>: R|kotlin/Pair<kotlin/Int, kotlin/String>| = R|/getPair|()
lvar v7: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component1: R|kotlin/Int|>|()
lvar v8: R|kotlin/String| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Pair.component2: R|kotlin/String|>|()
R|<local>/v7| = Int(2)
R|<local>/v8| = String(42)
lval <destruct>: R|kotlin/Triple<kotlin/Int, kotlin/Int, kotlin/Int>| = R|kotlin/Triple.Triple|<R|kotlin/Int|, R|kotlin/Int|, R|kotlin/Int|>(Int(1), Int(1), Int(1))
lval a: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component1: R|kotlin/Int|>|()
lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component2: R|kotlin/Int|>|()
lval c: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component3: R|kotlin/Int|>|()
lval <destruct>: R|kotlin/Triple<kotlin/Int, kotlin/Int, kotlin/Int>| = R|kotlin/Triple.Triple|<R|kotlin/Int|, R|kotlin/Int|, R|kotlin/Int|>(Int(1), Int(1), Int(1))
lvar x: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component1: R|kotlin/Int|>|()
lvar y: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component2: R|kotlin/Int|>|()
lvar z: R|kotlin/Int| = R|<local>/<destruct>|.R|FakeOverride<kotlin/Triple.component3: R|kotlin/Int|>|()
}
public final fun stackOverflowBug(): R|kotlin/Unit| {
lvar a: R|kotlin/Int|
R|<local>/a| = Int(1)
lval <iterator>: R|kotlin/collections/IntIterator| = Int(1).R|kotlin/Int.rangeTo|(Int(10)).R|kotlin/ranges/IntProgression.iterator|()
while(R|<local>/<iterator>|.R|kotlin/collections/Iterator.hasNext|()) {
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|kotlin/collections/IntIterator.next|()
R|kotlin/io/print|(R|<local>/i|)
}
}
public final fun smth(flag: R|kotlin/Boolean|): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(1)
when () {
R|<local>/flag| -> {
while(CMP(>, R|<local>/a|.R|kotlin/Int.compareTo|(Int(0)))) {
lval <unary>: R|kotlin/Int| = R|<local>/a|
R|<local>/a| = R|<local>/<unary>|.R|kotlin/Int.dec|()
R|<local>/<unary>|
}
}
}
}
public final fun withAnnotation(p: R|kotlin/collections/List<kotlin/Any>|): R|kotlin/Unit| {
@R|kotlin/Suppress|(vararg(String(UNCHECKED_CAST))) lvar v: R|kotlin/collections/List<kotlin/String>| = (R|<local>/p| as R|kotlin/collections/List<kotlin/String>|)
R|kotlin/io/print|(R|<local>/v|)
}
public final fun withReadonlyDeligate(): R|kotlin/Unit| {
lval s: R|kotlin/String|by R|kotlin/lazy|<R|kotlin/String|>(<L> = lazy@fun <anonymous>(): R|kotlin/String| {
^ String(Hello!)
}
)
R|<local>/s|.R|kotlin/Any.hashCode|()
}
public final fun getPair(): R|kotlin/Pair<kotlin/Int, kotlin/String>| {
^getPair R|kotlin/Pair.Pair|<R|kotlin/Int|, R|kotlin/String|>(Int(1), String(1))
}
public final fun listReceiver(p: R|kotlin/collections/List<kotlin/String>|): R|kotlin/Unit| {
}
public final fun withInitializer(): R|kotlin/Unit| {
lvar v1: R|kotlin/Int| = Int(1)
lvar v2: R|kotlin/Int| = Int(2)
lvar v3: R|kotlin/Int| = Int(3)
R|<local>/v1| = Int(1)
lval <unary>: R|kotlin/Int| = R|<local>/v2|
R|<local>/v2| = R|<local>/<unary>|.R|kotlin/Int.inc|()
R|<local>/<unary>|
R|kotlin/io/print|(R|<local>/v3|)
}
public final fun test(): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(0)
while(CMP(>, R|<local>/a|.R|kotlin/Int.compareTo|(Int(0)))) {
lval <unary>: R|kotlin/Int| = R|<local>/a|
R|<local>/a| = R|<local>/<unary>|.R|kotlin/Int.inc|()
R|<local>/<unary>|
}
}
public final fun foo(): R|kotlin/Unit| {
lvar a: R|kotlin/Int|
lval bool: R|kotlin/Boolean| = Boolean(true)
lval b: R|kotlin/String|
when () {
R|<local>/bool| -> {
R|<local>/a| = Int(4)
}
else -> {
R|<local>/a| = Int(42)
}
}
R|<local>/bool| = Boolean(false)
}
public final fun cycles(): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(10)
while(CMP(>, R|<local>/a|.R|kotlin/Int.compareTo|(Int(0)))) {
lval <unary>: R|kotlin/Int| = R|<local>/a|
R|<local>/a| = R|<local>/<unary>|.R|kotlin/Int.dec|()
R|<local>/<unary>|
}
lval b: R|kotlin/Int|
while(CMP(<, R|<local>/a|.R|kotlin/Int.compareTo|(Int(10)))) {
lval <unary>: R|kotlin/Int| = R|<local>/a|
R|<local>/a| = R|<local>/<unary>|.R|kotlin/Int.inc|()
R|<local>/<unary>|
R|<local>/b| = R|<local>/a|
}
}
public final fun assignedTwice(p: R|kotlin/Int|): R|kotlin/Unit| {
lvar v: R|kotlin/Int|
R|<local>/v| = Int(0)
when () {
CMP(>, R|<local>/p|.R|kotlin/Int.compareTo|(Int(0))) -> {
R|<local>/v| = Int(1)
}
}
}
public final fun main(args: R|kotlin/Array<kotlin/String?>|): R|kotlin/Unit| {
lvar a: R|kotlin/String?|
when () {
==(R|<local>/args|.R|kotlin/Array.size|, Int(1)) -> {
R|<local>/a| = R|<local>/args|.R|FakeOverride<kotlin/Array.get: R|kotlin/String?|>|(Int(0))
}
else -> {
R|<local>/a| = R|<local>/args|.R|kotlin/Any.toString|()
}
}
when () {
!=(R|<local>/a|, Null(null)) && R|<local>/a|.R|kotlin/Any.equals|(String(cde)) -> {
^main Unit
}
}
}
public final fun run(f: R|() -> kotlin/Unit|): R|kotlin/Unit| {
^run R|<local>/f|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()
}
public final fun lambda(): R|kotlin/Unit| {
lvar a: R|kotlin/Int|
R|<local>/a| = Int(10)
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| {
R|<local>/a| = Int(20)
}
)
}
public final fun lambdaInitialization(): R|kotlin/Unit| {
lvar a: R|kotlin/Int|
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| {
R|<local>/a| = Int(20)
}
)
}
public final fun notAssignedWhenNotUsed(p: R|kotlin/Int|): R|kotlin/Unit| {
lvar v: R|kotlin/Int|
when () {
CMP(>, R|<local>/p|.R|kotlin/Int.compareTo|(Int(0))) -> {
R|<local>/v| = Int(1)
R|kotlin/io/print|(R|<local>/v|)
}
}
}
public final var global: R|kotlin/Int| = Int(1)
public get(): R|kotlin/Int|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
public final class C : R|kotlin/Any| {
public constructor(): R|C| {
super<R|kotlin/Any|>()
}
public final var field: R|kotlin/Int| = Int(2)
public get(): R|kotlin/Int|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
public final fun foo(): R|kotlin/Unit| {
R|kotlin/io/print|(this@R|/C|.R|/C.field|)
R|kotlin/io/print|(R|/global|)
}
}
public final fun withDelegate(): R|kotlin/Unit| {
lvar s: R|kotlin/String|by Q|kotlin/properties/Delegates|.R|kotlin/properties/Delegates.notNull|<R|kotlin/String|>()
R|<local>/s| = String()
}

View File

@@ -1,7 +0,0 @@
fun goo() {
var a = 2
val b = 4
a <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> a + 1 + b
a <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> (a + 1)
a = a * b + 1
}

View File

@@ -1,8 +0,0 @@
FILE: BasicTest.kt
public final fun goo(): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(2)
lval b: R|kotlin/Int| = Int(4)
R|<local>/a| = R|<local>/a|.R|kotlin/Int.plus|(Int(1)).R|kotlin/Int.plus|(R|<local>/b|)
R|<local>/a| = R|<local>/a|.R|kotlin/Int.plus|(Int(1))
R|<local>/a| = R|<local>/a|.R|kotlin/Int.times|(R|<local>/b|).R|kotlin/Int.plus|(Int(1))
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var a = 0
a = (a + 1) / 2
}

View File

@@ -1,5 +0,0 @@
FILE: ComplexExpression.kt
public final fun foo(): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(0)
R|<local>/a| = R|<local>/a|.R|kotlin/Int.plus|(Int(1)).R|kotlin/Int.div|(Int(2))
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var a = 0
a += 10 + a
}

View File

@@ -1,5 +0,0 @@
FILE: OperatorAssignment.kt
public final fun foo(): R|kotlin/Unit| {
lvar a: R|kotlin/Int| = Int(0)
R|<local>/a| = R|<local>/a|.R|kotlin/Int.plus|(Int(10).R|kotlin/Int.plus|(R|<local>/a|))
}

View File

@@ -1,6 +0,0 @@
// WITH_RUNTIME
fun foo() {
var list1 = java.util.Collections.emptyList<String>()
val list2 = listOf("b")
list1 = list1 + list2
}

View File

@@ -1,6 +0,0 @@
FILE: flexibleTypeBug.kt
public final fun foo(): R|kotlin/Unit| {
lvar list1: R|ft<kotlin/collections/MutableList<ft<kotlin/String, kotlin/String?>!>, kotlin/collections/List<ft<kotlin/String, kotlin/String?>!>?>!| = Q|java/util/Collections|.R|java/util/Collections.emptyList|<R|ft<kotlin/String, kotlin/String?>!|>()
lval list2: R|kotlin/collections/List<kotlin/String>| = R|kotlin/collections/listOf|<R|kotlin/String|>(String(b))
R|<local>/list1| = R|<local>/list1|.R|kotlin/collections/plus|<R|ft<kotlin/String, kotlin/String?>!|>(R|<local>/list2|)
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var x = 0
x = x / 1 + 1
}

View File

@@ -1,5 +0,0 @@
FILE: illegalMultipleOperators.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/x|.R|kotlin/Int.div|(Int(1)).R|kotlin/Int.plus|(Int(1))
}

View File

@@ -1,5 +0,0 @@
fun foo() {
var x = 0
val y = 0
x = y / x + 0
}

View File

@@ -1,6 +0,0 @@
FILE: illegalMultipleOperatorsMiddle.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
lval y: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/y|.R|kotlin/Int.div|(R|<local>/x|).R|kotlin/Int.plus|(Int(0))
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var x = 0
x = 1 - x
}

View File

@@ -1,5 +0,0 @@
FILE: invalidSubtraction.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = Int(1).R|kotlin/Int.minus|(R|<local>/x|)
}

View File

@@ -1,7 +0,0 @@
// WITH_RUNTIME
fun foo() {
var list = listOf(1, 2, 3)
// Should not be highlighted because it's the way we use to say explicitly
// "yes, we want to re-assign this immutable list"
list = list + 4
}

View File

@@ -1,5 +0,0 @@
FILE: list.kt
public final fun foo(): R|kotlin/Unit| {
lvar list: R|kotlin/collections/List<kotlin/Int>| = R|kotlin/collections/listOf|<R|kotlin/Int|>(vararg(Int(1), Int(2), Int(3)))
R|<local>/list| = R|<local>/list|.R|kotlin/collections/plus|<R|kotlin/Int|>(Int(4))
}

View File

@@ -1,5 +0,0 @@
fun foo() {
var x = 0
<!CAN_BE_VAL!>var<!> y = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x + y + 5
}

View File

@@ -1,6 +0,0 @@
FILE: multipleOperators.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
lvar y: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/x|.R|kotlin/Int.plus|(R|<local>/y|).R|kotlin/Int.plus|(Int(5))
}

View File

@@ -1,5 +0,0 @@
fun foo() {
var x = 0
<!CAN_BE_VAL!>var<!> y = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> y + x + 5
}

View File

@@ -1,6 +0,0 @@
FILE: multipleOperatorsRightSideRepeat.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
lvar y: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/y|.R|kotlin/Int.plus|(R|<local>/x|).R|kotlin/Int.plus|(Int(5))
}

View File

@@ -1,9 +0,0 @@
// WITH_RUNTIME
fun foo() {
var listVar = mutableListOf(1, 2, 3)
// now, Idea hightlights this code like error (cuz listVar
// is mutable and listVar + 4 is immutable) and like warning
// (cuz can be replaced with +=)
listVar = listVar + 4
}

View File

@@ -1,5 +0,0 @@
FILE: mutableList.kt
public final fun foo(): R|kotlin/Unit| {
lvar listVar: R|kotlin/collections/MutableList<kotlin/Int>| = R|kotlin/collections/mutableListOf|<R|kotlin/Int|>(vararg(Int(1), Int(2), Int(3)))
R|<local>/listVar| = R|<local>/listVar|.R|kotlin/collections/plus|<R|kotlin/Int|>(Int(4))
}

View File

@@ -1,8 +0,0 @@
fun foo() {
var x = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x - 1 - 1
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x / 1
x = 1 / x
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> -1 + x
}

View File

@@ -1,8 +0,0 @@
FILE: nonCommutativeRepeat.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/x|.R|kotlin/Int.minus|(Int(1)).R|kotlin/Int.minus|(Int(1))
R|<local>/x| = R|<local>/x|.R|kotlin/Int.div|(Int(1))
R|<local>/x| = Int(1).R|kotlin/Int.div|(R|<local>/x|)
R|<local>/x| = Int(1).R|kotlin/Int.unaryMinus|().R|kotlin/Int.plus|(R|<local>/x|)
}

View File

@@ -1,6 +0,0 @@
fun foo() {
var x = 0
val y = 0
val z = 0
x = y + z
}

View File

@@ -1,7 +0,0 @@
FILE: nonRepeatingAssignment.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
lval y: R|kotlin/Int| = Int(0)
lval z: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/y|.R|kotlin/Int.plus|(R|<local>/z|)
}

View File

@@ -1,10 +0,0 @@
class A
operator fun A.plus(a: A): A = A()
operator fun A.plusAssign(a: A){}
fun foo() {
var a1 = A()
val a2 = A()
a1 = a1 + a2
}

View File

@@ -1,17 +0,0 @@
FILE: plusAssignConflict.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public final operator fun R|A|.plus(a: R|A|): R|A| {
^plus R|/A.A|()
}
public final operator fun R|A|.plusAssign(a: R|A|): R|kotlin/Unit| {
}
public final fun foo(): R|kotlin/Unit| {
lvar a1: R|A| = R|/A.A|()
lval a2: R|A| = R|/A.A|()
R|<local>/a1| = R|<local>/a1|.R|/plus|(R|<local>/a2|)
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var x = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> 1 + x
}

View File

@@ -1,5 +0,0 @@
FILE: rightSideRepeat.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = Int(1).R|kotlin/Int.plus|(R|<local>/x|)
}

View File

@@ -1,5 +0,0 @@
fun foo() {
var y = 0
val x = 0
y <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> y + x
}

View File

@@ -1,6 +0,0 @@
FILE: simpleAssign.kt
public final fun foo(): R|kotlin/Unit| {
lvar y: R|kotlin/Int| = Int(0)
lval x: R|kotlin/Int| = Int(0)
R|<local>/y| = R|<local>/y|.R|kotlin/Int.plus|(R|<local>/x|)
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var x = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x + 1
}

View File

@@ -1,5 +0,0 @@
FILE: validAddition.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/x|.R|kotlin/Int.plus|(Int(1))
}

View File

@@ -1,4 +0,0 @@
fun foo() {
var x = 0
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x - 1
}

View File

@@ -1,5 +0,0 @@
FILE: validSubtraction.kt
public final fun foo(): R|kotlin/Unit| {
lvar x: R|kotlin/Int| = Int(0)
R|<local>/x| = R|<local>/x|.R|kotlin/Int.minus|(Int(1))
}

View File

@@ -47,112 +47,4 @@ public class ExtendedFirDiagnosticsTestGenerated extends AbstractExtendedFirDiag
public void testRedundantVisibilityModifierChecker() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/RedundantVisibilityModifierChecker.kt");
}
@TestMetadata("VariableAssignmentChecker.kt")
public void testVariableAssignmentChecker() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/VariableAssignmentChecker.kt");
}
@TestMetadata("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CanBeReplacedWithOperatorAssignment extends AbstractExtendedFirDiagnosticsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInCanBeReplacedWithOperatorAssignment() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("BasicTest.kt")
public void testBasicTest() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/BasicTest.kt");
}
@TestMetadata("ComplexExpression.kt")
public void testComplexExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/ComplexExpression.kt");
}
@TestMetadata("flexibleTypeBug.kt")
public void testFlexibleTypeBug() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/flexibleTypeBug.kt");
}
@TestMetadata("illegalMultipleOperators.kt")
public void testIllegalMultipleOperators() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/illegalMultipleOperators.kt");
}
@TestMetadata("illegalMultipleOperatorsMiddle.kt")
public void testIllegalMultipleOperatorsMiddle() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/illegalMultipleOperatorsMiddle.kt");
}
@TestMetadata("invalidSubtraction.kt")
public void testInvalidSubtraction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/invalidSubtraction.kt");
}
@TestMetadata("list.kt")
public void testList() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/list.kt");
}
@TestMetadata("multipleOperators.kt")
public void testMultipleOperators() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/multipleOperators.kt");
}
@TestMetadata("multipleOperatorsRightSideRepeat.kt")
public void testMultipleOperatorsRightSideRepeat() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/multipleOperatorsRightSideRepeat.kt");
}
@TestMetadata("mutableList.kt")
public void testMutableList() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/mutableList.kt");
}
@TestMetadata("nonCommutativeRepeat.kt")
public void testNonCommutativeRepeat() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/nonCommutativeRepeat.kt");
}
@TestMetadata("nonRepeatingAssignment.kt")
public void testNonRepeatingAssignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/nonRepeatingAssignment.kt");
}
@TestMetadata("OperatorAssignment.kt")
public void testOperatorAssignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/OperatorAssignment.kt");
}
@TestMetadata("plusAssignConflict.kt")
public void testPlusAssignConflict() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/plusAssignConflict.kt");
}
@TestMetadata("rightSideRepeat.kt")
public void testRightSideRepeat() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/rightSideRepeat.kt");
}
@TestMetadata("simpleAssign.kt")
public void testSimpleAssign() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/simpleAssign.kt");
}
@TestMetadata("validAddition.kt")
public void testValidAddition() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/validAddition.kt");
}
@TestMetadata("validSubtraction.kt")
public void testValidSubtraction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/canBeReplacedWithOperatorAssignment/validSubtraction.kt");
}
}
}

View File

@@ -15514,11 +15514,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/namedArguments/mixedNamedPosition/oldInference.kt");
}
@TestMetadata("secondNamed.kt")
public void testSecondNamed() throws Exception {
runTest("compiler/testData/diagnostics/tests/namedArguments/mixedNamedPosition/secondNamed.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/namedArguments/mixedNamedPosition/simple.kt");
@@ -24847,11 +24842,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/varargs/assigningSingleElementsInNamedFormFunDeprecation_before.kt");
}
@TestMetadata("inferredNullableArrayAsVararg.kt")
public void testInferredNullableArrayAsVararg() throws Exception {
runTest("compiler/testData/diagnostics/tests/varargs/inferredNullableArrayAsVararg.kt");
}
@TestMetadata("kt1781.kt")
public void testKt1781() throws Exception {
runTest("compiler/testData/diagnostics/tests/varargs/kt1781.kt");

View File

@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
@@ -61,19 +60,15 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
override val constructorCheckers: List<FirConstructorChecker>
get() = _constructorCheckers
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker>
get() = _controlFlowAnalyserCheckers
private val _declarationCheckers: MutableList<FirBasicDeclarationChecker> = mutableListOf()
private val _memberDeclarationCheckers: MutableList<FirMemberDeclarationChecker> = mutableListOf()
private val _constructorCheckers: MutableList<FirConstructorChecker> = mutableListOf()
private val _controlFlowAnalyserCheckers: MutableList<FirControlFlowChecker> = mutableListOf()
fun register(checkers: DeclarationCheckers) {
_declarationCheckers += checkers.declarationCheckers
_memberDeclarationCheckers += checkers.allMemberDeclarationCheckers
_constructorCheckers += checkers.allConstructorCheckers
_controlFlowAnalyserCheckers += checkers.controlFlowAnalyserCheckers
}
}
@@ -84,18 +79,14 @@ private class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _qualifiedAccessCheckers
override val functionCallCheckers: List<FirFunctionCallChecker>
get() = _functionCallCheckers
override val variableAssignmentCheckers: List<FirVariableAssignmentChecker>
get() = _variableAssignmentCheckers
private val _expressionCheckers: MutableList<FirBasicExpresionChecker> = mutableListOf()
private val _qualifiedAccessCheckers: MutableList<FirQualifiedAccessChecker> = mutableListOf()
private val _functionCallCheckers: MutableList<FirFunctionCallChecker> = mutableListOf()
private val _variableAssignmentCheckers: MutableList<FirVariableAssignmentChecker> = mutableListOf()
fun register(checkers: ExpressionCheckers) {
_expressionCheckers += checkers.allExpressionCheckers
_qualifiedAccessCheckers += checkers.allQualifiedAccessCheckers
_functionCallCheckers += checkers.allFunctionCallCheckers
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2010-2020 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.fir.analysis.cfa
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
abstract class AbstractFirPropertyInitializationChecker : FirControlFlowChecker() {
abstract override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter)
class PropertyInitializationInfo(
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
) : ControlFlowInfo<PropertyInitializationInfo, FirPropertySymbol, EventOccurrencesRange>(map) {
companion object {
val EMPTY = PropertyInitializationInfo()
}
override val constructor: (PersistentMap<FirPropertySymbol, EventOccurrencesRange>) -> PropertyInitializationInfo =
::PropertyInitializationInfo
fun merge(other: PropertyInitializationInfo): PropertyInitializationInfo {
var result = this
for (symbol in keys.union(other.keys)) {
val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
result = result.put(symbol, kind1 or kind2)
}
return result
}
}
class LocalPropertyCollector private constructor() : ControlFlowGraphVisitorVoid() {
companion object {
fun collect(graph: ControlFlowGraph): MutableSet<FirPropertySymbol> {
val collector = LocalPropertyCollector()
graph.traverse(TraverseDirection.Forward, collector)
return collector.symbols
}
}
private val symbols: MutableSet<FirPropertySymbol> = mutableSetOf()
override fun visitNode(node: CFGNode<*>) {}
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
symbols += node.fir.symbol
}
}
class DataCollector(private val localProperties: Set<FirPropertySymbol>) :
ControlFlowGraphVisitor<PropertyInitializationInfo, Collection<PropertyInitializationInfo>>() {
override fun visitNode(node: CFGNode<*>, data: Collection<PropertyInitializationInfo>): PropertyInitializationInfo {
if (data.isEmpty()) return PropertyInitializationInfo.EMPTY
return data.reduce(PropertyInitializationInfo::merge)
}
override fun visitVariableAssignmentNode(
node: VariableAssignmentNode,
data: Collection<PropertyInitializationInfo>
): PropertyInitializationInfo {
val dataForNode = visitNode(node, data)
val reference = node.fir.lValue as? FirResolvedNamedReference ?: return dataForNode
val symbol = reference.resolvedSymbol as? FirPropertySymbol ?: return dataForNode
return if (symbol !in localProperties) {
dataForNode
} else {
processVariableWithAssignment(dataForNode, symbol)
}
}
override fun visitVariableDeclarationNode(
node: VariableDeclarationNode,
data: Collection<PropertyInitializationInfo>
): PropertyInitializationInfo {
val dataForNode = visitNode(node, data)
return if (node.fir.initializer == null && node.fir.delegate == null) {
dataForNode
} else {
processVariableWithAssignment(dataForNode, node.fir.symbol)
}
}
fun getData(graph: ControlFlowGraph) =
graph.collectDataForNode(TraverseDirection.Forward, PropertyInitializationInfo.EMPTY, DataCollector(localProperties))
private fun processVariableWithAssignment(
dataForNode: PropertyInitializationInfo,
symbol: FirPropertySymbol
): PropertyInitializationInfo {
val existingKind = dataForNode[symbol] ?: EventOccurrencesRange.ZERO
val kind = existingKind + EventOccurrencesRange.EXACTLY_ONCE
return dataForNode.put(symbol, kind)
}
}
}

View File

@@ -5,17 +5,15 @@
package org.jetbrains.kotlin.fir.analysis.cfa
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
class FirControlFlowAnalyzer(session: FirSession) {
private val checkers = session.checkersComponent.declarationCheckers.controlFlowAnalyserCheckers
class FirControlFlowAnalyzer {
private val propertyInitializationAnalyzer = FirPropertyInitializationAnalyzer()
fun analyzeClassInitializer(klass: FirClass<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
@@ -24,7 +22,7 @@ class FirControlFlowAnalyzer(session: FirSession) {
fun analyzeFunction(function: FirFunction<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
checkers.forEach { it.analyze(graph, reporter) }
propertyInitializationAnalyzer.analyze(graph, reporter)
}
fun analyzePropertyInitializer(property: FirProperty, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {

View File

@@ -5,24 +5,23 @@
package org.jetbrains.kotlin.fir.analysis.cfa
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraphVisitorVoid
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.QualifiedAccessNode
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
class FirPropertyInitializationAnalyzer {
fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
val localProperties = LocalPropertyCollector.collect(graph)
// we want to analyze only properties without initializers
localProperties.retainAll { it.fir.initializer == null && it.fir.delegate == null }
if (localProperties.isEmpty()) return
val data = DataCollector(localProperties).getData(graph)
val data = graph.collectDataForNode(TraverseDirection.Forward, PropertyInitializationInfo.EMPTY, DataCollector(localProperties))
val reporterVisitor = UninitializedPropertyReporter(data, localProperties, reporter)
graph.traverse(TraverseDirection.Forward, reporterVisitor)
}
@@ -46,4 +45,85 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
}
}
}
private class PropertyInitializationInfo(
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
) : ControlFlowInfo<PropertyInitializationInfo, FirPropertySymbol, EventOccurrencesRange>(map) {
companion object {
val EMPTY = PropertyInitializationInfo()
}
override val constructor: (PersistentMap<FirPropertySymbol, EventOccurrencesRange>) -> PropertyInitializationInfo =
::PropertyInitializationInfo
fun merge(other: PropertyInitializationInfo): PropertyInitializationInfo {
var result = this
for (symbol in keys.union(other.keys)) {
val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
result = result.put(symbol, kind1 or kind2)
}
return result
}
}
private class LocalPropertyCollector private constructor() : ControlFlowGraphVisitorVoid() {
companion object {
fun collect(graph: ControlFlowGraph): MutableSet<FirPropertySymbol> {
val collector = LocalPropertyCollector()
graph.traverse(TraverseDirection.Forward, collector)
return collector.symbols
}
}
private val symbols: MutableSet<FirPropertySymbol> = mutableSetOf()
override fun visitNode(node: CFGNode<*>) {}
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
symbols += node.fir.symbol
}
}
private class DataCollector(private val localProperties: Set<FirPropertySymbol>) : ControlFlowGraphVisitor<PropertyInitializationInfo, Collection<PropertyInitializationInfo>>() {
override fun visitNode(node: CFGNode<*>, data: Collection<PropertyInitializationInfo>): PropertyInitializationInfo {
if (data.isEmpty()) return PropertyInitializationInfo.EMPTY
return data.reduce(PropertyInitializationInfo::merge)
}
override fun visitVariableAssignmentNode(
node: VariableAssignmentNode,
data: Collection<PropertyInitializationInfo>
): PropertyInitializationInfo {
val dataForNode = visitNode(node, data)
val reference = node.fir.lValue as? FirResolvedNamedReference ?: return dataForNode
val symbol = reference.resolvedSymbol as? FirPropertySymbol ?: return dataForNode
return if (symbol !in localProperties) {
dataForNode
} else{
processVariableWithAssignment(dataForNode, symbol)
}
}
override fun visitVariableDeclarationNode(
node: VariableDeclarationNode,
data: Collection<PropertyInitializationInfo>
): PropertyInitializationInfo {
val dataForNode = visitNode(node, data)
return if (node.fir.initializer == null && node.fir.delegate == null) {
dataForNode
} else {
processVariableWithAssignment(dataForNode, node.fir.symbol)
}
}
private fun processVariableWithAssignment(
dataForNode: PropertyInitializationInfo,
symbol: FirPropertySymbol
): PropertyInitializationInfo {
val existingKind = dataForNode[symbol] ?: EventOccurrencesRange.ZERO
val kind = existingKind + EventOccurrencesRange.EXACTLY_ONCE
return dataForNode.put(symbol, kind)
}
}
}

View File

@@ -1,13 +0,0 @@
/*
* Copyright 2010-2020 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.fir.analysis.checkers.cfa
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
abstract class FirControlFlowChecker {
abstract fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter)
}

View File

@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
abstract class DeclarationCheckers {
companion object {
val EMPTY: DeclarationCheckers = object : DeclarationCheckers() {}
@@ -15,7 +13,6 @@ abstract class DeclarationCheckers {
open val declarationCheckers: List<FirBasicDeclarationChecker> = emptyList()
open val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = emptyList()
open val constructorCheckers: List<FirConstructorChecker> = emptyList()
open val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = emptyList()
internal val allMemberDeclarationCheckers: List<FirMemberDeclarationChecker> get() = memberDeclarationCheckers + declarationCheckers
internal val allConstructorCheckers: List<FirConstructorChecker> get() = constructorCheckers + allMemberDeclarationCheckers

View File

@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
object CommonDeclarationCheckers : DeclarationCheckers() {
override val declarationCheckers: List<FirBasicDeclarationChecker> = listOf(
FirAnnotationClassDeclarationChecker,
@@ -22,8 +19,4 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val constructorCheckers: List<FirConstructorChecker> = listOf(
FirConstructorAllowedChecker
)
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = listOf(
FirPropertyInitializationAnalyzer
)
}

View File

@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.extended.*
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantExplicitTypeChecker
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantModalityModifierChecker
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantReturnUnitType
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantVisibilityModifierChecker
object ExtendedDeclarationCheckers : DeclarationCheckers() {
override val declarationCheckers = listOf(
@@ -19,7 +21,4 @@ object ExtendedDeclarationCheckers : DeclarationCheckers() {
RedundantExplicitTypeChecker
)
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = listOf(
VariableAssignmentChecker
)
}
}

View File

@@ -13,7 +13,6 @@ abstract class ExpressionCheckers {
open val expressionCheckers: List<FirBasicExpresionChecker> = emptyList()
open val qualifiedAccessCheckers: List<FirQualifiedAccessChecker> = emptyList()
open val functionCallCheckers: List<FirFunctionCallChecker> = emptyList()
open val variableAssignmentCheckers: List<FirVariableAssignmentChecker> = emptyList()
internal val allExpressionCheckers get() = expressionCheckers
internal val allQualifiedAccessCheckers get() = qualifiedAccessCheckers + allExpressionCheckers

View File

@@ -1,14 +0,0 @@
/*
* Copyright 2010-2020 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.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.extended.CanBeReplacedWithOperatorAssignmentChecker
object ExtendedExpressionCheckers : ExpressionCheckers() {
override val variableAssignmentCheckers: List<FirVariableAssignmentChecker> = listOf(
CanBeReplacedWithOperatorAssignmentChecker
)
}

View File

@@ -7,16 +7,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
abstract class FirExpressionChecker<in E : FirStatement> {
abstract class FirExpressionChecker<in E : FirExpression> {
abstract fun check(functionCall: E, context: CheckerContext, reporter: DiagnosticReporter)
}
typealias FirBasicExpresionChecker = FirExpressionChecker<FirStatement>
typealias FirBasicExpresionChecker = FirExpressionChecker<FirExpression>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2010-2020 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.fir.analysis.checkers.extended
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.toFirPsiSourceElement
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
object CanBeReplacedWithOperatorAssignmentChecker : FirExpressionChecker<FirVariableAssignment>() {
override fun check(functionCall: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
val lValue = functionCall.lValue
if (lValue !is FirResolvedNamedReference) return
val operator = functionCall.psi?.children?.getOrNull(1) ?: return
if (operator.text != "=") return
val lValuePsi = lValue.psi as? KtNameReferenceExpression ?: return
val rValue = functionCall.rValue as? FirFunctionCall ?: return
val rValuePsi = rValue.psi as? KtBinaryExpression ?: return
val rValueClassId = rValue.explicitReceiver?.typeRef?.coneType?.classId
if (rValueClassId !in StandardClassIds.primitiveTypes) return
val rValueResolvedSymbol = rValue.toResolvedCallableSymbol() ?: return
if (rValueResolvedSymbol.callableId.classId !in StandardClassIds.primitiveTypes) return
if (rValuePsi.matcher(lValuePsi)) {
val operatorStatement = operator.toFirPsiSourceElement()
reporter.report(operatorStatement, FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT)
}
}
fun KtBinaryExpression.matcher(variable: KtNameReferenceExpression): Boolean {
if ((left as? KtNameReferenceExpression)?.getReferencedName() == variable.getReferencedName()) return true
if ((right as? KtNameReferenceExpression)?.getReferencedName() == variable.getReferencedName() && isCommutative()) return true
return if (isCommutative()) {
val leftExpression = left as? KtBinaryExpression
val rightExpression = right as? KtBinaryExpression
val isLeftMatch = isHierarchicallyTrue(operationToken, leftExpression?.operationToken)
&& leftExpression?.matcher(variable) == true
val isRightMatch = isHierarchicallyTrue(operationToken, rightExpression?.operationToken)
&& rightExpression?.matcher(variable) == true
isLeftMatch or isRightMatch
} else {
val leftExpression = left as? KtBinaryExpression
isHierarchicallyTrue(operationToken, leftExpression?.operationToken)
&& leftExpression?.matcher(variable) == true
}
}
private fun KtBinaryExpression.isCommutative() = this.operationToken == KtTokens.PLUS || this.operationToken == KtTokens.MUL
private fun isHierarchicallyTrue(currentOperation: IElementType, nextOperation: IElementType?) = currentOperation == nextOperation
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2010-2020 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.fir.analysis.checkers.extended
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.TraverseDirection
import org.jetbrains.kotlin.fir.analysis.cfa.traverse
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.toFirPsiSourceElement
import org.jetbrains.kotlin.psi.KtProperty
object VariableAssignmentChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
val unprocessedProperties = mutableSetOf<FirPropertySymbol>()
val propertiesCharacteristics = mutableMapOf<FirPropertySymbol, EventOccurrencesRange>()
val localProperties = LocalPropertyCollector.collect(graph)
if (localProperties.isEmpty()) return
val data = DataCollector(localProperties).getData(graph)
val reporterVisitor = UninitializedPropertyReporter(data, localProperties, unprocessedProperties, propertiesCharacteristics)
graph.traverse(TraverseDirection.Forward, reporterVisitor)
for (property in unprocessedProperties) {
if (property.fir.source is FirFakeSourceElement<*>) continue
if (property.callableId.callableName.asString() == "<destruct>") continue
propertiesCharacteristics[property] = EventOccurrencesRange.ZERO
}
var lastDestructuringSource: FirSourceElement? = null
var destructuringCanBeVal = false
var lastDestructuredVariables = 0
for ((symbol, value) in propertiesCharacteristics) {
val source = symbol.getValOrVarSource
if (symbol.callableId.callableName.asString() == "<destruct>") {
lastDestructuringSource = symbol.getValOrVarSource
val childrenCount = symbol.fir.psi?.children?.size ?: continue
lastDestructuredVariables = childrenCount - 1 // -1 cuz we don't need expression node after equals operator
destructuringCanBeVal = true
continue
}
if (lastDestructuringSource != null) {
// if this is the last variable in destructuring declaration and destructuringCanBeVal == true and it can be val
if (lastDestructuredVariables == 1 && destructuringCanBeVal && canBeVal(symbol, value)) {
reporter.report(lastDestructuringSource, FirErrors.CAN_BE_VAL)
lastDestructuringSource = null
} else if (!canBeVal(symbol, value)) {
destructuringCanBeVal = false
}
lastDestructuredVariables--
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null ) {
reporter.report(source, FirErrors.CAN_BE_VAL)
}
}
}
private fun canBeVal(symbol: FirPropertySymbol, value: EventOccurrencesRange) =
(value == EventOccurrencesRange.EXACTLY_ONCE
|| value == EventOccurrencesRange.AT_MOST_ONCE
|| value == EventOccurrencesRange.ZERO
) && symbol.fir.isVar
private class UninitializedPropertyReporter(
val data: Map<CFGNode<*>, PropertyInitializationInfo>,
val localProperties: Set<FirPropertySymbol>,
val unprocessedProperties: MutableSet<FirPropertySymbol>,
val propertiesCharacteristics: MutableMap<FirPropertySymbol, EventOccurrencesRange>
) : ControlFlowGraphVisitorVoid() {
override fun visitNode(node: CFGNode<*>) {}
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
val symbol = (node.fir.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol
?: return
if (symbol !in localProperties) return
unprocessedProperties.remove(symbol)
val currentCharacteristic = propertiesCharacteristics.getOrDefault(symbol, EventOccurrencesRange.ZERO)
propertiesCharacteristics[symbol] = currentCharacteristic.or(data.getValue(node)[symbol] ?: EventOccurrencesRange.ZERO)
}
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
val symbol = node.fir.symbol
if (node.fir.initializer == null && node.fir.delegate == null) {
unprocessedProperties.add(symbol)
} else {
propertiesCharacteristics[symbol] = EventOccurrencesRange.AT_MOST_ONCE
}
}
}
private val FirPropertySymbol.getValOrVarSource
get() = (fir.psi as? KtProperty)?.valOrVarKeyword?.toFirPsiSourceElement()
?: fir.psi?.firstChild?.toFirPsiSourceElement()
?: fir.source
}

View File

@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
class ControlFlowAnalysisDiagnosticComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
private val controlFlowAnalyzer = FirControlFlowAnalyzer(session)
private val controlFlowAnalyzer = FirControlFlowAnalyzer()
// ------------------------------- Class initializer -------------------------------

View File

@@ -79,11 +79,7 @@ class ExpressionCheckersDiagnosticComponent(collector: AbstractDiagnosticCollect
runCheck { checkers.expressionCheckers.check(getClassCall, data, it) }
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) {
runCheck { checkers.variableAssignmentCheckers.check(variableAssignment, data, it) }
}
private fun <E : FirStatement> List<FirExpressionChecker<E>>.check(expression: E, context: CheckerContext, reporter: DiagnosticReporter) {
private fun <E : FirExpression> List<FirExpressionChecker<E>>.check(expression: E, context: CheckerContext, reporter: DiagnosticReporter) {
for (checker in this) {
checker.check(expression, context, reporter)
}

View File

@@ -87,6 +87,6 @@ object FirErrors {
val REDUNDANT_MODALITY_MODIFIER by warning0<FirSourceElement, PsiElement>()
val REDUNDANT_RETURN_UNIT_TYPE by warning0<FirSourceElement, PsiTypeElement>()
val REDUNDANT_EXPLICIT_TYPE by warning0<FirSourceElement, PsiElement>()
val CAN_BE_VAL by warning0<FirSourceElement, PsiElement>()
val CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT by warning0<FirSourceElement, PsiElement>()
}

View File

@@ -310,8 +310,7 @@ class FirElementSerializer private constructor(
simpleFunction?.isTailRec == true,
simpleFunction?.isExternal == true,
simpleFunction?.isSuspend == true,
simpleFunction?.isExpect == true,
true // TODO: supply 'hasStableParameterNames' flag for metadata
simpleFunction?.isExpect == true
)
if (flags != builder.flags) {
builder.flags = flags
@@ -440,8 +439,7 @@ class FirElementSerializer private constructor(
val flags = Flags.getConstructorFlags(
constructor.nonSourceAnnotations(session).isNotEmpty(),
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
!constructor.isPrimary,
true // TODO: supply 'hasStableParameterNames' flag for metadata
!constructor.isPrimary
)
if (flags != builder.flags) {
builder.flags = flags

View File

@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -41,6 +42,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.types.*
@@ -459,7 +461,7 @@ internal fun IrDeclarationParent.declareThisReceiverParameter(
return symbolTable.declareValueParameter(
startOffset, endOffset, thisOrigin, receiverDescriptor, thisType
) { symbol ->
symbolTable.irFactory.createValueParameter(
IrValueParameterImpl(
startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), -1, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false

View File

@@ -22,11 +22,16 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrEnumEntryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeAliasImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedEnumEntryDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedTypeAliasDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol
@@ -190,7 +195,7 @@ class Fir2IrClassifierStorage(
preCacheTypeParameters(typeAlias)
return typeAlias.convertWithOffsets { startOffset, endOffset ->
declareIrTypeAlias(signature) { symbol ->
val irTypeAlias = irFactory.createTypeAlias(
val irTypeAlias = IrTypeAliasImpl(
startOffset, endOffset, symbol,
typeAlias.name, typeAlias.visibility,
typeAlias.expandedTypeRef.toIrType(),
@@ -227,10 +232,10 @@ class Fir2IrClassifierStorage(
} else {
regularClass.modality ?: Modality.FINAL
}
val signature = if (regularClass.isLocal) null else signatureComposer.composeSignature(regularClass)
val signature = signatureComposer.composeSignature(regularClass)
val irClass = regularClass.convertWithOffsets { startOffset, endOffset ->
declareIrClass(signature) { symbol ->
irFactory.createClass(
IrClassImpl(
startOffset,
endOffset,
origin,
@@ -270,10 +275,10 @@ class Fir2IrClassifierStorage(
): IrClass {
val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL
val signature = null
val signature = signatureComposer.composeSignature(anonymousObject)
val result = anonymousObject.convertWithOffsets { startOffset, endOffset ->
declareIrClass(signature) { symbol ->
irFactory.createClass(
IrClassImpl(
startOffset, endOffset, origin, symbol, name,
// NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects
anonymousObject.classKind.takeIf { it == ClassKind.ENUM_ENTRY } ?: ClassKind.CLASS,
@@ -307,7 +312,7 @@ class Fir2IrClassifierStorage(
val irTypeParameter = with(typeParameter) {
convertWithOffsets { startOffset, endOffset ->
symbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol ->
irFactory.createTypeParameter(
IrTypeParameterImpl(
startOffset, endOffset, origin, symbol,
name, if (index < 0) 0 else index,
isReified,
@@ -388,7 +393,7 @@ class Fir2IrClassifierStorage(
return enumEntry.convertWithOffsets { startOffset, endOffset ->
val signature = signatureComposer.composeSignature(enumEntry)
val result = declareIrEnumEntry(signature) { symbol ->
irFactory.createEnumEntry(
IrEnumEntryImpl(
startOffset, endOffset, origin, symbol, enumEntry.name
).apply {
declarationStorage.enterScope(this)
@@ -407,7 +412,7 @@ class Fir2IrClassifierStorage(
// which will be translated via visitor later.
} else if (irParent != null && origin == IrDeclarationOrigin.DEFINED) {
val constructor = irParent.constructors.first()
this.initializerExpression = factory.createExpressionBody(
this.initializerExpression = IrExpressionBodyImpl(
IrEnumConstructorCallImpl(
startOffset, endOffset, irType, constructor.symbol,
valueArgumentsCount = constructor.valueParameters.size,

View File

@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -18,11 +17,10 @@ interface Fir2IrComponents {
val scopeSession: ScopeSession
val symbolTable: SymbolTable
val irBuiltIns: IrBuiltIns
val irFactory: IrFactory
val classifierStorage: Fir2IrClassifierStorage
val declarationStorage: Fir2IrDeclarationStorage
val typeConverter: Fir2IrTypeConverter
val signatureComposer: Fir2IrSignatureComposer
val callGenerator: CallAndReferenceGenerator
val fakeOverrideGenerator: FakeOverrideGenerator
}
}

View File

@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer
import org.jetbrains.kotlin.fir.signaturer.FirMangler
import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -20,7 +19,6 @@ class Fir2IrComponentsStorage(
override val scopeSession: ScopeSession,
override val symbolTable: SymbolTable,
override val irBuiltIns: IrBuiltIns,
override val irFactory: IrFactory,
mangler: FirMangler
) : Fir2IrComponents {
override lateinit var classifierStorage: Fir2IrClassifierStorage
@@ -30,4 +28,4 @@ class Fir2IrComponentsStorage(
override lateinit var fakeOverrideGenerator: FakeOverrideGenerator
override val signatureComposer = FirBasedSignatureComposer(mangler)
}
}

View File

@@ -7,10 +7,10 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants
import org.jetbrains.kotlin.fir.backend.generators.AnnotationGenerator
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.psi
@@ -85,9 +85,7 @@ class Fir2IrConverter(
irClass: IrClass = classifierStorage.getCachedIrClass(anonymousObject)!!
): IrClass {
anonymousObject.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(
it, irClass, isLocal = true
)
irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
}
for (declaration in sortBySynthetic(anonymousObject.declarations)) {
if (declaration is FirRegularClass) {
@@ -112,9 +110,7 @@ class Fir2IrConverter(
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
): IrClass {
regularClass.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(
it, irClass, isLocal = regularClass.isLocal
)
irClass.declarations += declarationStorage.createIrConstructor(it, irClass)
}
for (declaration in sortBySynthetic(regularClass.declarations)) {
val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue
@@ -147,21 +143,15 @@ class Fir2IrConverter(
containingClass: FirClass<*>?,
parent: IrDeclarationParent
): IrDeclaration? {
val isLocal = containingClass != null &&
(containingClass !is FirRegularClass || containingClass.isLocal)
return when (declaration) {
is FirRegularClass -> {
processClassMembers(declaration)
}
is FirSimpleFunction -> {
declarationStorage.createIrFunction(
declaration, parent, isLocal = isLocal
)
declarationStorage.createIrFunction(declaration, parent)
}
is FirProperty -> {
declarationStorage.createIrProperty(
declaration, parent, isLocal = isLocal
)
declarationStorage.createIrProperty(declaration, parent)
}
is FirField -> {
if (declaration.isSynthetic) {
@@ -171,9 +161,7 @@ class Fir2IrConverter(
}
}
is FirConstructor -> if (!declaration.isPrimary) {
declarationStorage.createIrConstructor(
declaration, parent as IrClass, isLocal = isLocal
)
declarationStorage.createIrConstructor(declaration, parent as IrClass)
} else {
null
}
@@ -199,13 +187,13 @@ class Fir2IrConverter(
scopeSession: ScopeSession,
firFiles: List<FirFile>,
languageVersionSettings: LanguageVersionSettings,
fakeOverrideMode: FakeOverrideMode = FakeOverrideMode.NORMAL,
signaturer: IdSignatureComposer,
generatorExtensions: GeneratorExtensions,
mangler: FirMangler,
irFactory: IrFactory,
mangler: FirMangler
): Fir2IrResult {
val moduleDescriptor = FirModuleDescriptor(session)
val symbolTable = SymbolTable(signaturer, irFactory)
val symbolTable = SymbolTable(signaturer)
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator = TypeTranslator(
symbolTable,
@@ -218,7 +206,7 @@ class Fir2IrConverter(
val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
FirBuiltinSymbols(builtIns, moduleDescriptor.builtIns, symbolTable)
val sourceManager = PsiSourceManager()
val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, builtIns, irFactory, mangler)
val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, builtIns, mangler)
val conversionScope = Fir2IrConversionScope()
val classifierStorage = Fir2IrClassifierStorage(components)
val declarationStorage = Fir2IrDeclarationStorage(components, moduleDescriptor)
@@ -247,17 +235,17 @@ class Fir2IrConverter(
converter.processClassHeaders(firFile)
}
val fakeOverrideGenerator = FakeOverrideGenerator(
session, scopeSession, classifierStorage, declarationStorage, conversionScope, FakeOverrideMode.NORMAL
session, scopeSession, classifierStorage, declarationStorage, conversionScope, fakeOverrideMode
)
components.fakeOverrideGenerator = fakeOverrideGenerator
val fir2irVisitor = Fir2IrVisitor(converter, components, conversionScope)
val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope)
components.callGenerator = callGenerator
declarationStorage.annotationGenerator = AnnotationGenerator(components)
for (firFile in firFiles) {
converter.processFileAndClassMembers(firFile)
}
val fir2irVisitor = Fir2IrVisitor(converter, components, conversionScope)
val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope)
components.callGenerator = callGenerator
declarationStorage.annotationGenerator = AnnotationGenerator(components)
for (firFile in firFiles) {
val irFile = firFile.accept(fir2irVisitor, null) as IrFile
val fileEntry = sourceManager.getOrCreateFileEntry(firFile.psi as KtFile)

View File

@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAMES
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.fir.FirAnnotationContainer
@@ -26,27 +26,20 @@ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.isKFunctionInvoke
import org.jetbrains.kotlin.fir.symbols.Fir2IrConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.Fir2IrPropertySymbol
import org.jetbrains.kotlin.fir.symbols.Fir2IrSimpleFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -245,7 +238,7 @@ class Fir2IrDeclarationStorage(
symbolTable.declareValueParameter(
startOffset, endOffset, origin, descriptor, type
) { symbol ->
irFactory.createValueParameter(
IrValueParameterImpl(
startOffset, endOffset, IrDeclarationOrigin.DEFINED, symbol,
Name.special("<set-?>"), 0, type,
varargElementType = null,
@@ -306,9 +299,7 @@ class Fir2IrDeclarationStorage(
)
}
}
// See [LocalDeclarationsLowering]: "local function must not have dispatch receiver."
val isLocal = function is FirSimpleFunction && function.isLocal
if (function !is FirAnonymousFunction && containingClass != null && !isStatic && !isLocal) {
if (function !is FirAnonymousFunction && containingClass != null && !isStatic) {
dispatchReceiverParameter = declareThisReceiverParameter(
symbolTable,
thisType = containingClass.thisReceiver?.type ?: error("No this receiver"),
@@ -376,8 +367,7 @@ class Fir2IrDeclarationStorage(
function: FirFunction<*>,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
isLocal: Boolean = false
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrSimpleFunction {
val simpleFunction = function as? FirSimpleFunction
val isLambda = function.source?.elementType == KtNodeTypes.FUNCTION_LITERAL
@@ -394,10 +384,10 @@ class Fir2IrDeclarationStorage(
val isSuspend =
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.isSuspend == true
else simpleFunction?.isSuspend == true
val signature = if (isLocal) null else signatureComposer.composeSignature(function)
val signature = signatureComposer.composeSignature(function)
val created = function.convertWithOffsets { startOffset, endOffset ->
val result = declareIrSimpleFunction(signature, simpleFunction?.containerSource) { symbol ->
irFactory.createFunction(
IrFunctionImpl(
startOffset, endOffset, updatedOrigin, symbol,
name, visibility,
simpleFunction?.modality ?: Modality.FINAL,
@@ -465,15 +455,14 @@ class Fir2IrDeclarationStorage(
fun createIrConstructor(
constructor: FirConstructor,
irParent: IrClass,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
isLocal: Boolean = false
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrConstructor {
val isPrimary = constructor.isPrimary
classifierStorage.preCacheTypeParameters(constructor)
val signature = if (isLocal) null else signatureComposer.composeSignature(constructor)
val signature = signatureComposer.composeSignature(constructor)
val created = constructor.convertWithOffsets { startOffset, endOffset ->
declareIrConstructor(signature) { symbol ->
irFactory.createConstructor(
IrConstructorImpl(
startOffset, endOffset, origin, symbol,
Name.special("<init>"), constructor.visibility,
constructor.returnTypeRef.toIrType(),
@@ -515,18 +504,17 @@ class Fir2IrDeclarationStorage(
isSetter: Boolean,
origin: IrDeclarationOrigin,
startOffset: Int,
endOffset: Int,
isLocal: Boolean = false
endOffset: Int
): IrSimpleFunction {
val prefix = if (isSetter) "set" else "get"
val signature = if (isLocal) null else signatureComposer.composeAccessorSignature(property, isSetter)
val signature = signatureComposer.composeAccessorSignature(property, isSetter)
return declareIrAccessor(
signature,
(correspondingProperty.descriptor as? WrappedPropertyDescriptorWithContainerSource)?.containerSource,
isGetter = !isSetter
) { symbol ->
val accessorReturnType = if (isSetter) irBuiltIns.unitType else propertyType
irFactory.createFunction(
IrFunctionImpl(
startOffset, endOffset, origin, symbol,
Name.special("<$prefix-${correspondingProperty.name}>"),
propertyAccessor?.visibility ?: correspondingProperty.visibility,
@@ -586,7 +574,7 @@ class Fir2IrDeclarationStorage(
return symbolTable.declareField(
startOffset, endOffset, origin, descriptor, inferredType
) { symbol ->
irFactory.createField(
IrFieldImpl(
startOffset, endOffset, origin, symbol,
name, inferredType,
visibility, isFinal = isFinal,
@@ -629,14 +617,13 @@ class Fir2IrDeclarationStorage(
property: FirProperty,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
isLocal: Boolean = false
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrProperty {
classifierStorage.preCacheTypeParameters(property)
val signature = if (isLocal) null else signatureComposer.composeSignature(property)
val signature = signatureComposer.composeSignature(property)
return property.convertWithOffsets { startOffset, endOffset ->
val result = declareIrProperty(signature, property.containerSource) { symbol ->
irFactory.createProperty(
IrPropertyImpl(
startOffset, endOffset, origin, symbol,
property.name, property.visibility, property.modality!!,
isVar = property.isVar,
@@ -671,7 +658,7 @@ class Fir2IrDeclarationStorage(
if (initializer is FirConstExpression<*>) {
// TODO: Normally we shouldn't have error type here
val constType = initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type
field.initializer = factory.createExpressionBody(initializer.toIrConst(constType))
field.initializer = IrExpressionBodyImpl(initializer.toIrConst(constType))
}
}
} else if (delegate != null) {
@@ -693,7 +680,7 @@ class Fir2IrDeclarationStorage(
getter is FirDefaultPropertyGetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
startOffset, endOffset, isLocal
startOffset, endOffset
)
if (property.isVar) {
this.setter = createIrPropertyAccessor(
@@ -703,7 +690,7 @@ class Fir2IrDeclarationStorage(
setter is FirDefaultPropertySetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
startOffset, endOffset, isLocal
startOffset, endOffset
)
}
leaveScope(this)
@@ -755,7 +742,7 @@ class Fir2IrDeclarationStorage(
startOffset, endOffset,
origin, descriptor, type
) { symbol ->
irFactory.createField(
IrFieldImpl(
startOffset, endOffset, origin, symbol,
field.name, type, field.visibility,
isFinal = field.modality == Modality.FINAL,
@@ -783,7 +770,7 @@ class Fir2IrDeclarationStorage(
symbolTable.declareValueParameter(
startOffset, endOffset, origin, descriptor, type
) { symbol ->
irFactory.createValueParameter(
IrValueParameterImpl(
startOffset, endOffset, origin, symbol,
valueParameter.name, index, type,
if (!valueParameter.isVararg) null
@@ -795,7 +782,7 @@ class Fir2IrDeclarationStorage(
it != null && (useStubForDefaultValueStub || it !is FirExpressionStub)
}
) {
this.defaultValue = factory.createExpressionBody(
this.defaultValue = IrExpressionBodyImpl(
IrErrorExpressionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, type,
"Stub expression for default value of ${valueParameter.name}"

View File

@@ -127,7 +127,7 @@ class Fir2IrVisitor(
memberGenerator.convertClassContent(correspondingClass, anonymousObject)
}
val constructor = correspondingClass.constructors.first()
irEnumEntry.initializerExpression = irFactory.createExpressionBody(
irEnumEntry.initializerExpression = IrExpressionBodyImpl(
IrEnumConstructorCallImpl(
startOffset, endOffset, enumEntry.returnTypeRef.toIrType(),
constructor.symbol,
@@ -144,9 +144,7 @@ class Fir2IrVisitor(
val delegatedConstructor = primaryConstructor?.delegatedConstructor
if (delegatedConstructor != null) {
with(memberGenerator) {
irEnumEntry.initializerExpression = irFactory.createExpressionBody(
delegatedConstructor.toIrDelegatingConstructorCall()
)
irEnumEntry.initializerExpression = IrExpressionBodyImpl(delegatedConstructor.toIrDelegatingConstructorCall())
}
}
}
@@ -224,7 +222,7 @@ class Fir2IrVisitor(
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement {
val irFunction = if (simpleFunction.visibility == Visibilities.LOCAL) {
declarationStorage.createIrFunction(
simpleFunction, irParent = conversionScope.parent(), isLocal = true
simpleFunction, irParent = conversionScope.parent()
)
} else {
declarationStorage.getCachedIrFunction(simpleFunction)!!
@@ -239,7 +237,7 @@ class Fir2IrVisitor(
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): IrElement {
return anonymousFunction.convertWithOffsets { startOffset, endOffset ->
val irFunction = declarationStorage.createIrFunction(
anonymousFunction, irParent = conversionScope.parent(), isLocal = true
anonymousFunction, irParent = conversionScope.parent()
)
conversionScope.withFunction(irFunction) {
memberGenerator.convertFunctionContent(irFunction, anonymousFunction, containingClass = null)
@@ -318,20 +316,16 @@ class Fir2IrVisitor(
)
} else convertToIrExpression(this)
private fun convertToIrCall(functionCall: FirFunctionCall, annotationMode: Boolean): IrExpression {
val explicitReceiverExpression = convertToIrReceiverExpression(
functionCall.explicitReceiver, functionCall.calleeReference
)
return callGenerator.convertToIrCall(functionCall, functionCall.typeRef, explicitReceiverExpression, annotationMode)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Any?): IrExpression {
val convertibleCall = if (functionCall.toResolvedCallableSymbol()?.fir is FirIntegerOperator) {
functionCall.copy().transformSingle(integerApproximator, null)
} else {
functionCall
}
return convertToIrCall(functionCall = convertibleCall, annotationMode = false)
val explicitReceiverExpression = convertToIrReceiverExpression(
functionCall.explicitReceiver, functionCall.calleeReference
)
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef, explicitReceiverExpression)
}
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: Any?): IrElement {
@@ -519,7 +513,7 @@ class Fir2IrVisitor(
return accept(this@Fir2IrVisitor, null) as IrStatement
}
internal fun convertToIrExpression(expression: FirExpression, annotationMode: Boolean = false): IrExpression {
internal fun convertToIrExpression(expression: FirExpression): IrExpression {
return when (expression) {
is FirBlock -> expression.convertToIrExpressionOrBlock()
is FirUnitExpression -> expression.convertWithOffsets { startOffset, endOffset ->
@@ -528,18 +522,7 @@ class Fir2IrVisitor(
this.symbolTable.referenceClass(this.irBuiltIns.builtIns.unit)
)
}
else -> {
val unwrappedExpression = if (expression is FirWrappedArgumentExpression) {
expression.expression
} else {
expression
}
if (annotationMode && unwrappedExpression is FirFunctionCall) {
convertToIrCall(unwrappedExpression, annotationMode)
} else {
expression.accept(this, null) as IrExpression
}
}
else -> expression.accept(this, null) as IrExpression
}
}
@@ -582,7 +565,7 @@ class Fir2IrVisitor(
internal fun convertToIrBlockBody(block: FirBlock): IrBlockBody {
return block.convertWithOffsets { startOffset, endOffset ->
val irStatements = block.mapToIrStatements()
irFactory.createBlockBody(
IrBlockBodyImpl(
startOffset, endOffset,
if (irStatements.isNotEmpty()) {
irStatements.filterNotNull().takeIf { it.isNotEmpty() }

View File

@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
@@ -21,28 +18,21 @@ import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
import org.jetbrains.kotlin.fir.resolve.getCorrespondingConstructorReferenceOrNull
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.toArrayOrPrimitiveArrayType
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
@@ -96,18 +86,12 @@ class CallAndReferenceGenerator(
}
is IrFunctionSymbol -> {
val function = symbol.owner
// TODO: should refer to LanguageVersionSettings.SuspendConversion
if (requiresSuspendConversion(type, function)) {
val adaptedType = callableReferenceAccess.typeRef.coneType.kFunctionTypeToFunctionType()
generateAdaptedCallableReference(callableReferenceAccess, symbol, adaptedType)
} else {
IrFunctionReferenceImpl(
startOffset, endOffset, type, symbol,
typeArgumentsCount = function.typeParameters.size,
valueArgumentsCount = function.valueParameters.size,
reflectionTarget = symbol
)
}
IrFunctionReferenceImpl(
startOffset, endOffset, type, symbol,
typeArgumentsCount = function.typeParameters.size,
valueArgumentsCount = function.valueParameters.size,
reflectionTarget = symbol
)
}
else -> {
IrErrorCallExpressionImpl(
@@ -118,156 +102,6 @@ class CallAndReferenceGenerator(
}.applyTypeArguments(callableReferenceAccess).applyReceivers(callableReferenceAccess, explicitReceiverExpression)
}
private fun requiresSuspendConversion(type: IrType, function: IrFunction): Boolean =
type.isKSuspendFunction() && !function.isSuspend
private fun ConeKotlinType.kFunctionTypeToFunctionType(): IrSimpleType {
val kind =
if (isSuspendFunctionType(session)) FunctionClassDescriptor.Kind.SuspendFunction
else FunctionClassDescriptor.Kind.Function
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
val coneType = ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(functionalTypeId), typeArguments, isNullable = false)
return coneType.toIrType() as IrSimpleType
}
private fun generateAdaptedCallableReference(
callableReferenceAccess: FirCallableReferenceAccess,
adapteeSymbol: IrFunctionSymbol,
type: IrSimpleType
): IrExpression {
val firAdaptee = callableReferenceAccess.toResolvedCallableReference()?.resolvedSymbol?.fir as? FirSimpleFunction
val adaptee = adapteeSymbol.owner
// TODO: handle bound receiver, e.g., c::foo
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset ->
val irAdapterFunction = createAdapterFunctionForSuspendConversion(startOffset, endOffset, firAdaptee!!, adaptee, type)
val irCall = createAdapteeCall(callableReferenceAccess, adapteeSymbol, irAdapterFunction)
irAdapterFunction.body = irFactory.createBlockBody(startOffset, endOffset) {
if (firAdaptee.returnTypeRef.isUnit) {
statements.add(irCall)
} else {
statements.add(IrReturnImpl(startOffset, endOffset, irBuiltIns.nothingType, irAdapterFunction.symbol, irCall))
}
}
IrFunctionExpressionImpl(startOffset, endOffset, type, irAdapterFunction, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
}
}
private fun createAdapterFunctionForSuspendConversion(
startOffset: Int,
endOffset: Int,
firAdaptee: FirSimpleFunction,
adaptee: IrFunction,
type: IrSimpleType,
): IrSimpleFunction {
val returnType = type.arguments.last().typeOrNull!!
val parameterTypes = type.arguments.dropLast(1).map { it.typeOrNull!! }
val adapterFunctionDescriptor = WrappedSimpleFunctionDescriptor()
return symbolTable.declareSimpleFunction(adapterFunctionDescriptor) { irAdapterSymbol ->
irFactory.createFunction(
startOffset, endOffset,
IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE,
irAdapterSymbol,
adaptee.name,
Visibilities.LOCAL,
Modality.FINAL,
returnType,
isInline = firAdaptee.isInline,
isExternal = firAdaptee.isExternal,
isTailrec = firAdaptee.isTailRec,
isSuspend = true,
isOperator = firAdaptee.isOperator,
isInfix = firAdaptee.isInfix,
isExpect = firAdaptee.isExpect,
isFakeOverride = false
).also { irAdapterFunction ->
adapterFunctionDescriptor.bind(irAdapterFunction)
irAdapterFunction.metadata = FirMetadataSource.Function(firAdaptee)
symbolTable.enterScope(irAdapterFunction)
irAdapterFunction.valueParameters += parameterTypes.mapIndexed { index, parameterType ->
createAdapterParameter(irAdapterFunction, Name.identifier("p$index"), index, parameterType)
}
symbolTable.leaveScope(irAdapterFunction)
irAdapterFunction.parent = conversionScope.parent()!!
}
}
}
private fun createAdapterParameter(
adapterFunction: IrFunction,
name: Name,
index: Int,
type: IrType
): IrValueParameter {
val startOffset = adapterFunction.startOffset
val endOffset = adapterFunction.endOffset
val descriptor = WrappedValueParameterDescriptor()
return symbolTable.declareValueParameter(
startOffset, endOffset, IrDeclarationOrigin.ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE, descriptor, type
) { irAdapterParameterSymbol ->
irFactory.createValueParameter(
startOffset, endOffset,
IrDeclarationOrigin.ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE,
irAdapterParameterSymbol,
name,
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).also { irAdapterValueParameter ->
descriptor.bind(irAdapterValueParameter)
irAdapterValueParameter.parent = adapterFunction
}
}
}
private fun createAdapteeCall(
callableReferenceAccess: FirCallableReferenceAccess,
adapteeSymbol: IrFunctionSymbol,
adapterFunction: IrFunction
): IrExpression {
val adapteeFunction = adapteeSymbol.owner
val startOffset = adapteeFunction.startOffset
val endOffset = adapteeFunction.endOffset
val type = adapteeFunction.returnType
val irCall =
if (adapteeSymbol is IrConstructorSymbol) {
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, adapteeSymbol)
} else {
IrCallImpl(
startOffset,
endOffset,
type,
adapteeSymbol,
callableReferenceAccess.typeArguments.size,
adapteeFunction.valueParameters.size,
origin = null,
superQualifierSymbol = null
)
}
// TODO: handle non-transient, bound dispatch/extension receiver
adapteeFunction.valueParameters.mapIndexed { index, valueParameter ->
when {
valueParameter.hasDefaultValue() -> {
irCall.putValueArgument(index, null)
}
valueParameter.isVararg -> {
// TODO: handle vararg and spread
irCall.putValueArgument(index, null)
}
else -> {
val irValueArgument = adapterFunction.valueParameters[index]
irCall.putValueArgument(index, IrGetValueImpl(startOffset, endOffset, irValueArgument.type, irValueArgument.symbol))
}
}
}
return irCall.applyTypeArguments(callableReferenceAccess)
}
private fun FirQualifiedAccess.tryConvertToSamConstructorCall(type: IrType): IrTypeOperatorCall? {
val calleeReference = calleeReference as? FirResolvedNamedReference ?: return null
val fir = calleeReference.resolvedSymbol.fir
@@ -284,8 +118,7 @@ class CallAndReferenceGenerator(
fun convertToIrCall(
qualifiedAccess: FirQualifiedAccess,
typeRef: FirTypeRef,
explicitReceiverExpression: IrExpression?,
annotationMode: Boolean = false
explicitReceiverExpression: IrExpression?
): IrExpression {
val type = typeRef.toIrType()
val samConstructorCall = qualifiedAccess.tryConvertToSamConstructorCall(type)
@@ -367,7 +200,7 @@ class CallAndReferenceGenerator(
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type)
}
}.applyCallArguments(qualifiedAccess as? FirCall, annotationMode)
}.applyCallArguments(qualifiedAccess as? FirCall)
.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, explicitReceiverExpression)
}
@@ -452,7 +285,7 @@ class CallAndReferenceGenerator(
)
}
}
}.applyCallArguments(annotationCall, annotationMode = true)
}.applyCallArguments(annotationCall)
}
fun convertToGetObject(qualifier: FirResolvedQualifier): IrExpression {
@@ -482,7 +315,7 @@ class CallAndReferenceGenerator(
}
}
internal fun IrExpression.applyCallArguments(call: FirCall?, annotationMode: Boolean): IrExpression {
internal fun IrExpression.applyCallArguments(call: FirCall?): IrExpression {
if (call == null) return this
return when (this) {
is IrMemberAccessExpression<*> -> {
@@ -500,7 +333,7 @@ class CallAndReferenceGenerator(
val argumentMapping = call.argumentMapping
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
if (valueParameters != null) {
return applyArgumentsWithReorderingIfNeeded(call, argumentMapping, valueParameters, annotationMode)
return applyArgumentsWithReorderingIfNeeded(call, argumentMapping, valueParameters)
}
}
for ((index, argument) in call.arguments.withIndex()) {
@@ -534,11 +367,10 @@ class CallAndReferenceGenerator(
call: FirCall,
argumentMapping: Map<FirExpression, FirValueParameter>,
valueParameters: List<FirValueParameter>,
annotationMode: Boolean
): IrExpression {
// Assuming compile-time constants only inside annotation, we don't need a block to reorder arguments to preserve semantics.
// But, we still need to pick correct indices for named arguments.
if (!annotationMode &&
if (call !is FirAnnotationCall &&
needArgumentReordering(argumentMapping.values, valueParameters)
) {
return IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL).apply {
@@ -559,21 +391,9 @@ class CallAndReferenceGenerator(
}
} else {
for ((argument, parameter) in argumentMapping) {
val argumentExpression =
visitor.convertToIrExpression(argument, annotationMode)
.applySamConversionIfNeeded(argument, parameter)
val argumentExpression = visitor.convertToIrExpression(argument).applySamConversionIfNeeded(argument, parameter)
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
}
if (annotationMode) {
for ((index, parameter) in valueParameters.withIndex()) {
if (parameter.isVararg && !argumentMapping.containsValue(parameter)) {
val elementType = parameter.returnTypeRef.toIrType()
putValueArgument(
index, IrVarargImpl(-1, -1, elementType, elementType.toArrayOrPrimitiveArrayType(irBuiltIns))
)
}
}
}
return this
}
}

View File

@@ -27,10 +27,7 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.isAnnotationClass
import org.jetbrains.kotlin.ir.util.isSetter
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.*
internal class ClassMemberGenerator(
private val components: Fir2IrComponents,
@@ -127,7 +124,7 @@ internal class ClassMemberGenerator(
annotationGenerator.generate(irFunction, firFunction)
}
if (firFunction is FirConstructor && irFunction is IrConstructor && !parentAsClass.isAnnotationClass && !firFunction.isExpect) {
val body = factory.createBlockBody(startOffset, endOffset)
val body = IrBlockBodyImpl(startOffset, endOffset)
val delegatedConstructor = firFunction.delegatedConstructor
if (delegatedConstructor != null) {
val irDelegatingConstructorCall = delegatedConstructor.toIrDelegatingConstructorCall()
@@ -224,7 +221,7 @@ internal class ClassMemberGenerator(
declarationStorage.enterScope(this@initializeBackingField)
// NB: initializer can be already converted
if (initializer == null && initializerExpression != null) {
initializer = irFactory.createExpressionBody(visitor.convertToIrExpression(initializerExpression))
initializer = IrExpressionBodyImpl(visitor.convertToIrExpression(initializerExpression))
}
declarationStorage.leaveScope(this@initializeBackingField)
}
@@ -250,7 +247,7 @@ internal class ClassMemberGenerator(
val fieldSymbol = backingField?.symbol
val declaration = this
if (fieldSymbol != null) {
body = factory.createBlockBody(
body = IrBlockBodyImpl(
startOffset, endOffset,
listOf(
if (isSetter) {
@@ -350,7 +347,7 @@ internal class ClassMemberGenerator(
it.dispatchReceiver = visitor.convertToIrExpression(firDispatchReceiver)
}
with(callGenerator) {
it.applyCallArguments(this@toIrDelegatingConstructorCall, annotationMode = false)
it.applyCallArguments(this@toIrDelegatingConstructorCall)
}
}
}
@@ -359,7 +356,7 @@ internal class ClassMemberGenerator(
private fun IrValueParameter.setDefaultValue(firValueParameter: FirValueParameter) {
val firDefaultValue = firValueParameter.defaultValue
if (firDefaultValue != null) {
this.defaultValue = factory.createExpressionBody(visitor.convertToIrExpression(firDefaultValue))
this.defaultValue = IrExpressionBodyImpl(visitor.convertToIrExpression(firDefaultValue))
}
}
}
}

View File

@@ -6,9 +6,15 @@
package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.FirMetadataSource
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.backend.declareThisReceiverParameter
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
@@ -19,16 +25,20 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitBooleanTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitIntTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitStringTypeRef
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.IrGeneratorContextBase
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -233,12 +243,25 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
)
}
}
val signature = if (classId.isLocal) null else components.signatureComposer.composeSignature(firFunction)
val signature = components.signatureComposer.composeSignature(firFunction)
return components.declarationStorage.declareIrSimpleFunction(signature, null) { symbol ->
components.irFactory.createFunction(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, name, Visibilities.PUBLIC, Modality.OPEN, returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isExpect = false,
isFakeOverride = false, isOperator = false, isInfix = false,
IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
symbol,
name,
Visibilities.PUBLIC,
Modality.OPEN,
returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
isExpect = false,
isFakeOverride = false,
isOperator = false,
isInfix = false
).apply {
if (otherParameterNeeded) {
val irValueParameter = createSyntheticIrParameter(
@@ -265,11 +288,23 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
private fun createSyntheticIrParameter(irFunction: IrFunction, name: Name, type: IrType, index: Int = 0): IrValueParameter {
val descriptor = WrappedValueParameterDescriptor()
return components.symbolTable.declareValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, descriptor, type
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
descriptor,
type
) { symbol ->
components.irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, name, index, type, null,
isCrossinline = false, isNoinline = false
IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
symbol,
name,
index,
type,
null,
isCrossinline = false,
isNoinline = false
)
}.apply {
parent = irFunction
@@ -302,4 +337,4 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
fun getComponentIndex(irFunction: IrFunction): Int? =
irFunction.name.identifier.substring("component".length).toIntOrNull()
}
}
}

View File

@@ -23,14 +23,15 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedPropertyDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -114,7 +115,7 @@ internal class DelegatedMemberGenerator(
} == true
lateinit var irTypeSubstitutor: IrTypeSubstitutor
val delegateFunction = symbolTable.declareSimpleFunction(descriptor) { symbol ->
irFactory.createFunction(
IrFunctionImpl(
startOffset,
endOffset,
origin,
@@ -145,7 +146,7 @@ internal class DelegatedMemberGenerator(
typeParameters += symbolTable.declareScopedTypeParameter(
startOffset, endOffset, origin, parameterDescriptor
) { symbol ->
irFactory.createTypeParameter(
IrTypeParameterImpl(
startOffset,
endOffset,
origin,
@@ -175,7 +176,7 @@ internal class DelegatedMemberGenerator(
valueParameters += symbolTable.declareValueParameter(
startOffset, endOffset, origin, parameterDescriptor, substedType
) { symbol ->
irFactory.createValueParameter(
IrValueParameterImpl(
startOffset, endOffset, origin, symbol,
valueParameter.name, valueParameter.index, substedType,
null, valueParameter.isCrossinline, valueParameter.isNoinline
@@ -215,7 +216,7 @@ internal class DelegatedMemberGenerator(
}
}
val body = irFactory.createBlockBody(startOffset, endOffset)
val body = IrBlockBodyImpl(startOffset, endOffset)
val irCall = IrCallImpl(
startOffset,
endOffset,
@@ -281,7 +282,7 @@ internal class DelegatedMemberGenerator(
startOffset, endOffset,
IrDeclarationOrigin.DELEGATED_MEMBER, descriptor, superProperty.isDelegated
) { symbol ->
irFactory.createProperty(
IrPropertyImpl(
startOffset, endOffset, IrDeclarationOrigin.DELEGATED_MEMBER, symbol,
superProperty.name, superProperty.visibility,
modality,

View File

@@ -67,7 +67,6 @@ class FakeOverrideGenerator(
for (name in superTypesCallableNames) {
if (name in processedCallableNames) continue
processedCallableNames += name
val isLocal = klass !is FirRegularClass || klass.isLocal
useSiteMemberScope.processFunctionsByName(name) { functionSymbol ->
if (functionSymbol is FirNamedFunctionSymbol) {
val originalFunction = functionSymbol.fir
@@ -92,8 +91,7 @@ class FakeOverrideGenerator(
originalFunction,
irParent = this,
thisReceiverOwner = declarationStorage.findIrParent(baseSymbol.fir) as? IrClass,
origin = origin,
isLocal = isLocal
origin = origin
)
// In fake overrides, parent logic is a bit specific, because
// parent of *original* function (base class) is used for dispatch receiver,
@@ -117,8 +115,7 @@ class FakeOverrideGenerator(
fakeOverrideFunction,
irParent = this,
thisReceiverOwner = declarationStorage.findIrParent(originalFunction) as? IrClass,
origin = origin,
isLocal = isLocal
origin = origin
)
if (irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() }) {
return@processFunctionsByName
@@ -145,8 +142,7 @@ class FakeOverrideGenerator(
?: declarationStorage.createIrProperty(
originalProperty, irParent = this,
thisReceiverOwner = declarationStorage.findIrParent(baseSymbol.fir) as? IrClass,
origin = origin,
isLocal = isLocal
origin = origin
)
irProperty.parent = this
result += irProperty.withProperty {
@@ -166,8 +162,7 @@ class FakeOverrideGenerator(
val irProperty = declarationStorage.createIrProperty(
fakeOverrideProperty, irParent = this,
thisReceiverOwner = declarationStorage.findIrParent(originalProperty) as? IrClass,
origin = origin,
isLocal = isLocal
origin = origin
)
if (irProperty.backingField?.type?.containsErrorType() == true ||
irProperty.getter?.returnType?.containsErrorType() == true

View File

@@ -25,9 +25,6 @@ abstract class AbstractFir2IrLazyDeclaration<F : FirMemberDeclaration, D : IrSym
val fir: F,
open val symbol: Fir2IrBindableSymbol<*, D>
) : IrElementBase(startOffset, endOffset), IrDeclaration, IrDeclarationParent, Fir2IrComponents by components {
override val factory: IrFactory
get() = components.irFactory
internal fun prepareTypeParameters() {
typeParameters = fir.typeParameters.mapIndexedNotNull { index, typeParameter ->
if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null

View File

@@ -14,13 +14,16 @@ import org.jetbrains.kotlin.fir.resolve.buildUseSiteMemberScope
import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.isNullableAny
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.transform
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
class Fir2IrLazyClass(
@@ -128,20 +131,12 @@ class Fir2IrLazyClass(
is FirSimpleFunction -> {
if (declaration.name !in processedNames) {
processedNames += declaration.name
if (fir.classKind == ClassKind.ENUM_CLASS && declaration.isStatic &&
declaration.returnTypeRef is FirResolvedTypeRef
) {
// Handle values() / valueOf() separately
// TODO: handle other static functions / properties properly
result += declarationStorage.getIrFunctionSymbol(declaration.symbol).owner
} else {
scope.processFunctionsByName(declaration.name) {
if (it is FirNamedFunctionSymbol && it.callableId.classId == fir.symbol.classId) {
if (it.isAbstractMethodOfAny()) {
return@processFunctionsByName
}
result += declarationStorage.getIrFunctionSymbol(it).owner
scope.processFunctionsByName(declaration.name) {
if (it is FirNamedFunctionSymbol && it.callableId.classId == fir.symbol.classId) {
if (it.isAbstractMethodOfAny()) {
return@processFunctionsByName
}
result += declarationStorage.getIrFunctionSymbol(it).owner
}
}
}
@@ -188,4 +183,19 @@ class Fir2IrLazyClass(
else -> false
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitClass(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
thisReceiver?.accept(visitor, data)
typeParameters.forEach { it.accept(visitor, data) }
declarations.forEach { it.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
thisReceiver = thisReceiver?.transform(transformer, data)
typeParameters = typeParameters.transformIfNeeded(transformer, data)
declarations.transform { it.transform(transformer, data) }
}
}

View File

@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
@@ -112,4 +114,24 @@ class Fir2IrLazyConstructor(
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstructor(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
typeParameters.forEach { it.accept(visitor, data) }
dispatchReceiverParameter?.accept(visitor, data)
extensionReceiverParameter?.accept(visitor, data)
valueParameters.forEach { it.accept(visitor, data) }
body?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
typeParameters = typeParameters.transformIfNeeded(transformer, data)
dispatchReceiverParameter = dispatchReceiverParameter?.transform(transformer, data)
extensionReceiverParameter = extensionReceiverParameter?.transform(transformer, data)
valueParameters = valueParameters.transformIfNeeded(transformer, data)
body = body?.transform(transformer, data)
}
}

View File

@@ -18,9 +18,12 @@ import org.jetbrains.kotlin.fir.symbols.Fir2IrPropertySymbol
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
class Fir2IrLazyProperty(
@@ -100,7 +103,7 @@ class Fir2IrLazyProperty(
if (initializer is FirConstExpression<*>) {
// TODO: Normally we shouldn't have error type here
val constType = with(typeConverter) { initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type }
field.initializer = factory.createExpressionBody(initializer.toIrConst(constType))
field.initializer = IrExpressionBodyImpl(initializer.toIrConst(constType))
}
}
}
@@ -150,4 +153,20 @@ class Fir2IrLazyProperty(
override var metadata: MetadataSource?
get() = null
set(_) = error("We should never need to store metadata of external declarations.")
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitProperty(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
backingField?.accept(visitor, data)
getter?.accept(visitor, data)
setter?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
backingField = backingField?.transform(transformer, data) as? IrField
getter = getter?.run { transform(transformer, data) as IrSimpleFunction }
setter = setter?.run { transform(transformer, data) as IrSimpleFunction }
}
}

View File

@@ -21,6 +21,9 @@ import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
class Fir2IrLazySimpleFunction(
@@ -138,4 +141,28 @@ class Fir2IrLazySimpleFunction(
override var metadata: MetadataSource?
get() = null
set(_) = error("We should never need to store metadata of external declarations.")
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitSimpleFunction(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
typeParameters.forEach { it.accept(visitor, data) }
dispatchReceiverParameter?.accept(visitor, data)
extensionReceiverParameter?.accept(visitor, data)
valueParameters.forEach { it.accept(visitor, data) }
body?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
typeParameters = typeParameters.transformIfNeeded(transformer, data)
dispatchReceiverParameter = dispatchReceiverParameter?.transform(transformer, data)
extensionReceiverParameter = extensionReceiverParameter?.transform(transformer, data)
valueParameters = valueParameters.transformIfNeeded(transformer, data)
body = body?.transform(transformer, data)
}
}

View File

@@ -63,30 +63,30 @@ class FirBasedSignatureComposer(private val mangler: FirMangler) : Fir2IrSignatu
override fun composeSignature(declaration: FirDeclaration): IdSignature? {
if (declaration is FirAnonymousObject || declaration is FirAnonymousFunction) return null
val builder = SignatureBuilder()
try {
declaration.accept(builder)
} catch (t: Throwable) {
throw IllegalStateException("Error while composing signature for ${declaration.render()}", t)
if (declaration is FirMemberDeclaration && declaration.effectiveVisibility == FirEffectiveVisibilityImpl.Local) {
return null
}
return when (declaration) {
is FirRegularClass -> {
val builder = SignatureBuilder()
declaration.accept(builder)
return when {
declaration is FirRegularClass && declaration.visibility != Visibilities.LOCAL -> {
// TODO: private classes are probably not acceptable here too
val classId = declaration.classId
IdSignature.PublicSignature(
classId.packageFqName.asString(), classId.relativeClassName.asString(), builder.hashId, builder.mask
)
}
is FirTypeAlias -> {
declaration is FirTypeAlias -> {
if (declaration.visibility == Visibilities.PRIVATE) return null
val classId = declaration.symbol.classId
IdSignature.PublicSignature(
classId.packageFqName.asString(), classId.relativeClassName.asString(), builder.hashId, builder.mask
)
}
is FirCallableMemberDeclaration<*> -> {
declaration is FirCallableMemberDeclaration<*> -> {
if (declaration.visibility == Visibilities.PRIVATE) return null
val callableId = declaration.symbol.callableId
if (callableId.classId?.isLocal == true) return null
IdSignature.PublicSignature(
callableId.packageName.asString(), callableId.relativeCallableName.asString(), builder.hashId, builder.mask
)

View File

@@ -61,11 +61,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/annotations/annotationProperty.kt");
}
@TestMetadata("annotationTargets.kt")
public void testAnnotationTargets() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotationTargets.kt");
}
@TestMetadata("annotationWithKotlinProperty.kt")
public void testAnnotationWithKotlinProperty() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotationWithKotlinProperty.kt");
@@ -15640,11 +15635,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
}
@TestMetadata("deprecatedAnnotation.kt")
public void testDeprecatedAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/deprecatedAnnotation.kt");
}
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
public void testInheritedFunctionWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");

View File

@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveProcessor
import org.jetbrains.kotlin.ir.AbstractIrTextTestCase
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import java.io.File
abstract class AbstractFir2IrTextTest : AbstractIrTextTestCase() {
@@ -88,11 +87,10 @@ abstract class AbstractFir2IrTextTest : AbstractIrTextTestCase() {
return Fir2IrConverter.createModuleFragment(
session, resolveTransformer.scopeSession, firFiles,
myEnvironment.configuration.languageVersionSettings,
signaturer,
signaturer = signaturer,
// TODO: differentiate JVM resolve from other targets, such as JS resolve.
JvmGeneratorExtensions(generateFacades = false),
FirJvmKotlinMangler(session),
IrFactoryImpl,
generatorExtensions = JvmGeneratorExtensions(generateFacades = false),
mangler = FirJvmKotlinMangler(session)
).irModuleFragment
}
}
}

View File

@@ -1690,24 +1690,6 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
}
}
@TestMetadata("compiler/testData/ir/irText/firProblems")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FirProblems extends AbstractFir2IrTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.ANY, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInFirProblems() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/firProblems"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("deprecated.kt")
public void testDeprecated() throws Exception {
runTest("compiler/testData/ir/irText/firProblems/deprecated.kt");
}
}
@TestMetadata("compiler/testData/ir/irText/lambdas")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -96,6 +96,7 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
if (state == State.VARARG_POSITION) {
completeVarargPositionArguments()
}
state = State.NAMED_ONLY_ARGUMENTS
processNamedArgument(argument, argumentName)
}
@@ -136,8 +137,6 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
addDiagnostic(NamedArgumentNotAllowed(argument, function))
}
val stateAllowsMixedNamedAndPositionArguments = state != State.NAMED_ONLY_ARGUMENTS
state = State.NAMED_ONLY_ARGUMENTS
val parameter = findParameterByName(argument, name) ?: return
result[parameter]?.let {
@@ -147,7 +146,7 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
result[parameter] = ResolvedCallArgument.SimpleArgument(argument)
if (stateAllowsMixedNamedAndPositionArguments && parameters.getOrNull(currentPositionedParameterIndex) == parameter) {
if (parameters.getOrNull(currentPositionedParameterIndex) == parameter) {
state = State.POSITION_ARGUMENTS
currentPositionedParameterIndex++
}
@@ -264,9 +263,7 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
private val FirExpression.argumentName: Name?
get() = (this as? FirNamedArgumentExpression)?.name
// TODO: handle functions with non-stable parameter names, see also
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto
// TODO: handle java functions
private val FirFunction<*>.hasStableParameterNames: Boolean
get() = true
}

View File

@@ -11,17 +11,18 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.inference.*
import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.ClassId
@@ -92,7 +93,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
override fun Candidate.getReceiverType(): ConeKotlinType? {
val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null
val callable = with(bodyResolveComponents) { callableSymbol.phasedFir }
val callable = callableSymbol.fir
val receiverType = callable.receiverTypeRef?.coneType
if (receiverType != null) return receiverType
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
@@ -155,7 +156,7 @@ private fun FirExpression.isSuperReferenceExpression(): Boolean {
internal object MapArguments : ResolutionStage() {
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val symbol = candidate.symbol as? FirFunctionSymbol<*> ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
val function = with(candidate.bodyResolveComponents) { symbol.phasedFir }
val function = symbol.fir
val mapping = mapArguments(callInfo.arguments, function)
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
@@ -220,18 +221,12 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
}
val returnTypeRef = candidate.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir)
// If the expected type is a suspend function type and the current argument of interest is a function reference, we need to do
// "suspend conversion." Here, during resolution, we bypass constraint system by making resulting type be KSuspendFunction.
// Then, during conversion, we need to create an adapter function and replace the function reference created here with an adapted
// callable reference.
// TODO: should refer to LanguageVersionSettings.SuspendConversion
val requireSuspendConversion = expectedType?.isSuspendFunctionType(callInfo.session) == true
// TODO: handle callable reference with vararg
val resultingType: ConeKotlinType = when (fir) {
is FirFunction -> callInfo.session.createKFunctionType(
fir, resultingReceiverType, returnTypeRef,
expectedParameterNumberWithReceiver = expectedType?.let { it.typeArguments.size - 1 },
isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true || requireSuspendConversion,
isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true,
expectedReturnType = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, callInfo.session)?.outputType
)
is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef)
@@ -570,4 +565,4 @@ internal object PostponedVariablesInitializerResolutionStage : ResolutionStage()
private fun FirValueParameter.hasBuilderInferenceMarker(): Boolean {
return this.hasAnnotation(BUILDER_INFERENCE_CLASS_ID)
}
}
}

View File

@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.resolve.transformers.TransformImplicitType
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.runContractResolveForLocalClass
import org.jetbrains.kotlin.fir.symbols.impl.FirAccessorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -86,9 +87,9 @@ fun <F : FirClass<F>> F.runContractAndBodiesResolutionForLocalClass(
components.session, components.scopeSession,
implicitBodyResolveComputationSession,
FirResolvePhase.BODY_RESOLVE,
outerBodyResolveContext = newContext,
implicitTypeOnly = false,
returnTypeCalculator,
outerBodyResolveContext = newContext
returnTypeCalculator
)
val graphBuilder = components.context.dataFlowAnalyzerContext.graphBuilder

View File

@@ -124,6 +124,7 @@ class FirIntegerOperator @FirImplementationDetail constructor(
FirDeclarationOrigin.Synthetic,
returnTypeRef,
receiverTypeRef,
typeParameters = mutableListOf(),
valueParameters = mutableListOf(),
body = null,
status,
@@ -132,7 +133,6 @@ class FirIntegerOperator @FirImplementationDetail constructor(
kind.operatorName,
symbol,
annotations = mutableListOf(),
typeParameters = mutableListOf(),
) {
enum class Kind(val unary: Boolean, val operatorName: Name) {
PLUS(false, OperatorNameConventions.PLUS),

View File

@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.config.JvmTarget
@@ -15,21 +14,15 @@ import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.resolve.LanguageVersionSettingsProvider
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPrivateApi
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.annotations.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.util.getNonPrivateTraitMembersForDelegation
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : DeclarationChecker {
private val ideService = LanguageVersionSettingsProvider.getInstance(project)
class JvmDefaultChecker(val jvmTarget: JvmTarget) : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val jvmDefaultMode = context.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
@@ -82,79 +75,46 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
}
}
}
}
if (!jvmDefaultMode.isEnabled || descriptor !is ClassDescriptor || isInterface(descriptor) || isAnnotationClass(descriptor)) return
// JvmDefaults members checks across class hierarchy:
// 1. If in old scheme class have implicit override with different signature than overriden method (e.g. generic specialization)
// report error because absent of it's can affect library ABI
// 2. If it's mixed hierarchy with implicit override in base class and override one in inherited derived interface report error.
// Otherwise the implicit class override would be used for dispatching method calls (but not more specialized)
val performSpecializationCheck = jvmDefaultMode.isCompatibility && !descriptor.hasJvmDefaultNoCompatibilityAnnotation() &&
//TODO: maybe remove this check for JVM compatibility
!(descriptor.modality !== Modality.OPEN && descriptor.modality !== Modality.ABSTRACT || descriptor.isEffectivelyPrivateApi)
//Should we check clash with implicit class member (that comes from old compilation scheme) and specialization for compatibility mode
// If specialization check is reported clash one shouldn't be reported
if (descriptor.getSuperClassNotAny() == null && !performSpecializationCheck) return
getNonPrivateTraitMembersForDelegation(
descriptor,
returnImplNotDelegate = true
).filter { (_, actualImplementation) -> actualImplementation.isCompiledToJvmDefaultWithProperMode(jvmDefaultMode) }
.forEach { (inheritedMember, actualImplementation) ->
if (actualImplementation is FunctionDescriptor && inheritedMember is FunctionDescriptor) {
if (checkSpecializationInCompatibilityMode(
inheritedMember,
actualImplementation,
context,
declaration,
performSpecializationCheck
)
) {
checkPossibleClashMember(inheritedMember, jvmDefaultMode, context, declaration)
}
} else if (actualImplementation is PropertyDescriptor && inheritedMember is PropertyDescriptor) {
val getterImpl = actualImplementation.getter
val getterInherited = inheritedMember.getter
if (getterImpl == null || getterInherited == null || !jvmDefaultMode.isCompatibility ||
checkSpecializationInCompatibilityMode(
getterInherited,
getterImpl,
context,
declaration,
performSpecializationCheck
)
) {
if (actualImplementation.isVar && inheritedMember.isVar) {
val setterImpl = actualImplementation.setter
val setterInherited = inheritedMember.setter
if (setterImpl != null && setterInherited != null) {
if (!checkSpecializationInCompatibilityMode(
setterInherited,
setterImpl,
context,
declaration,
performSpecializationCheck
)
) return@forEach
} else if (jvmDefaultMode.isCompatibility &&
!isInterface(descriptor) &&
!isAnnotationClass(descriptor) &&
descriptor is ClassDescriptor &&
!descriptor.hasJvmDefaultNoCompatibilityAnnotation()
) {
val modality = descriptor.modality
//TODO: maybe remove this check for jvm compatibility
if (modality !== Modality.OPEN && modality !== Modality.ABSTRACT || descriptor.isEffectivelyPrivateApi) return
for ((inheritedMember, actualImplementation) in getNonPrivateTraitMembersForDelegation(
descriptor,
returnImplNotDelegate = true
)) {
if (actualImplementation.isCallableMemberCompiledToJvmDefault(jvmDefaultMode)) {
if (actualImplementation is FunctionDescriptor && inheritedMember is FunctionDescriptor) {
processMember(inheritedMember, actualImplementation, context, declaration)
} else if (actualImplementation is PropertyDescriptor && inheritedMember is PropertyDescriptor) {
val getterImpl = actualImplementation.getter
val getterInherited = inheritedMember.getter
if (getterImpl == null || getterInherited == null || processMember(getterImpl, getterImpl, context, declaration)) {
if (actualImplementation.isVar && inheritedMember.isVar) {
val setterImpl = actualImplementation.setter
val setterInherited = inheritedMember.setter
if (setterImpl != null && setterInherited != null) {
processMember(setterImpl, setterImpl, context, declaration)
}
}
}
checkPossibleClashMember(inheritedMember, jvmDefaultMode, context, declaration)
}
}
}
}
}
private fun checkSpecializationInCompatibilityMode(
private fun processMember(
inheritedFun: FunctionDescriptor,
actualImplementation: FunctionDescriptor,
context: DeclarationCheckerContext,
declaration: KtDeclaration,
performSpecializationCheck: Boolean
declaration: KtDeclaration
): Boolean {
if (!performSpecializationCheck) return true
val inheritedSignature = inheritedFun.computeJvmDescriptor(withReturnType = true, withName = false)
val originalImplementation = actualImplementation.original
val actualSignature = originalImplementation.computeJvmDescriptor(withReturnType = true, withName = false)
@@ -172,39 +132,6 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
return true
}
private fun checkPossibleClashMember(
inheritedFun: CallableMemberDescriptor,
jvmDefaultMode: JvmDefaultMode,
context: DeclarationCheckerContext,
declaration: KtDeclaration
) {
val clashMember = findPossibleClashMember(inheritedFun, jvmDefaultMode)
if (clashMember != null) {
context.trace.report(
ErrorsJvm.EXPLICIT_OVERRIDE_REQUIRED_IN_MIXED_MODE.on(
declaration,
getDirectMember(inheritedFun),
getDirectMember(clashMember),
jvmDefaultMode.description
)
)
}
}
private fun findPossibleClashMember(
inheritedFun: CallableMemberDescriptor,
jvmDefaultMode: JvmDefaultMode
): CallableMemberDescriptor? {
val classDescriptor = inheritedFun.containingDeclaration
if (classDescriptor !is ClassDescriptor || classDescriptor.getSuperClassNotAny() == null) return null
val classMembers =
inheritedFun.overriddenDescriptors.filter { !isInterface(it.containingDeclaration) && !isAnnotationClass(it.containingDeclaration) }
val implicitDefaultImplsDelegate =
classMembers.firstOrNull { getNonPrivateTraitMembersForDelegation(it, true)?.isCompiledToJvmDefaultWithProperMode(jvmDefaultMode) == false }
if (implicitDefaultImplsDelegate != null) return implicitDefaultImplsDelegate
return classMembers.firstNotNullResult { findPossibleClashMember(it, jvmDefaultMode) }
}
private fun checkJvmDefaultsInHierarchy(descriptor: DeclarationDescriptor, jvmDefaultMode: JvmDefaultMode): Boolean {
if (jvmDefaultMode.isEnabled) return true
@@ -213,16 +140,9 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
return descriptor.unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>()
.all { memberDescriptor ->
memberDescriptor.kind.isReal || OverridingUtil.filterOutOverridden(memberDescriptor.overriddenDescriptors.toSet()).all {
!isInterface(it.containingDeclaration) || !it.isCompiledToJvmDefaultWithProperMode(jvmDefaultMode) || it.modality == Modality.ABSTRACT
!isInterface(it.containingDeclaration) || !it.isCompiledToJvmDefault(jvmDefaultMode) || it.modality == Modality.ABSTRACT
}
}
}
private fun CallableMemberDescriptor.isCompiledToJvmDefaultWithProperMode(compilationDefaultMode: JvmDefaultMode): Boolean {
val jvmDefault =
if (this is DeserializedDescriptor) compilationDefaultMode else ideService?.getModuleLanguageVersionSettings(module)
?.getFlag(JvmAnalysisFlags.jvmDefaultMode) ?: compilationDefaultMode
return isCompiledToJvmDefault(jvmDefault)
}
}

Some files were not shown because too many files have changed in this diff Show More