diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 26fe17949c8..a94a4e9f644 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2844,6 +2844,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS) { firDiagnostic -> + ExplicitTypeArgumentsInPropertyAccessImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.EXPECTED_DECLARATION_WITH_BODY) { firDiagnostic -> ExpectedDeclarationWithBodyImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index d991121749c..07328327fa9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2008,6 +2008,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = LocalVariableWithTypeParameters::class } + abstract class ExplicitTypeArgumentsInPropertyAccess : KtFirDiagnostic() { + override val diagnosticClass get() = ExplicitTypeArgumentsInPropertyAccess::class + } + abstract class ExpectedDeclarationWithBody : KtFirDiagnostic() { override val diagnosticClass get() = ExpectedDeclarationWithBody::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 26a594c2a6d..44ba3108c4a 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2418,6 +2418,11 @@ internal class LocalVariableWithTypeParametersImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic +internal class ExplicitTypeArgumentsInPropertyAccessImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.ExplicitTypeArgumentsInPropertyAccess(), KtAbstractFirDiagnostic + internal class ExpectedDeclarationWithBodyImpl( override val firDiagnostic: KtPsiDiagnostic, override val token: KtLifetimeToken, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index 681fa38430e..266a34adcd8 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -2159,6 +2159,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/privateVisibility.kt"); } + @Test + @TestMetadata("propertyAccessWithExplicitTypeArguments.kt") + public void testPropertyAccessWithExplicitTypeArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt"); + } + @Test @TestMetadata("protectedVisibility.kt") public void testProtectedVisibility() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index e8bc116e3f5..3c9c1da0b11 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -1881,6 +1881,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/privateVisibility.kt"); } + @TestMetadata("propertyAccessWithExplicitTypeArguments.kt") + public void testPropertyAccessWithExplicitTypeArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt"); + } + @TestMetadata("protectedVisibility.kt") public void testProtectedVisibility() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/protectedVisibility.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.fir.txt new file mode 100644 index 00000000000..83e4d64aea4 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.fir.txt @@ -0,0 +1,88 @@ +FILE: propertyAccessWithExplicitTypeArguments.kt + public final fun f1(x: R|kotlin/Int|): R|kotlin/Unit| { + lval y: R|kotlin/Int| = Int(5) + lval s: R|kotlin/String| = String(hello) + R|/x| + R|/x| + R|/y| + R|/y| + R|/s| + R|/s| + } + public final val property: R|kotlin/Int| = Int(10) + public get(): R|kotlin/Int| + public final fun f2(): R|kotlin/Unit| { + R|/property| + } + public final val property2: R|kotlin/Int| + public get(): R|kotlin/Int| { + ^ Int(10) + } + public final fun f3(): R|kotlin/Unit| { + R|/property2| + } + public abstract interface Context : R|kotlin/Any| { + } + public final class ContextImpl : R|Context| { + public constructor(): R|ContextImpl| { + super() + } + + } + public final class Receiver : R|kotlin/Any| { + public constructor(): R|Receiver| { + super() + } + + } + public final val R|Receiver|.hello1: R|kotlin/String| + public get(): R|kotlin/String| { + ^ String(hello 1) + } + context(R|Context|) + public final val hello2: R|kotlin/String| + public get(): R|kotlin/String| { + ^ String(hello 2) + } + context(R|Context|) + public final val R|Receiver|.hello3: R|kotlin/String| + public get(): R|kotlin/String| { + ^ String(hello 3) + } + public final operator fun R|kotlin/String|.invoke(): R|kotlin/String| { + ^invoke String(world) + } + public final fun f4(): R|kotlin/Unit| { + lval receiver: R|Receiver| = R|/Receiver.Receiver|() + R|/receiver|.R|/hello1| + R|/receiver|.R|/hello1| + R|/receiver|.R|/hello1|.R|/invoke|() + R|/receiver|.R|/hello1| + R|/receiver|.R|/hello1| + R|/receiver|.R|/hello1| + R|kotlin/with||, R|kotlin/String|>(R|/ContextImpl.ContextImpl|(), = with@fun R|ContextImpl|.(): R|kotlin/String| { + R|/hello2| + R|/hello2| + R|/hello2|.R|/invoke|() + R|/hello2| + R|/hello2| + R|/hello2| + R|/receiver|.R|/hello3| + R|/receiver|.R|/hello3| + R|/receiver|.R|/hello3|.R|/invoke|() + R|/receiver|.R|/hello3| + R|/receiver|.R|/hello3| + ^ R|/receiver|.R|/hello3| + } + ) + } + public final val R|Receiver|.helloReified: R|kotlin/String| + public inline get(): R|kotlin/String| { + ^ String(hello) + } + public final fun f5(): R|kotlin/Unit| { + lval receiver: R|Receiver| = R|/Receiver.Receiver|() + R|/receiver|.R|/helloReified| + R|/receiver|.R|/helloReified| + R|/receiver|.R|/helloReified| + } diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt new file mode 100644 index 00000000000..7a5f19714e2 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt @@ -0,0 +1,85 @@ +// ISSUE: KT-54978 + +// Case 1: Parameters and local variables +fun f1(x: Int) { + val y = 5 + val s = "hello" + + x + x + y + y + s + s +} + +// Case 2: Simple property +val property: Int = 10 + +fun f2() { + property +} + +// Case 3: Simple property with getter +val property2: Int + get() = 10 + +fun f3() { + property2 +} + +// Case 4: Property with extension and/or context receiver +interface Context +class ContextImpl : Context +class Receiver + +val Receiver.hello1: String + get() = "hello 1" + +context(Context) +val hello2: String + get() = "hello 2" + +context(Context) +val Receiver.hello3: String + get() = "hello 3" + +operator fun String.invoke(): String = "world" + +fun f4() { + val receiver = Receiver() + + receiver.hello1 + receiver.hello1 + receiver.hello1() // legal `String.invoke` call + receiver.hello1 + receiver.hello1 + receiver.hello1 + + with (ContextImpl()) { + hello2 + hello2 + hello2() // legal `String.invoke` call + hello2 + hello2 + hello2 + + receiver.hello3 + receiver.hello3 + receiver.hello3() // legal `String.invoke` call + receiver.hello3 + receiver.hello3 + receiver.hello3 + } +} + +// Case 5: Property with receiver and reified type parameter +inline val Receiver.helloReified: String + get() = "hello" + +fun f5() { + val receiver = Receiver() + receiver.helloReified + receiver.helloReified + receiver.helloReified +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 663b7882872..2dce587400e 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -2159,6 +2159,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/privateVisibility.kt"); } + @Test + @TestMetadata("propertyAccessWithExplicitTypeArguments.kt") + public void testPropertyAccessWithExplicitTypeArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt"); + } + @Test @TestMetadata("protectedVisibility.kt") public void testProtectedVisibility() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 89a3898872f..d100318a864 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -2159,6 +2159,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/privateVisibility.kt"); } + @Test + @TestMetadata("propertyAccessWithExplicitTypeArguments.kt") + public void testPropertyAccessWithExplicitTypeArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt"); + } + @Test @TestMetadata("protectedVisibility.kt") public void testProtectedVisibility() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index 59523c8e015..4d4e236226d 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -35,6 +35,7 @@ fun main(args: Array) { alias("QualifiedAccessExpressionChecker") alias("CallChecker") alias("FunctionCallChecker") + alias("PropertyAccessExpressionChecker") alias("IntegerLiteralOperatorCallChecker") alias("VariableAssignmentChecker") alias("TryExpressionChecker") diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index ad0e93a786d..56ba9175a58 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -1007,6 +1007,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error(PositioningStrategy.ABSTRACT_MODIFIER) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning(PositioningStrategy.TYPE_PARAMETERS_LIST) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error(PositioningStrategy.TYPE_PARAMETERS_LIST) + val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) } val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt index 28d6b45a276..b7de21b6e51 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt @@ -23,6 +23,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() { get() = _callCheckers override val functionCallCheckers: Set get() = _functionCallCheckers + override val propertyAccessExpressionCheckers: Set + get() = _propertyAccessExpressionCheckers override val integerLiteralOperatorCallCheckers: Set get() = _integerLiteralOperatorCallCheckers override val variableAssignmentCheckers: Set @@ -81,6 +83,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() { private val _qualifiedAccessExpressionCheckers: MutableSet = mutableSetOf() private val _callCheckers: MutableSet = mutableSetOf() private val _functionCallCheckers: MutableSet = mutableSetOf() + private val _propertyAccessExpressionCheckers: MutableSet = mutableSetOf() private val _integerLiteralOperatorCallCheckers: MutableSet = mutableSetOf() private val _variableAssignmentCheckers: MutableSet = mutableSetOf() private val _tryExpressionCheckers: MutableSet = mutableSetOf() @@ -115,6 +118,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() { _qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers _callCheckers += checkers.callCheckers _functionCallCheckers += checkers.functionCallCheckers + _propertyAccessExpressionCheckers += checkers.propertyAccessExpressionCheckers _integerLiteralOperatorCallCheckers += checkers.integerLiteralOperatorCallCheckers _variableAssignmentCheckers += checkers.variableAssignmentCheckers _tryExpressionCheckers += checkers.tryExpressionCheckers diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt index 5c72a5057e9..b9065d75a23 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt @@ -22,6 +22,7 @@ abstract class ExpressionCheckers { open val qualifiedAccessExpressionCheckers: Set = emptySet() open val callCheckers: Set = emptySet() open val functionCallCheckers: Set = emptySet() + open val propertyAccessExpressionCheckers: Set = emptySet() open val integerLiteralOperatorCallCheckers: Set = emptySet() open val variableAssignmentCheckers: Set = emptySet() open val tryExpressionCheckers: Set = emptySet() @@ -54,6 +55,7 @@ abstract class ExpressionCheckers { @CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers } @CheckersComponentInternal internal val allCallCheckers: Set by lazy { callCheckers + basicExpressionCheckers } @CheckersComponentInternal internal val allFunctionCallCheckers: Set by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers } + @CheckersComponentInternal internal val allPropertyAccessExpressionCheckers: Set by lazy { propertyAccessExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers } @CheckersComponentInternal internal val allIntegerLiteralOperatorCallCheckers: Set by lazy { integerLiteralOperatorCallCheckers + functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers } @CheckersComponentInternal internal val allVariableAssignmentCheckers: Set by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers } @CheckersComponentInternal internal val allTryExpressionCheckers: Set by lazy { tryExpressionCheckers + basicExpressionCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt index c04a232123e..6511fa142f1 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall import org.jetbrains.kotlin.fir.expressions.FirLoop import org.jetbrains.kotlin.fir.expressions.FirLoopJump +import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier @@ -47,6 +48,7 @@ typealias FirQualifiedAccessChecker = FirExpressionChecker typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker typealias FirCallChecker = FirExpressionChecker typealias FirFunctionCallChecker = FirExpressionChecker +typealias FirPropertyAccessExpressionChecker = FirExpressionChecker typealias FirIntegerLiteralOperatorCallChecker = FirExpressionChecker typealias FirVariableAssignmentChecker = FirExpressionChecker typealias FirTryExpressionChecker = FirExpressionChecker diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index faa7cf40d3e..ea7c57c97af 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -552,6 +552,7 @@ object FirErrors { val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0(SourceElementPositioningStrategies.ABSTRACT_MODIFIER) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) + val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) // Multi-platform projects val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index 0b4a3a635c0..6a7173da933 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -64,6 +64,11 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirUnderscoredTypeArgumentSyntaxChecker, ) + override val propertyAccessExpressionCheckers: Set + get() = setOf( + FirPropertyAccessTypeArgumentsChecker, + ) + override val tryExpressionCheckers: Set get() = setOf( FirCatchParameterChecker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirPropertyAccessTypeArgumentsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirPropertyAccessTypeArgumentsChecker.kt new file mode 100644 index 00000000000..b182e151a2e --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirPropertyAccessTypeArgumentsChecker.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.expression + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression +import org.jetbrains.kotlin.fir.references.FirErrorNamedReference + +object FirPropertyAccessTypeArgumentsChecker : FirPropertyAccessExpressionChecker() { + override fun check(expression: FirPropertyAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + // Property accesses may not have explicit type arguments (see KT-54978). Additionally, the callee reference's errors should take + // precedence, if any exist. For example, the callee reference might be a function `Collections.emptyList`, but the programmer + // has forgotten to add function call parentheses, making it a property access. + if (expression.calleeReference !is FirErrorNamedReference) { + val hasExplicitTypeArgument = expression.typeArguments.any { it.source != null } + if (hasExplicitTypeArgument) { + reporter.reportOn(expression.source, FirErrors.EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS, context) + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt index 56ff3cd0c08..9e815a298db 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt @@ -41,7 +41,7 @@ class ExpressionCheckersDiagnosticComponent( } override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: CheckerContext) { - checkers.allQualifiedAccessExpressionCheckers.check(propertyAccessExpression, data) + checkers.allPropertyAccessExpressionCheckers.check(propertyAccessExpression, data) } override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index a445fd2d100..7a1b1e5e8ff 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -192,6 +192,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_EXTENSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_FUNCTION_RETURN_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PROPERTY_TYPE @@ -1622,6 +1623,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, "This property cannot be declared abstract") map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING, "Type parameters for local variables are deprecated") map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS, "Local variables are not allowed to have type parameters") + map.put(EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS, "A property access cannot have explicit type arguments") map.put(CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, "Const 'val' are only allowed on top level, in named objects, or in companion objects") map.put(CONST_VAL_WITH_GETTER, "Const 'val' should not have a getter") diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.fir.kt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.fir.kt index 6fd31355395..2f4780bc6e2 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.fir.kt @@ -17,17 +17,19 @@ class Test { val List.a: Int get() = size val List.b: Int? get() = size - fun List.testCallable1(): () -> Unit = a::foo + fun List.testCallable1(): () -> Unit = a::foo + fun List.testCallable1a(): () -> Unit = a::foo fun List.testCallable2(): () -> Unit = b?::foo - fun List.testCallable3(): () -> Unit = b::foo - fun List.testCallable4(): () -> Unit = b?::foo + fun List.testCallable3(): () -> Unit = b::foo + fun List.testCallable4(): () -> Unit = b?::foo - fun List.testClassLiteral1() = a::class + fun List.testClassLiteral1() = a::class + fun List.testClassLiteral1a() = a::class fun List.testClassLiteral2() = b?::class - fun List.testClassLiteral3() = b::class + fun List.testClassLiteral3() = b::class fun List.testUnresolved1() = unresolved::foo - fun List.testUnresolved2() = a<unresolved>::foo + fun List.testUnresolved2() = a<unresolved>::foo fun List.testUnresolved3() = a<>::foo fun List.testUnresolved4() = unresolved?::foo } diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.kt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.kt index 60573150638..03508a0acfd 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.kt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.kt @@ -17,12 +17,14 @@ class Test { val List.a: Int get() = size val List.b: Int? get() = size - fun List.testCallable1(): () -> Unit = a::foo + fun List.testCallable1(): () -> Unit = a::foo + fun List.testCallable1a(): () -> Unit = a::foo fun List.testCallable2(): () -> Unit = b?::foo fun List.testCallable3(): () -> Unit = b::foo fun List.testCallable4(): () -> Unit = b?::foo - fun List.testClassLiteral1() = a::class + fun List.testClassLiteral1() = a::class + fun List.testClassLiteral1a() = a::class fun List.testClassLiteral2() = b?::class fun List.testClassLiteral3() = b::class diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.txt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.txt index 2d8c50e20d8..b6c9589e112 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.txt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax.txt @@ -18,10 +18,12 @@ package test { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public final fun kotlin.collections.List.testCallable1(): () -> kotlin.Unit + public final fun kotlin.collections.List.testCallable1a(): () -> kotlin.Unit public final fun kotlin.collections.List.testCallable2(): () -> kotlin.Unit public final fun kotlin.collections.List.testCallable3(): () -> kotlin.Unit public final fun kotlin.collections.List.testCallable4(): () -> kotlin.Unit public final fun kotlin.collections.List.testClassLiteral1(): kotlin.reflect.KClass + public final fun kotlin.collections.List.testClassLiteral1a(): kotlin.reflect.KClass public final fun kotlin.collections.List.testClassLiteral2(): kotlin.reflect.KClass public final fun kotlin.collections.List.testClassLiteral3(): kotlin.reflect.KClass public final fun kotlin.collections.List.testUnresolved1(): [Error type: Return type for function cannot be resolved] diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.fir.kt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.fir.kt index d862d9c81e5..42cc0877a3d 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.fir.kt @@ -21,8 +21,9 @@ class Test { val Int.c: Int get() = 42 - val test1: () -> Right = a.b.c::foo - val test1a: () -> Right = a.b.c::foo + val test1: () -> Right = a.b.c::foo + val test1a: () -> Right = a.b.c::foo - val test2: () -> Right = a.b.c?::foo + val test2: () -> Right = a.b.c?::foo + val test2a: () -> Right = a.b.c?::foo } diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.kt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.kt index 2f31e39ee14..7ffa2ef0e6a 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.kt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.kt @@ -21,8 +21,9 @@ class Test { val Int.c: Int get() = 42 - val test1: () -> Right = a.b<Int>.c::foo - val test1a: () -> Right = a.b.c::foo + val test1: () -> Right = a.b.c::foo + val test1a: () -> Right = a.b<Int>.c::foo - val test2: () -> Right = a.b<Int>.c?::foo + val test2: () -> Right = a.b.c?::foo + val test2a: () -> Right = a.b<Int>.c?::foo } diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.txt b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.txt index 41f98de3f0f..11236fc3892 100644 --- a/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.txt +++ b/compiler/testData/diagnostics/tests/callableReference/bound/reservedExpressionSyntax3.txt @@ -16,6 +16,7 @@ package test { public final val test1: () -> test.Right public final val test1a: () -> test.Right public final val test2: () -> test.Right + public final val test2a: () -> test.Right public final val kotlin.collections.List.b: kotlin.Int public final val kotlin.Int.c: kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/testData/diagnostics/tests/syntax/complicatedLTGT.fir.kt b/compiler/testData/diagnostics/tests/syntax/complicatedLTGT.fir.kt index 7fe44c53a54..e775b521c75 100644 --- a/compiler/testData/diagnostics/tests/syntax/complicatedLTGT.fir.kt +++ b/compiler/testData/diagnostics/tests/syntax/complicatedLTGT.fir.kt @@ -2,7 +2,7 @@ // ISSUE: KT-8263 fun test(x: Int, y: Int) { - if (x < (if (y > 115) 1 else 2)) { + if (x < (if (y > 115) 1 else 2)) { Unit } }