[FIR] KT-54978 Prohibit explicit type arguments in property accesses
- Add a checker which ensures that property accesses have no explicit type arguments. If an error on the property access's callee reference already exists, the new error is not reported in favor of the existing error, as the property access may have been intended to be a function call. - `complicatedLTGT.fir.kt`: The underlying parser issue is not yet solved, which is why `x` is parsed as a property access with explicit type arguments. - `reservedExpressionSyntax` tests: This new check makes a lot of the access expressions in these tests illegal, so valid lines have been added and invalid lines appropriately marked with `EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS` errors. ^KT-54978 fixed
This commit is contained in:
committed by
teamcity
parent
4d20b43619
commit
d4e6a4ad54
+6
@@ -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,
|
||||
|
||||
+4
@@ -2008,6 +2008,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = LocalVariableWithTypeParameters::class
|
||||
}
|
||||
|
||||
abstract class ExplicitTypeArgumentsInPropertyAccess : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ExplicitTypeArgumentsInPropertyAccess::class
|
||||
}
|
||||
|
||||
abstract class ExpectedDeclarationWithBody : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = ExpectedDeclarationWithBody::class
|
||||
}
|
||||
|
||||
+5
@@ -2418,6 +2418,11 @@ internal class LocalVariableWithTypeParametersImpl(
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic<KtProperty>
|
||||
|
||||
internal class ExplicitTypeArgumentsInPropertyAccessImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.ExplicitTypeArgumentsInPropertyAccess(), KtAbstractFirDiagnostic<KtExpression>
|
||||
|
||||
internal class ExpectedDeclarationWithBodyImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+88
@@ -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|<local>/x|<R|kotlin/Int|>
|
||||
R|<local>/x|<R|kotlin/String|, R|kotlin/String|>
|
||||
R|<local>/y|<R|kotlin/Int|>
|
||||
R|<local>/y|<R|kotlin/String|, R|kotlin/Int|>
|
||||
R|<local>/s|<R|kotlin/String|>
|
||||
R|<local>/s|<R|kotlin/Int|, R|kotlin/String|>
|
||||
}
|
||||
public final val property: R|kotlin/Int| = Int(10)
|
||||
public get(): R|kotlin/Int|
|
||||
public final fun f2(): R|kotlin/Unit| {
|
||||
R|/property|<R|kotlin/String|>
|
||||
}
|
||||
public final val property2: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int| {
|
||||
^ Int(10)
|
||||
}
|
||||
public final fun f3(): R|kotlin/Unit| {
|
||||
R|/property2|<R|kotlin/String|>
|
||||
}
|
||||
public abstract interface Context<A> : R|kotlin/Any| {
|
||||
}
|
||||
public final class ContextImpl<A> : R|Context<A>| {
|
||||
public constructor<A>(): R|ContextImpl<A>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class Receiver<A> : R|kotlin/Any| {
|
||||
public constructor<A>(): R|Receiver<A>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final val <A> R|Receiver<A>|.hello1: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 1)
|
||||
}
|
||||
context(R|Context<A>|)
|
||||
public final val <A> hello2: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 2)
|
||||
}
|
||||
context(R|Context<B>|)
|
||||
public final val <A, B> R|Receiver<A>|.hello3: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 3)
|
||||
}
|
||||
public final operator fun <A, B> R|kotlin/String|.invoke(): R|kotlin/String| {
|
||||
^invoke String(world)
|
||||
}
|
||||
public final fun f4(): R|kotlin/Unit| {
|
||||
lval receiver: R|Receiver<kotlin/Int>| = R|/Receiver.Receiver|<R|kotlin/Int|>()
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>.R|/invoke|<R|kotlin/Int|, R|kotlin/String|>()
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|kotlin/with|<R|ContextImpl<kotlin/String>|, R|kotlin/String|>(R|/ContextImpl.ContextImpl|<R|kotlin/String|>(), <L> = with@fun R|ContextImpl<kotlin/String>|.<anonymous>(): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>.R|/invoke|<R|kotlin/String|, R|kotlin/Int|>()
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>.R|/invoke|<R|kotlin/Int|, R|kotlin/String|>()
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
^ R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
}
|
||||
)
|
||||
}
|
||||
public final val <reified A> R|Receiver<A>|.helloReified: R|kotlin/String|
|
||||
public inline get(): R|kotlin/String| {
|
||||
^ String(hello)
|
||||
}
|
||||
public final fun f5(): R|kotlin/Unit| {
|
||||
lval receiver: R|Receiver<kotlin/Int>| = R|/Receiver.Receiver|<R|kotlin/Int|>()
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
}
|
||||
compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
// ISSUE: KT-54978
|
||||
|
||||
// Case 1: Parameters and local variables
|
||||
fun f1(x: Int) {
|
||||
val y = 5
|
||||
val s = "hello"
|
||||
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>x<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>x<!><String, String>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>y<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>y<!><String, Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>s<!><String>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>s<!><Int, String>
|
||||
}
|
||||
|
||||
// Case 2: Simple property
|
||||
val property: Int = 10
|
||||
|
||||
fun f2() {
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>property<!><String>
|
||||
}
|
||||
|
||||
// Case 3: Simple property with getter
|
||||
val property2: Int
|
||||
get() = 10
|
||||
|
||||
fun f3() {
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>property2<!><String>
|
||||
}
|
||||
|
||||
// Case 4: Property with extension and/or context receiver
|
||||
interface Context<A>
|
||||
class ContextImpl<A> : Context<A>
|
||||
class Receiver<A>
|
||||
|
||||
val <A> Receiver<A>.hello1: String
|
||||
get() = "hello 1"
|
||||
|
||||
context(Context<A>)
|
||||
val <A> hello2: String
|
||||
get() = "hello 2"
|
||||
|
||||
context(Context<B>)
|
||||
val <A, B> Receiver<A>.hello3: String
|
||||
get() = "hello 3"
|
||||
|
||||
operator fun <A, B> String.invoke(): String = "world"
|
||||
|
||||
fun f4() {
|
||||
val receiver = Receiver<Int>()
|
||||
|
||||
receiver.hello1
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int>
|
||||
receiver.hello1<Int, String>() // legal `String.invoke` call
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><String>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int, String>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int, String, String>
|
||||
|
||||
with (ContextImpl<String>()) {
|
||||
hello2
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String>
|
||||
hello2<String, Int>() // legal `String.invoke` call
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String, Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String, Int, Int>
|
||||
|
||||
receiver.hello3
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int, String>
|
||||
receiver.hello3<Int, String>() // legal `String.invoke` call
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><String, Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int, String, String>
|
||||
}
|
||||
}
|
||||
|
||||
// Case 5: Property with receiver and reified type parameter
|
||||
inline val <reified A> Receiver<A>.helloReified: String
|
||||
get() = "hello"
|
||||
|
||||
fun f5() {
|
||||
val receiver = Receiver<Int>()
|
||||
receiver.helloReified
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>helloReified<!><Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>helloReified<!><String>
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ fun main(args: Array<String>) {
|
||||
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
|
||||
alias<FirCall>("CallChecker")
|
||||
alias<FirFunctionCall>("FunctionCallChecker")
|
||||
alias<FirPropertyAccessExpression>("PropertyAccessExpressionChecker")
|
||||
alias<FirIntegerLiteralOperatorCall>("IntegerLiteralOperatorCallChecker")
|
||||
alias<FirVariableAssignment>("VariableAssignmentChecker")
|
||||
alias<FirTryExpression>("TryExpressionChecker")
|
||||
|
||||
+1
@@ -1007,6 +1007,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
|
||||
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
|
||||
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
|
||||
val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error<KtExpression>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
}
|
||||
|
||||
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
|
||||
|
||||
+4
@@ -23,6 +23,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _callCheckers
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = _functionCallCheckers
|
||||
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
|
||||
get() = _propertyAccessExpressionCheckers
|
||||
override val integerLiteralOperatorCallCheckers: Set<FirIntegerLiteralOperatorCallChecker>
|
||||
get() = _integerLiteralOperatorCallCheckers
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
@@ -81,6 +83,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
|
||||
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
|
||||
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
|
||||
private val _propertyAccessExpressionCheckers: MutableSet<FirPropertyAccessExpressionChecker> = mutableSetOf()
|
||||
private val _integerLiteralOperatorCallCheckers: MutableSet<FirIntegerLiteralOperatorCallChecker> = mutableSetOf()
|
||||
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
|
||||
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = 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
|
||||
|
||||
+2
@@ -22,6 +22,7 @@ abstract class ExpressionCheckers {
|
||||
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
|
||||
open val callCheckers: Set<FirCallChecker> = emptySet()
|
||||
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
|
||||
open val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker> = emptySet()
|
||||
open val integerLiteralOperatorCallCheckers: Set<FirIntegerLiteralOperatorCallChecker> = emptySet()
|
||||
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
|
||||
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
|
||||
@@ -54,6 +55,7 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allPropertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker> by lazy { propertyAccessExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allIntegerLiteralOperatorCallCheckers: Set<FirIntegerLiteralOperatorCallChecker> by lazy { integerLiteralOperatorCallCheckers + functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
|
||||
|
||||
+2
@@ -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<FirQualifiedAccess>
|
||||
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
|
||||
typealias FirCallChecker = FirExpressionChecker<FirCall>
|
||||
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
|
||||
typealias FirPropertyAccessExpressionChecker = FirExpressionChecker<FirPropertyAccessExpression>
|
||||
typealias FirIntegerLiteralOperatorCallChecker = FirExpressionChecker<FirIntegerLiteralOperatorCall>
|
||||
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
|
||||
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
|
||||
|
||||
@@ -552,6 +552,7 @@ object FirErrors {
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
|
||||
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||
val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
|
||||
// Multi-platform projects
|
||||
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
+5
@@ -64,6 +64,11 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirUnderscoredTypeArgumentSyntaxChecker,
|
||||
)
|
||||
|
||||
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
|
||||
get() = setOf(
|
||||
FirPropertyAccessTypeArgumentsChecker,
|
||||
)
|
||||
|
||||
override val tryExpressionCheckers: Set<FirTryExpressionChecker>
|
||||
get() = setOf(
|
||||
FirCatchParameterChecker
|
||||
|
||||
+27
@@ -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<Int>`, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+2
@@ -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")
|
||||
|
||||
Vendored
+8
-6
@@ -17,17 +17,19 @@ class Test {
|
||||
val <T> List<T>.a: Int get() = size
|
||||
val <T> List<T>.b: Int? get() = size
|
||||
|
||||
fun <T> List<T>.testCallable1(): () -> Unit = a<T>::foo
|
||||
fun <T> List<T>.testCallable1(): () -> Unit = a::foo
|
||||
fun <T> List<T>.testCallable1a(): () -> Unit = <!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>a<!><T>::foo
|
||||
fun <T> List<T>.testCallable2(): () -> Unit = b?::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
fun <T> List<T>.testCallable3(): () -> Unit = b<T, Any>::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
fun <T> List<T>.testCallable4(): () -> Unit = b<T>?::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
fun <T> List<T>.testCallable3(): () -> Unit = <!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>b<!><T, Any>::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
fun <T> List<T>.testCallable4(): () -> Unit = <!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>b<!><T>?::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
|
||||
fun <T> List<T>.testClassLiteral1() = a<T>::class
|
||||
fun <T> List<T>.testClassLiteral1() = a::class
|
||||
fun <T> List<T>.testClassLiteral1a() = <!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>a<!><T>::class
|
||||
fun <T> List<T>.testClassLiteral2() = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>b<!>?::class
|
||||
fun <T> List<T>.testClassLiteral3() = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>b<T, Any><!>::class
|
||||
fun <T> List<T>.testClassLiteral3() = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!><!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>b<!><T, Any><!>::class
|
||||
|
||||
fun <T> List<T>.testUnresolved1() = <!UNRESOLVED_REFERENCE!>unresolved<!><T>::foo
|
||||
fun <T> List<T>.testUnresolved2() = a<<!UNRESOLVED_REFERENCE!>unresolved<!>>::foo
|
||||
fun <T> List<T>.testUnresolved2() = <!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>a<!><<!UNRESOLVED_REFERENCE!>unresolved<!>>::foo
|
||||
fun <T> List<T>.testUnresolved3() = a<<!SYNTAX!><!>>::foo
|
||||
fun <T> List<T>.testUnresolved4() = <!UNRESOLVED_REFERENCE!>unresolved<!>?::foo
|
||||
}
|
||||
|
||||
+4
-2
@@ -17,12 +17,14 @@ class Test {
|
||||
val <T> List<T>.a: Int get() = size
|
||||
val <T> List<T>.b: Int? get() = size
|
||||
|
||||
fun <T> List<T>.testCallable1(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::foo
|
||||
fun <T> List<T>.testCallable1(): () -> Unit = a::foo
|
||||
fun <T> List<T>.testCallable1a(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::foo
|
||||
fun <T> List<T>.testCallable2(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<!>?::<!TYPE_MISMATCH, UNSAFE_CALL!>foo<!>
|
||||
fun <T> List<T>.testCallable3(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T, Any><!>::<!TYPE_MISMATCH, UNSAFE_CALL!>foo<!>
|
||||
fun <T> List<T>.testCallable4(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T><!>?::<!TYPE_MISMATCH, UNSAFE_CALL!>foo<!>
|
||||
|
||||
fun <T> List<T>.testClassLiteral1() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::class
|
||||
fun <T> List<T>.testClassLiteral1() = a::class
|
||||
fun <T> List<T>.testClassLiteral1a() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::class
|
||||
fun <T> List<T>.testClassLiteral2() = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<!>?::class
|
||||
fun <T> List<T>.testClassLiteral3() = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T, Any><!>::class
|
||||
|
||||
|
||||
+2
@@ -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 </*0*/ T> kotlin.collections.List<T>.testCallable1(): () -> kotlin.Unit
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testCallable1a(): () -> kotlin.Unit
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testCallable2(): () -> kotlin.Unit
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testCallable3(): () -> kotlin.Unit
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testCallable4(): () -> kotlin.Unit
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testClassLiteral1(): kotlin.reflect.KClass<out kotlin.Int>
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testClassLiteral1a(): kotlin.reflect.KClass<out kotlin.Int>
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testClassLiteral2(): kotlin.reflect.KClass<out kotlin.Int?>
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testClassLiteral3(): kotlin.reflect.KClass<out kotlin.Int?>
|
||||
public final fun </*0*/ T> kotlin.collections.List<T>.testUnresolved1(): [Error type: Return type for function cannot be resolved]
|
||||
|
||||
Vendored
+4
-3
@@ -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.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>b<!><Int>.c::foo
|
||||
|
||||
val test2: () -> Right = a.b<Int>.c?::foo
|
||||
val test2: () -> Right = a.b.c?::foo
|
||||
val test2a: () -> Right = a.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>b<!><Int>.c?::foo
|
||||
}
|
||||
|
||||
+4
-3
@@ -21,8 +21,9 @@ class Test {
|
||||
|
||||
val Int.c: Int get() = 42
|
||||
|
||||
val test1: () -> Right = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!><!DEBUG_INFO_MISSING_UNRESOLVED!>a<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>b<!><<!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>>.<!DEBUG_INFO_MISSING_UNRESOLVED!>c<!><!>::<!DEBUG_INFO_MISSING_UNRESOLVED!>foo<!>
|
||||
val test1a: () -> Right = a.<!DEBUG_INFO_LEAKING_THIS!>b<!>.<!DEBUG_INFO_LEAKING_THIS!>c<!>::foo
|
||||
val test1: () -> Right = a.<!DEBUG_INFO_LEAKING_THIS!>b<!>.<!DEBUG_INFO_LEAKING_THIS!>c<!>::foo
|
||||
val test1a: () -> Right = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!><!DEBUG_INFO_MISSING_UNRESOLVED!>a<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>b<!><<!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>>.<!DEBUG_INFO_MISSING_UNRESOLVED!>c<!><!>::<!DEBUG_INFO_MISSING_UNRESOLVED!>foo<!>
|
||||
|
||||
val test2: () -> Right = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!><!DEBUG_INFO_MISSING_UNRESOLVED!>a<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>b<!><<!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>>.<!DEBUG_INFO_MISSING_UNRESOLVED!>c<!><!>?::<!DEBUG_INFO_MISSING_UNRESOLVED!>foo<!>
|
||||
val test2: () -> Right = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a.<!DEBUG_INFO_LEAKING_THIS!>b<!>.<!DEBUG_INFO_LEAKING_THIS!>c<!><!>?::foo
|
||||
val test2a: () -> Right = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!><!DEBUG_INFO_MISSING_UNRESOLVED!>a<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>b<!><<!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>>.<!DEBUG_INFO_MISSING_UNRESOLVED!>c<!><!>?::<!DEBUG_INFO_MISSING_UNRESOLVED!>foo<!>
|
||||
}
|
||||
|
||||
+1
@@ -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 </*0*/ T> kotlin.collections.List<T>.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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ISSUE: KT-8263
|
||||
|
||||
fun test(x: Int, y: Int) {
|
||||
if (<!CONDITION_TYPE_MISMATCH!>x < (<!SYNTAX!>if<!><!SYNTAX!><!> <!SYNTAX!>(<!><!UNRESOLVED_REFERENCE!><!SYNTAX!><!>y<!> ><!><!SYNTAX!><!> 115<!SYNTAX!>) 1 else 2))<!> {
|
||||
if (<!CONDITION_TYPE_MISMATCH!><!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>x<!> < (<!SYNTAX!>if<!><!SYNTAX!><!> <!SYNTAX!>(<!><!UNRESOLVED_REFERENCE!><!SYNTAX!><!>y<!> ><!><!SYNTAX!><!> 115<!SYNTAX!>) 1 else 2))<!> {
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user