BOBKO_ITERABLE_OVERLOADS & BOBKO_COLLECTION_OVERLOADS impact estimation
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
index 8c12a18..7d2270f 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt
@@ -233,6 +233,20 @@
token,
)
}
+ add(FirErrors.BOBKO_ITERABLE_OVERLOADS) { firDiagnostic ->
+ BobkoIterableOverloadsImpl(
+ firDiagnostic.a,
+ firDiagnostic as KtPsiDiagnostic,
+ token,
+ )
+ }
+ add(FirErrors.BOBKO_COLLECTION_OVERLOADS) { firDiagnostic ->
+ BobkoCollectionOverloadsImpl(
+ firDiagnostic.a,
+ firDiagnostic as KtPsiDiagnostic,
+ token,
+ )
+ }
add(FirErrors.VAL_OR_VAR_ON_LOOP_PARAMETER) { firDiagnostic ->
ValOrVarOnLoopParameterImpl(
firDiagnostic.a,
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
index 0734cf3..985d6a4 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt
@@ -206,6 +206,16 @@
override val diagnosticClass get() = DivisionByZero::class
}
+ interface BobkoIterableOverloads : KaFirDiagnostic<KtExpression> {
+ override val diagnosticClass get() = BobkoIterableOverloads::class
+ val text: String
+ }
+
+ interface BobkoCollectionOverloads : KaFirDiagnostic<KtExpression> {
+ override val diagnosticClass get() = BobkoCollectionOverloads::class
+ val text: String
+ }
+
interface ValOrVarOnLoopParameter : KaFirDiagnostic<KtParameter> {
override val diagnosticClass get() = ValOrVarOnLoopParameter::class
val valOrVar: KtKeywordToken
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
index c9a2de2..6b1f711 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt
@@ -232,6 +232,18 @@
token: KaLifetimeToken,
) : KaAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KaFirDiagnostic.DivisionByZero
+internal class BobkoIterableOverloadsImpl(
+ override val text: String,
+ firDiagnostic: KtPsiDiagnostic,
+ token: KaLifetimeToken,
+) : KaAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KaFirDiagnostic.BobkoIterableOverloads
+
+internal class BobkoCollectionOverloadsImpl(
+ override val text: String,
+ firDiagnostic: KtPsiDiagnostic,
+ token: KaLifetimeToken,
+) : KaAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KaFirDiagnostic.BobkoCollectionOverloads
+
internal class ValOrVarOnLoopParameterImpl(
override val valOrVar: KtKeywordToken,
firDiagnostic: KtPsiDiagnostic,
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 55ffafc..8bc2780 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
@@ -91,6 +91,12 @@
val WRONG_LONG_SUFFIX by error<KtElement>(PositioningStrategy.LONG_LITERAL_SUFFIX)
val UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH by error<KtElement>()
val DIVISION_BY_ZERO by warning<KtExpression>()
+ val BOBKO_ITERABLE_OVERLOADS by error<KtExpression> {
+ parameter<String>("text")
+ }
+ val BOBKO_COLLECTION_OVERLOADS by error<KtExpression> {
+ parameter<String>("text")
+ }
val VAL_OR_VAR_ON_LOOP_PARAMETER by error<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE) {
parameter<KtKeywordToken>("valOrVar")
}
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 7b7b661..ea28262 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
@@ -171,6 +171,8 @@
val WRONG_LONG_SUFFIX: KtDiagnosticFactory0 = KtDiagnosticFactory0("WRONG_LONG_SUFFIX", ERROR, SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX, KtElement::class)
val UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH: KtDiagnosticFactory0 = KtDiagnosticFactory0("UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH", ERROR, SourceElementPositioningStrategies.DEFAULT, KtElement::class)
val DIVISION_BY_ZERO: KtDiagnosticFactory0 = KtDiagnosticFactory0("DIVISION_BY_ZERO", WARNING, SourceElementPositioningStrategies.DEFAULT, KtExpression::class)
+ val BOBKO_ITERABLE_OVERLOADS: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("BOBKO_ITERABLE_OVERLOADS", ERROR, SourceElementPositioningStrategies.DEFAULT, KtExpression::class)
+ val BOBKO_COLLECTION_OVERLOADS: KtDiagnosticFactory1<String> = KtDiagnosticFactory1("BOBKO_COLLECTION_OVERLOADS", ERROR, SourceElementPositioningStrategies.DEFAULT, KtExpression::class)
val VAL_OR_VAR_ON_LOOP_PARAMETER: KtDiagnosticFactory1<KtKeywordToken> = KtDiagnosticFactory1("VAL_OR_VAR_ON_LOOP_PARAMETER", ERROR, SourceElementPositioningStrategies.VAL_OR_VAR_NODE, KtParameter::class)
val VAL_OR_VAR_ON_FUN_PARAMETER: KtDiagnosticFactory1<KtKeywordToken> = KtDiagnosticFactory1("VAL_OR_VAR_ON_FUN_PARAMETER", ERROR, SourceElementPositioningStrategies.VAL_OR_VAR_NODE, KtParameter::class)
val VAL_OR_VAR_ON_CATCH_PARAMETER: KtDiagnosticFactory1<KtKeywordToken> = KtDiagnosticFactory1("VAL_OR_VAR_ON_CATCH_PARAMETER", ERROR, SourceElementPositioningStrategies.VAL_OR_VAR_NODE, KtParameter::class)
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
index bc13cf6..f575321 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt
@@ -36,6 +36,8 @@
"FLOAT_LITERAL_OUT_OF_RANGE",
"WRONG_LONG_SUFFIX",
"UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH",
+ "BOBKO_ITERABLE_OVERLOADS",
+ "BOBKO_COLLECTION_OVERLOADS",
"VAL_OR_VAR_ON_LOOP_PARAMETER",
"VAL_OR_VAR_ON_FUN_PARAMETER",
"VAL_OR_VAR_ON_CATCH_PARAMETER",
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
index 4bf0646..fa962d8 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt
@@ -107,6 +107,7 @@
FirNotImplementedOverrideSimpleEnumEntryChecker.Regular,
FirNotImplementedOverrideSimpleEnumEntryChecker.ForExpectClass,
FirThrowableSubclassChecker,
+ FirIterableOverloadsInClassChecker,
FirOpenMemberChecker,
FirClassVarianceChecker,
FirSealedSupertypeChecker,
@@ -166,6 +167,7 @@
get() = setOf(
FirImportsChecker,
FirOptInImportsChecker,
+ FirIterableCollectionOverloadsInFileChecker,
FirUnresolvedInMiddleOfImportChecker,
FirTopLevelPropertiesChecker,
FirPackageConflictsWithClassifierChecker,
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCollectionOverloadChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCollectionOverloadChecker.kt
new file mode 100644
index 0000000..d33a546
--- /dev/null
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCollectionOverloadChecker.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2024 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.declaration
+
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
+import org.jetbrains.kotlin.fir.declarations.FirClass
+import org.jetbrains.kotlin.fir.declarations.FirDeclaration
+import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
+import org.jetbrains.kotlin.fir.render
+import org.jetbrains.kotlin.fir.types.ConeTypeProjection
+import org.jetbrains.kotlin.fir.types.coneType
+import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
+import org.jetbrains.kotlin.fir.types.isSubtypeOf
+import org.jetbrains.kotlin.fir.types.toLookupTag
+import org.jetbrains.kotlin.name.StandardClassIds
+
+object FirIterableCollectionOverloadsInFileChecker : FirFileChecker(MppCheckerKind.Common) {
+ override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
+ _check(declaration.declarations, context, reporter)
+ }
+}
+
+object FirIterableOverloadsInClassChecker : FirClassChecker(MppCheckerKind.Common) {
+ override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
+ _check(declaration.declarations, context, reporter)
+ }
+}
+
+private val iterable = ConeClassLikeTypeImpl(
+ StandardClassIds.Iterable.toLookupTag(),
+ arrayOf(
+ ConeClassLikeTypeImpl(
+ StandardClassIds.Any.toLookupTag(),
+ ConeTypeProjection.EMPTY_ARRAY,
+ isMarkedNullable = false
+ )
+ ),
+ isMarkedNullable = false
+)
+
+private val collection = ConeClassLikeTypeImpl(
+ StandardClassIds.Collection.toLookupTag(),
+ arrayOf(
+ ConeClassLikeTypeImpl(
+ StandardClassIds.Any.toLookupTag(),
+ ConeTypeProjection.EMPTY_ARRAY,
+ isMarkedNullable = false
+ )
+ ),
+ isMarkedNullable = false
+)
+
+private fun _check(declarations: List<FirDeclaration>, context: CheckerContext, reporter: DiagnosticReporter) {
+ for (overloadGroup in declarations.filterIsInstance<FirSimpleFunction>().groupBy { it.name }.values) {
+ var paramIndex = 0
+ while (true) {
+ val params = overloadGroup.mapNotNull { fn -> fn.valueParameters.getOrNull(paramIndex)?.let { fn to it } }
+ .takeIf { it.isNotEmpty() }
+ ?: break
+
+ val iterableParams = params.filter { (_, param) -> param.returnTypeRef.coneType.isSubtypeOf(iterable, context.session) }
+ if (iterableParams.size > 1) {
+ reporter.reportOn(
+ iterableParams.first().second.source,
+ FirErrors.BOBKO_ITERABLE_OVERLOADS,
+ iterableParams.first().first.render(),
+ context
+ )
+ } else {
+ val collectionParams = params.filter { (_, param) -> param.returnTypeRef.coneType.isSubtypeOf(collection, context.session) }
+ if (collectionParams.size > 1) {
+ reporter.reportOn(
+ collectionParams.first().second.source,
+ FirErrors.BOBKO_COLLECTION_OVERLOADS,
+ iterableParams.first().first.render(),
+ context
+ )
+ }
+ }
+
+ paramIndex++
+ }
+ }
+}
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 e766d81..07cf3d7 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
@@ -91,8 +91,8 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER
-import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_IN_WHERE_CLAUSE_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_IN_CONTRACT_ERROR
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_IN_WHERE_CLAUSE_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ON_SUPERCLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT
@@ -114,6 +114,8 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_FOR_DELEGATED_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOBKO_COLLECTION_OVERLOADS
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOBKO_ITERABLE_OVERLOADS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY
@@ -867,6 +869,8 @@
map.put(EXPRESSION_EXPECTED, "Only expressions are allowed here.")
map.put(DIVISION_BY_ZERO, "Division by zero.")
+ map.put(BOBKO_ITERABLE_OVERLOADS, "BOBKO_ITERABLE_OVERLOADS: ", STRING)
+ map.put(BOBKO_COLLECTION_OVERLOADS, "BOBKO_COLLECTION_OVERLOADS: ", STRING)
map.put(INT_LITERAL_OUT_OF_RANGE, "Value out of range.")
map.put(WRONG_LONG_SUFFIX, "Use 'L' instead of 'l'.")
map.put(EMPTY_CHARACTER_LITERAL, "Empty character literal.")