mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
1/2 Refactor: reuse kotlin ranges parsing code in AbstractRangeInspection
Why: 1. To support `rangeUntil` operator in the next commit. Because now it's easier to implement the support. 2. To get rid of "Range parsing logic" duplicate This commit doesn't change any user visible behaviour (at least I tried to make it this way) GitOrigin-RevId: 9713b8eb18f6ff3647df98c0a5072883bd3f13d3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
71e07cb22c
commit
f30e8ca592
@@ -168,7 +168,7 @@ enum class HintType(
|
||||
KotlinBundle.message("hints.settings.dont.show.ranges"),
|
||||
true
|
||||
) {
|
||||
override fun isApplicable(e: PsiElement): Boolean = e is KtBinaryExpression && e.isRangeExpression()
|
||||
override fun isApplicable(e: PsiElement): Boolean = e is KtBinaryExpression && e.isRangeExpression(context = null)
|
||||
|
||||
override fun provideHintDetails(e: PsiElement): List<InlayInfoDetails> {
|
||||
val binaryExpression = e.safeAs<KtBinaryExpression>() ?: return emptyList()
|
||||
|
||||
+29
-9
@@ -1,10 +1,22 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.codeInsight.hints
|
||||
|
||||
import com.intellij.codeInsight.hints.*
|
||||
import com.intellij.codeInsight.hints.ChangeListener
|
||||
import com.intellij.codeInsight.hints.ImmediateConfigurable
|
||||
import com.intellij.codeInsight.hints.InlayGroup
|
||||
import com.intellij.codeInsight.hints.SettingsKey
|
||||
import com.intellij.ui.layout.*
|
||||
import com.intellij.util.castSafelyTo
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyze
|
||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import javax.swing.JComponent
|
||||
|
||||
class KotlinValuesHintsProvider : KotlinAbstractHintsProvider<KotlinValuesHintsProvider.Settings>() {
|
||||
@@ -63,18 +75,26 @@ class KotlinValuesHintsProvider : KotlinAbstractHintsProvider<KotlinValuesHintsP
|
||||
get() = KotlinBundle.message("inlay.kotlin.values.hints")
|
||||
}
|
||||
|
||||
internal fun KtBinaryExpression.isRangeExpression(): Boolean = getRangeBinaryExpressionType() != null
|
||||
internal fun KtExpression.isRangeExpression(context: Lazy<BindingContext>?): Boolean = getRangeBinaryExpressionType(context) != null
|
||||
|
||||
fun KtBinaryExpression.getRangeBinaryExpressionType() =
|
||||
when (operationReference.getReferencedNameAsName().asString()) {
|
||||
".." -> RangeBinaryKtExpressionType.rangeTo
|
||||
"..<" -> RangeBinaryKtExpressionType.rangeUntil
|
||||
"downTo" -> RangeBinaryKtExpressionType.downTo
|
||||
"until" -> RangeBinaryKtExpressionType.until
|
||||
internal fun KtExpression.getRangeBinaryExpressionType(context: Lazy<BindingContext>?): RangeKtExpressionType? {
|
||||
val name = castSafelyTo<KtBinaryExpression>()?.operationReference?.getReferencedNameAsName()?.asString()
|
||||
?: castSafelyTo<KtDotQualifiedExpression>()?.callExpression?.calleeExpression?.text
|
||||
return when (name) {
|
||||
".." -> RangeKtExpressionType.rangeTo
|
||||
"rangeTo" -> RangeKtExpressionType.rangeTo
|
||||
"..<" -> RangeKtExpressionType.rangeUntil
|
||||
"rangeUntil" -> RangeKtExpressionType.rangeUntil
|
||||
"downTo" -> RangeKtExpressionType.downTo
|
||||
"until" -> RangeKtExpressionType.until
|
||||
else -> null
|
||||
}?.takeIf {
|
||||
val notNullContext = context?.value ?: safeAnalyze(BodyResolveMode.PARTIAL)
|
||||
getResolvedCall(notNullContext)?.resultingDescriptor?.fqNameOrNull()?.asString()?.startsWith("kotlin.") == true
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
enum class RangeBinaryKtExpressionType {
|
||||
enum class RangeKtExpressionType {
|
||||
rangeTo, rangeUntil, downTo, until
|
||||
}
|
||||
|
||||
+17
-30
@@ -3,40 +3,39 @@
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.util.castSafelyTo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeKtExpressionType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.getRangeBinaryExpressionType
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getType
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection
|
||||
|
||||
abstract class AbstractRangeInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : KtVisitorVoid() {
|
||||
override fun visitBinaryExpression(binaryExpression: KtBinaryExpression) {
|
||||
val operator = binaryExpression.operationReference.text
|
||||
visitRange(binaryExpression, operator, holder)
|
||||
visitRange(binaryExpression, holder)
|
||||
}
|
||||
|
||||
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
|
||||
val callee = expression.callExpression?.calleeExpression?.text ?: return
|
||||
visitRange(expression, callee, holder)
|
||||
visitRange(expression, holder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitRange(expression: KtExpression, operator: String, holder: ProblemsHolder) {
|
||||
if (operator !in rangeFunctions) return
|
||||
val context = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
val fqName = expression.getResolvedCall(context)?.resultingDescriptor?.fqNameOrNull() ?: return
|
||||
when (fqName) {
|
||||
in rangeToFqNames -> visitRangeTo(expression, context, holder)
|
||||
untilFqName -> visitUntil(expression, context, holder)
|
||||
downToFqNames -> visitDownTo(expression, context, holder)
|
||||
private fun visitRange(expression: KtExpression, holder: ProblemsHolder) {
|
||||
val context = lazy { expression.analyze(BodyResolveMode.PARTIAL) }
|
||||
when (expression.getRangeBinaryExpressionType(context) ?: return) {
|
||||
RangeKtExpressionType.rangeTo -> visitRangeTo(expression, context.value, holder)
|
||||
RangeKtExpressionType.rangeUntil -> Unit
|
||||
RangeKtExpressionType.downTo -> visitDownTo(expression, context.value, holder)
|
||||
RangeKtExpressionType.until -> visitUntil(expression, context.value, holder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +46,6 @@ abstract class AbstractRangeInspection : AbstractKotlinInspection() {
|
||||
abstract fun visitDownTo(expression: KtExpression, context: BindingContext, holder: ProblemsHolder)
|
||||
|
||||
companion object {
|
||||
private val rangeFunctions = listOf("..", "rangeTo", "until", "downTo")
|
||||
|
||||
private val rangeToFqNames = listOf(
|
||||
"Char",
|
||||
"Byte", "Short", "Int", "Long",
|
||||
"UByte", "UShort", "UInt", "ULong"
|
||||
).map { FqName("kotlin.$it.rangeTo") }
|
||||
|
||||
private val untilFqName = FqName("kotlin.ranges.until")
|
||||
|
||||
private val downToFqNames = FqName("kotlin.ranges.downTo")
|
||||
|
||||
fun KtExpression.constantValueOrNull(context: BindingContext? = null): ConstantValue<Any?>? {
|
||||
val c = context ?: this.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.constants.*
|
||||
|
||||
/**
|
||||
* Tests:
|
||||
* [org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testEmptyRange_inspectionData_Inspections_test]
|
||||
* [org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.EmptyRange]
|
||||
*/
|
||||
class EmptyRangeInspection : AbstractRangeInspection() {
|
||||
override fun visitRangeTo(expression: KtExpression, context: BindingContext, holder: ProblemsHolder) {
|
||||
expression.startAndEndValueSignedOrNull(context)?.let { (startValue, endValue) ->
|
||||
|
||||
+13
-4
@@ -8,14 +8,19 @@ import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.intentions.getArguments
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.typeUtil.isDouble
|
||||
import org.jetbrains.kotlin.types.typeUtil.isFloat
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
|
||||
class ReplaceRangeToWithUntilInspection : AbstractRangeInspection() {
|
||||
override fun visitRangeTo(expression: KtExpression, context: BindingContext, holder: ProblemsHolder) {
|
||||
if (!isApplicable(expression)) return
|
||||
if (!isApplicable(expression, context)) return
|
||||
holder.registerProblem(
|
||||
expression,
|
||||
KotlinBundle.message("inspection.replace.range.to.with.until.display.name"),
|
||||
@@ -43,11 +48,15 @@ class ReplaceRangeToWithUntilInspection : AbstractRangeInspection() {
|
||||
|
||||
companion object {
|
||||
fun applyFixIfApplicable(expression: KtExpression) {
|
||||
if (isApplicable(expression)) applyFix(expression)
|
||||
if (isApplicable(expression, expression.analyze(BodyResolveMode.PARTIAL_NO_ADDITIONAL))) applyFix(expression)
|
||||
}
|
||||
|
||||
private fun isApplicable(expression: KtExpression): Boolean {
|
||||
return expression.getArguments()?.second?.deparenthesize()?.isMinusOne() == true
|
||||
private fun isApplicable(expression: KtExpression, context: BindingContext): Boolean {
|
||||
val (left, right) = expression.getArguments() ?: return false
|
||||
// `until` isn't available for floating point numbers
|
||||
fun KtExpression.isIntegerType() = context.getType(this)
|
||||
?.let { it.isPrimitiveNumberType() && !it.isDouble() && !it.isFloat() }
|
||||
return right?.deparenthesize()?.isMinusOne() == true && left?.isIntegerType() == true && right.isIntegerType() == true
|
||||
}
|
||||
|
||||
private fun applyFix(element: KtExpression) {
|
||||
|
||||
+3
-4
@@ -41,8 +41,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyzeNonSourceRootCode
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeBinaryKtExpressionType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeBinaryKtExpressionType.*
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeKtExpressionType.*
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.getRangeBinaryExpressionType
|
||||
import org.jetbrains.kotlin.idea.core.resolveType
|
||||
import org.jetbrains.kotlin.idea.inspections.dfa.KotlinAnchor.*
|
||||
@@ -960,7 +959,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
}
|
||||
is KtBinaryExpression -> {
|
||||
val (leftRelation, rightRelation) =
|
||||
range.getRangeBinaryExpressionType()?.getRelationType() ?: (null to null)
|
||||
range.getRangeBinaryExpressionType(context = null)?.getRelationType() ?: (null to null)
|
||||
if (leftRelation != null && rightRelation != null) {
|
||||
val left = range.left
|
||||
val right = range.right
|
||||
@@ -1277,7 +1276,7 @@ class KtControlFlowBuilder(val factory: DfaValueFactory, val context: KtExpressi
|
||||
private fun processInCheck(kotlinType: KotlinType?, range: KtExpression?, anchor: KotlinAnchor, negated: Boolean) {
|
||||
if (kotlinType != null && (kotlinType.isInt() || kotlinType.isLong())) {
|
||||
if (range is KtBinaryExpression) {
|
||||
val type = range.getRangeBinaryExpressionType()
|
||||
val type = range.getRangeBinaryExpressionType(context = null)
|
||||
val pair = when (type) {
|
||||
rangeTo, until, rangeUntil -> range.left to range.right
|
||||
null, downTo -> null
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
package org.jetbrains.kotlin.idea.inspections.dfa
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.value.RelationType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeBinaryKtExpressionType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.hints.RangeKtExpressionType
|
||||
|
||||
fun RangeBinaryKtExpressionType.getRelationType() =
|
||||
fun RangeKtExpressionType.getRelationType() =
|
||||
when (this) {
|
||||
RangeBinaryKtExpressionType.rangeTo -> RelationType.GE to RelationType.LE
|
||||
RangeBinaryKtExpressionType.rangeUntil, RangeBinaryKtExpressionType.until -> RelationType.GE to RelationType.LT
|
||||
RangeBinaryKtExpressionType.downTo -> RelationType.LE to RelationType.GE
|
||||
RangeKtExpressionType.rangeTo -> RelationType.GE to RelationType.LE
|
||||
RangeKtExpressionType.rangeUntil, RangeKtExpressionType.until -> RelationType.GE to RelationType.LT
|
||||
RangeKtExpressionType.downTo -> RelationType.LE to RelationType.GE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user