diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceUntilWithRangeUntilInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceUntilWithRangeUntilInspection.kt index 872ed12ced53..0177d2532787 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceUntilWithRangeUntilInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceUntilWithRangeUntilInspection.kt @@ -10,6 +10,7 @@ import org.jetbrains.annotations.ApiStatus import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.resources.KotlinBundle +import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.intentions.getArguments import org.jetbrains.kotlin.idea.intentions.receiverType import org.jetbrains.kotlin.idea.statistics.KotlinLanguageFeaturesFUSCollector @@ -17,6 +18,7 @@ import org.jetbrains.kotlin.idea.statistics.NewAndDeprecatedFeaturesInspectionDa import org.jetbrains.kotlin.idea.util.RangeKtExpressionType import org.jetbrains.kotlin.idea.util.RangeKtExpressionType.RANGE_UNTIL import org.jetbrains.kotlin.idea.util.RangeKtExpressionType.UNTIL +import org.jetbrains.kotlin.idea.util.WasExperimentalOptInsNecessityCheckerFe10 import org.jetbrains.kotlin.idea.util.projectStructure.module import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName @@ -91,7 +93,13 @@ class ReplaceUntilWithRangeUntilInspection : AbstractRangeInspection( private fun KtElement.isOtpInRequiredForRangeUntil(annotationFqName: FqName, context: BindingContext): Boolean { val rangeUntilFunctionDescriptor = findRangeUntilFunctionDescriptor(context) ?: return false - return rangeUntilFunctionDescriptor.annotations.hasAnnotation(annotationFqName) + if (rangeUntilFunctionDescriptor.annotations.hasAnnotation(annotationFqName)) { + return true + } + val necessaryOptIns = WasExperimentalOptInsNecessityCheckerFe10.getNecessaryOptInsFromWasExperimental( + rangeUntilFunctionDescriptor.annotations, findModuleDescriptor(), languageVersionSettings.apiVersion + ) + return annotationFqName in necessaryOptIns } private fun KtElement.findRangeUntilFunctionDescriptor(context: BindingContext): CallableDescriptor? { diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/UnnecessaryOptInAnnotationInspection.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/UnnecessaryOptInAnnotationInspection.kt index 875b23287c4b..58b5ad179d25 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/UnnecessaryOptInAnnotationInspection.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/inspections/UnnecessaryOptInAnnotationInspection.kt @@ -11,32 +11,33 @@ import com.intellij.psi.util.parentOfType import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings import org.jetbrains.kotlin.idea.base.psi.KotlinPsiHeuristics +import org.jetbrains.kotlin.idea.base.resources.KotlinBundle import org.jetbrains.kotlin.idea.base.util.names.FqNames import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny +import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection import org.jetbrains.kotlin.idea.core.OPT_IN_FQ_NAMES import org.jetbrains.kotlin.idea.core.getDirectlyOverriddenDeclarations +import org.jetbrains.kotlin.idea.inspections.CanSealedSubClassBeObjectInspection.Companion.asKtClass import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.idea.references.ReadWriteAccessChecker import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor +import org.jetbrains.kotlin.idea.util.WasExperimentalOptInsNecessityCheckerFe10 import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.SINCE_KOTLIN_FQ_NAME import org.jetbrains.kotlin.resolve.checkers.OptInNames -import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.KClassValue -import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -54,12 +55,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs * any names. For these redundant markers, the inspection proposes a quick fix to remove the marker * or the entire unnecessary `@OptIn` annotation if it contains a single marker. */ -import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection -import org.jetbrains.kotlin.idea.inspections.CanSealedSubClassBeObjectInspection.Companion.asKtClass -import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor -import org.jetbrains.kotlin.idea.util.WasExperimentalOptInsNecessityCheckerFe10 -import org.jetbrains.kotlin.resolve.descriptorUtil.* - class UnnecessaryOptInAnnotationInspection : AbstractKotlinInspection() { /** @@ -314,8 +309,6 @@ private class MarkerCollector(private val resolutionFacade: ResolutionFacade) { */ private fun KtReferenceExpression.isSetterCall(): Boolean = readWriteAccessChecker.readWriteAccessWithFullExpression(this, true).first.isWrite - - private val VERSION_ARGUMENT = Name.identifier("version") } /** diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt index 5108c33710e4..3506e20ef129 100644 --- a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt @@ -1,20 +1,5 @@ -// COMPILER_ARGUMENTS: -XXLanguage:+RangeUntilOperator // WITH_STDLIB -// LANGUAGE_VERSION: 1.9 -package kotlin - -class MyObj { - @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - @SinceKotlin("1.9") - @WasExperimental(ExperimentalStdlibApi::class) - @kotlin.internal.InlineOnly - operator inline fun rangeUntil(o: MyObj) = Unit -} - -// Since `until` is only defined for primitives, we create this fake function in kotlin package -// to activate the inspection and make it look at MyObj.rangeUntil, which is without opt-in. -infix fun MyObj.until(o: MyObj) = Unit - +// API_VERSION: 1.9 fun main() { - MyObj() until MyObj() + 0 until 10 } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt.after b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt.after index fa23164158a3..e9eb53ea577c 100644 --- a/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt.after +++ b/plugins/kotlin/idea/tests/testData/inspectionsLocal/replaceUntilWithRangeUntil/optInIsNotRequired.kt.after @@ -1,20 +1,5 @@ -// COMPILER_ARGUMENTS: -XXLanguage:+RangeUntilOperator -// WITH_STDLIB // LANGUAGE_VERSION: 1.9 -package kotlin - -class MyObj { - @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") - @SinceKotlin("1.9") - @WasExperimental(ExperimentalStdlibApi::class) - @kotlin.internal.InlineOnly - operator inline fun rangeUntil(o: MyObj) = Unit -} - -// Since `until` is only defined for primitives, we create this fake function in kotlin package -// to activate the inspection and make it look at MyObj.rangeUntil, which is without opt-in. -infix fun MyObj.until(o: MyObj) = Unit - +// WITH_STDLIB fun main() { - MyObj()..