diff --git a/compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt b/compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt index cb6d3aa922c..95799cb27a0 100644 --- a/compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt +++ b/compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt @@ -1,5 +1,5 @@ fun test( - val f: String.() -> Int = { length } + f: String.() -> Int = { length } ): Int { return "".f() } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt index 0431d3a915f..07b507704e1 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt @@ -3,5 +3,5 @@ interface A(val s: String) interface B constructor(val s: String) interface C { - constructor(val s: String) {} + constructor(s: String) {} } 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 5b321e1543e..2c97bb44d62 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -69,6 +70,18 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val FLOAT_LITERAL_OUT_OF_RANGE by error() val WRONG_LONG_SUFFIX by error(PositioningStrategy.LONG_LITERAL_SUFFIX) val DIVISION_BY_ZERO by warning() + val VAL_OR_VAR_ON_LOOP_PARAMETER by warning(PositioningStrategy.VAL_OR_VAR_NODE) { + parameter("valOrVar") + } + val VAL_OR_VAR_ON_FUN_PARAMETER by warning(PositioningStrategy.VAL_OR_VAR_NODE) { + parameter("valOrVar") + } + val VAL_OR_VAR_ON_CATCH_PARAMETER by warning(PositioningStrategy.VAL_OR_VAR_NODE) { + parameter("valOrVar") + } + val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning(PositioningStrategy.VAL_OR_VAR_NODE) { + parameter("valOrVar") + } } val UNRESOLVED by object : DiagnosticGroup("Unresolved") { 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 e90687f01c6..664138a9b07 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 @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotation @@ -100,6 +101,10 @@ object FirErrors { val FLOAT_LITERAL_OUT_OF_RANGE by error0() val WRONG_LONG_SUFFIX by error0(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX) val DIVISION_BY_ZERO by warning0() + val VAL_OR_VAR_ON_LOOP_PARAMETER by warning1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) + val VAL_OR_VAR_ON_FUN_PARAMETER by warning1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) + val VAL_OR_VAR_ON_CATCH_PARAMETER by warning1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) + val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning1(SourceElementPositioningStrategies.VAL_OR_VAR_NODE) // Unresolved val INVISIBLE_REFERENCE by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirKeywordUtils.kt similarity index 88% rename from compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierUtils.kt rename to compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirKeywordUtils.kt index b83d20620c5..818b6262829 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirKeywordUtils.kt @@ -11,10 +11,13 @@ import com.intellij.psi.tree.TokenSet import com.intellij.util.diff.FlyweightCapableTreeStructure import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.analysis.diagnostics.valOrVarKeyword +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtModifierList import org.jetbrains.kotlin.psi.KtModifierListOwner +import org.jetbrains.kotlin.psi.KtValVarKeywordOwner // DO // - use this to retrieve modifiers on the source and confirm a certain modifier indeed appears @@ -96,3 +99,10 @@ operator fun FirModifierList?.contains(token: KtModifierKeywordToken): Boolean = fun FirElement.getModifier(token: KtModifierKeywordToken): FirModifier<*>? = source.getModifierList()?.get(token) fun FirElement.hasModifier(token: KtModifierKeywordToken): Boolean = token in source.getModifierList() + +internal val FirSourceElement?.valOrVarKeyword: KtKeywordToken? + get() = when (this) { + null -> null + is FirPsiSourceElement<*> -> (psi as? KtValVarKeywordOwner)?.valOrVarKeyword?.let { it.node?.elementType as? KtKeywordToken } + is FirLightSourceElement -> treeStructure.valOrVarKeyword(lighterASTNode)?.tokenType as? KtKeywordToken + } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunctionParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunctionParameterChecker.kt index 1b3ca6e6233..50e0ddefe30 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunctionParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunctionParameterChecker.kt @@ -6,12 +6,13 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirRealSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.isInline -import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOnWithSuppression +import org.jetbrains.kotlin.fir.analysis.checkers.valOrVarKeyword +import org.jetbrains.kotlin.fir.analysis.diagnostics.* +import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic @@ -31,10 +32,11 @@ object FirFunctionParameterChecker : FirFunctionChecker() { checkVarargParameters(declaration, context, reporter) checkParameterTypes(declaration, context, reporter) checkUninitializedParameter(declaration, context, reporter) + checkValOrVarParameter(declaration, context, reporter) } - private fun checkParameterTypes(declaration: FirFunction<*>, context: CheckerContext, reporter: DiagnosticReporter) { - for (valueParameter in declaration.valueParameters) { + private fun checkParameterTypes(function: FirFunction<*>, context: CheckerContext, reporter: DiagnosticReporter) { + for (valueParameter in function.valueParameters) { val returnTypeRef = valueParameter.returnTypeRef if (returnTypeRef !is FirErrorTypeRef) continue // type problems on real source are already reported by ConeDiagnostic.toFirDiagnostics @@ -105,4 +107,23 @@ object FirFunctionParameterChecker : FirFunctionChecker() { }) } } + + private fun checkValOrVarParameter(function: FirFunction<*>, context: CheckerContext, reporter: DiagnosticReporter) { + if (function is FirConstructor && function.isPrimary) { + // `val/var` is valid for primary constructors, but not for secondary constructors + return + } + + for (valueParameter in function.valueParameters) { + val source = valueParameter.source + if (source?.kind is FirFakeSourceElementKind) continue + source.valOrVarKeyword?.let { + if (function is FirConstructor) { + reporter.reportOn(source, FirErrors.VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, it, context) + } else { + reporter.reportOn(source, FirErrors.VAL_OR_VAR_ON_FUN_PARAMETER, it, context) + } + } + } + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt index 5195992239b..6b2cba50ee3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeOfThrowable +import org.jetbrains.kotlin.fir.analysis.checkers.valOrVarKeyword import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn @@ -18,9 +19,14 @@ object FirCatchParameterChecker : FirTryExpressionChecker() { override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { for (catchEntry in expression.catches) { val catchParameter = catchEntry.parameter + val source = catchParameter.source ?: continue if (catchParameter.defaultValue != null) { - reporter.reportOn(catchParameter.source, FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE, context) + reporter.reportOn(source, FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE, context) + } + + source.valOrVarKeyword?.let { + reporter.reportOn(source, FirErrors.VAL_OR_VAR_ON_CATCH_PARAMETER, it, context) } val coneType = catchParameter.returnTypeRef.coneType @@ -28,15 +34,15 @@ object FirCatchParameterChecker : FirTryExpressionChecker() { val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified if (isReified) { - reporter.reportOn(catchParameter.source, FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE, context) + reporter.reportOn(source, FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE, context) } else { - reporter.reportOn(catchParameter.source, FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE, context) + reporter.reportOn(source, FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE, context) } } val session = context.session if (!coneType.isSubtypeOfThrowable(session)) { - reporter.reportOn(catchParameter.source, FirErrors.THROWABLE_TYPE_MISMATCH, coneType, context) + reporter.reportOn(source, FirErrors.THROWABLE_TYPE_MISMATCH, coneType, context) } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt index b6beed3f626..5c2a6a802b5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.valOrVarKeyword import org.jetbrains.kotlin.fir.analysis.diagnostics.* import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_NONE_APPLICABLE @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess object FirForLoopChecker : FirBlockChecker() { override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) { if (expression.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) return + val statements = expression.statements val iteratorDeclaration = statements[0] as? FirProperty ?: return val whileLoop = statements[1] as? FirWhileLoop ?: return @@ -57,6 +59,7 @@ object FirForLoopChecker : FirBlockChecker() { ) { return } + val hasNextCall = whileLoop.condition as FirFunctionCall checkSpecialFunctionCall( hasNextCall, @@ -67,9 +70,10 @@ object FirForLoopChecker : FirBlockChecker() { HAS_NEXT_MISSING, noneApplicableFactory = HAS_NEXT_FUNCTION_NONE_APPLICABLE ) - val elementDeclaration = whileLoop.block.statements.firstOrNull() as? FirProperty ?: return - if (elementDeclaration.initializer?.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) return - val nextCall = elementDeclaration.initializer as FirFunctionCall + + val loopParameter = whileLoop.block.statements.firstOrNull() as? FirProperty ?: return + if (loopParameter.initializer?.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) return + val nextCall = loopParameter.initializer as FirFunctionCall checkSpecialFunctionCall( nextCall, reporter, @@ -79,6 +83,11 @@ object FirForLoopChecker : FirBlockChecker() { NEXT_MISSING, noneApplicableFactory = NEXT_NONE_APPLICABLE ) + + val loopParameterSource = loopParameter.source + loopParameterSource.valOrVarKeyword?.let { + reporter.reportOn(loopParameterSource, FirErrors.VAL_OR_VAR_ON_LOOP_PARAMETER, it, context) + } } private fun checkSpecialFunctionCall( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index af91891a44f..07c3d7ffbf3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -328,6 +328,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_IS_CHECK import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_CLONEABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_CATCH_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_FUN_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_LOOP_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_REASSIGNMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR @@ -384,6 +388,10 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(VARIABLE_EXPECTED, "Variable expected") map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation") map.put(NESTED_CLASS_NOT_ALLOWED, "{0} is not allowed here", TO_STRING) + map.put(VAL_OR_VAR_ON_LOOP_PARAMETER, "''{0}'' on loop parameter is not allowed", TO_STRING); + map.put(VAL_OR_VAR_ON_FUN_PARAMETER, "''{0}'' on function parameter is not allowed", TO_STRING); + map.put(VAL_OR_VAR_ON_CATCH_PARAMETER, "''{0}'' on catch parameter is not allowed", TO_STRING); + map.put(VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, "''{0}'' on secondary constructor parameter is not allowed", TO_STRING); // Unresolved map.put(INVISIBLE_REFERENCE, "Symbol {0} is invisible", SYMBOL) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index 1b7e1c42c5f..a963263cf2e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -865,7 +865,7 @@ private fun FlyweightCapableTreeStructure.rightParenthesis(node: private fun FlyweightCapableTreeStructure.objectKeyword(node: LighterASTNode): LighterASTNode? = findChildByType(node, KtTokens.OBJECT_KEYWORD) -private fun FlyweightCapableTreeStructure.valOrVarKeyword(node: LighterASTNode): LighterASTNode? = +internal fun FlyweightCapableTreeStructure.valOrVarKeyword(node: LighterASTNode): LighterASTNode? = findChildByType(node, VAL_VAR_TOKEN_SET) internal fun FlyweightCapableTreeStructure.visibilityModifier(declaration: LighterASTNode): LighterASTNode? = @@ -1021,7 +1021,7 @@ fun FlyweightCapableTreeStructure.collectDescendantsOfType( return result } -private fun FlyweightCapableTreeStructure.findChildByType(node: LighterASTNode, type: TokenSet): LighterASTNode? { +fun FlyweightCapableTreeStructure.findChildByType(node: LighterASTNode, type: TokenSet): LighterASTNode? { val childrenRef = Ref>() getChildren(node, childrenRef) return childrenRef.get()?.firstOrNull { it?.tokenType in type } diff --git a/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.fir.kt deleted file mode 100644 index f9b78e45309..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -fun f() { - try { - } catch (val e: Exception) { - } - - try { - } catch (var e: Exception) { - } - - try { - } catch (e: Exception) { - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.kt b/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.kt index d1c07627240..e7cb4fa4d72 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/valVarCatchParameter.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun f() { try { } catch (val e: Exception) { diff --git a/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.fir.kt deleted file mode 100644 index 54716ccce9f..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.fir.kt +++ /dev/null @@ -1,32 +0,0 @@ -class Pair { - operator fun component1(): Int = null!! - operator fun component2(): Int = null!! -} - -class Coll { - operator fun iterator(): It = It() -} - -class It { - operator fun next() = Pair() - operator fun hasNext() = false -} - - -fun f() { - for (val i in 1..4) { - - } - - for (var i in 1..4) { - - } - - for (val (i,j) in Coll()) { - - } - - for (var (i,j) in Coll()) { - - } -} diff --git a/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.kt b/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.kt index a1956f7f86d..2e664d6829c 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/valVarLoopParameter.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class Pair { operator fun component1(): Int = null!! operator fun component2(): Int = null!! diff --git a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.fir.kt deleted file mode 100644 index cd3b4ba4186..00000000000 --- a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.fir.kt +++ /dev/null @@ -1,15 +0,0 @@ -// KT-2667 Support multi-declarations in for-loops in control flow analysis -package d - -class A { - operator fun component1() = 1 - operator fun component2() = 2 - operator fun component3() = 3 -} - -fun foo(list: List) { - for (var (c1, c2, c3) in list) { - c1 = 1 - c3 + 1 - } -} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt index 4e185172718..378bc6b05b1 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // KT-2667 Support multi-declarations in for-loops in control flow analysis package d diff --git a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.fir.kt deleted file mode 100644 index e74defe5461..00000000000 --- a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -fun f( - val a: Int, - var b: Int, - c: Int, - vararg var d: Int, - vararg val e: Int, - vararg f: Int -) { - - - a + b + c + d[0] + e[0] + f[0] // to avoid 'unused parameter' -} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt b/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt index acf95d9adb4..619b772d0c4 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/valVarFunctionParameter.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun f( val a: Int, var b: Int, diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/valOrValAndModifiersInCtr.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/valOrValAndModifiersInCtr.fir.kt index c922826f602..843f8f7dc3e 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/valOrValAndModifiersInCtr.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/valOrValAndModifiersInCtr.fir.kt @@ -1,7 +1,7 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER class A { constructor( - val x: Int, y: Int, - var z: Int, + val x: Int, y: Int, + var z: Int, public a: Int) } diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt index 46943a7c336..a63213e3188 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtExpression @@ -235,6 +236,7 @@ private object FirToKtConversionCreator { Int::class, Name::class, EventOccurrencesRange::class, + KtKeywordToken::class, KtModifierKeywordToken::class, Visibility::class, EffectiveVisibility::class, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 4ca387b5a21..c684d733e7c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -194,6 +194,34 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.VAL_OR_VAR_ON_LOOP_PARAMETER) { firDiagnostic -> + ValOrVarOnLoopParameterImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.VAL_OR_VAR_ON_FUN_PARAMETER) { firDiagnostic -> + ValOrVarOnFunParameterImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.VAL_OR_VAR_ON_CATCH_PARAMETER) { firDiagnostic -> + ValOrVarOnCatchParameterImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER) { firDiagnostic -> + ValOrVarOnSecondaryConstructorParameterImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic -> InvisibleReferenceImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index ce3b40c74b6..99d600c0497 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableSymbol import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotation @@ -157,6 +158,26 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = DivisionByZero::class } + abstract class ValOrVarOnLoopParameter : KtFirDiagnostic() { + override val diagnosticClass get() = ValOrVarOnLoopParameter::class + abstract val valOrVar: KtKeywordToken + } + + abstract class ValOrVarOnFunParameter : KtFirDiagnostic() { + override val diagnosticClass get() = ValOrVarOnFunParameter::class + abstract val valOrVar: KtKeywordToken + } + + abstract class ValOrVarOnCatchParameter : KtFirDiagnostic() { + override val diagnosticClass get() = ValOrVarOnCatchParameter::class + abstract val valOrVar: KtKeywordToken + } + + abstract class ValOrVarOnSecondaryConstructorParameter : KtFirDiagnostic() { + override val diagnosticClass get() = ValOrVarOnSecondaryConstructorParameter::class + abstract val valOrVar: KtKeywordToken + } + abstract class InvisibleReference : KtFirDiagnostic() { override val diagnosticClass get() = InvisibleReference::class abstract val reference: KtSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 984aa9bd246..151597931e3 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableSymbol import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.lexer.KtKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotation @@ -224,6 +225,38 @@ internal class DivisionByZeroImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class ValOrVarOnLoopParameterImpl( + override val valOrVar: KtKeywordToken, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ValOrVarOnLoopParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class ValOrVarOnFunParameterImpl( + override val valOrVar: KtKeywordToken, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ValOrVarOnFunParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class ValOrVarOnCatchParameterImpl( + override val valOrVar: KtKeywordToken, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ValOrVarOnCatchParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class ValOrVarOnSecondaryConstructorParameterImpl( + override val valOrVar: KtKeywordToken, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ValOrVarOnSecondaryConstructorParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class InvisibleReferenceImpl( override val reference: KtSymbol, firDiagnostic: FirPsiDiagnostic<*>,