From 9f9e358083c7df5f6aa21db3037fca0889715940 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Mon, 23 Dec 2024 14:21:23 +0100 Subject: [PATCH] add redundant ref deref inspection with fix --- .../MvRedundantRefDerefInspection.kt | 49 +++++++ .../move/lang/core/psi/ext/MvParensExpr.kt | 9 ++ src/main/resources/META-INF/plugin.xml | 4 + .../MvRedundantRefDeref.html | 5 + .../MvRedundantRefDerefInspectionTest.kt | 120 ++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 src/main/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspection.kt create mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvParensExpr.kt create mode 100644 src/main/resources/inspectionDescriptions/MvRedundantRefDeref.html create mode 100644 src/test/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspectionTest.kt diff --git a/src/main/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspection.kt new file mode 100644 index 00000000..f29d8fd2 --- /dev/null +++ b/src/main/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspection.kt @@ -0,0 +1,49 @@ +package org.move.ide.inspections + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.move.lang.core.psi.MvBorrowExpr +import org.move.lang.core.psi.MvDerefExpr +import org.move.lang.core.psi.MvExpr +import org.move.lang.core.psi.MvParensExpr +import org.move.lang.core.psi.MvVisitor +import org.move.lang.core.psi.ext.unwrap + +class MvRedundantRefDerefInspection: MvLocalInspectionTool() { + override fun buildMvVisitor( + holder: ProblemsHolder, + isOnTheFly: Boolean + ): MvVisitor = object: MvVisitor() { + + override fun visitDerefExpr(o: MvDerefExpr) { + val innerExpr = o.innerExpr + if (innerExpr is MvBorrowExpr) { + if (innerExpr.expr == null) return + holder.registerProblem( + o, + "Needless pair of `*` and `&` operators: consider removing them", + ProblemHighlightType.WEAK_WARNING, + RemoveRefDerefFix(o) + ) + } + } + } + + private class RemoveRefDerefFix(element: MvDerefExpr): DiagnosticFix(element) { + + override fun getText(): String = "Remove needless `*`, `&` operators" + + override fun invoke(project: Project, file: PsiFile, element: MvDerefExpr) { + val borrowExpr = element.innerExpr as? MvBorrowExpr ?: return + val itemExpr = borrowExpr.expr ?: return + element.replace(itemExpr) + } + } +} + +private val MvDerefExpr.innerExpr: MvExpr? get() { + val expr = this.expr + return if (expr !is MvParensExpr) expr else expr.unwrap() +} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvParensExpr.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvParensExpr.kt new file mode 100644 index 00000000..f10a0dc3 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvParensExpr.kt @@ -0,0 +1,9 @@ +package org.move.lang.core.psi.ext + +import org.move.lang.core.psi.MvExpr +import org.move.lang.core.psi.MvParensExpr + +fun MvParensExpr.unwrap(): MvExpr? { + val expr = this.expr + return if (expr !is MvParensExpr) expr else expr.unwrap() +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 1dd6aa1a..be8eaf1a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -305,6 +305,10 @@ displayName="Convert to compound expr" enabledByDefault="true" level="WEAK WARNING" implementationClass="org.move.ide.inspections.compilerV2.MvReplaceWithCompoundAssignmentInspection" /> + + +

Needless pair of `*` and `&` operators

+ + \ No newline at end of file diff --git a/src/test/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspectionTest.kt new file mode 100644 index 00000000..488192e4 --- /dev/null +++ b/src/test/kotlin/org/move/ide/inspections/MvRedundantRefDerefInspectionTest.kt @@ -0,0 +1,120 @@ +package org.move.ide.inspections + +import org.intellij.lang.annotations.Language +import org.move.utils.tests.annotation.InspectionTestBase + +class MvRedundantRefDerefInspectionTest: InspectionTestBase(MvRedundantRefDerefInspection::class) { + fun `test no error`() = checkWarnings( + """ + module 0x1::m { + fun main() { + &1; + *1; + **1; + &&1; + } + } + """ + ) + + fun `test no error for deref and then borrow as it can be a copy op`() = checkWarnings( + """ + module 0x1::m { + fun main() { + &*1; + } + } + """ + ) + + fun `test error for borrow and then deref`() = checkFixByText( + """ + module 0x1::m { + fun main() { + */*caret*/&1; + } + } + """, """ + module 0x1::m { + fun main() { + 1; + } + } + """ + ) + + fun `test error for borrow and then deref with parens`() = checkFixByText( + """ + module 0x1::m { + fun main() { + */*caret*/(&1); + } + } + """, """ + module 0x1::m { + fun main() { + 1; + } + } + """ + ) + + fun `test error for mutable borrow and then deref`() = checkFixByText( + """ + module 0x1::m { + fun main() { + *&mut /*caret*/1; + } + } + """,""" + module 0x1::m { + fun main() { + 1; + } + } + """, + ) + + fun `test error for mutable borrow and then deref with parens`() = checkFixByText( + """ + module 0x1::m { + fun main() { + *(&mut /*caret*/1); + } + } + """,""" + module 0x1::m { + fun main() { + 1; + } + } + """, + ) + + fun `test error for mutable borrow and then deref with parens on item`() = checkFixByText( + """ + module 0x1::m { + fun main() { + *&mut (/*caret*/1); + } + } + """,""" + module 0x1::m { + fun main() { + (1); + } + } + """, + ) + + private fun checkFixByText( + @Language("Move") before: String, + @Language("Move") after: String, + ) = checkFixByText( + "Remove needless `*`, `&` operators", + before, + after, + checkWarn = false, + checkWeakWarn = true + ) +} \ No newline at end of file