Skip to content

Commit

Permalink
replace with compound operator inspection
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurnikov committed Oct 29, 2024
1 parent 5ab83cf commit 7aa4fbc
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.move.ide.inspections.compilerV2

import com.intellij.codeInsight.PsiEquivalenceUtil
import com.intellij.codeInspection.ProblemHighlightType.WEAK_WARNING
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.move.ide.inspections.DiagnosticFix
import org.move.lang.core.MOVE_ARITHMETIC_BINARY_OPS
import org.move.lang.core.psi.MvAssignmentExpr
import org.move.lang.core.psi.MvBinaryExpr
import org.move.lang.core.psi.ext.elementType
import org.move.lang.core.psi.ext.operator
import org.move.lang.core.psi.psiFactory

class MvReplaceWithCompoundAssignmentInspection:
Move2OnlyInspectionBase<MvAssignmentExpr>(MvAssignmentExpr::class.java) {

override fun visitTargetElement(element: MvAssignmentExpr, holder: ProblemsHolder, isOnTheFly: Boolean) {
val lhsExpr = element.expr
val initializerExpr = element.initializer.expr ?: return
if (initializerExpr is MvBinaryExpr
&& initializerExpr.operator.elementType in MOVE_ARITHMETIC_BINARY_OPS
) {
// take lhs of binary plus expr
val argumentExpr = initializerExpr.left
if (PsiEquivalenceUtil.areElementsEquivalent(lhsExpr, argumentExpr)) {
val op = initializerExpr.operator.text
holder.registerProblem(
element,
"Can be replaced with compound assignment",
WEAK_WARNING,
ReplaceWithCompoundAssignmentFix(element, op)
)
}
}
}

class ReplaceWithCompoundAssignmentFix(assignmentExpr: MvAssignmentExpr, val op: String):
DiagnosticFix<MvAssignmentExpr>(assignmentExpr) {

override fun getText(): String = "Replace with compound assignment expr"

override fun invoke(project: Project, file: PsiFile, element: MvAssignmentExpr) {
val lhsExpr = element.expr
val rhsExpr = (element.initializer.expr as? MvBinaryExpr)?.right ?: return

val psiFactory = project.psiFactory
val assignBinExpr = psiFactory.expr<MvBinaryExpr>("x $op= 1")
assignBinExpr.left.replace(lhsExpr)
assignBinExpr.right?.replace(rhsExpr)

element.replace(assignBinExpr)
}
}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/org/move/lang/core/MvTokenType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ val TYPES = tokenSetOf(PATH_TYPE, REF_TYPE, TUPLE_TYPE)

val MOVE_COMMENTS = tokenSetOf(BLOCK_COMMENT, EOL_COMMENT, EOL_DOC_COMMENT)

val MOVE_ARITHMETIC_BINARY_OPS = tokenSetOf(
PLUS, MINUS, MUL, DIV, MODULO,
AND, OR, XOR,
LT_LT, GT_GT,
)
val MOVE_BINARY_OPS = tokenSetOf(
OR_OR, AND_AND,
EQ_EQ_GT, LT_EQ_EQ_GT,
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/org/move/lang/core/psi/ext/MvBinaryExpr.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.move.lang.core.psi.ext

import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement
import org.move.lang.MvElementTypes.BINARY_OP
import org.move.lang.core.psi.MvBinaryExpr
import org.move.lang.core.psi.MvElementImpl

val MvBinaryExpr.operator: PsiElement get() = binaryOp.operator

abstract class MvBinaryExprMixin(node: ASTNode): MvElementImpl(node),
MvBinaryExpr {
override fun toString(): String {
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@
displayName="Convert to index expr"
enabledByDefault="true" level="WEAK WARNING"
implementationClass="org.move.ide.inspections.compilerV2.MvReplaceWithIndexExprInspection" />
<localInspection language="Move" groupName="Move"
displayName="Convert to compound expr"
enabledByDefault="true" level="WEAK WARNING"
implementationClass="org.move.ide.inspections.compilerV2.MvReplaceWithCompoundAssignmentInspection" />

<!-- cannot be run on-the-fly, therefore enabled -->
<globalInspection language="Move" groupName="Move"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Replaces `x = x + 1` with `x += 1`
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.move.ide.inspections.compilerV2

import org.intellij.lang.annotations.Language
import org.move.utils.tests.MoveV2
import org.move.utils.tests.annotation.InspectionTestBase

@MoveV2
class MvReplaceWithCompoundAssignmentInspectionTest:
InspectionTestBase(MvReplaceWithCompoundAssignmentInspection::class) {

fun `test replace variable assignment with plus`() = doFixTest(
"""
module 0x1::m {
fun main() {
let x = 1;
<weak_warning descr="Can be replaced with compound assignment">/*caret*/x = x + 1</weak_warning>;
}
}
""", """
module 0x1::m {
fun main() {
let x = 1;
x += 1;
}
}
"""
)

fun `test replace variable assignment with left shift`() = doFixTest(
"""
module 0x1::m {
fun main() {
let x = 1;
<weak_warning descr="Can be replaced with compound assignment">/*caret*/x = x << 1</weak_warning>;
}
}
""", """
module 0x1::m {
fun main() {
let x = 1;
x <<= 1;
}
}
"""
)

fun `test replace deref assignment with plus`() = doFixTest(
"""
module 0x1::m {
fun main(p: &u8) {
<weak_warning descr="Can be replaced with compound assignment">/*caret*/*p = *p + 1</weak_warning>;
}
}
""", """
module 0x1::m {
fun main(p: &u8) {
*p += 1;
}
}
"""
)

private fun doTest(@Language("Move") text: String) =
checkByText(text, checkWarn = false, checkWeakWarn = true)

private fun doFixTest(
@Language("Move") before: String,
@Language("Move") after: String,
) =
checkFixByText("Replace with compound assignment expr", before, after,
checkWarn = false, checkWeakWarn = true)
}

0 comments on commit 7aa4fbc

Please sign in to comment.