diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 454b769c5..281ebdfd8 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] - gradle-properties-version: [ 231, 232, 233 ] + gradle-properties-version: [ 232, 233 ] runs-on: ${{ matrix.os }} env: @@ -27,7 +27,7 @@ jobs: java-version: 17 - name: Setup Gradle and dependencies - uses: gradle/gradle-build-action@v2.7.0 + uses: gradle/actions/setup-gradle@v3.1.0 with: gradle-version: wrapper cache-read-only: false diff --git a/build.gradle.kts b/build.gradle.kts index 513c6dffc..5249b6b94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,14 +12,14 @@ fun prop(name: String): String = ?: error("Property `$name` is not defined in gradle.properties for environment `$shortPlatformVersion`") val shortPlatformVersion = prop("shortPlatformVersion") -val codeVersion = "1.34.0" +val codeVersion = "1.35.0" val pluginVersion = "$codeVersion.$shortPlatformVersion" val pluginGroup = "org.move" val javaVersion = JavaVersion.VERSION_17 val pluginJarName = "intellij-move-$pluginVersion" val kotlinReflectVersion = "1.8.10" -val aptosVersion = "2.4.0" +val aptosVersion = "3.1.0" group = pluginGroup version = pluginVersion @@ -27,8 +27,8 @@ version = pluginVersion plugins { id("java") kotlin("jvm") version "1.9.22" - id("org.jetbrains.intellij") version "1.16.1" - id("org.jetbrains.grammarkit") version "2022.3.2.1" + id("org.jetbrains.intellij") version "1.17.2" + id("org.jetbrains.grammarkit") version "2022.3.2.2" id("net.saliman.properties") version "1.5.2" id("org.gradle.idea") id("de.undercouch.download") version "5.5.0" @@ -170,13 +170,12 @@ project(":") { tasks { generateLexer { sourceFile.set(file("src/main/grammars/MoveLexer.flex")) - targetDir.set("src/main/gen/org/move/lang") - targetClass.set("_MoveLexer") + targetOutputDir.set(file("src/main/gen/org/move/lang")) purgeOldFiles.set(true) } generateParser { sourceFile.set(file("src/main/grammars/MoveParser.bnf")) - targetRoot.set("src/main/gen") + targetRootOutputDir.set(file("src/main/gen")) pathToParser.set("/org/move/lang/MoveParser.java") pathToPsiRoot.set("/org/move/lang/psi") purgeOldFiles.set(true) diff --git a/changelog/1.35.0.md b/changelog/1.35.0.md new file mode 100644 index 000000000..faf615091 --- /dev/null +++ b/changelog/1.35.0.md @@ -0,0 +1,17 @@ +# INTELLIJ MOVE CHANGELOG: 1.35.0 + +24 Mar 2024 + +## Features + +* Add support for the nested attributes (Sui lints). + +## Fixes + +* Fix issue with saving Aptos-Cli path in Settings. +* Fix Run / View function Run Configuration dialog. + +## Internal + +* Update bundled Aptos-Cli to 3.1.0. +* Drop 2023.1 support. diff --git a/gradle-231.properties b/gradle-231.properties deleted file mode 100644 index 6648da29d..000000000 --- a/gradle-231.properties +++ /dev/null @@ -1,13 +0,0 @@ -# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html -# for insight into build numbers and IntelliJ Platform versions. -pluginSinceBuild = 231 -pluginUntilBuild = 231.* - -# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties -platformType = PC -platformVersion = 2023.1 - -# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html -# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 -platformPlugins = org.toml.lang -verifierIdeVersions = PC-2023.1 diff --git a/gradle.properties b/gradle.properties index 9318dcecf..1e6ab00fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,4 @@ propertiesPluginEnvironmentNameProperty=shortPlatformVersion # properties files # supported versions are 231, 232, 233, default is 231 # pass ORG_GRADLE_PROJECT_shortPlatformVersion environment variable to overwrite -shortPlatformVersion=233 +shortPlatformVersion=232 diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 592b14299..38890bd6d 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -153,19 +153,21 @@ File ::= (NamedAddressDef | Script | AddressDef | Module | ModuleSpec)* QualPathCodeFragmentElement ::= FQModulePathIdent? TypeArgumentList? Attr ::= '#' '[' <> ']' { pin = 1 } -AttrItem ::= IDENTIFIER (AttrItemArguments | AttrItemInitializer)? -{ - implements = [ "org.move.lang.core.psi.MvNamedElement" ] - mixin = "org.move.lang.core.psi.ext.MvAttrItemMixin" -} -AttrItemArguments ::= '(' <>? ')' { pin = 1 } -AttrItemArgument ::= IDENTIFIER ('=' Expr)? +AttrItem ::= IDENTIFIER (AttrItemList | AttrItemInitializer)? { implements = [ "org.move.lang.core.resolve.ref.MvReferenceElement" ] - mixin = "org.move.lang.core.psi.ext.MvAttrItemArgumentMixin" + mixin = "org.move.lang.core.psi.ext.MvAttrItemMixin" } +AttrItemList ::= '(' <>? ')' { pin = 1 } +//AttrItemArgument ::= IDENTIFIER ('=' Expr)? +//{ +// implements = [ +// "org.move.lang.core.resolve.ref.MvReferenceElement" +// ] +// mixin = "org.move.lang.core.psi.ext.MvAttrItemArgumentMixin" +//} AttrItemInitializer ::= '=' Expr { pin = 1 } NamedAddressDef ::= address IDENTIFIER '=' AddressRef ';' { pin = 3 } diff --git a/src/main/kotlin/org/move/cli/MoveProjectTaskQueueService.kt b/src/main/kotlin/org/move/cli/MoveProjectTaskQueueService.kt index 81c4cd7ab..4bc6f3391 100644 --- a/src/main/kotlin/org/move/cli/MoveProjectTaskQueueService.kt +++ b/src/main/kotlin/org/move/cli/MoveProjectTaskQueueService.kt @@ -7,7 +7,7 @@ import com.intellij.openapi.progress.Task import com.intellij.openapi.project.Project import org.move.utils.MvBackgroundTaskQueue -@Service +@Service(Service.Level.PROJECT) class MvProjectTaskQueueService(val project: Project): Disposable { private val queue = MvBackgroundTaskQueue() diff --git a/src/main/kotlin/org/move/cli/MoveProjectsService.kt b/src/main/kotlin/org/move/cli/MoveProjectsService.kt index 36e473a52..444de64df 100644 --- a/src/main/kotlin/org/move/cli/MoveProjectsService.kt +++ b/src/main/kotlin/org/move/cli/MoveProjectsService.kt @@ -84,7 +84,7 @@ class MoveProjectsService(val project: Project): Disposable { } // requires ReadAccess - fun findMoveProject(psiElement: PsiElement): MoveProject? { + fun findMoveProjectForPsiElement(psiElement: PsiElement): MoveProject? { // read access required for the psiElement.containingFile checkReadAccessAllowed() val file = when (psiElement) { @@ -115,7 +115,7 @@ class MoveProjectsService(val project: Project): Disposable { return findMoveProjectForFile(file) } - fun findMoveProject(path: Path): MoveProject? { + fun findMoveProjectForPath(path: Path): MoveProject? { val file = path.toVirtualFile() ?: return null return findMoveProjectForFile(file) } diff --git a/src/main/kotlin/org/move/cli/manifest/AptosConfigYaml.kt b/src/main/kotlin/org/move/cli/manifest/AptosConfigYaml.kt index 6e2bb77a1..eb08da40b 100644 --- a/src/main/kotlin/org/move/cli/manifest/AptosConfigYaml.kt +++ b/src/main/kotlin/org/move/cli/manifest/AptosConfigYaml.kt @@ -1,6 +1,6 @@ package org.move.cli.manifest -import com.intellij.util.io.readText +import kotlin.io.path.readText import org.yaml.snakeyaml.Yaml import org.yaml.snakeyaml.error.YAMLException import java.nio.file.Path diff --git a/src/main/kotlin/org/move/cli/projectAware/MoveSettingsFilesService.kt b/src/main/kotlin/org/move/cli/projectAware/MoveSettingsFilesService.kt index 18e4f57c4..82bdb506c 100644 --- a/src/main/kotlin/org/move/cli/projectAware/MoveSettingsFilesService.kt +++ b/src/main/kotlin/org/move/cli/projectAware/MoveSettingsFilesService.kt @@ -6,7 +6,7 @@ import com.intellij.openapi.project.Project import org.move.cli.Consts import org.move.cli.moveProjectsService -@Service +@Service(Service.Level.PROJECT) class MoveSettingsFilesService(private val project: Project) { fun collectSettingsFiles(): List { val out = mutableListOf() diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/CommandConfigurationHandler.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/CommandConfigurationHandler.kt index 3b8baf9f2..7142ac000 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/CommandConfigurationHandler.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/CommandConfigurationHandler.kt @@ -48,7 +48,7 @@ abstract class CommandConfigurationHandler { abstract fun getFunctionCompletionVariants(moveProject: MoveProject): Collection - abstract fun getFunction(moveProject: MoveProject, functionQualName: String): MvFunction? + abstract fun getFunctionItem(moveProject: MoveProject, functionQualName: String): MvFunction? abstract fun getFunctionByCmdName(moveProject: MoveProject, functionCmdName: String): MvFunction? @@ -56,8 +56,8 @@ abstract class CommandConfigurationHandler { fun generateCommand( moveProject: MoveProject, - profileName: String, - functionCall: FunctionCall + functionCall: FunctionCall, + signerAccount: String?, ): RsResult { val functionId = functionCall.functionId(moveProject) ?: return RsResult.Err("FunctionId is null") @@ -68,12 +68,13 @@ abstract class CommandConfigurationHandler { val commandArguments = listOf( subCommand.split(' '), - listOf("--profile", profileName), + listOf("--profile", signerAccount), listOf("--function-id", functionId), typeParams, params ).flatten() - return RsResult.Ok(commandArguments.joinToString(" ")) + val command = commandArguments.joinToString(" ") + return RsResult.Ok(command) } fun parseCommand( @@ -91,14 +92,14 @@ abstract class CommandConfigurationHandler { val function = getFunctionByCmdName(moveProject, functionId) ?: return RsResult.Err("function with this functionId does not exist in the current project") - val aptosConfig = moveProject.aptosConfigYaml - if (aptosConfig == null) { - return RsResult.Err("Aptos account is not initialized / is invalid for the current project") - } - - if (profileName !in aptosConfig.profiles) { - return RsResult.Err("account '$profileName' is not present in the project's accounts") - } +// val aptosConfig = moveProject.aptosConfigYaml +// if (aptosConfig == null) { +// return RsResult.Err("Aptos account is not initialized / is invalid for the current project") +// } +// +// if (profileName !in aptosConfig.profiles) { +// return RsResult.Err("account '$profileName' is not present in the project's accounts") +// } val transaction = FunctionCall.template(function) val typeParameterNames = function.typeParameters.mapNotNull { it.name } diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationBase.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationBase.kt index be7ca1399..54796a53c 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationBase.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationBase.kt @@ -14,8 +14,8 @@ abstract class FunctionCallConfigurationBase( val configurationHandler: CommandConfigurationHandler, ): CommandConfigurationBase(project, factory) { - var moveProject: MoveProject? - get() = workingDirectory?.let { project.moveProjectsService.findMoveProject(it) } + var moveProjectFromWorkingDirectory: MoveProject? + get() = workingDirectory?.let { wdir -> project.moveProjectsService.findMoveProjectForPath(wdir) } set(value) { workingDirectory = value?.contentRootPath } @@ -23,9 +23,9 @@ abstract class FunctionCallConfigurationBase( override fun getCliPath(project: Project): Path? = project.aptosPath fun firstRunShouldOpenEditor(): Boolean { - val moveProject = moveProject ?: return true - val functionCall = configurationHandler - .parseCommand(moveProject, command).unwrapOrNull()?.second ?: return true + val moveProject = moveProjectFromWorkingDirectory ?: return true + val (_, functionCall) = configurationHandler + .parseCommand(moveProject, command).unwrapOrNull() ?: return true return functionCall.parametersRequired() } } diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationEditor.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationEditor.kt index ad22f82aa..8e8e91f0e 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationEditor.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallConfigurationEditor.kt @@ -9,12 +9,15 @@ import com.intellij.openapi.ui.MessageType import com.intellij.openapi.util.Disposer import com.intellij.ui.JBColor import com.intellij.ui.dsl.builder.* +import com.intellij.xdebugger.impl.ui.TextViewer import org.move.cli.MoveProject import org.move.cli.moveProjectsService import org.move.stdext.RsResult import org.move.utils.ui.whenItemSelectedFromUi +import org.move.utils.ui.whenTextChangedFromUi import javax.swing.JComponent import javax.swing.JLabel +import javax.swing.JTextField data class MoveProjectItem(val moveProject: MoveProject) { override fun toString(): String { @@ -23,7 +26,7 @@ data class MoveProjectItem(val moveProject: MoveProject) { } class FunctionCallConfigurationEditor( - private val handler: CommandConfigurationHandler, + private val commandHandler: CommandConfigurationHandler, private var moveProject: MoveProject, ) : SettingsEditor() { @@ -34,9 +37,10 @@ class FunctionCallConfigurationEditor( private var functionCall: FunctionCall? = null private val projectComboBox: ComboBox = ComboBox() - private val accountComboBox: ComboBox = ComboBox() + private val accountTextField = JTextField() + private val rawCommandField = TextViewer("", project, true) - private val functionCallPanel = FunctionCallPanel(handler, moveProject) + private val functionParametersPanel = FunctionParametersPanel(commandHandler, moveProject) private val errorLabel = JLabel("") @@ -51,19 +55,19 @@ class FunctionCallConfigurationEditor( projectComboBox.isEnabled = projectComboBox.model.size > 1 projectComboBox.selectedItem = MoveProjectItem(moveProject) - fillAccountsComboBox() - val editor = this - functionCallPanel.addFunctionCallListener(object : FunctionCallPanel.FunctionCallListener { - override fun functionCallChanged(functionCall: FunctionCall) { + functionParametersPanel.addFunctionCallListener(object : FunctionParameterPanelListener { + override fun functionParametersChanged(functionCall: FunctionCall) { editor.functionCall = functionCall + editor.rawCommandField.text = + commandHandler.generateCommand(moveProject, functionCall, signerAccount).unwrapOrNull() ?: "" } }) - functionCallPanel.reset(moveProject) + functionParametersPanel.setMoveProjectAndCompletionVariants(moveProject) } override fun resetEditorFrom(s: T) { - val moveProject = s.workingDirectory?.let { project.moveProjectsService.findMoveProject(it) } + val moveProject = s.workingDirectory?.let { project.moveProjectsService.findMoveProjectForPath(it) } if (moveProject == null) { setErrorText("Deserialization error: no Aptos project found in the specified working directory") editorPanel.isVisible = false @@ -71,9 +75,8 @@ class FunctionCallConfigurationEditor( this.functionCall = null return } - fillAccountsComboBox() - val res = handler.parseCommand(moveProject, s.command) + val res = commandHandler.parseCommand(moveProject, s.command) val (profile, functionCall) = when (res) { is RsResult.Ok -> res.ok is RsResult.Err -> { @@ -85,27 +88,19 @@ class FunctionCallConfigurationEditor( } } this.signerAccount = profile - this.accountComboBox.selectedItem = profile + this.accountTextField.text = profile - functionCallPanel.updateFromFunctionCall(functionCall) + functionParametersPanel.updateFromFunctionCall(functionCall) } override fun applyEditorTo(s: T) { - val moveProject = moveProject - val profile = signerAccount - val functionCall = functionCall - - s.moveProject = moveProject - if (profile != null && functionCall != null) { - s.command = - handler.generateCommand(moveProject, profile, functionCall).unwrapOrNull() ?: "" - } else { - s.command = "" - } + functionParametersPanel.fireChangeEvent() + s.command = rawCommandField.text + s.moveProjectFromWorkingDirectory = moveProject } override fun disposeEditor() { - Disposer.dispose(functionCallPanel) + Disposer.dispose(functionParametersPanel) } override fun createEditor(): JComponent { @@ -115,8 +110,6 @@ class FunctionCallConfigurationEditor( row { cell(editorPanel) .align(AlignX.FILL + AlignY.FILL) -// .verticalAlign(VerticalAlign.FILL) -// .horizontalAlign(HorizontalAlign.FILL) } } return DumbService.getInstance(project).wrapGently(outerPanel, this) @@ -128,43 +121,34 @@ class FunctionCallConfigurationEditor( row("Project") { cell(projectComboBox) .align(AlignX.FILL) -// .horizontalAlign(HorizontalAlign.FILL) .columns(COLUMNS_LARGE) .whenItemSelectedFromUi { moveProject = it.moveProject - fillAccountsComboBox() - functionCallPanel.reset(moveProject) + functionParametersPanel.setMoveProjectAndCompletionVariants(moveProject) } } row("Account") { - cell(accountComboBox) + cell(accountTextField) .align(AlignX.FILL) -// .horizontalAlign(HorizontalAlign.FILL) - .whenItemSelectedFromUi { + .whenTextChangedFromUi { signerAccount = it } } separator() row { - cell(functionCallPanel) + cell(functionParametersPanel) .align(AlignX.FILL + AlignY.FILL) -// .verticalAlign(VerticalAlign.FILL) -// .horizontalAlign(HorizontalAlign.FILL) + } + separator() + row("Raw") { + cell(rawCommandField) + .align(AlignX.FILL) } } editorPanel.registerValidators(this) return editorPanel } - fun fillAccountsComboBox() { - accountComboBox.removeAllItems() - val accounts = moveProject.aptosConfigYaml?.profiles.orEmpty() - accounts.forEach { accountName -> - accountComboBox.addItem(accountName) - } - accountComboBox.isEnabled = accountComboBox.model.size > 1 - } - // private fun validateEditor() { // val functionCall = this.functionCall // if (functionCall == null) { diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallPanel.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionParametersPanel.kt similarity index 69% rename from src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallPanel.kt rename to src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionParametersPanel.kt index 9ed45caa2..02d0a1650 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionCallPanel.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/FunctionParametersPanel.kt @@ -21,7 +21,7 @@ import javax.swing.JButton import javax.swing.JPanel typealias TypeParamsMap = MutableMap -typealias ValueParamsMap = MutableMap +//typealias ValueParamsMap = MutableMap class TypeParameterTextField( project: Project, @@ -48,18 +48,29 @@ class TypeParameterTextField( } } -class FunctionCallPanel( - val handler: CommandConfigurationHandler, +interface FunctionParameterPanelListener { + fun functionParametersChanged(functionCall: FunctionCall) +} + +/** + * Panel that covers UI elements of transaction run / view Run Configurations + * Consists of: + * - function name (with completion variants) + * - type parameters + * - parameters + */ +class FunctionParametersPanel( + val commandHandler: CommandConfigurationHandler, var moveProject: MoveProject, ) : BorderLayoutPanel(), Disposable { - private lateinit var item: MvFunction + private lateinit var functionItem: MvFunction private lateinit var typeParams: TypeParamsMap private lateinit var valueParams: MutableMap - private val functionCompletionField = CompletionTextField(project, "", emptyList()) - private val functionApplyButton = JButton("Apply") + private val functionItemField = CompletionTextField(project, "", emptyList()) + private val functionApplyButton = JButton("Select and refresh UI") private val functionValidator: ComponentValidator @@ -68,63 +79,68 @@ class FunctionCallPanel( init { val panel = this - functionCompletionField.addDocumentListener(object : DocumentListener { + // enables Apply button if function name is changed and valid + functionItemField.addDocumentListener(object : DocumentListener { override fun documentChanged(event: DocumentEvent) { - val oldFunctionName = panel.item.qualName?.editorText() + val oldFunctionName = panel.functionItem.qualName?.editorText() val newFunctionName = event.document.text functionApplyButton.isEnabled = newFunctionName != oldFunctionName - && handler.getFunction(moveProject, newFunctionName) != null + && commandHandler.getFunctionItem(moveProject, newFunctionName) != null } }) + + // update type parameters form and value parameters form on "Apply" button click functionApplyButton.addActionListener { - val itemName = functionCompletionField.text - val function = handler.getFunction(moveProject, itemName) + val itemName = functionItemField.text + val functionItem = commandHandler.getFunctionItem(moveProject, itemName) ?: error("Button should be disabled if function name is invalid") - val functionCall = function.instantiateCall() + val functionCall = functionItem.newFunctionCall() this.updateFromFunctionCall(functionCall) fireChangeEvent() } - functionValidator = ComponentValidator(panel) + // validates + this.functionValidator = ComponentValidator(panel) .withValidator(Supplier { - val text = functionCompletionField.text - if (text.isBlank()) return@Supplier ValidationInfo("Required", functionCompletionField) - val function = handler.getFunction(moveProject, text) - if (function == null) { - return@Supplier ValidationInfo("Invalid entry function", functionCompletionField) + val text = functionItemField.text + if (text.isBlank()) return@Supplier ValidationInfo("Required", functionItemField) + val functionItem = commandHandler.getFunctionItem(moveProject, text) + if (functionItem == null) { + return@Supplier ValidationInfo("Invalid entry function", functionItemField) } null }) - .andRegisterOnDocumentListener(functionCompletionField) - .installOn(functionCompletionField) + .andRegisterOnDocumentListener(functionItemField) + .installOn(functionItemField) } override fun dispose() { } fun updateFromFunctionCall(functionCall: FunctionCall) { - this.item = functionCall.item + this.functionItem = functionCall.item this.typeParams = functionCall.typeParams this.valueParams = functionCall.valueParams - this.functionCompletionField.text = functionCall.itemName() ?: "" - val completionVariants = handler.getFunctionCompletionVariants(moveProject) - this.functionCompletionField.setVariants(completionVariants) + this.functionItemField.text = functionCall.itemName() ?: "" + + val completionVariants = commandHandler.getFunctionCompletionVariants(moveProject) + this.functionItemField.setVariants(completionVariants) recreateInnerPanel() functionValidator.revalidate() } - fun reset(moveProject: MoveProject) { + fun setMoveProjectAndCompletionVariants(moveProject: MoveProject) { this.moveProject = moveProject - val variants = handler.getFunctionCompletionVariants(moveProject) - this.item = variants.firstOrNull() - ?.let { handler.getFunction(this.moveProject, it) } + val variants = commandHandler.getFunctionCompletionVariants(moveProject) + this.functionItem = variants.firstOrNull() + ?.let { commandHandler.getFunctionItem(this.moveProject, it) } ?: error("Should always have one valid function") - val functionCall = this.item.instantiateCall() + val functionCall = this.functionItem.newFunctionCall() updateFromFunctionCall(functionCall) } @@ -134,32 +150,28 @@ class FunctionCallPanel( validate() } - interface FunctionCallListener { - fun functionCallChanged(functionCall: FunctionCall) - } - - private val eventListeners = mutableListOf() + private val eventListeners = mutableListOf() - fun addFunctionCallListener(listener: FunctionCallListener) { + fun addFunctionCallListener(listener: FunctionParameterPanelListener) { eventListeners.add(listener) } - private fun fireChangeEvent() { - val functionCall = FunctionCall(this.item, this.typeParams, this.valueParams) + fun fireChangeEvent() { + val functionCall = FunctionCall(this.functionItem, this.typeParams, this.valueParams) eventListeners.forEach { - it.functionCallChanged(functionCall) + it.functionParametersChanged(functionCall) } } private fun getInnerPanel(): JPanel { - val function = this.item + val function = this.functionItem val outerPanel = this return panel { val typeParameters = function.typeParameters - val parameters = handler.getFunctionParameters(function).map { it.bindingPat } + val parameters = commandHandler.getFunctionParameters(function).map { it.bindingPat } row("Function") { - cell(functionCompletionField) + cell(functionItemField) .align(AlignX.FILL) // .horizontalAlign(HorizontalAlign.FILL) .resizableColumn() @@ -224,4 +236,4 @@ class FunctionCallPanel( } } -fun MvFunction.instantiateCall(): FunctionCall = FunctionCall.template(this) +fun MvFunction.newFunctionCall(): FunctionCall = FunctionCall.template(this) diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/run/RunCommandConfigurationHandler.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/run/RunCommandConfigurationHandler.kt index 29153e3bd..66a97b635 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/run/RunCommandConfigurationHandler.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/run/RunCommandConfigurationHandler.kt @@ -17,7 +17,7 @@ class RunCommandConfigurationHandler : CommandConfigurationHandler() { override fun functionPredicate(function: MvFunction): Boolean = function.isEntry && !function.hasTestAttr - override fun getFunction(moveProject: MoveProject, functionQualName: String): MvFunction? { + override fun getFunctionItem(moveProject: MoveProject, functionQualName: String): MvFunction? { return getEntryFunction(moveProject, functionQualName) } diff --git a/src/main/kotlin/org/move/cli/runConfigurations/aptos/view/ViewCommandConfigurationHandler.kt b/src/main/kotlin/org/move/cli/runConfigurations/aptos/view/ViewCommandConfigurationHandler.kt index 2c6a8224d..185e40a94 100644 --- a/src/main/kotlin/org/move/cli/runConfigurations/aptos/view/ViewCommandConfigurationHandler.kt +++ b/src/main/kotlin/org/move/cli/runConfigurations/aptos/view/ViewCommandConfigurationHandler.kt @@ -17,7 +17,7 @@ class ViewCommandConfigurationHandler : CommandConfigurationHandler() { override fun functionPredicate(function: MvFunction): Boolean = function.isView && !function.hasTestAttr - override fun getFunction(moveProject: MoveProject, functionQualName: String): MvFunction? { + override fun getFunctionItem(moveProject: MoveProject, functionQualName: String): MvFunction? { return getViewFunction(moveProject, functionQualName) } diff --git a/src/main/kotlin/org/move/cli/settings/PerProjectMoveConfigurable.kt b/src/main/kotlin/org/move/cli/settings/PerProjectMoveConfigurable.kt index c36e14566..9e524039f 100644 --- a/src/main/kotlin/org/move/cli/settings/PerProjectMoveConfigurable.kt +++ b/src/main/kotlin/org/move/cli/settings/PerProjectMoveConfigurable.kt @@ -20,7 +20,7 @@ class PerProjectMoveConfigurable(val project: Project): private val settingsState: MoveProjectSettingsService.State = project.moveSettings.state - private val chooseAptosCliPanel = ChooseAptosCliPanel() + private val chooseAptosCliPanel = ChooseAptosCliPanel(versionUpdateListener = null) private val chooseSuiCliPanel = ChooseSuiCliPanel() override fun createPanel(): DialogPanel { @@ -85,7 +85,6 @@ class PerProjectMoveConfigurable(val project: Project): } // .visible(true) .align(AlignX.RIGHT) - // .horizontalAlign(HorizontalAlign.RIGHT) } } } @@ -121,8 +120,9 @@ class PerProjectMoveConfigurable(val project: Project): // calls apply() for createPanel().value super.apply() project.moveSettings.state = - settingsState.copy(aptosPath = chooseAptosCliPanel.selectedAptosExec.pathToSettingsFormat()) - project.moveSettings.state = - settingsState.copy(suiPath = chooseSuiCliPanel.getSuiCliPath()) + settingsState.copy( + aptosPath = chooseAptosCliPanel.selectedAptosExec.pathToSettingsFormat(), + suiPath = chooseSuiCliPanel.getSuiCliPath() + ) } } diff --git a/src/main/kotlin/org/move/cli/settings/VersionLabel.kt b/src/main/kotlin/org/move/cli/settings/VersionLabel.kt index caa9bdbbd..a55f8e7e3 100644 --- a/src/main/kotlin/org/move/cli/settings/VersionLabel.kt +++ b/src/main/kotlin/org/move/cli/settings/VersionLabel.kt @@ -18,7 +18,7 @@ class VersionLabel( private val versionUpdateDebouncer = UiDebouncer(parentDisposable) - fun updateValueWithListener(execPath: Path) { + fun updateAndNotifyListeners(execPath: Path) { versionUpdateDebouncer.update( onPooledThread = { if (!isUnitTestMode) { diff --git a/src/main/kotlin/org/move/cli/settings/aptos/ChooseAptosCliPanel.kt b/src/main/kotlin/org/move/cli/settings/aptos/ChooseAptosCliPanel.kt index 85c362e7e..26f6ee9f3 100644 --- a/src/main/kotlin/org/move/cli/settings/aptos/ChooseAptosCliPanel.kt +++ b/src/main/kotlin/org/move/cli/settings/aptos/ChooseAptosCliPanel.kt @@ -8,9 +8,7 @@ import org.move.cli.settings.VersionLabel import org.move.openapiext.pathField import org.move.stdext.toPathOrNull -class ChooseAptosCliPanel( - private val versionUpdateListener: (() -> Unit)? = null -): Disposable { +class ChooseAptosCliPanel(versionUpdateListener: (() -> Unit)?): Disposable { private val localPathField = pathField( @@ -20,7 +18,7 @@ class ChooseAptosCliPanel( onTextChanged = { text -> val exec = AptosExec.LocalPath(text) _aptosExec = exec - exec.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + exec.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } }) private val versionLabel = VersionLabel(this, versionUpdateListener) @@ -36,7 +34,7 @@ class ChooseAptosCliPanel( else -> localPathField.text = aptosExec.execPath } - aptosExec.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + aptosExec.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } } fun attachToLayout(layout: Panel): Row { @@ -49,11 +47,21 @@ class ChooseAptosCliPanel( buttonsGroup { row { radioButton("Bundled", AptosExec.Bundled) - .actionListener { _, _ -> - _aptosExec = AptosExec.Bundled - AptosExec.Bundled.toPathOrNull() - ?.let { versionLabel.updateValueWithListener(it) } - } + .bindSelected( + { _aptosExec is AptosExec.Bundled }, + { + _aptosExec = AptosExec.Bundled + val bundledPath = AptosExec.Bundled.toPathOrNull() + if (bundledPath != null) { + versionLabel.updateAndNotifyListeners(bundledPath) + } + } + ) +// .actionListener { _, _ -> +// _aptosExec = AptosExec.Bundled +// AptosExec.Bundled.toPathOrNull() +// ?.let { versionLabel.updateValueWithListener(it) } +// } .enabled(AptosExec.isBundledSupportedForThePlatform()) comment( "Bundled version is not available for this platform (refer to the official Aptos docs for more)" @@ -62,11 +70,21 @@ class ChooseAptosCliPanel( } row { val button = radioButton("Local", AptosExec.LocalPath("")) - .actionListener { _, _ -> - _aptosExec = AptosExec.LocalPath(localPathField.text) - localPathField.text.toPathOrNull() - ?.let { versionLabel.updateValueWithListener(it) } - } + .bindSelected( + { _aptosExec is AptosExec.LocalPath }, + { + _aptosExec = AptosExec.LocalPath(localPathField.text) + val localPath = localPathField.text.toPathOrNull() + if (localPath != null) { + versionLabel.updateAndNotifyListeners(localPath) + } + } + ) +// .actionListener { _, _ -> +// _aptosExec = AptosExec.LocalPath(localPathField.text) +// localPathField.text.toPathOrNull() +// ?.let { versionLabel.updateAndNotifyListeners(it) } +// } cell(localPathField) .enabledIf(button.selected) .align(AlignX.FILL).resizableColumn() @@ -85,7 +103,7 @@ class ChooseAptosCliPanel( ) } } - _aptosExec.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + _aptosExec.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } return resultRow } diff --git a/src/main/kotlin/org/move/cli/settings/sui/ChooseSuiCliPanel.kt b/src/main/kotlin/org/move/cli/settings/sui/ChooseSuiCliPanel.kt index c61b5abbd..250254c81 100644 --- a/src/main/kotlin/org/move/cli/settings/sui/ChooseSuiCliPanel.kt +++ b/src/main/kotlin/org/move/cli/settings/sui/ChooseSuiCliPanel.kt @@ -21,7 +21,7 @@ class ChooseSuiCliPanel( "Choose Sui CLI", onTextChanged = { text -> _suiCliPath = text - _suiCliPath.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + _suiCliPath.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } }) private val versionLabel = VersionLabel(this, versionUpdateListener) @@ -31,7 +31,7 @@ class ChooseSuiCliPanel( fun setSuiCliPath(path: String) { this._suiCliPath = path localPathField.text = path - path.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + path.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } } fun attachToLayout(layout: Panel): Row { @@ -50,14 +50,14 @@ class ChooseSuiCliPanel( { _suiCliPath = it } ) .onChanged { - localPathField.text.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + localPathField.text.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } } .align(AlignX.FILL).resizableColumn() } row("--version :") { cell(versionLabel) } } } - _suiCliPath.toPathOrNull()?.let { versionLabel.updateValueWithListener(it) } + _suiCliPath.toPathOrNull()?.let { versionLabel.updateAndNotifyListeners(it) } return resultRow } diff --git a/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt b/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt index dbe606c8e..928bf241a 100644 --- a/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt +++ b/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt @@ -55,7 +55,7 @@ class MoveFmtBlock( isLeaf && childType !in setOf(R_PAREN, R_BRACE) -> noneWrap parentType == FUNCTION_PARAMETER_LIST -> chopListWrap parentType == VALUE_ARGUMENT_LIST -> chopListWrap - parentType == ATTR_ITEM_ARGUMENTS -> chopListWrap + parentType == ATTR_ITEM_LIST -> chopListWrap parentType == USE_ITEM_GROUP -> chopListWrap else -> null } diff --git a/src/main/kotlin/org/move/ide/formatter/impl/utils.kt b/src/main/kotlin/org/move/ide/formatter/impl/utils.kt index 2312821ad..34a936afc 100644 --- a/src/main/kotlin/org/move/ide/formatter/impl/utils.kt +++ b/src/main/kotlin/org/move/ide/formatter/impl/utils.kt @@ -21,7 +21,7 @@ val ONE_LINE_ITEMS = ts(USE_STMT, CONST) val PAREN_DELIMITED_BLOCKS = ts( PARENS_EXPR, TUPLE_PAT, TUPLE_TYPE, TUPLE_LIT_EXPR, CONDITION, - FUNCTION_PARAMETER_LIST, VALUE_ARGUMENT_LIST, ATTR_ITEM_ARGUMENTS + FUNCTION_PARAMETER_LIST, VALUE_ARGUMENT_LIST, ATTR_ITEM_LIST ) val ANGLE_DELIMITED_BLOCKS = ts(TYPE_PARAMETER_LIST, TYPE_ARGUMENT_LIST) val BRACKET_DELIMITED_BLOCKS = ts(VECTOR_LIT_ITEMS) diff --git a/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt b/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt index 810b9b6ef..71100a487 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt @@ -44,7 +44,7 @@ abstract class MvLocalInspectionTool : LocalInspectionTool() { private fun isApplicableTo(file: MoveFile): Boolean { if (isUnitTestMode) return true if (isSyntaxOnly) return true - return file.project.moveProjectsService.findMoveProject(file) != null + return file.project.moveProjectsService.findMoveProjectForPsiElement(file) != null } } diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnusedVariableInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnusedVariableInspection.kt index b8f6406f6..001a2908e 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnusedVariableInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnusedVariableInspection.kt @@ -35,7 +35,7 @@ class MvUnusedVariableInspection : MvLocalInspectionTool() { val references = binding.searchReferences() // filter out #[test] attributes - .filter { it.element !is MvAttrItemArgument } + .filter { it.element !is MvAttrItem } if (references.none()) { val fixes = when (binding.owner) { is MvFunctionParameter -> arrayOf( diff --git a/src/main/kotlin/org/move/ide/inspections/UnusedTestSignerInspection.kt b/src/main/kotlin/org/move/ide/inspections/UnusedTestSignerInspection.kt index 954b8ee3c..b8849842a 100644 --- a/src/main/kotlin/org/move/ide/inspections/UnusedTestSignerInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/UnusedTestSignerInspection.kt @@ -3,25 +3,30 @@ package org.move.ide.inspections import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import org.move.ide.inspections.fixes.RemoveTestSignerFix +import org.move.lang.core.psi.MvAttr import org.move.lang.core.psi.MvAttrItem -import org.move.lang.core.psi.MvAttrItemArgument import org.move.lang.core.psi.MvVisitor -import org.move.lang.core.psi.ext.ancestorStrict -class UnusedTestSignerInspection : MvLocalInspectionTool() { +class UnusedTestSignerInspection: MvLocalInspectionTool() { override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): MvVisitor = - object : MvVisitor() { - override fun visitAttrItemArgument(itemArgument: MvAttrItemArgument) { - val attr = itemArgument.ancestorStrict() ?: return - if (attr.name != "test") return - val attrName = itemArgument.referenceName ?: return - if (!itemArgument.resolvable) { - holder.registerProblem( - itemArgument, - "Unused test signer", - ProblemHighlightType.LIKE_UNUSED_SYMBOL, - RemoveTestSignerFix(itemArgument, attrName) - ) + object: MvVisitor() { + override fun visitAttrItem(attrItem: MvAttrItem) { + // stop if not a top-level item + if (attrItem.parent !is MvAttr) return + // stop if not a #[test] + if (attrItem.referenceName != "test") return + + val innerAttrItems = attrItem.attrItemList?.attrItemList.orEmpty() + for (innerAttrItem in innerAttrItems) { + val refName = innerAttrItem.referenceName ?: continue + if (innerAttrItem.unresolved) { + holder.registerProblem( + innerAttrItem, + "Unused test signer", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + RemoveTestSignerFix(innerAttrItem, refName) + ) + } } } } diff --git a/src/main/kotlin/org/move/ide/inspections/fixes/RemoveParameterFix.kt b/src/main/kotlin/org/move/ide/inspections/fixes/RemoveParameterFix.kt index 89a8bc7e6..f5d40849a 100644 --- a/src/main/kotlin/org/move/ide/inspections/fixes/RemoveParameterFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/fixes/RemoveParameterFix.kt @@ -48,16 +48,16 @@ private fun removeArguments(function: MvFunction, parameterIndex: Int) { } } -private fun removeTestSignerAssignment(function: MvFunction, parameterName: String) { +private fun removeTestSignerAssignment(function: MvFunction, signerParameterName: String) { val testAttrItem = function.testAttrItem if (testAttrItem != null) { - val attrArguments = testAttrItem.attrItemArguments - if (attrArguments != null) { + val attrItemList = testAttrItem.attrItemList + if (attrItemList != null) { val signerAssigment = - attrArguments.attrItemArgumentList.find { it.identifier.text == parameterName } + attrItemList.attrItemList.find { it.identifier.text == signerParameterName } signerAssigment?.deleteWithSurroundingCommaAndWhitespace() - if (attrArguments.attrItemArgumentList.isEmpty()) { - attrArguments.delete() + if (attrItemList.attrItemList.isEmpty()) { + attrItemList.delete() } } } diff --git a/src/main/kotlin/org/move/ide/inspections/fixes/RemoveTestSignerFix.kt b/src/main/kotlin/org/move/ide/inspections/fixes/RemoveTestSignerFix.kt index 29c7e4d46..0c0d89b8c 100644 --- a/src/main/kotlin/org/move/ide/inspections/fixes/RemoveTestSignerFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/fixes/RemoveTestSignerFix.kt @@ -4,36 +4,36 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import org.move.ide.inspections.DiagnosticFix import org.move.lang.MvElementTypes -import org.move.lang.core.psi.MvAttrItemArgument -import org.move.lang.core.psi.MvAttrItemArguments +import org.move.lang.core.psi.MvAttrItem +import org.move.lang.core.psi.MvAttrItemList import org.move.lang.core.psi.ext.elementType import org.move.lang.core.psi.ext.getNextNonCommentSibling import org.move.lang.core.psi.ext.getPrevNonCommentSibling class RemoveTestSignerFix( - itemArgument: MvAttrItemArgument, + attrItem: MvAttrItem, val signerName: String -) : DiagnosticFix(itemArgument) { +): DiagnosticFix(attrItem) { override fun getText(): String = "Remove '$signerName'" override fun getFamilyName(): String = "Remove unused test signer" - override fun invoke(project: Project, file: PsiFile, element: MvAttrItemArgument) { - val argument = element - val container = element.parent as MvAttrItemArguments + override fun invoke(project: Project, file: PsiFile, element: MvAttrItem) { + val attrItem = element + val attrItemList = element.parent as MvAttrItemList // remove trailing comma - argument.getNextNonCommentSibling() + attrItem.getNextNonCommentSibling() ?.takeIf { it.elementType == MvElementTypes.COMMA } ?.delete() // remove previous comma if this is last element - val index = container.attrItemArgumentList.indexOf(argument) - if (index == container.attrItemArgumentList.size - 1) { + val index = attrItemList.attrItemList.indexOf(attrItem) + if (index == attrItemList.attrItemList.size - 1) { element.getPrevNonCommentSibling() ?.takeIf { it.elementType == MvElementTypes.COMMA } ?.delete() } - argument.delete() + attrItem.delete() } } diff --git a/src/main/kotlin/org/move/ide/intentions/ChopListIntention.kt b/src/main/kotlin/org/move/ide/intentions/ChopListIntention.kt index 7d87e4dfd..02a5c3d0f 100644 --- a/src/main/kotlin/org/move/ide/intentions/ChopListIntention.kt +++ b/src/main/kotlin/org/move/ide/intentions/ChopListIntention.kt @@ -60,9 +60,9 @@ class ChopValueArgumentListIntention : ChopListIntentionBase( - MvAttrItemArguments::class.java, - MvAttrItemArgument::class.java, +class ChopAttrArgumentListIntention : ChopListIntentionBase( + MvAttrItemList::class.java, + MvAttrItem::class.java, "Put arguments on separate lines" ) diff --git a/src/main/kotlin/org/move/lang/MoveFile.kt b/src/main/kotlin/org/move/lang/MoveFile.kt index 4419bfe65..e65dc18d4 100644 --- a/src/main/kotlin/org/move/lang/MoveFile.kt +++ b/src/main/kotlin/org/move/lang/MoveFile.kt @@ -17,7 +17,6 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.ancestorOrSelf import org.move.lang.core.psi.ext.childrenOfType import org.move.lang.core.psi.ext.modules -import org.move.openapiext.checkReadAccessAllowed import org.move.openapiext.resolveAbsPath import org.move.openapiext.toPsiFile import org.move.stdext.chain @@ -38,7 +37,7 @@ fun findMoveTomlPath(currentFilePath: Path): Path? { // requires ReadAccess val PsiElement.moveProject: MoveProject? get() { - return project.moveProjectsService.findMoveProject(this) + return project.moveProjectsService.findMoveProjectForPsiElement(this) } fun VirtualFile.hasChild(name: String) = this.findChild(name) != null diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItem.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItem.kt index dbe5a327d..eb771539c 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItem.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItem.kt @@ -1,10 +1,35 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode -import org.move.lang.core.psi.MvAttr -import org.move.lang.core.psi.MvAttrItem +import org.move.lang.core.psi.* import org.move.lang.core.psi.impl.MvNamedElementImpl +import org.move.lang.core.resolve.ref.MvPolyVariantReference +import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached -val MvAttrItem.attr: MvAttr get() = this.parent as MvAttr +val MvAttrItem.attr: MvAttr? get() = this.parent as? MvAttr -abstract class MvAttrItemMixin(node: ASTNode) : MvNamedElementImpl(node), MvAttrItem +class AttrItemReferenceImpl( + element: MvAttrItem, + val ownerFunction: MvFunction +) : MvPolyVariantReferenceCached(element) { + + override fun multiResolveInner(): List { + return ownerFunction.parameters + .map { it.bindingPat } + .filter { it.name == element.referenceName } + } +} + +abstract class MvAttrItemMixin(node: ASTNode): MvNamedElementImpl(node), + MvAttrItem { + + override fun getReference(): MvPolyVariantReference? { + val attr = this.ancestorStrict() ?: return null + attr.attrItemList + .singleOrNull() + ?.takeIf { it.identifier.text == "test" } ?: return null + val ownerFunction = attr.owner as? MvFunction ?: return null + return AttrItemReferenceImpl(this, ownerFunction) + } + +} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItemArgument.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItemArgument.kt deleted file mode 100644 index b5b696bb5..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvAttrItemArgument.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.move.lang.core.psi.ext - -import com.intellij.lang.ASTNode -import org.move.lang.core.psi.* -import org.move.lang.core.resolve.ref.MvPolyVariantReference -import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached - -class AttrItemArgumentReferenceImpl( - element: MvAttrItemArgument, - val ownerFunction: MvFunction -) : MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner(): List { - return ownerFunction.parameters - .map { it.bindingPat } - .filter { it.name == element.referenceName } - } -} - -abstract class MvAttrItemArgumentMixin(node: ASTNode) : MvElementImpl(node), - MvAttrItemArgument { - - override fun getReference(): MvPolyVariantReference? { - val attr = this.ancestorStrict() ?: return null - attr.attrItemList - .singleOrNull() - ?.takeIf { it.identifier.text == "test" } ?: return null - val ownerFunction = attr.owner as? MvFunction ?: return null - return AttrItemArgumentReferenceImpl(this, ownerFunction) - } -} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvDocAndAttributeOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvDocAndAttributeOwner.kt index 2e43223e7..05df1cc65 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvDocAndAttributeOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvDocAndAttributeOwner.kt @@ -65,7 +65,7 @@ class QueryAttributes( fun hasAttrItem(attributeName: String): Boolean = getAttrItem(attributeName) != null fun getAttrItem(attributeName: String): MvAttrItem? { - return this.attrItems.find { it.name == attributeName } + return this.attrItems.find { it.referenceName == attributeName } } val attrItems: Sequence get() = this.attributes.flatMap { it.attrItemList } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvElement.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvElement.kt index a489699a5..d7d2807c8 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvElement.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvElement.kt @@ -21,7 +21,7 @@ fun MvElement.isInsideAssignmentLhs(): Boolean { fun PsiFileSystemItem.findMoveProject(): MoveProject? { if (this is MoveFile) return this.moveProject val path = virtualFile.toNioPathOrNull() ?: return null - return project.moveProjectsService.findMoveProject(path) + return project.moveProjectsService.findMoveProjectForPath(path) } //private val MSL_KEY: Key> = Key.create("SIGNATURE_KEY") diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvRefExpr.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvRefExpr.kt index 0a1dd0a7e..06a7dba1f 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvRefExpr.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvRefExpr.kt @@ -1,14 +1,15 @@ package org.move.lang.core.psi.ext +import org.move.lang.core.psi.MvAttr import org.move.lang.core.psi.MvAttrItem -import org.move.lang.core.psi.MvAttrItemArgument import org.move.lang.core.psi.MvFunction import org.move.lang.core.psi.MvRefExpr fun MvRefExpr.isAbortCodeConst(): Boolean { - val itemArgument = this.parent as? MvAttrItemArgument ?: return false - if (itemArgument.identifier.text != "abort_code") return false - - val attrItem = itemArgument.parent?.parent as? MvAttrItem ?: return false - return (attrItem.attr.owner as? MvFunction)?.hasTestAttr ?: false + val abortCodeItem = + (this.parent.parent as? MvAttrItem) + ?.takeIf { it.identifier.text == "abort_code" } + ?: return false + val attr = abortCodeItem.ancestorStrict() ?: return false + return (attr.owner as? MvFunction)?.hasTestAttr ?: false } diff --git a/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt b/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt index 930179876..780a69729 100644 --- a/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt +++ b/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt @@ -38,10 +38,10 @@ interface MvAttributeOwnerStub { var verifyOnly = false for (attrItem in query.attrItems) { hasAttrs = true - if (attrItem.name == "test_only") { + if (attrItem.referenceName == "test_only") { testOnly = true } - if (attrItem.name == "verify_only") { + if (attrItem.referenceName == "verify_only") { verifyOnly = true } } diff --git a/src/main/kotlin/org/move/stdext/Paths.kt b/src/main/kotlin/org/move/stdext/Paths.kt index 271e5fb7d..f03ba85d6 100644 --- a/src/main/kotlin/org/move/stdext/Paths.kt +++ b/src/main/kotlin/org/move/stdext/Paths.kt @@ -2,7 +2,7 @@ package org.move.stdext import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.SystemInfo -import com.intellij.util.io.isDirectory +import kotlin.io.path.isDirectory import java.nio.file.Files import java.nio.file.InvalidPathException import java.nio.file.Path diff --git a/src/main/resources/inspectionDescriptions/MvFunctionNaming.html b/src/main/resources/inspectionDescriptions/MvFunctionNaming.html new file mode 100644 index 000000000..c1884cdc6 --- /dev/null +++ b/src/main/resources/inspectionDescriptions/MvFunctionNaming.html @@ -0,0 +1,5 @@ + + +

Checks function naming.

+ + \ No newline at end of file diff --git a/src/test/kotlin/org/move/cli/runConfigurations/CommandConfigurationHandlerTest.kt b/src/test/kotlin/org/move/cli/runConfigurations/CommandConfigurationHandlerTest.kt index 55ad12277..eb887e3b3 100644 --- a/src/test/kotlin/org/move/cli/runConfigurations/CommandConfigurationHandlerTest.kt +++ b/src/test/kotlin/org/move/cli/runConfigurations/CommandConfigurationHandlerTest.kt @@ -79,7 +79,7 @@ profiles: check(profile == expectedProfile) { "Unexpected profile $profile" } - val generatedCommand = handler.generateCommand(moveProject, profile, functionCall).unwrap() + val generatedCommand = handler.generateCommand(moveProject, functionCall, profile).unwrap() check(command == generatedCommand) { "Commands are not equal. \n" + "Original: $command\n" + diff --git a/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt b/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt index b0c65d83e..64a3c25b5 100644 --- a/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt +++ b/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt @@ -189,7 +189,7 @@ class NamedAddressValuesTest : MvProjectTestBase() { val (address, data) = myFixture.findElementAndDataInEditor() val expectedValue = data.trim() - val moveProject = project.moveProjectsService.findMoveProject(address)!! + val moveProject = project.moveProjectsService.findMoveProjectForPsiElement(address)!! val actualValue = moveProject.getNamedAddress(address.referenceName)!!.text() check(actualValue == expectedValue) { diff --git a/src/test/resources/org/move/lang/parser/complete/attributes.move b/src/test/resources/org/move/lang/parser/complete/attributes.move index 325dfef6d..952062f2c 100644 --- a/src/test/resources/org/move/lang/parser/complete/attributes.move +++ b/src/test/resources/org/move/lang/parser/complete/attributes.move @@ -35,6 +35,7 @@ module 0x1::M { #[expected_failure(abort_code = liquidswap::liquidity_pool::ERR_ADMIN)] fun abort_test() {} + #[allow(lint(self_transfer))] #[expected_failure( abort_code = liquidity_pool::ERR_ADMIN, location = aptos_framework::ed25519, diff --git a/src/test/resources/org/move/lang/parser/complete/attributes.txt b/src/test/resources/org/move/lang/parser/complete/attributes.txt index 89dcbade6..3e36c0e30 100644 --- a/src/test/resources/org/move/lang/parser/complete/attributes.txt +++ b/src/test/resources/org/move/lang/parser/complete/attributes.txt @@ -171,43 +171,46 @@ FILE PsiElement([)('[') MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('test') - MvAttrItemArgumentsImpl(ATTR_ITEM_ARGUMENTS) + MvAttrItemListImpl(ATTR_ITEM_LIST) PsiElement(()('(') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('a') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvLitExprImpl(LIT_EXPR) - MvAddressLitImpl(ADDRESS_LIT) - PsiElement(@)('@') - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvLitExprImpl(LIT_EXPR) + MvAddressLitImpl(ADDRESS_LIT) + PsiElement(@)('@') + MvAddressRefImpl(ADDRESS_REF) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(,)(',') PsiWhiteSpace(' ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('b') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvLitExprImpl(LIT_EXPR) - MvAddressLitImpl(ADDRESS_LIT) - PsiElement(@)('@') - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x2') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvLitExprImpl(LIT_EXPR) + MvAddressLitImpl(ADDRESS_LIT) + PsiElement(@)('@') + MvAddressRefImpl(ADDRESS_REF) + PsiElement(DIEM_ADDRESS)('0x2') PsiElement(,)(',') PsiWhiteSpace(' ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('c') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvLitExprImpl(LIT_EXPR) - MvAddressLitImpl(ADDRESS_LIT) - PsiElement(@)('@') - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Std') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvLitExprImpl(LIT_EXPR) + MvAddressLitImpl(ADDRESS_LIT) + PsiElement(@)('@') + MvAddressRefImpl(ADDRESS_REF) + MvNamedAddressImpl(NAMED_ADDRESS) + PsiElement(IDENTIFIER)('Std') PsiElement())(')') PsiElement(])(']') PsiWhiteSpace('\n ') @@ -228,7 +231,7 @@ FILE PsiElement([)('[') MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('test') - MvAttrItemArgumentsImpl(ATTR_ITEM_ARGUMENTS) + MvAttrItemListImpl(ATTR_ITEM_LIST) PsiElement(()('(') PsiElement())(')') PsiElement(])(']') @@ -268,13 +271,13 @@ FILE PsiElement([)('[') MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('show') - MvAttrItemArgumentsImpl(ATTR_ITEM_ARGUMENTS) + MvAttrItemListImpl(ATTR_ITEM_LIST) PsiElement(()('(') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('book_orders_sdk') PsiElement(,)(',') PsiWhiteSpace(' ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('book_price_levels_sdk') PsiElement())(')') PsiElement(])(']') @@ -296,23 +299,24 @@ FILE PsiElement([)('[') MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('expected_failure') - MvAttrItemArgumentsImpl(ATTR_ITEM_ARGUMENTS) + MvAttrItemListImpl(ATTR_ITEM_LIST) PsiElement(()('(') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('abort_code') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvRefExprImpl(REF_EXPR) - MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('liquidswap') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvFQModuleRefImpl(FQ_MODULE_REF) + MvAddressRefImpl(ADDRESS_REF) + MvNamedAddressImpl(NAMED_ADDRESS) + PsiElement(IDENTIFIER)('liquidswap') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('liquidity_pool') PsiElement(::)('::') - PsiElement(IDENTIFIER)('liquidity_pool') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('ERR_ADMIN') + PsiElement(IDENTIFIER)('ERR_ADMIN') PsiElement())(')') PsiElement(])(']') PsiWhiteSpace('\n ') @@ -328,55 +332,75 @@ FILE PsiElement(})('}') PsiWhiteSpace('\n\n ') MvFunctionImpl(FUNCTION) + MvAttrImpl(ATTR) + PsiElement(#)('#') + PsiElement([)('[') + MvAttrItemImpl(ATTR_ITEM) + PsiElement(IDENTIFIER)('allow') + MvAttrItemListImpl(ATTR_ITEM_LIST) + PsiElement(()('(') + MvAttrItemImpl(ATTR_ITEM) + PsiElement(IDENTIFIER)('lint') + MvAttrItemListImpl(ATTR_ITEM_LIST) + PsiElement(()('(') + MvAttrItemImpl(ATTR_ITEM) + PsiElement(IDENTIFIER)('self_transfer') + PsiElement())(')') + PsiElement())(')') + PsiElement(])(']') + PsiWhiteSpace('\n ') MvAttrImpl(ATTR) PsiElement(#)('#') PsiElement([)('[') MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('expected_failure') - MvAttrItemArgumentsImpl(ATTR_ITEM_ARGUMENTS) + MvAttrItemListImpl(ATTR_ITEM_LIST) PsiElement(()('(') PsiWhiteSpace('\n ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('abort_code') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvRefExprImpl(REF_EXPR) - MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) - PsiElement(IDENTIFIER)('liquidity_pool') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('ERR_ADMIN') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvModuleRefImpl(MODULE_REF) + PsiElement(IDENTIFIER)('liquidity_pool') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('ERR_ADMIN') PsiElement(,)(',') PsiWhiteSpace('\n ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('location') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvRefExprImpl(REF_EXPR) - MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) - PsiElement(IDENTIFIER)('aptos_framework') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('ed25519') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvModuleRefImpl(MODULE_REF) + PsiElement(IDENTIFIER)('aptos_framework') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('ed25519') PsiElement(,)(',') PsiWhiteSpace('\n ') - MvAttrItemArgumentImpl(ATTR_ITEM_ARGUMENT) + MvAttrItemImpl(ATTR_ITEM) PsiElement(IDENTIFIER)('location') PsiWhiteSpace(' ') - PsiElement(=)('=') - PsiWhiteSpace(' ') - MvRefExprImpl(REF_EXPR) - MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('aptos_framework') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + PsiWhiteSpace(' ') + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvFQModuleRefImpl(FQ_MODULE_REF) + MvAddressRefImpl(ADDRESS_REF) + MvNamedAddressImpl(NAMED_ADDRESS) + PsiElement(IDENTIFIER)('aptos_framework') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('ed25519') PsiElement(::)('::') - PsiElement(IDENTIFIER)('ed25519') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('myfunction') + PsiElement(IDENTIFIER)('myfunction') PsiElement(,)(',') PsiWhiteSpace('\n ') PsiElement())(')')