Change API in AbstractApplicabilityBasedInspection

Replace all inspectionTarget with inspectionHighlightRangeInElement & change type of element in applyTo from PsiElement to TElement
This commit is contained in:
Dmitry Gridin
2019-06-06 13:33:52 +07:00
parent 1ad7a50087
commit 4f8c0653c5
30 changed files with 164 additions and 212 deletions
@@ -20,7 +20,6 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtVisitorVoid
@@ -44,7 +43,7 @@ abstract class AbstractApplicabilityBasedInspection<TElement : KtElement>(
if (!isApplicable(element)) return
holder.registerProblemWithoutOfflineInformation(
inspectionTarget(element),
element,
inspectionText(element),
isOnTheFly,
inspectionHighlightType(element),
@@ -55,8 +54,6 @@ abstract class AbstractApplicabilityBasedInspection<TElement : KtElement>(
open fun inspectionHighlightRangeInElement(element: TElement): TextRange? = null
open fun inspectionTarget(element: TElement): PsiElement = element
open fun inspectionHighlightType(element: TElement): ProblemHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING
abstract fun inspectionText(element: TElement): String
@@ -67,7 +64,7 @@ abstract class AbstractApplicabilityBasedInspection<TElement : KtElement>(
abstract fun isApplicable(element: TElement): Boolean
abstract fun applyTo(element: PsiElement, project: Project = element.project, editor: Editor? = null)
abstract fun applyTo(element: TElement, project: Project = element.project, editor: Editor? = null)
open val startFixInWriteAction = true
@@ -75,7 +72,8 @@ abstract class AbstractApplicabilityBasedInspection<TElement : KtElement>(
override fun startInWriteAction() = startFixInWriteAction
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.psiElement
@Suppress("UNCHECKED_CAST")
val element = descriptor.psiElement as TElement
applyTo(element, project, element.findExistingEditor())
}
@@ -7,17 +7,15 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.refactoring.withExpectedActuals
import org.jetbrains.kotlin.idea.util.nameIdentifierTextRangeInThis
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.util.OperatorChecks
class AddOperatorModifierInspection : AbstractApplicabilityBasedInspection<KtNamedFunction>(KtNamedFunction::class.java) {
override fun inspectionHighlightRangeInElement(element: KtNamedFunction) =
element.nameIdentifier?.textRange?.shiftLeft(element.startOffset)
override fun inspectionHighlightRangeInElement(element: KtNamedFunction) = element.nameIdentifierTextRangeInThis()
override fun inspectionText(element: KtNamedFunction) = "Function should have 'operator' modifier"
@@ -29,8 +27,8 @@ class AddOperatorModifierInspection : AbstractApplicabilityBasedInspection<KtNam
return !functionDescriptor.isOperator && OperatorChecks.check(functionDescriptor).isSuccess
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
for (declaration in (element as KtNamedFunction).withExpectedActuals()) {
override fun applyTo(element: KtNamedFunction, project: Project, editor: Editor?) {
for (declaration in element.withExpectedActuals()) {
declaration.addModifier(KtTokens.OPERATOR_KEYWORD)
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
@@ -22,8 +21,8 @@ import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.core.unblockDocument
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.textRangeIn
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -38,14 +37,13 @@ import java.util.*
class DeprecatedCallableAddReplaceWithInspection : AbstractApplicabilityBasedInspection<KtCallableDeclaration>(
KtCallableDeclaration::class.java
) {
override fun inspectionText(element: KtCallableDeclaration) =
"@Deprecated annotation without 'replaceWith' argument"
override fun inspectionText(element: KtCallableDeclaration) = "@Deprecated annotation without 'replaceWith' argument"
override fun inspectionTarget(element: KtCallableDeclaration): KtAnnotationEntry =
element.annotationEntries.first { it.shortName == DEPRECATED_NAME }
override fun inspectionHighlightRangeInElement(element: KtCallableDeclaration) = element.annotationEntries.first {
it.shortName == DEPRECATED_NAME
}.textRangeIn(element)
override val defaultFixText =
"Add 'replaceWith' argument to specify replacement pattern"
override val defaultFixText = "Add 'replaceWith' argument to specify replacement pattern"
private class ReplaceWith(val expression: String, vararg val imports: String)
@@ -54,14 +52,13 @@ class DeprecatedCallableAddReplaceWithInspection : AbstractApplicabilityBasedIns
return element.suggestReplaceWith() != null
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val declaration = element.getParentOfType<KtCallableDeclaration>(strict = true) ?: return
val replaceWith = declaration.suggestReplaceWith()!!
override fun applyTo(element: KtCallableDeclaration, project: Project, editor: Editor?) {
val replaceWith = element.suggestReplaceWith()!!
assert('\n' !in replaceWith.expression && '\r' !in replaceWith.expression) { "Formatted expression text should not contain \\n or \\r" }
val annotationEntry = declaration.deprecatedAnnotationWithNoReplaceWith()!!
val psiFactory = KtPsiFactory(declaration)
val annotationEntry = element.deprecatedAnnotationWithNoReplaceWith()!!
val psiFactory = KtPsiFactory(element)
var escapedText = replaceWith.expression.replace("\\", "\\\\").replace("\"", "\\\"")
@@ -212,8 +209,8 @@ class DeprecatedCallableAddReplaceWithInspection : AbstractApplicabilityBasedIns
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val bindingContext = expression.analyze()
val target = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression]
?: bindingContext[BindingContext.REFERENCE_TARGET, expression]
?: return
?: bindingContext[BindingContext.REFERENCE_TARGET, expression]
?: return
if (target.isExtension || expression.getReceiverExpression() == null) {
val fqName = target.importableFqName ?: return
if (!importHelper.isImportedWithDefault(ImportPath(fqName, false), file)
@@ -22,14 +22,13 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.core.setType
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.elvisPattern
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.expressionComparedToNull
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.fromIfKeywordToRightParenthesisTextRangeInThis
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.shouldBeTransformed
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.textRange
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.isError
@@ -43,16 +42,15 @@ class FoldInitializerAndIfToElvisInspection : AbstractApplicabilityBasedInspecti
override val defaultFixText: String = "Replace 'if' with elvis operator"
override fun inspectionHighlightRangeInElement(element: KtIfExpression): TextRange? = element.textRange().shiftLeft(element.startOffset)
override fun inspectionHighlightRangeInElement(element: KtIfExpression) = element.fromIfKeywordToRightParenthesisTextRangeInThis()
override fun inspectionHighlightType(element: KtIfExpression): ProblemHighlightType =
if (element.shouldBeTransformed()) ProblemHighlightType.GENERIC_ERROR_OR_WARNING else ProblemHighlightType.INFORMATION
override fun isApplicable(element: KtIfExpression): Boolean = Companion.isApplicable(element)
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val newElvis = Companion.applyTo(element as KtIfExpression)
editor?.caretModel?.moveToOffset(newElvis.right!!.textOffset)
override fun applyTo(element: KtIfExpression, project: Project, editor: Editor?) {
Companion.applyTo(element).right?.textOffset?.let { editor?.caretModel?.moveToOffset(it) }
}
companion object {
@@ -62,7 +60,7 @@ class FoldInitializerAndIfToElvisInspection : AbstractApplicabilityBasedInspecti
val type = data.ifNullExpression.analyze().getType(data.ifNullExpression) ?: return null
if (!type.isNothing()) return null
return element.textRange()
return element.fromIfKeywordToRightParenthesisTextRangeInThis()
}
fun isApplicable(element: KtIfExpression): Boolean = applicabilityRange(element) != null
@@ -5,20 +5,19 @@
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.getLastLambdaExpression
import org.jetbrains.kotlin.idea.inspections.collections.isMap
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.util.calleeTextRangeInThis
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -41,16 +40,14 @@ class JavaMapForEachInspection : AbstractApplicabilityBasedInspection<KtDotQuali
return resolvedCall.isResolvedWithSamConversions()
}
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression): TextRange? = element.calleeTextRangeInThis()
override fun inspectionText(element: KtDotQualifiedExpression) = "Java Map.forEach method call should be replaced with Kotlin's forEach"
override fun inspectionHighlightType(element: KtDotQualifiedExpression) = ProblemHighlightType.GENERIC_ERROR_OR_WARNING
override val defaultFixText = "Replace with Kotlin's forEach"
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val call = element.getStrictParentOfType<KtCallExpression>() ?: return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val call = element.callExpression ?: return
val lambda = call.lambda() ?: return
val valueParameters = lambda.valueParameters
lambda.functionLiteral.valueParameterList?.replace(
@@ -8,14 +8,12 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
import org.jetbrains.kotlin.idea.core.getLastLambdaExpression
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.idea.util.textRangeIn
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.unpackFunctionLiteral
@@ -36,19 +34,17 @@ class MoveLambdaOutsideParenthesesInspection : AbstractApplicabilityBasedInspect
override fun isApplicable(element: KtCallExpression) = element.canMoveLambdaOutsideParentheses()
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element.getParentOfType<KtCallExpression>(strict = false) ?: return
if (expression.canMoveLambdaOutsideParentheses()) {
expression.moveFunctionLiteralOutsideParentheses()
override fun applyTo(element: KtCallExpression, project: Project, editor: Editor?) {
if (element.canMoveLambdaOutsideParentheses()) {
element.moveFunctionLiteralOutsideParentheses()
}
}
override fun inspectionText(element: KtCallExpression) = "Lambda argument ${element.verb} be moved out of parentheses"
override fun inspectionTarget(element: KtCallExpression): KtElement {
return element.getLastLambdaExpression()?.getStrictParentOfType<KtValueArgument>()?.asElement() ?: element
}
override fun inspectionHighlightRangeInElement(element: KtCallExpression) = element.getLastLambdaExpression()
?.getStrictParentOfType<KtValueArgument>()?.asElement()
?.textRangeIn(element)
override val defaultFixText = "Move lambda argument out of parentheses"
}
@@ -75,7 +75,7 @@ class NullableBooleanElvisInspection : AbstractKotlinInspection(), CleanupLocalI
val prefixExpression = equalityCheckExpression.getParentOfType<KtPrefixExpression>(strict = true) ?: return
val simplifier = SimplifyNegatedBinaryExpressionInspection()
if (simplifier.isApplicable(prefixExpression)) {
simplifier.applyTo(prefixExpression.operationReference)
simplifier.applyTo(prefixExpression)
}
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.canDropBraces
import org.jetbrains.kotlin.idea.core.dropBraces
import org.jetbrains.kotlin.psi.KtBlockStringTemplateEntry
@@ -20,7 +19,7 @@ class RemoveCurlyBracesFromTemplateInspection :
override fun isApplicable(element: KtBlockStringTemplateEntry): Boolean = element.canDropBraces()
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
(element as KtBlockStringTemplateEntry).dropBraces()
override fun applyTo(element: KtBlockStringTemplateEntry, project: Project, editor: Editor?) {
element.dropBraces()
}
}
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.resolvedToArrayType
import org.jetbrains.kotlin.lexer.KtTokens
@@ -28,24 +27,23 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
class ReplaceArrayEqualityOpWithArraysEqualsInspection : AbstractApplicabilityBasedInspection<KtBinaryExpression>(
KtBinaryExpression::class.java
KtBinaryExpression::class.java
) {
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element as? KtBinaryExpression ?: return
val right = expression.right ?: return
val left = expression.left ?: return
override fun applyTo(element: KtBinaryExpression, project: Project, editor: Editor?) {
val right = element.right ?: return
val left = element.left ?: return
val factory = KtPsiFactory(project)
val template = buildString {
if (expression.operationToken == KtTokens.EXCLEQ) append("!")
if (element.operationToken == KtTokens.EXCLEQ) append("!")
append("$0.contentEquals($1)")
}
expression.replace(factory.createExpressionByPattern(template, left, right))
element.replace(factory.createExpressionByPattern(template, left, right))
}
override fun isApplicable(element: KtBinaryExpression): Boolean {
val operationToken = element.operationToken
when (operationToken) {
KtTokens.EQEQ, KtTokens.EXCLEQ -> {}
when (element.operationToken) {
KtTokens.EQEQ, KtTokens.EXCLEQ -> {
}
else -> return false
}
val right = element.right
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
@@ -39,21 +38,20 @@ class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBa
return (element.replaceableAssertion() != null)
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element as? KtCallExpression ?: return
val valueArguments = expression.valueArguments
override fun applyTo(element: KtCallExpression, project: Project, editor: Editor?) {
val valueArguments = element.valueArguments
val condition = valueArguments.firstOrNull()?.getArgumentExpression() as? KtBinaryExpression ?: return
val left = condition.left ?: return
val right = condition.right ?: return
val assertion = expression.replaceableAssertion() ?: return
val assertion = element.replaceableAssertion() ?: return
val file = expression.containingKtFile
val file = element.containingKtFile
val factory = KtPsiFactory(project)
val replaced = if (valueArguments.size == 2) {
val message = valueArguments[1].getArgumentExpression() ?: return
expression.replaced(factory.createExpressionByPattern("$assertion($0, $1, $2)", left, right, message))
element.replaced(factory.createExpressionByPattern("$assertion($0, $1, $2)", left, right, message))
} else {
expression.replaced(factory.createExpressionByPattern("$assertion($0, $1)", left, right))
element.replaced(factory.createExpressionByPattern("$assertion($0, $1)", left, right))
}
ShortenReferences.DEFAULT.process(replaced)
OptimizeImportsProcessor(project, file).run()
@@ -79,11 +77,11 @@ class ReplaceAssertBooleanWithAssertEqualityInspection : AbstractApplicabilityBa
return assertionMap[Pair(referencedName, operationToken)]
}
private fun KtExpression.descriptor(context: BindingContext): CallableDescriptor? {
return getResolvedCall(context)?.resultingDescriptor
}
private fun KtExpression.type(context: BindingContext): KotlinType? {
return descriptor(context)?.returnType
}
@@ -18,15 +18,14 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.util.calleeTextRangeInThis
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -63,26 +62,25 @@ class ReplacePutWithAssignmentInspection : AbstractApplicabilityBasedInspection<
return receiverClass.isSubclassOf(DefaultBuiltIns.Instance.mutableMap)
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element.getParentOfType<KtDotQualifiedExpression>(strict = false) ?: return
val valueArguments = expression.callExpression?.valueArguments ?: return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val valueArguments = element.callExpression?.valueArguments ?: return
val firstArg = valueArguments[0]?.getArgumentExpression() ?: return
val secondArg = valueArguments[1]?.getArgumentExpression() ?: return
val label = if (secondArg is KtLambdaExpression) {
val returnLabel = secondArg.findDescendantOfType<KtReturnExpression>()?.getLabelName()
compatibleNames.firstOrNull { it == returnLabel }?.plus("@") ?: ""
} else ""
expression.replace(
KtPsiFactory(expression).createExpressionByPattern(
element.replace(
KtPsiFactory(element).createExpressionByPattern(
"$0[$1] = $label$2",
expression.receiverExpression,
element.receiverExpression,
firstArg,
secondArg
)
)
}
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression) = element.calleeTextRangeInThis()
override fun inspectionText(element: KtDotQualifiedExpression): String = "map.put() should be converted to assignment"
@@ -7,13 +7,11 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.intentions.isToString
import org.jetbrains.kotlin.psi.KtBlockStringTemplateEntry
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
class ReplaceToStringWithStringTemplateInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
KtDotQualifiedExpression::class.java
@@ -24,15 +22,12 @@ class ReplaceToStringWithStringTemplateInspection : AbstractApplicabilityBasedIn
return element.isToString()
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element.getParentOfType<KtDotQualifiedExpression>(strict = false) ?: return
val variable = expression.receiverExpression.text
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val variable = element.receiverExpression.text
element.replace(KtPsiFactory(element).createExpression("\"$$variable\""))
}
override fun inspectionText(element: KtDotQualifiedExpression) = "Call of 'toString' could be replaced with string template"
override fun inspectionTarget(element: KtDotQualifiedExpression) = element
override val defaultFixText = "Replace 'toString' with string template"
}
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -115,8 +114,8 @@ class ReplaceWithOperatorAssignmentInspection : AbstractApplicabilityBasedInspec
operationToken == KtTokens.DIV ||
operationToken == KtTokens.PERC
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
(element as? KtBinaryExpression)?.replace(buildOperatorAssignment(element))
override fun applyTo(element: KtBinaryExpression, project: Project, editor: Editor?) {
element.replace(buildOperatorAssignment(element))
}
private fun buildOperatorAssignment(element: KtBinaryExpression): KtBinaryExpression {
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.CodeInsightUtilCore
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.ShortenReferences
@@ -69,35 +68,34 @@ class SimplifyAssertNotNullInspection : AbstractApplicabilityBasedInspection<KtC
override fun fixText(element: KtCallExpression): String {
return if (element.valueArguments.size == 1) {
"Replace with '!!' operator"
}
else {
} else {
"Replace with '?: error(...)'"
}
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element as? KtCallExpression ?: return
val declaration = findVariableDeclaration(expression)!!
val initializer = declaration.initializer!!
val message = extractMessage(expression)
override fun applyTo(element: KtCallExpression, project: Project, editor: Editor?) {
val declaration = findVariableDeclaration(element) ?: return
val initializer = declaration.initializer ?: return
val message = extractMessage(element)
val commentSaver = CommentSaver(expression)
val commentSaver = CommentSaver(element)
if (message == null) {
val newInitializer = KtPsiFactory(expression).createExpressionByPattern("$0!!", initializer)
val newInitializer = KtPsiFactory(element).createExpressionByPattern("$0!!", initializer)
initializer.replace(newInitializer)
}
else {
val newInitializer = KtPsiFactory(expression).createExpressionByPattern("$0 ?: kotlin.error($1)", initializer, message)
} else {
val newInitializer = KtPsiFactory(element).createExpressionByPattern("$0 ?: kotlin.error($1)", initializer, message)
val result = initializer.replace(newInitializer)
val qualifiedExpression = (result as KtBinaryExpression).right as KtDotQualifiedExpression
ShortenReferences.DEFAULT.process(expression.containingKtFile,
qualifiedExpression.startOffset,
(qualifiedExpression.selectorExpression as KtCallExpression).calleeExpression!!.endOffset)
ShortenReferences.DEFAULT.process(
element.containingKtFile,
qualifiedExpression.startOffset,
(qualifiedExpression.selectorExpression as KtCallExpression).calleeExpression!!.endOffset
)
}
expression.delete()
element.delete()
commentSaver.restore(declaration)
@@ -120,8 +118,8 @@ class SimplifyAssertNotNullInspection : AbstractApplicabilityBasedInspection<KtC
val arguments = element.valueArguments
if (arguments.size != 2) return null
return (arguments[1].getArgumentExpression() as? KtLambdaExpression)
?.bodyExpression
?.statements
?.singleOrNull()
?.bodyExpression
?.statements
?.singleOrNull()
}
}
@@ -18,15 +18,13 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.idea.util.textRangeIn
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
class SimplifyNegatedBinaryExpressionInspection : AbstractApplicabilityBasedInspection<KtPrefixExpression>(
KtPrefixExpression::class.java
) {
class SimplifyNegatedBinaryExpressionInspection : AbstractApplicabilityBasedInspection<KtPrefixExpression>(KtPrefixExpression::class.java) {
private fun IElementType.negate(): KtSingleValueToken? = when (this) {
KtTokens.IN_KEYWORD -> KtTokens.NOT_IN
@@ -47,7 +45,7 @@ class SimplifyNegatedBinaryExpressionInspection : AbstractApplicabilityBasedInsp
else -> null
}
override fun inspectionTarget(element: KtPrefixExpression) = element.operationReference
override fun inspectionHighlightRangeInElement(element: KtPrefixExpression) = element.operationReference.textRangeIn(element)
override fun inspectionText(element: KtPrefixExpression) = "Negated operation should be simplified"
@@ -73,9 +71,8 @@ class SimplifyNegatedBinaryExpressionInspection : AbstractApplicabilityBasedInsp
return (expression.operationReference.getReferencedNameElementType() as? KtSingleValueToken)?.negate() != null
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val prefixExpression = element.parent as? KtPrefixExpression ?: return
val expression = KtPsiUtil.deparenthesize(prefixExpression.baseExpression) ?: return
override fun applyTo(element: KtPrefixExpression, project: Project, editor: Editor?) {
val expression = KtPsiUtil.deparenthesize(element.baseExpression) ?: return
val operation = (expression as KtOperationExpression).operationReference.getReferencedNameElementType().negate()?.value ?: return
val psiFactory = KtPsiFactory(expression)
@@ -87,6 +84,6 @@ class SimplifyNegatedBinaryExpressionInspection : AbstractApplicabilityBasedInsp
else ->
throw IllegalArgumentException()
}
prefixExpression.replace(newExpression)
element.replace(newExpression)
}
}
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -27,9 +26,9 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
import org.jetbrains.kotlin.idea.util.nameIdentifierTextRangeInThis
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
@@ -40,7 +39,7 @@ class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtPro
override fun isApplicable(element: KtProperty) = statusFor(element) != null
override fun inspectionTarget(element: KtProperty) = element.nameIdentifier ?: element
override fun inspectionHighlightRangeInElement(element: KtProperty) = element.nameIdentifierTextRangeInThis()
override fun inspectionText(element: KtProperty) = when (statusFor(element)) {
Status.RETURN_ONLY ->
@@ -54,9 +53,8 @@ class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtPro
override val startFixInWriteAction = false
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val property = element.getParentOfType<KtProperty>(strict = false) ?: return
KotlinInlineValHandler(withPrompt = false).inlineElement(project, editor, property)
override fun applyTo(element: KtProperty, project: Project, editor: Editor?) {
KotlinInlineValHandler(withPrompt = false).inlineElement(project, editor, element)
}
companion object {
@@ -72,7 +70,7 @@ class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtPro
fun isExactCopy(): Boolean {
if (!property.isVar && initializer is KtNameReferenceExpression && property.typeReference == null) {
val initializerDescriptor = initializer.resolveToCall(BodyResolveMode.FULL)?.resultingDescriptor as? VariableDescriptor
?: return false
?: return false
if (initializerDescriptor.isVar) return false
if (initializerDescriptor.containingDeclaration !is FunctionDescriptor) return false
@@ -10,8 +10,6 @@ import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -21,7 +19,6 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -42,14 +39,11 @@ class IfThenToElvisInspection(
else
ProblemHighlightType.INFORMATION
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
convert(
element as KtIfExpression,
editor
)
override fun applyTo(element: KtIfExpression, project: Project, editor: Editor?) {
convert(element, editor)
}
override fun inspectionHighlightRangeInElement(element: KtIfExpression): TextRange? = element.textRange().shiftLeft(element.startOffset)
override fun inspectionHighlightRangeInElement(element: KtIfExpression) = element.fromIfKeywordToRightParenthesisTextRangeInThis()
override fun createOptionsPanel(): JComponent? = MultipleCheckboxOptionsPanel(this).also {
it.addCheckbox("Report also on statement", "highlightStatement")
@@ -19,9 +19,7 @@ package org.jetbrains.kotlin.idea.inspections.branchedTransformations
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection
@@ -40,7 +38,7 @@ class IfThenToSafeAccessInspection : AbstractApplicabilityBasedInspection<KtIfEx
override fun isApplicable(element: KtIfExpression): Boolean = isApplicableTo(element, expressionShouldBeStable = true)
override fun inspectionHighlightRangeInElement(element: KtIfExpression): TextRange? = element.textRange().shiftLeft(element.startOffset)
override fun inspectionHighlightRangeInElement(element: KtIfExpression) = element.fromIfKeywordToRightParenthesisTextRangeInThis()
override fun inspectionText(element: KtIfExpression) = "Foldable if-then"
@@ -53,8 +51,8 @@ class IfThenToSafeAccessInspection : AbstractApplicabilityBasedInspection<KtIfEx
override val startFixInWriteAction = false
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
convert(element as KtIfExpression, editor)
override fun applyTo(element: KtIfExpression, project: Project, editor: Editor?) {
convert(element, editor)
}
companion object {
@@ -18,18 +18,17 @@ package org.jetbrains.kotlin.idea.inspections.branchedTransformations
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.getSubjectToIntroduce
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceSubject
import org.jetbrains.kotlin.idea.util.textRangeIn
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
class IntroduceWhenSubjectInspection : AbstractApplicabilityBasedInspection<KtWhenExpression>(KtWhenExpression::class.java) {
override fun isApplicable(element: KtWhenExpression) = element.getSubjectToIntroduce() != null
override fun inspectionTarget(element: KtWhenExpression) = element.whenKeyword
override fun inspectionHighlightRangeInElement(element: KtWhenExpression) = element.whenKeyword.textRangeIn(element)
override fun inspectionText(element: KtWhenExpression) = "'when' with subject should be used"
@@ -40,7 +39,7 @@ class IntroduceWhenSubjectInspection : AbstractApplicabilityBasedInspection<KtWh
return "Introduce '${subject.text}' as subject of 'when'"
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
element.getParentOfType<KtWhenExpression>(strict = true)?.introduceSubject()
override fun applyTo(element: KtWhenExpression, project: Project, editor: Editor?) {
element.introduceSubject()
}
}
@@ -35,11 +35,12 @@ import org.jetbrains.kotlin.idea.intentions.isReceiverExpressionWithValue
import org.jetbrains.kotlin.idea.intentions.toResolvedCall
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.platform
import org.jetbrains.kotlin.idea.util.calleeTextRangeInThis
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.calls.callUtil.getFirstArgumentExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
@@ -47,7 +48,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.getKotlinTypeWithPossibleSmartCastToFP
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -82,7 +82,7 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
return element.isReceiverExpressionWithValue()
}
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression) = element.calleeTextRangeInThis()
override fun inspectionHighlightType(element: KtDotQualifiedExpression): ProblemHighlightType {
val calleeExpression = element.callExpression?.calleeExpression as? KtSimpleNameExpression
@@ -118,28 +118,27 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
return "Replace with '${operation.value}'"
}
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val qualifiedExpression = element.getParentOfType<KtDotQualifiedExpression>(strict = false) ?: return
val callExpression = qualifiedExpression.callExpression ?: return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val callExpression = element.callExpression ?: return
val operation = operation(callExpression.calleeExpression as? KtSimpleNameExpression ?: return) ?: return
val argument = callExpression.valueArguments.single().getArgumentExpression() ?: return
val receiver = qualifiedExpression.receiverExpression
val receiver = element.receiverExpression
val factory = KtPsiFactory(qualifiedExpression)
val factory = KtPsiFactory(element)
when (operation) {
KtTokens.EXCLEQ -> {
val prefixExpression = qualifiedExpression.getWrappingPrefixExpressionIfAny() ?: return
val prefixExpression = element.getWrappingPrefixExpressionIfAny() ?: return
val newExpression = factory.createExpressionByPattern("$0 != $1", receiver, argument)
prefixExpression.replace(newExpression)
}
in OperatorConventions.COMPARISON_OPERATIONS -> {
val binaryParent = qualifiedExpression.parent as? KtBinaryExpression ?: return
val binaryParent = element.parent as? KtBinaryExpression ?: return
val newExpression = factory.createExpressionByPattern("$0 ${operation.value} $1", receiver, argument)
binaryParent.replace(newExpression)
}
else -> {
val newExpression = factory.createExpressionByPattern("$0 ${operation.value} $1", receiver, argument)
qualifiedExpression.replace(newExpression)
element.replace(newExpression)
}
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspectio
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.intentions.isReceiverExpressionWithValue
import org.jetbrains.kotlin.idea.intentions.toResolvedCall
import org.jetbrains.kotlin.idea.util.calleeTextRangeInThis
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
@@ -39,7 +40,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator
class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
KtDotQualifiedExpression::class.java
KtDotQualifiedExpression::class.java
) {
private fun FunctionDescriptor.isExplicitOperator(): Boolean {
return if (overriddenDescriptors.isEmpty())
@@ -75,10 +76,9 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
override fun inspectionText(element: KtDotQualifiedExpression) = "Should be replaced with indexing"
override fun inspectionHighlightType(element: KtDotQualifiedExpression): ProblemHighlightType {
return if ((element.toResolvedCall(BodyResolveMode.PARTIAL)!!.resultingDescriptor as FunctionDescriptor).isExplicitOperator()) {
return if ((element.toResolvedCall(BodyResolveMode.PARTIAL)?.resultingDescriptor as? FunctionDescriptor)?.isExplicitOperator() == true) {
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
}
else {
} else {
ProblemHighlightType.INFORMATION
}
}
@@ -92,16 +92,15 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
return "Replace '${resolvedCall.resultingDescriptor.name.asString()}' call with indexing operator"
}
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression) = element.calleeTextRangeInThis()
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
val expression = element as? KtDotQualifiedExpression ?: element.parent.parent as? KtDotQualifiedExpression ?: return
val isSet = expression.toResolvedCall(BodyResolveMode.PARTIAL)!!.resultingDescriptor.name == OperatorNameConventions.SET
val allArguments = expression.callExpression!!.valueArguments
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val isSet = element.toResolvedCall(BodyResolveMode.PARTIAL)?.resultingDescriptor?.name == OperatorNameConventions.SET
val allArguments = element.callExpression!!.valueArguments
assert(allArguments.isNotEmpty())
val newExpression = KtPsiFactory(expression).buildExpression {
appendExpression(expression.receiverExpression)
val newExpression = KtPsiFactory(element).buildExpression {
appendExpression(element.receiverExpression)
appendFixedText("[")
@@ -116,7 +115,7 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
}
}
val newElement = expression.replace(newExpression)
val newElement = element.replace(newExpression)
if (editor != null) {
moveCaret(editor, isSet, newElement)
@@ -125,12 +124,11 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
private fun moveCaret(editor: Editor, isSet: Boolean, newElement: PsiElement) {
val arrayAccessExpression = if (isSet) {
newElement.getChildOfType<KtArrayAccessExpression>()!!
}
else {
newElement as KtArrayAccessExpression
}
newElement.getChildOfType()
} else {
newElement as? KtArrayAccessExpression
} ?: return
editor.caretModel.moveToOffset(arrayAccessExpression.leftBracket!!.startOffset)
arrayAccessExpression.leftBracket?.startOffset?.let { editor.caretModel.moveToOffset(it) }
}
}
@@ -5,22 +5,22 @@
package org.jetbrains.kotlin.idea.inspections.substring
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.evaluatesTo
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.intentions.toResolvedCall
import org.jetbrains.kotlin.idea.util.calleeTextRangeInThis
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
abstract class ReplaceSubstringInspection :
AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(KtDotQualifiedExpression::class.java) {
abstract class ReplaceSubstringInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
KtDotQualifiedExpression::class.java
) {
protected abstract fun isApplicableInner(element: KtDotQualifiedExpression): Boolean
protected open val isAlwaysStable: Boolean = false
@@ -30,8 +30,7 @@ abstract class ReplaceSubstringInspection :
} else
false
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression): TextRange? =
element.callExpression?.calleeExpression?.textRange?.shiftLeft(element.startOffset)
override fun inspectionHighlightRangeInElement(element: KtDotQualifiedExpression) = element.calleeTextRangeInThis()
protected fun isIndexOfCall(expression: KtExpression?, expectedReceiver: KtExpression): Boolean {
return expression is KtDotQualifiedExpression
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections.substring
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.evaluatesTo
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.lexer.KtTokens
@@ -20,10 +19,9 @@ class ReplaceSubstringWithDropLastInspection : ReplaceSubstringInspection() {
override fun inspectionText(element: KtDotQualifiedExpression): String = "Replace 'substring' call with 'dropLast' call"
override val defaultFixText: String = "Replace 'substring' call with 'dropLast' call"
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
if (element !is KtDotQualifiedExpression) return
val argument = element.callExpression!!.valueArguments[1].getArgumentExpression()!!
val rightExpression = (argument as KtBinaryExpression).right!!
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val argument = element.callExpression?.valueArguments?.elementAtOrNull(1)?.getArgumentExpression() ?: return
val rightExpression = (argument as? KtBinaryExpression)?.right ?: return
element.replaceWith("$0.dropLast($1)", rightExpression)
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections.substring
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.psi.KtConstantExpression
@@ -15,14 +14,12 @@ import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
class ReplaceSubstringWithIndexingOperationInspection :
ReplaceSubstringInspection() {
class ReplaceSubstringWithIndexingOperationInspection : ReplaceSubstringInspection() {
override fun inspectionText(element: KtDotQualifiedExpression): String = "Replace 'substring' call with indexing operation call"
override val defaultFixText: String = "Replace 'substring' call with indexing operation call"
override val isAlwaysStable: Boolean = true
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
if (element !is KtDotQualifiedExpression) return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val expression = element.callExpression?.valueArguments?.firstOrNull()?.getArgumentExpression() ?: return
element.replaceWith("$0[$1]", expression)
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections.substring
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtExpression
@@ -17,8 +16,7 @@ class ReplaceSubstringWithSubstringAfterInspection : ReplaceSubstringInspection(
override val defaultFixText: String = "Replace 'substring' call with 'substringAfter' call"
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
if (element !is KtDotQualifiedExpression) return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
element.replaceWith(
"$0.substringAfter($1)",
(element.getArgumentExpression(0) as KtDotQualifiedExpression).getArgumentExpression(0)
@@ -36,8 +34,7 @@ class ReplaceSubstringWithSubstringBeforeInspection : ReplaceSubstringInspection
override val defaultFixText: String = "Replace 'substring' call with 'substringBefore' call"
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
if (element !is KtDotQualifiedExpression) return
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
element.replaceWith(
"$0.substringBefore($1)",
(element.getArgumentExpression(1) as KtDotQualifiedExpression).getArgumentExpression(0)
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.inspections.substring
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
@@ -16,9 +15,8 @@ class ReplaceSubstringWithTakeInspection : ReplaceSubstringInspection() {
override val defaultFixText: String = "Replace 'substring' call with 'take' call"
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
if (element !is KtDotQualifiedExpression) return
val argument = element.callExpression!!.valueArguments[1].getArgumentExpression()!!
override fun applyTo(element: KtDotQualifiedExpression, project: Project, editor: Editor?) {
val argument = element.callExpression?.valueArguments?.elementAtOrNull(1)?.getArgumentExpression() ?: return
element.replaceWith("$0.take($1)", argument)
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinI
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.textRangeIn
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
@@ -317,9 +318,9 @@ internal fun KtIfExpression.shouldBeTransformed(): Boolean = when (val condition
else -> false
}
fun KtIfExpression.textRange(): TextRange {
val rightOffset = rightParenthesis?.endOffset ?: return ifKeyword.textRange
return TextRange(ifKeyword.startOffset, rightOffset)
fun KtIfExpression.fromIfKeywordToRightParenthesisTextRangeInThis(): TextRange {
val rightOffset = rightParenthesis?.endOffset ?: return ifKeyword.textRangeIn(this)
return TextRange(ifKeyword.startOffset, rightOffset).shiftLeft(startOffset)
}
private fun KtExpression.checkedExpression() = when (this) {
@@ -198,7 +198,7 @@ object J2KPostProcessingRegistrarImpl : J2KPostProcessingRegistrar {
if (!isApplicable(tElement)) return null
return {
if (isApplicable(tElement)) { // check availability of the inspection again because something could change
inspection.applyTo(inspection.inspectionTarget(tElement))
inspection.applyTo(tElement)
}
}
}
@@ -5,10 +5,14 @@
package org.jetbrains.kotlin.idea.util
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -32,4 +36,10 @@ fun KtExpression.hasNoSideEffects(): Boolean = when (this) {
is KtStringTemplateExpression -> !hasInterpolation()
is KtConstantExpression -> true
else -> ConstantExpressionEvaluator.getConstant(this, analyze(BodyResolveMode.PARTIAL)) != null
}
}
fun PsiElement.textRangeIn(other: PsiElement): TextRange = textRange.shiftLeft(other.startOffset)
fun KtDotQualifiedExpression.calleeTextRangeInThis(): TextRange? = callExpression?.calleeExpression?.textRangeIn(this)
fun KtNamedDeclaration.nameIdentifierTextRangeInThis(): TextRange? = nameIdentifier?.textRangeIn(this)
@@ -287,7 +287,7 @@ inline fun <reified TElement : PsiElement, TInspection : AbstractApplicabilityBa
if (!isApplicable(tElement)) return null
return {
if (isApplicable(tElement)) { // isApplicableTo availability of the inspection again because something could change
inspection.applyTo(inspection.inspectionTarget(tElement))
inspection.applyTo(tElement)
}
}
}