From a736d62edd7bfadc248ac15e6009b0e998e4feae Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 16 Apr 2021 15:24:16 +0300 Subject: [PATCH] FirForLoopChecker: report also OPERATOR_MODIFIER if appropriate + minor This commits checks iterator/hasNext/next functions whether they are declared as operator or not. Also, it changes logic of hasNext/next error reporting, now we're able to report errors about both these functions. --- .../diagnostics/forLoopChecker.fir.txt | 25 +++++- .../diagnostics/forLoopChecker.kt | 26 +++++- .../diagnostics/FirDiagnosticsList.kt | 4 + .../fir/analysis/diagnostics/FirErrors.kt | 2 + .../checkers/expression/FirForLoopChecker.kt | 82 +++++++++++-------- .../tests/ForRangeConventions.fir.kt | 2 +- .../diagnostics/tests/Operators.fir.kt | 29 ++++++- .../testData/diagnostics/tests/Operators.kt | 29 ++++++- .../testData/diagnostics/tests/Operators.txt | 29 +++++++ .../forWithNullableIterator.fir.kt | 12 --- .../forWithNullableIterator.kt | 1 + .../typeInferenceFailedOnIteratorCall.fir.kt | 2 +- .../fir/generator/HLDiagnosticConverter.kt | 5 ++ .../diagnostics/KtFirDataClassConverters.kt | 9 ++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 7 ++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 10 +++ 16 files changed, 222 insertions(+), 52 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt index 7f2c5817073..a6e1f2b28ca 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.fir.txt @@ -143,6 +143,16 @@ FILE: forLoopChecker.kt public abstract operator fun next(): R|kotlin/Int| + } + public abstract class ImproperIterator6 : R|kotlin/Any| { + public constructor(): R|ImproperIterator6| { + super() + } + + public abstract fun hasNext(): R|kotlin/Boolean| + + public abstract fun next(): R|kotlin/Int| + } public abstract class NotRange8 : R|kotlin/Any| { public constructor(): R|NotRange8| { @@ -152,7 +162,15 @@ FILE: forLoopChecker.kt public abstract operator fun iterator(): R|ImproperIterator5| } - public final fun test(notRange1: R|NotRange1|, notRange2: R|NotRange2|, notRange3: R|NotRange3|, notRange4: R|NotRange4|, notRange5: R|NotRange5|, notRange6: R|NotRange6|, notRange7: R|NotRange7|, notRange8: R|NotRange8|, range0: R|Range0|, range1: R|Range1|): R|kotlin/Unit| { + public abstract class NotRange9 : R|kotlin/Any| { + public constructor(): R|NotRange9| { + super() + } + + public abstract fun iterator(): R|ImproperIterator6| + + } + public final fun test(notRange1: R|NotRange1|, notRange2: R|NotRange2|, notRange3: R|NotRange3|, notRange4: R|NotRange4|, notRange5: R|NotRange5|, notRange6: R|NotRange6|, notRange7: R|NotRange7|, notRange8: R|NotRange8|, notRange9: R|NotRange9|, range0: R|Range0|, range1: R|Range1|): R|kotlin/Unit| { lval : R|ERROR CLASS: Unresolved name: iterator| = R|/notRange1|.#() while(R|/|.#()) { lval i: R|ERROR CLASS: Unresolved name: next| = R|/|.#() @@ -193,6 +211,11 @@ FILE: forLoopChecker.kt lval i: R|kotlin/Int| = R|/|.R|/ImproperIterator5.next|() } + lval : R|ImproperIterator6| = R|/notRange9|.R|/NotRange9.iterator|() + while(R|/|.R|/ImproperIterator6.hasNext|()) { + lval i: R|kotlin/Int| = R|/|.R|/ImproperIterator6.next|() + } + lval : R|GoodIterator| = R|/range0|.R|/Range0.iterator|() while(R|/|.R|/GoodIterator.hasNext|()) { lval i: R|kotlin/Int| = R|/|.R|/GoodIterator.next|() diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt index 6f0459ccc61..24cdb140ab5 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt @@ -70,20 +70,42 @@ abstract class ImproperIterator5 { abstract operator fun next() : Int } +abstract class ImproperIterator6 { + abstract fun hasNext() : Boolean + abstract fun next() : Int +} + abstract class NotRange8() { abstract operator fun iterator() : ImproperIterator5 } +abstract class NotRange9() { + abstract fun iterator(): ImproperIterator6 +} -fun test(notRange1: NotRange1, notRange2: NotRange2, notRange3: NotRange3, notRange4: NotRange4, notRange5: NotRange5, notRange6: NotRange6, notRange7: NotRange7, notRange8: NotRange8, range0: Range0, range1: Range1) { + +fun test( + notRange1: NotRange1, + notRange2: NotRange2, + notRange3: NotRange3, + notRange4: NotRange4, + notRange5: NotRange5, + notRange6: NotRange6, + notRange7: NotRange7, + notRange8: NotRange8, + notRange9: NotRange9, + range0: Range0, + range1: Range1 +) { for (i in notRange1); - for (i in notRange2); + for (i in notRange2); for (i in notRange3); for (i in notRange4); for (i in notRange5); for (i in notRange6); for (i in notRange7); for (i in notRange8); + for (i in notRange9); for (i in range0); for (i in range1); } 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 abb69d7d3af..f80029dd8fd 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 @@ -185,6 +185,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() { parameter("modifier") parameter("target") } + val OPERATOR_MODIFIER_REQUIRED by error { + parameter("functionSymbol") + parameter("name") + } } val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") { 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 072e90c92dc..52de915c19b 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 @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol @@ -173,6 +174,7 @@ object FirErrors { val INCOMPATIBLE_MODIFIERS by error2() val REDUNDANT_OPEN_IN_INTERFACE by warning0(SourceElementPositioningStrategies.OPEN_MODIFIER) val WRONG_MODIFIER_TARGET by error2() + val OPERATOR_MODIFIER_REQUIRED by error2() // Inline classes val INLINE_CLASS_NOT_TOP_LEVEL by error0(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER) 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 90ec46ec8b4..cf6a4b1015d 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 @@ -19,16 +19,20 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_ON_NULLA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_MISSING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_NONE_APPLICABLE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPERATOR_MODIFIER_REQUIRED import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.isOperator import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirWhileLoop import org.jetbrains.kotlin.fir.references.FirErrorNamedReference +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.calls.InapplicableWrongReceiver import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.calls.tower.isSuccess @@ -54,18 +58,15 @@ object FirForLoopChecker : FirBlockChecker() { continue } val hasNextCall = whileLoop.condition as FirFunctionCall - if (checkSpecialFunctionCall( - hasNextCall, - reporter, - source, - context, - HAS_NEXT_FUNCTION_AMBIGUITY, - HAS_NEXT_MISSING, - noneApplicableFactory = HAS_NEXT_FUNCTION_NONE_APPLICABLE - ) - ) { - continue - } + checkSpecialFunctionCall( + hasNextCall, + reporter, + source, + context, + HAS_NEXT_FUNCTION_AMBIGUITY, + HAS_NEXT_MISSING, + noneApplicableFactory = HAS_NEXT_FUNCTION_NONE_APPLICABLE + ) val elementDeclaration = whileLoop.block.statements.firstOrNull() as? FirProperty ?: continue if (elementDeclaration.initializer?.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) continue val nextCall = elementDeclaration.initializer as FirFunctionCall @@ -91,33 +92,48 @@ object FirForLoopChecker : FirBlockChecker() { noneApplicableFactory: FirDiagnosticFactory1>>? = null, unsafeCallFactory: FirDiagnosticFactory0? = null, ): Boolean { - val calleeReference = call.calleeReference - if (calleeReference is FirErrorNamedReference) { - when (val diagnostic = calleeReference.diagnostic) { - is ConeAmbiguityError -> if (diagnostic.applicability.isSuccess) { - reporter.reportOn(reportSource, ambiguityFactory, diagnostic.candidates, context) - } else if (noneApplicableFactory != null) { - reporter.reportOn(reportSource, noneApplicableFactory, diagnostic.candidates, context) - } - is ConeUnresolvedNameError -> { - reporter.reportOn(reportSource, missingFactory, context) - } - is ConeInapplicableCandidateError -> { - if (unsafeCallFactory != null || noneApplicableFactory != null) { - diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.forEach { - if (it is InapplicableWrongReceiver) { - if (unsafeCallFactory != null) { - reporter.reportOn(reportSource, unsafeCallFactory, context) - } else { - reporter.reportOn(reportSource, noneApplicableFactory!!, listOf(diagnostic.candidate.symbol), context) + when (val calleeReference = call.calleeReference) { + is FirErrorNamedReference -> { + when (val diagnostic = calleeReference.diagnostic) { + is ConeAmbiguityError -> if (diagnostic.applicability.isSuccess) { + reporter.reportOn(reportSource, ambiguityFactory, diagnostic.candidates, context) + } else if (noneApplicableFactory != null) { + reporter.reportOn(reportSource, noneApplicableFactory, diagnostic.candidates, context) + } + is ConeUnresolvedNameError -> { + reporter.reportOn(reportSource, missingFactory, context) + } + is ConeInapplicableCandidateError -> { + if (unsafeCallFactory != null || noneApplicableFactory != null) { + diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.forEach { + if (it is InapplicableWrongReceiver) { + if (unsafeCallFactory != null) { + reporter.reportOn( + reportSource, unsafeCallFactory, context + ) + } else { + reporter.reportOn( + reportSource, noneApplicableFactory!!, listOf(diagnostic.candidate.symbol), context + ) + } + return true } - return true } } } } + return true + } + is FirResolvedNamedReference -> { + val symbol = calleeReference.resolvedSymbol + if (symbol is FirNamedFunctionSymbol) { + val function = symbol.fir + if (!function.isOperator) { + reporter.reportOn(reportSource, OPERATOR_MODIFIER_REQUIRED, symbol, function.name.asString(), context) + // Don't return true as we want to report other errors + } + } } - return true } return false } diff --git a/compiler/testData/diagnostics/tests/ForRangeConventions.fir.kt b/compiler/testData/diagnostics/tests/ForRangeConventions.fir.kt index 68e03f81840..1f5ac003d33 100644 --- a/compiler/testData/diagnostics/tests/ForRangeConventions.fir.kt +++ b/compiler/testData/diagnostics/tests/ForRangeConventions.fir.kt @@ -79,7 +79,7 @@ abstract class NotRange8() { fun test(notRange1: NotRange1, notRange2: NotRange2, notRange3: NotRange3, notRange4: NotRange4, notRange5: NotRange5, notRange6: NotRange6, notRange7: NotRange7, notRange8: NotRange8, range0: Range0, range1: Range1) { for (i in notRange1); - for (i in notRange2); + for (i in notRange2); for (i in notRange3); for (i in notRange4); for (i in notRange5); diff --git a/compiler/testData/diagnostics/tests/Operators.fir.kt b/compiler/testData/diagnostics/tests/Operators.fir.kt index 4e99d4993d7..ba2b63936ac 100644 --- a/compiler/testData/diagnostics/tests/Operators.fir.kt +++ b/compiler/testData/diagnostics/tests/Operators.fir.kt @@ -111,4 +111,31 @@ fun test2() { Anc() + Anc() Anc() - Anc() Anc2() + Anc2() -} \ No newline at end of file +} + +fun Int.iterator(): MyIntIterator = null!! + +operator fun Double.iterator(): MyDoubleIterator = null!! + +operator fun Boolean.iterator(): MyBooleanIterator = null!! + +interface MyIntIterator { + operator fun hasNext(): Boolean + operator fun next(): Int +} + +interface MyDoubleIterator { + operator fun hasNext(): Boolean + fun next(): Double +} + +interface MyBooleanIterator { + fun hasNext(): Boolean + operator fun next(): Boolean +} + +fun test3(i: Int, d: Double, b: Boolean) { + for (element in i) {} + for (element in d) {} + for (element in b) {} +} diff --git a/compiler/testData/diagnostics/tests/Operators.kt b/compiler/testData/diagnostics/tests/Operators.kt index 689a8a85c4c..bffab02feab 100644 --- a/compiler/testData/diagnostics/tests/Operators.kt +++ b/compiler/testData/diagnostics/tests/Operators.kt @@ -111,4 +111,31 @@ fun test2() { Anc() + Anc() Anc() - Anc() Anc2() + Anc2() -} \ No newline at end of file +} + +fun Int.iterator(): MyIntIterator = null!! + +operator fun Double.iterator(): MyDoubleIterator = null!! + +operator fun Boolean.iterator(): MyBooleanIterator = null!! + +interface MyIntIterator { + operator fun hasNext(): Boolean + operator fun next(): Int +} + +interface MyDoubleIterator { + operator fun hasNext(): Boolean + fun next(): Double +} + +interface MyBooleanIterator { + fun hasNext(): Boolean + operator fun next(): Boolean +} + +fun test3(i: Int, d: Double, b: Boolean) { + for (element in i) {} + for (element in d) {} + for (element in b) {} +} diff --git a/compiler/testData/diagnostics/tests/Operators.txt b/compiler/testData/diagnostics/tests/Operators.txt index 9841dd7b485..4649786c79d 100644 --- a/compiler/testData/diagnostics/tests/Operators.txt +++ b/compiler/testData/diagnostics/tests/Operators.txt @@ -2,6 +2,10 @@ package public fun test(): kotlin.Unit public fun test2(): kotlin.Unit +public fun test3(/*0*/ i: kotlin.Int, /*1*/ d: kotlin.Double, /*2*/ b: kotlin.Boolean): kotlin.Unit +public operator fun kotlin.Boolean.iterator(): MyBooleanIterator +public operator fun kotlin.Double.iterator(): MyDoubleIterator +public fun kotlin.Int.iterator(): MyIntIterator public open class Anc : Base { public constructor Anc() @@ -65,3 +69,28 @@ public final class Example2 { public final operator fun rangeTo(/*0*/ o: Example2): Example2 public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + +public interface MyBooleanIterator { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun hasNext(): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract operator fun next(): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface MyDoubleIterator { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract operator fun hasNext(): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun next(): kotlin.Double + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface MyIntIterator { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract operator fun hasNext(): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract operator fun next(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + diff --git a/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.fir.kt deleted file mode 100644 index 5ec65699826..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -class Coll { - operator fun iterator(): It? = null -} - -class It { - operator fun next() = 1 - operator fun hasNext() = false -} - -fun test() { - for (x in Coll()) {} -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.kt b/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.kt index 906a2ef847c..381e0acbc66 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/forWithNullableIterator.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class Coll { operator fun iterator(): It? = null } diff --git a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.fir.kt b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.fir.kt index d0f279d0dcd..5093ee66f47 100644 --- a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.fir.kt @@ -4,6 +4,6 @@ class X operator fun X.iterator(): Iterable = TODO() fun test() { - for (i in X()) { + for (i in X()) { } } 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 124e39b564b..728d610a603 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 @@ -186,6 +186,11 @@ private object FirToKtConversionCreator { KtSymbol::class.createType(), importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirDeclaration") ), + FirNamedFunctionSymbol::class to HLFunctionCallConversion( + "firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol({0}.fir)", + KtFunctionLikeSymbol::class.createType(), + importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirSimpleFunction") + ), ) private val allowedTypesWithoutTypeParams = setOf( 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 9db6d82745c..aff177f9356 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirTypeParameter import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.psi @@ -630,6 +631,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.OPERATOR_MODIFIER_REQUIRED) { firDiagnostic -> + OperatorModifierRequiredImpl( + firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol(firDiagnostic.a.fir), + firDiagnostic.b, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.INLINE_CLASS_NOT_TOP_LEVEL) { firDiagnostic -> InlineClassNotTopLevelImpl( firDiagnostic as FirPsiDiagnostic<*>, 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 9b52d6d1be4..dd4dc00dd6e 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 @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol @@ -459,6 +460,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val target: String } + abstract class OperatorModifierRequired : KtFirDiagnostic() { + override val diagnosticClass get() = OperatorModifierRequired::class + abstract val functionSymbol: KtFunctionLikeSymbol + abstract val name: String + } + abstract class InlineClassNotTopLevel : KtFirDiagnostic() { override val diagnosticClass get() = InlineClassNotTopLevel::class } 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 b1acc6ba14e..9d8de501305 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 @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol @@ -727,6 +728,15 @@ internal class WrongModifierTargetImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class OperatorModifierRequiredImpl( + override val functionSymbol: KtFunctionLikeSymbol, + override val name: String, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.OperatorModifierRequired(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class InlineClassNotTopLevelImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,