From 89b6ccf21eb398166a4a85fd09cb07c5aeb97fa3 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 10 Jul 2024 00:44:13 +0300 Subject: [PATCH 01/43] parser support for 4-element paths --- src/main/grammars/MoveParser.bnf | 53 +++- .../ide/inspections/imports/AutoImportFix.kt | 5 +- .../move/ide/inspections/imports/PathStart.kt | 1 + .../org/move/lang/MoveParserDefinition.kt | 2 +- .../providers/ModulesCompletionProvider.kt | 1 + .../providers/MvPathCompletionProvider.kt | 5 +- .../kotlin/org/move/lang/core/psi/PathExpr.kt | 2 +- .../org/move/lang/core/psi/ext/MvPath.kt | 2 + .../core/resolve/ref/MovePathReferenceImpl.kt | 5 +- .../move/lang/parser/CompleteParsingTest.kt | 2 + .../lang/parser/complete/access_control.txt | 16 +- .../move/lang/parser/complete/attributes.move | 2 +- .../move/lang/parser/complete/attributes.txt | 38 +-- .../lang/parser/complete/function_calls.txt | 18 +- .../parser/complete/function_declarations.txt | 31 +-- .../move/lang/parser/complete/index_expr.txt | 16 +- .../org/move/lang/parser/complete/paths.move | 22 ++ .../org/move/lang/parser/complete/paths.txt | 226 ++++++++++++++++++ .../org/move/lang/parser/complete/vectors.txt | 4 +- .../move/lang/parser/partial/dot_exprs.txt | 2 +- .../move/lang/parser/partial/expressions.move | 2 + .../move/lang/parser/partial/expressions.txt | 69 ++++-- 22 files changed, 416 insertions(+), 108 deletions(-) create mode 100644 src/test/resources/org/move/lang/parser/complete/paths.move create mode 100644 src/test/resources/org/move/lang/parser/complete/paths.txt diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 919dd60d5..126300858 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -465,17 +465,17 @@ ResourceAccessItemList ::= <> ResourceAccessItem* ResourceAccessItem ::= pure | (('!')? (acquires | reads | writes) AccessSpecifierList) AccessSpecifierList ::= <> -AccessSpecifier ::= <> AddressSpecifier? +AccessSpecifier ::= <> AddressSpecifier? AddressSpecifier ::= '(' AddressSpecifierArg ')' { pin = 1 } AddressSpecifierArg ::= '*' | AddressSpecifierLit - | <> + | <> | IDENTIFIER AddressSpecifierLit ::= DIEM_ADDRESS | INTEGER_LITERAL -AddressSpecifierCallParam ::= AddressSpecifierParamPath -AddressSpecifierParamPath ::= LocalPathIdent { elementType = Path } +AddressSpecifierCallParam ::= AddressSpecifierCallParamImpl +AddressSpecifierCallParamImpl ::= PathIdent { elementType = Path } // acquires T, Record AcquiresType ::= acquires AcquiresType_items { pin = 1 } @@ -583,7 +583,7 @@ RefType ::= RefTypeStart Type } RefTypeStart ::= '&' mut? -PathType ::= Path +PathType ::= PathImpl { name = "type" } @@ -657,7 +657,7 @@ BindingPat ::= IDENTIFIER { TuplePat ::= '(' <>? ')' -StructPat ::= Path StructPatFieldsBlock +StructPat ::= PathImpl StructPatFieldsBlock StructPatFieldsBlock ::= '{' StructPatField_with_recover* '}' { pin = 1 } private StructPatField_with_recover ::= !'}' StructPatField (',' | &'}') @@ -903,7 +903,7 @@ VectorLitItems ::= '[' <>? ']' pin = 1 } -StructLitExpr ::= <> Path StructLitFieldsBlock +StructLitExpr ::= <> PathImpl StructLitFieldsBlock { implements = ["org.move.lang.core.psi.PathExpr"] } @@ -965,7 +965,7 @@ private AnyLitToken_first ::= HEX_INTEGER_LITERAL AddressLit ::= '@' AddressRef { pin = 1 } -CallExpr ::= (Path &'(') ValueArgumentList { +CallExpr ::= (PathImpl &'(') ValueArgumentList { pin = 1 implements = [ "org.move.lang.core.psi.PathExpr" @@ -1045,11 +1045,21 @@ IndexExpr ::= Expr IndexArg // Do not inline this rule, it breaks expression parsing private IndexArg ::= '[' Expr ']' -RefExpr ::= Path !'{' { +RefExpr ::= PathImpl !'{' { +//RefExpr ::= Path !'{' { implements = ["org.move.lang.core.psi.PathExpr"] } -Path ::= (ModulePathIdent | FQModulePathIdent | LocalPathIdent) TypeArgumentList? +//Path3Impl ::= (ModulePathIdent | FQModulePathIdent | LocalPathIdent) TypeArgumentList? +//{ +// implements = [ +// "org.move.lang.core.resolve.ref.MvPathReferenceElement" +// "org.move.lang.core.psi.ext.MvMethodOrPath" +// ] +// mixin = "org.move.lang.core.psi.ext.MvPathMixin" +//} + +fake Path ::= (Path '::')? (PathIdent | PathAddress) TypeArgumentList? { implements = [ "org.move.lang.core.resolve.ref.MvPathReferenceElement" @@ -1058,6 +1068,25 @@ Path ::= (ModulePathIdent | FQModulePathIdent | LocalPathIdent) TypeArgumentList mixin = "org.move.lang.core.psi.ext.MvPathMixin" } +private PathImpl ::= PathStart PathSegment* + +PathStart ::= ((PathAddress &'::') | PathIdent) TypeArgumentList? +{ + name = "path" + elementType = Path +} +left PathSegment ::= '::' PathIdent TypeArgumentList? { + pin = 1 + elementType = Path +} + +private PathIdent ::= PATH_MODE_IDENTIFIER +PathAddress ::= DIEM_ADDRESS + | INTEGER_LITERAL + | PLACEHOLDER_ADDRESS + | BECH32_ADDRESS + | POLKADOT_ADDRESS + private LocalPathIdent ::= PATH_MODE_IDENTIFIER private ModulePathIdent ::= ModuleRef ('::' !(PATH_MODE_IDENTIFIER '::')) PATH_MODE_IDENTIFIER { @@ -1411,7 +1440,7 @@ IfElseIncludeItem ::= if Condition SchemaLit else SchemaLit extends = IncludeItem } -SchemaLit ::= Path SchemaFieldsBlock? +SchemaLit ::= PathImpl SchemaFieldsBlock? { implements = [ "org.move.lang.core.psi.MslOnlyElement" @@ -1499,7 +1528,7 @@ ApplyExcept ::= except <> { implements = [ "org.move.lang.core.psi.MslOnlyElement" ] } -SchemaRef ::= Path ('{' <> '}')? +SchemaRef ::= PathImpl ('{' <> '}')? { implements = [ "org.move.lang.core.psi.MslOnlyElement" ] } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index 0ef032ced..d2113131e 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -10,10 +10,7 @@ import org.move.ide.utils.imports.ImportCandidate import org.move.ide.utils.imports.ImportCandidateCollector import org.move.ide.utils.imports.import import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.ancestorStrict -import org.move.lang.core.psi.ext.asSmartPointer -import org.move.lang.core.psi.ext.hasAncestor -import org.move.lang.core.psi.ext.importCandidateNamespaces +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.resolve.letStmtScope import org.move.lang.core.resolve.ref.MvReferenceElement diff --git a/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt b/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt index 4e2b83efc..e7e4a4a7a 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt @@ -4,6 +4,7 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.MvDocAndAttributeOwner import org.move.lang.core.psi.ext.hasTestAttr import org.move.lang.core.psi.ext.hasTestOnlyAttr +import org.move.lang.core.psi.ext.moduleRef // only Main/Test for now val MvPath.pathUsageScope: NamedItemScope diff --git a/src/main/kotlin/org/move/lang/MoveParserDefinition.kt b/src/main/kotlin/org/move/lang/MoveParserDefinition.kt index 2317eaac1..10d9bc741 100644 --- a/src/main/kotlin/org/move/lang/MoveParserDefinition.kt +++ b/src/main/kotlin/org/move/lang/MoveParserDefinition.kt @@ -63,6 +63,6 @@ class MoveParserDefinition : ParserDefinition { /** * Should be increased after any change of parser rules */ - const val PARSER_VERSION: Int = LEXER_VERSION + 49 + const val PARSER_VERSION: Int = LEXER_VERSION + 50 } } diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt index 991cbcd23..ff3de5481 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt @@ -15,6 +15,7 @@ import org.move.lang.core.psi.MvPath import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.containingModuleSpec import org.move.lang.core.psi.ext.equalsTo +import org.move.lang.core.psi.ext.moduleRef import org.move.lang.core.psi.refItemScopes import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.resolve.letStmtScope diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index 35dd00cb6..e0cfb2591 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -12,10 +12,7 @@ import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.ancestors -import org.move.lang.core.psi.ext.endOffset -import org.move.lang.core.psi.ext.isMslScope -import org.move.lang.core.psi.ext.isSelfModuleRef +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace diff --git a/src/main/kotlin/org/move/lang/core/psi/PathExpr.kt b/src/main/kotlin/org/move/lang/core/psi/PathExpr.kt index 6ef30b302..0ed77ecf3 100644 --- a/src/main/kotlin/org/move/lang/core/psi/PathExpr.kt +++ b/src/main/kotlin/org/move/lang/core/psi/PathExpr.kt @@ -1,5 +1,5 @@ package org.move.lang.core.psi interface PathExpr : MvElement { - val path: MvPath + val path: MvPath get() = error("unreachable") } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 2ed9700d1..171a53294 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -91,3 +91,5 @@ fun MvReferenceElement.importCandidateNamespaces(): Set { } } } + +val MvPath.moduleRef: MvModuleRef? get() = error("stub") \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt index 367110ef7..d186c25e8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt @@ -1,10 +1,7 @@ package org.move.lang.core.resolve.ref import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.isSelfModuleRef -import org.move.lang.core.psi.ext.isUpdateFieldArg2 -import org.move.lang.core.psi.ext.itemUseSpeck -import org.move.lang.core.psi.ext.namespaces +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* class MvPathReferenceImpl( diff --git a/src/test/kotlin/org/move/lang/parser/CompleteParsingTest.kt b/src/test/kotlin/org/move/lang/parser/CompleteParsingTest.kt index 355f13d63..33366f34c 100644 --- a/src/test/kotlin/org/move/lang/parser/CompleteParsingTest.kt +++ b/src/test/kotlin/org/move/lang/parser/CompleteParsingTest.kt @@ -44,6 +44,8 @@ class CompleteParsingTest: MvParsingTestCase("complete") { fun `test macros`() = doTest() fun `test loops`() = doTest() + fun `test paths`() = doTest() + // compiler v2 fun `test index expr`() = doTest() fun `test public package`() = doTest() diff --git a/src/test/resources/org/move/lang/parser/complete/access_control.txt b/src/test/resources/org/move/lang/parser/complete/access_control.txt index 25b53f6be..56ea09ea5 100644 --- a/src/test/resources/org/move/lang/parser/complete/access_control.txt +++ b/src/test/resources/org/move/lang/parser/complete/access_control.txt @@ -189,9 +189,10 @@ FILE MvAccessSpecifierListImpl(ACCESS_SPECIFIER_LIST) MvAccessSpecifierImpl(ACCESS_SPECIFIER) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x42') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x42') PsiElement(::)('::') PsiElement(*)('*') PsiElement(::)('::') @@ -216,9 +217,10 @@ FILE MvAccessSpecifierListImpl(ACCESS_SPECIFIER_LIST) MvAccessSpecifierImpl(ACCESS_SPECIFIER) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x42') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x42') PsiElement(::)('::') PsiElement(IDENTIFIER)('m') PsiElement(::)('::') @@ -486,7 +488,7 @@ FILE PsiElement(()('(') MvAddressSpecifierArgImpl(ADDRESS_SPECIFIER_ARG) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('signer') PsiElement(::)('::') PsiElement(IDENTIFIER)('address_of') 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 952062f2c..a680cc46f 100644 --- a/src/test/resources/org/move/lang/parser/complete/attributes.move +++ b/src/test/resources/org/move/lang/parser/complete/attributes.move @@ -32,7 +32,7 @@ module 0x1::M { #[show(book_orders_sdk, book_price_levels_sdk)] fun test() {} - #[expected_failure(abort_code = liquidswap::liquidity_pool::ERR_ADMIN)] + #[expected_failure(abort_code = liquidswap::liquidity_pool::ERR_ADMIN, location=0x1::liquidity_pool)] fun abort_test() {} #[allow(lint(self_transfer))] 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 3e36c0e30..1264a7d63 100644 --- a/src/test/resources/org/move/lang/parser/complete/attributes.txt +++ b/src/test/resources/org/move/lang/parser/complete/attributes.txt @@ -121,10 +121,9 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('std') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') PsiElement(::)('::') PsiElement(IDENTIFIER)('type_name') PsiElement(::)('::') @@ -309,14 +308,26 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('liquidswap') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('liquidswap') PsiElement(::)('::') PsiElement(IDENTIFIER)('liquidity_pool') PsiElement(::)('::') PsiElement(IDENTIFIER)('ERR_ADMIN') + PsiElement(,)(',') + PsiWhiteSpace(' ') + MvAttrItemImpl(ATTR_ITEM) + PsiElement(IDENTIFIER)('location') + MvAttrItemInitializerImpl(ATTR_ITEM_INITIALIZER) + PsiElement(=)('=') + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('liquidity_pool') PsiElement())(')') PsiElement(])(']') PsiWhiteSpace('\n ') @@ -365,7 +376,7 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('liquidity_pool') PsiElement(::)('::') PsiElement(IDENTIFIER)('ERR_ADMIN') @@ -379,7 +390,7 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('aptos_framework') PsiElement(::)('::') PsiElement(IDENTIFIER)('ed25519') @@ -393,10 +404,9 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('aptos_framework') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('aptos_framework') PsiElement(::)('::') PsiElement(IDENTIFIER)('ed25519') PsiElement(::)('::') diff --git a/src/test/resources/org/move/lang/parser/complete/function_calls.txt b/src/test/resources/org/move/lang/parser/complete/function_calls.txt index 564e480a6..f34cb93e7 100644 --- a/src/test/resources/org/move/lang/parser/complete/function_calls.txt +++ b/src/test/resources/org/move/lang/parser/complete/function_calls.txt @@ -245,9 +245,10 @@ FILE MvTypeArgumentImpl(TYPE_ARGUMENT) MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Mod') PsiElement(::)('::') @@ -267,10 +268,9 @@ FILE MvTypeArgumentImpl(TYPE_ARGUMENT) MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Sender') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Sender') PsiElement(::)('::') PsiElement(IDENTIFIER)('Mod') PsiElement(::)('::') @@ -356,7 +356,7 @@ FILE MvValueArgumentImpl(VALUE_ARGUMENT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') PsiElement(IDENTIFIER)('new') @@ -383,7 +383,7 @@ FILE MvExprStmtImpl(EXPR_STMT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') PsiElement(IDENTIFIER)('call') diff --git a/src/test/resources/org/move/lang/parser/complete/function_declarations.txt b/src/test/resources/org/move/lang/parser/complete/function_declarations.txt index 4d06fefac..5b00034ca 100644 --- a/src/test/resources/org/move/lang/parser/complete/function_declarations.txt +++ b/src/test/resources/org/move/lang/parser/complete/function_declarations.txt @@ -332,7 +332,7 @@ FILE PsiElement(&)('&') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') PsiElement(IDENTIFIER)('Sender') @@ -385,7 +385,7 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') PsiElement(IDENTIFIER)('Sender') @@ -395,9 +395,10 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') @@ -437,7 +438,7 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') PsiElement(IDENTIFIER)('Sender') @@ -445,9 +446,10 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') @@ -456,10 +458,9 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Std') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Std') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') @@ -468,7 +469,7 @@ FILE PsiWhiteSpace(' ') MvPathTypeImpl(PATH_TYPE) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Loans') PsiElement(::)('::') PsiElement(IDENTIFIER)('Loan') @@ -678,4 +679,4 @@ FILE PsiElement(IDENTIFIER)('T') PsiElement(;)(';') PsiWhiteSpace('\n') - PsiElement(})('}') + PsiElement(})('}') \ No newline at end of file diff --git a/src/test/resources/org/move/lang/parser/complete/index_expr.txt b/src/test/resources/org/move/lang/parser/complete/index_expr.txt index 30fff8a0e..6dd5453f9 100644 --- a/src/test/resources/org/move/lang/parser/complete/index_expr.txt +++ b/src/test/resources/org/move/lang/parser/complete/index_expr.txt @@ -388,7 +388,7 @@ FILE MvIndexExprImpl(INDEX_EXPR) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('test') PsiElement(::)('::') PsiElement(IDENTIFIER)('Y') @@ -486,9 +486,10 @@ FILE MvIndexExprImpl(INDEX_EXPR) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x42') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x42') PsiElement(::)('::') PsiElement(IDENTIFIER)('test') PsiElement(::)('::') @@ -700,9 +701,10 @@ FILE MvIndexExprImpl(INDEX_EXPR) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x42') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x42') PsiElement(::)('::') PsiElement(IDENTIFIER)('test') PsiElement(::)('::') diff --git a/src/test/resources/org/move/lang/parser/complete/paths.move b/src/test/resources/org/move/lang/parser/complete/paths.move new file mode 100644 index 000000000..8d16094a3 --- /dev/null +++ b/src/test/resources/org/move/lang/parser/complete/paths.move @@ -0,0 +1,22 @@ +module 0x1::paths { + fun main() { + 0x1; + 0x1::m; + std::m; + + 0x1::m::call; + std::m::call; + + 0x1::m::Enum::EnumType; + std::m::Enum::EnumType; + + std<>; + std<>::item; + std::m<>; + std::m<>::item; + std::m::call<>; + std::m::call<>::item; + std::m::Enum::EnumType<>; + std::m::Enum::EnumType<>::item; + } +} diff --git a/src/test/resources/org/move/lang/parser/complete/paths.txt b/src/test/resources/org/move/lang/parser/complete/paths.txt new file mode 100644 index 000000000..937f6de0e --- /dev/null +++ b/src/test/resources/org/move/lang/parser/complete/paths.txt @@ -0,0 +1,226 @@ +FILE + MvModuleImpl(MODULE) + PsiElement(module)('module') + PsiWhiteSpace(' ') + MvAddressRefImpl(ADDRESS_REF) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('paths') + PsiWhiteSpace(' ') + MvModuleBlockImpl(MODULE_BLOCK) + PsiElement({)('{') + PsiWhiteSpace('\n ') + MvFunctionImpl(FUNCTION) + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('main') + MvFunctionParameterListImpl(FUNCTION_PARAMETER_LIST) + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + MvCodeBlockImpl(CODE_BLOCK) + PsiElement({)('{') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvLitExprImpl(LIT_EXPR) + PsiElement(HEX_INTEGER_LITERAL)('0x1') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(;)(';') + PsiWhiteSpace('\n\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + PsiElement(;)(';') + PsiWhiteSpace('\n\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Enum') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('EnumType') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Enum') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('EnumType') + PsiElement(;)(';') + PsiWhiteSpace('\n\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('item') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('item') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('item') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Enum') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('EnumType') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Enum') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('EnumType') + MvTypeArgumentListImpl(TYPE_ARGUMENT_LIST) + PsiElement(<)('<') + PsiElement(>)('>') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('item') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + PsiElement(})('}') + PsiWhiteSpace('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/src/test/resources/org/move/lang/parser/complete/vectors.txt b/src/test/resources/org/move/lang/parser/complete/vectors.txt index fcf92971d..4bee53d3f 100644 --- a/src/test/resources/org/move/lang/parser/complete/vectors.txt +++ b/src/test/resources/org/move/lang/parser/complete/vectors.txt @@ -117,7 +117,7 @@ FILE MvExprStmtImpl(EXPR_STMT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('vector') PsiElement(::)('::') PsiElement(IDENTIFIER)('add') @@ -128,4 +128,4 @@ FILE PsiWhiteSpace('\n ') PsiElement(})('}') PsiWhiteSpace('\n') - PsiElement(})('}') + PsiElement(})('}') \ No newline at end of file diff --git a/src/test/resources/org/move/lang/parser/partial/dot_exprs.txt b/src/test/resources/org/move/lang/parser/partial/dot_exprs.txt index 0f9c55ae5..bc6bcf186 100644 --- a/src/test/resources/org/move/lang/parser/partial/dot_exprs.txt +++ b/src/test/resources/org/move/lang/parser/partial/dot_exprs.txt @@ -124,7 +124,7 @@ FILE MvExprStmtImpl(EXPR_STMT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('aptos_token') PsiElement(::)('::') PsiElement(IDENTIFIER)('get_token') diff --git a/src/test/resources/org/move/lang/parser/partial/expressions.move b/src/test/resources/org/move/lang/parser/partial/expressions.move index 744d8e043..08f62be3c 100644 --- a/src/test/resources/org/move/lang/parser/partial/expressions.move +++ b/src/test/resources/org/move/lang/parser/partial/expressions.move @@ -15,5 +15,7 @@ script { while (true) {} return 0hello + + RMRK:: ::; } } diff --git a/src/test/resources/org/move/lang/parser/partial/expressions.txt b/src/test/resources/org/move/lang/parser/partial/expressions.txt index a551608be..466b8ff90 100644 --- a/src/test/resources/org/move/lang/parser/partial/expressions.txt +++ b/src/test/resources/org/move/lang/parser/partial/expressions.txt @@ -57,34 +57,35 @@ FILE MvExprStmtImpl(EXPR_STMT) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('RMRK') PsiElement(::)('::') - PsiErrorElement:, IDENTIFIER or '{' expected, got '0x1' + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got '0x1' PsiWhiteSpace('\n ') MvExprStmtImpl(EXPR_STMT) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) PsiElement(DIEM_ADDRESS)('0x1') - PsiElement(::)('::') - PsiErrorElement:'::', , IDENTIFIER or '{' expected, got ';' - + PsiElement(::)('::') + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got ';' + PsiWhiteSpace(' ') PsiElement(;)(';') PsiWhiteSpace('\n ') MvExprStmtImpl(EXPR_STMT) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('RMRK') PsiElement(::)('::') - PsiErrorElement:, IDENTIFIER or '{' expected, got ';' + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got ';' PsiWhiteSpace(' ') PsiElement(;)(';') @@ -92,14 +93,13 @@ FILE MvExprStmtImpl(EXPR_STMT) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Sender') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Sender') PsiElement(::)('::') PsiElement(IDENTIFIER)('RMRK') PsiElement(::)('::') - PsiErrorElement:, IDENTIFIER or '{' expected, got ';' + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got ';' PsiWhiteSpace(' ') PsiElement(;)(';') @@ -107,14 +107,13 @@ FILE MvExprStmtImpl(EXPR_STMT) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Sender') + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Sender') PsiElement(::)('::') PsiElement(IDENTIFIER)('RMRK') PsiElement(::)('::') - PsiErrorElement:, IDENTIFIER or '{' expected, got 'while' + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got 'while' PsiWhiteSpace('\n\n ') MvExprStmtImpl(EXPR_STMT) @@ -133,11 +132,29 @@ FILE PsiErrorElement:';' expected, got 'return' PsiWhiteSpace('\n ') - MvReturnExprImpl(RETURN_EXPR) - PsiElement(return)('return') - PsiWhiteSpace('\n ') - MvLitExprImpl(LIT_EXPR) - PsiElement(INTEGER_LITERAL)('0hello') + MvExprStmtImpl(EXPR_STMT) + MvReturnExprImpl(RETURN_EXPR) + PsiElement(return)('return') + PsiWhiteSpace('\n ') + MvLitExprImpl(LIT_EXPR) + PsiElement(INTEGER_LITERAL)('0hello') + PsiErrorElement:';' expected, got 'RMRK' + + PsiWhiteSpace('\n\n ') + MvExprStmtImpl(EXPR_STMT) + MvRefExprImpl(REF_EXPR) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('RMRK') + PsiElement(::)('::') + PsiErrorElement:'::', <, or IDENTIFIER expected, got '::' + + PsiWhiteSpace(' ') + PsiElement(::)('::') + PsiErrorElement:'::', <, , IDENTIFIER or '{' expected, got ';' + + PsiElement(;)(';') PsiWhiteSpace('\n ') PsiElement(})('}') PsiWhiteSpace('\n') From cdc56bdfacb54a36cfd8494d11eca7ff45c12917 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 10 Jul 2024 14:00:36 +0300 Subject: [PATCH 02/43] add two resolve tests --- .../move/lang/resolve/ResolveVariablesTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt index 8537dd22e..62aa4e187 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt @@ -348,4 +348,26 @@ module 0x1::string_tests { } } """) + + fun `test cannot resolve path address`() = checkByCode(""" + module 0x1::m { + fun main() { + 0x1::; + //^ unresolved + } + } + """) + + fun `test resolve attribute location`() = checkByCode(""" + module 0x1::m { + //X + fun main() { + } + #[test(location=0x1::m)] + //^ + fun test_main() { + + } + } + """) } From 7c9237d3a13af54d63a93d804bd21e9a4d5f0359 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 10 Jul 2024 21:21:30 +0300 Subject: [PATCH 03/43] module alias tests --- .../move/lang/resolve/ResolveFunctionTest.kt | 216 +++++++++++++----- 1 file changed, 161 insertions(+), 55 deletions(-) diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index c45580f16..087757088 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -2,7 +2,7 @@ package org.move.lang.resolve import org.move.utils.tests.resolve.ResolveTestCase -class ResolveFunctionTest : ResolveTestCase() { +class ResolveFunctionTest: ResolveTestCase() { fun `test resolve reference to function`() = checkByCode( """ module M { @@ -354,7 +354,8 @@ class ResolveFunctionTest : ResolveTestCase() { """ ) - fun `test resolve fully qualified path from the same module`() = checkByCode(""" + fun `test resolve fully qualified path from the same module`() = checkByCode( + """ module 0x1::M { struct Loan {} public fun call() acquires Loan {} @@ -364,9 +365,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ } } - """) + """ + ) - fun `test public script function available in test`() = checkByCode(""" + fun `test public script function available in test`() = checkByCode( + """ module 0x1::M { public(script) fun call() {} //X @@ -381,9 +384,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ } } - """) + """ + ) - fun `test resolve fun in test_only module from another test_only`() = checkByCode(""" + fun `test resolve fun in test_only module from another test_only`() = checkByCode( + """ #[test_only] module 0x1::M1 { public fun call() {} @@ -398,9 +403,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ } } - """) + """ + ) - fun `test test_only function is not accessible from non test_only module`() = checkByCode(""" + fun `test test_only function is not accessible from non test_only module`() = checkByCode( + """ module 0x1::M1 { #[test_only] public fun call() {} @@ -412,9 +419,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ unresolved } } - """) + """ + ) - fun `test test_only module is not accessible from non_test_only module`() = checkByCode(""" + fun `test test_only module is not accessible from non_test_only module`() = checkByCode( + """ #[test_only] module 0x1::M1 { public fun call() {} @@ -426,9 +435,11 @@ class ResolveFunctionTest : ResolveTestCase() { M1::call(); } } - """) + """ + ) - fun `test unittest functions are not accessible as items`() = checkByCode(""" + fun `test unittest functions are not accessible as items`() = checkByCode( + """ #[test_only] module 0x1::M { #[test] @@ -438,9 +449,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ unresolved } } - """) + """ + ) - fun `test unittest functions are not accessible as module items`() = checkByCode(""" + fun `test unittest functions are not accessible as module items`() = checkByCode( + """ #[test_only] module 0x1::M1 { #[test] @@ -455,9 +468,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ unresolved } } - """) + """ + ) - fun `test module and spec module blocks share the same namespace`() = checkByCode(""" + fun `test module and spec module blocks share the same namespace`() = checkByCode( + """ module 0x1::caller { public fun call() {} //X @@ -471,9 +486,11 @@ class ResolveFunctionTest : ResolveTestCase() { spec 0x1::main { use 0x1::caller::call; } - """) + """ + ) - fun `test friend function from another module with spaces after public`() = checkByCode(""" + fun `test friend function from another module with spaces after public`() = checkByCode( + """ module 0x1::A { friend 0x1::B; public ( friend) fun call_a() {} @@ -487,9 +504,11 @@ class ResolveFunctionTest : ResolveTestCase() { //^ } } - """) + """ + ) - fun `test use item inside function block`() = checkByCode(""" + fun `test use item inside function block`() = checkByCode( + """ module 0x1::string { public fun utf8() {} //X @@ -501,9 +520,11 @@ module 0x1::main { //^ } } - """) + """ + ) - fun `test resolve with self alias`() = checkByCode(""" + fun `test resolve with self alias`() = checkByCode( + """ module 0x1::string { public fun utf8() {} //X @@ -515,9 +536,11 @@ module 0x1::main { //^ } } - """) + """ + ) - fun `test resolve inline function from same module`() = checkByCode(""" + fun `test resolve inline function from same module`() = checkByCode( + """ module 0x1::string { inline fun foreach(v: vector, f: |Element|) {} //X @@ -526,9 +549,11 @@ module 0x1::string { //^ } } - """) + """ + ) - fun `test resolve inline function from different module`() = checkByCode(""" + fun `test resolve inline function from different module`() = checkByCode( + """ module 0x1::string { public inline fun foreach(v: vector, f: |Element|) {} //X @@ -540,9 +565,11 @@ module 0x1::main { //^ } } - """) + """ + ) - fun `test inline function lambda variable`() = checkByCode(""" + fun `test inline function lambda variable`() = checkByCode( + """ module 0x1::m { public inline fun for_each(o: Element, f: |Element|) {} fun main() { @@ -553,9 +580,11 @@ module 0x1::m { ) } } - """) + """ + ) - fun `test inline function lambda two variables`() = checkByCode(""" + fun `test inline function lambda two variables`() = checkByCode( + """ module 0x1::m { public inline fun for_each(o: Element, f: |Element|) {} fun main() { @@ -566,9 +595,11 @@ module 0x1::m { ) } } - """) + """ + ) - fun `test resolve lambda function call expr`() = checkByCode(""" + fun `test resolve lambda function call expr`() = checkByCode( + """ module 0x1::mod { public inline fun fold(elem: Element, func: |Element| Accumulator): Accumulator { //X @@ -576,18 +607,22 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test cannot resolve function to parameter`() = checkByCode(""" + fun `test cannot resolve function to parameter`() = checkByCode( + """ module 0x1::mod { public inline fun fold(elem: Element, func: |Element| Accumulator): Accumulator { elem(1); //^ unresolved } } - """) + """ + ) - fun `test functions have separate namespace from variables`() = checkByCode(""" + fun `test functions have separate namespace from variables`() = checkByCode( + """ module 0x1::mod { fun name() {} //X @@ -597,9 +632,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test resolve local function when module with same name is imported as Self`() = checkByCode(""" + fun `test resolve local function when module with same name is imported as Self`() = checkByCode( + """ module 0x1::royalty {} module 0x1::m { use 0x1::royalty::Self; @@ -610,9 +647,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test resolve local function when function with the same name imported`() = checkByCode(""" + fun `test resolve local function when function with the same name imported`() = checkByCode( + """ module 0x1::royalty { public fun royalty() {} } @@ -625,9 +664,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test resolve spec fun defined in module spec`() = checkByCode(""" + fun `test resolve spec fun defined in module spec`() = checkByCode( + """ module 0x1::m { } spec 0x1::m { @@ -643,9 +684,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test verify_only function accessible in spec`() = checkByCode(""" + fun `test verify_only function accessible in spec`() = checkByCode( + """ module 0x1::m { #[verify_only] fun call(): u8 { 1 } @@ -656,9 +699,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test verify_only function accessible in other verify_only function`() = checkByCode(""" + fun `test verify_only function accessible in other verify_only function`() = checkByCode( + """ module 0x1::m { #[verify_only] fun call(): u8 { 1 } @@ -669,9 +714,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test verify_only not accessible in the regular code`() = checkByCode(""" + fun `test verify_only not accessible in the regular code`() = checkByCode( + """ module 0x1::m { #[verify_only] fun call(): u8 { 1 } @@ -680,9 +727,11 @@ module 0x1::mod { //^ unresolved } } - """) + """ + ) - fun `test cannot resolve non-test-only import into test-only item`() = checkByCode(""" + fun `test cannot resolve non-test-only import into test-only item`() = checkByCode( + """ module 0x1::m { #[test_only] public fun call() {} @@ -691,9 +740,11 @@ module 0x1::mod { use 0x1::m::call; //^ unresolved } - """) + """ + ) - fun `test resolve local test-only import into test-only item`() = checkByCode(""" + fun `test resolve local test-only import into test-only item`() = checkByCode( + """ module 0x1::m { #[test_only] public fun call() {} @@ -706,9 +757,11 @@ module 0x1::mod { //^ } } - """) + """ + ) - fun `test resolve use item spec fun defined in module spec verify scope always available`() = checkByCode(""" + fun `test resolve use item spec fun defined in module spec verify scope always available`() = checkByCode( + """ module 0x1::m { } spec 0x1::m { @@ -724,5 +777,58 @@ module 0x1::mod { spec_sip_hash(); 1 } } - """) + """ + ) + + fun `test resolve function to another module with module alias`() = checkByCode( + """ + module 0x1::m { + public fun call() {} + //X + } + + module 0x1::main { + use 0x1::m as m_alias; + + fun main() { + m_alias::call(); + //^ + } + } + """ + ) + + fun `test resolve function to another module with local module alias`() = checkByCode( + """ + module 0x1::m { + public fun call() {} + //X + } + + module 0x1::main { + fun main() { + use 0x1::m as m_alias; + m_alias::call(); + //^ + } + } + """ + ) + + fun `test function with module alias cannot use original module name`() = checkByCode( + """ + module 0x1::m { + public fun call() {} + } + + module 0x1::main { + use 0x1::m as m_alias; + + fun main() { + m::call(); + //^ unresolved + } + } + """ + ) } From 55890c6cf99dc2b8f5c5182d55793bf2a6538d4a Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Fri, 12 Jul 2024 19:18:07 +0300 Subject: [PATCH 04/43] UseSpeck with path in parser --- src/main/grammars/MoveParser.bnf | 31 ++- .../intentions/RemoveCurlyBracesIntention.kt | 1 + .../org/move/ide/utils/imports/ImportUtils.kt | 1 + .../org/move/lang/core/psi/MvImportsOwner.kt | 4 +- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 4 + .../move/lang/parser/complete/attributes.txt | 9 +- .../move/lang/parser/complete/index_expr.txt | 9 +- .../org/move/lang/parser/complete/use.move | 8 +- .../org/move/lang/parser/complete/use.txt | 212 ++++++++++----- .../org/move/lang/parser/complete/vectors.txt | 9 +- .../move/lang/parser/partial/module_uses.txt | 243 +++++++++--------- .../lang/parser/partial/top_level_items.txt | 122 +++++---- 12 files changed, 392 insertions(+), 261 deletions(-) diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 126300858..8a509bfad 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -255,6 +255,7 @@ private Item_first ::= use | public | native | fun | CONST_KW | STRUCT_KW | spec private Item_recover ::= !('}' | <> | Item_first) private ModuleItem_item ::= UseStmt +// | UseStmt | FriendDecl | StructItem | FunctionItem @@ -517,10 +518,33 @@ FriendDecl ::= Attr* friend FQModuleRef ';' implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] } -UseStmt ::= Attr* use (ItemUseSpeck | ModuleUseSpeck) ';' { +UseStmt2 ::= Attr* use (ItemUseSpeck | ModuleUseSpeck) ';' { pin = "use" implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] } + +UseStmt ::= Attr* use UseSpeck ';' { + pin = "use" + extends = Stmt + implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] +} +UseSpeck ::= PathWithoutTypeArgs ( UseAlias | ('::' UseSpeckProjection) )? + +private UseSpeckProjection ::= UseGroup + +UseGroup ::= '{' UseSpeck_with_recover* '}' +{ + pin = 1 +} +// todo: +private PathWithoutTypeArgs ::= PathImpl + +private UseSpeck_with_recover ::= !'}' UseSpeck (','|&'}') { + pin = 1 + recoverWhile = UseSpeck_recover +} +private UseSpeck_recover ::= !('}' | '{' | IDENTIFIER | '::' ) + ModuleUseSpeck ::= (AddressRef !'::') | FQModuleRef UseAlias? { name = "qual path to module" @@ -1075,8 +1099,9 @@ PathStart ::= ((PathAddress &'::') | PathIdent) TypeArgumentList? name = "path" elementType = Path } -left PathSegment ::= '::' PathIdent TypeArgumentList? { - pin = 1 +// negation for UseSpeck +left PathSegment ::= '::' !'{' PathIdent TypeArgumentList? { + pin = 2 elementType = Path } diff --git a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt index 5f79728ed..7fec55559 100644 --- a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt +++ b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt @@ -7,6 +7,7 @@ import org.move.lang.core.psi.MvUseItemGroup import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.ancestorStrict import org.move.lang.core.psi.ext.endOffset +import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.psi.ext.startOffset import org.move.lang.core.psi.psiFactory diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index d933b52a4..c9e09fb60 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -3,6 +3,7 @@ package org.move.ide.utils.imports import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.childrenOfType import org.move.lang.core.psi.ext.hasTestOnlyAttr +import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.psi.ext.names import org.move.lang.core.types.ItemQualName import org.move.openapiext.checkWriteAccessAllowed diff --git a/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt index 0d32486aa..ea750ad7d 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt @@ -3,9 +3,11 @@ package org.move.lang.core.psi import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache import org.move.lang.core.psi.ext.addressRef import org.move.lang.core.psi.ext.isSelf +import org.move.lang.core.psi.ext.itemUseSpeck +import org.move.lang.core.psi.ext.moduleUseSpeck interface MvImportsOwner: MvElement { - val useStmtList: List + val useStmtList: List get() = emptyList() } fun MvImportsOwner.items(): Sequence { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index f6d635318..221d18b7b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -1,9 +1,13 @@ package org.move.lang.core.psi.ext +import com.intellij.lang.ASTNode import org.move.ide.inspections.imports.declaredItemScope import org.move.lang.core.psi.* import org.move.stdext.wrapWithList +val MvUseStmt.moduleUseSpeck: MvModuleUseSpeck? get() = null +val MvUseStmt.itemUseSpeck: MvItemUseSpeck? get() = null + val MvUseStmt.addressRef: MvAddressRef? get() { val moduleUseSpeck = this.moduleUseSpeck 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 1264a7d63..ba7abfed8 100644 --- a/src/test/resources/org/move/lang/parser/complete/attributes.txt +++ b/src/test/resources/org/move/lang/parser/complete/attributes.txt @@ -27,10 +27,11 @@ FILE PsiWhiteSpace('\n ') PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('SomeOtherModule') PsiElement(;)(';') diff --git a/src/test/resources/org/move/lang/parser/complete/index_expr.txt b/src/test/resources/org/move/lang/parser/complete/index_expr.txt index 6dd5453f9..6935a2ef5 100644 --- a/src/test/resources/org/move/lang/parser/complete/index_expr.txt +++ b/src/test/resources/org/move/lang/parser/complete/index_expr.txt @@ -363,10 +363,11 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x42') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x42') PsiElement(::)('::') PsiElement(IDENTIFIER)('test') PsiElement(;)(';') diff --git a/src/test/resources/org/move/lang/parser/complete/use.move b/src/test/resources/org/move/lang/parser/complete/use.move index 6adaac68c..4283d196b 100644 --- a/src/test/resources/org/move/lang/parser/complete/use.move +++ b/src/test/resources/org/move/lang/parser/complete/use.move @@ -1,10 +1,14 @@ -script { +module 0x1::m { use 0x1::Transaction; use 0x1::Transaction::Instance; use 0x1::Transaction::{}; use 0x1::Transaction::{Self, EventHandle}; use 0x1::Transaction::foo as bar; - use 0x1::Transaction::{foo, foo as bar}; + use 0x1::Transaction::{foo, foo as bar, foo::Handle}; + + use liquidswap::Transaction::call; + use liquidswap::Transaction::call::Handle; + use liquidswap::Transaction::call::{Handle1, Handle2}; fun main() { use 0x1::Transaction; diff --git a/src/test/resources/org/move/lang/parser/complete/use.txt b/src/test/resources/org/move/lang/parser/complete/use.txt index 58ade02be..100df47b2 100644 --- a/src/test/resources/org/move/lang/parser/complete/use.txt +++ b/src/test/resources/org/move/lang/parser/complete/use.txt @@ -1,17 +1,23 @@ FILE - MvScriptImpl(SCRIPT) - PsiElement(script_kw)('script') + MvModuleImpl(MODULE) + PsiElement(module)('module') PsiWhiteSpace(' ') - MvScriptBlockImpl(SCRIPT_BLOCK) + MvAddressRefImpl(ADDRESS_REF) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('m') + PsiWhiteSpace(' ') + MvModuleBlockImpl(MODULE_BLOCK) PsiElement({)('{') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(;)(';') @@ -19,28 +25,30 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('Instance') PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') PsiElement(})('}') PsiElement(;)(';') @@ -48,66 +56,138 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('Self') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Self') PsiElement(,)(',') PsiWhiteSpace(' ') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('EventHandle') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('EventHandle') PsiElement(})('}') PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + MvUseAliasImpl(USE_ALIAS) + PsiElement(as)('as') PsiWhiteSpace(' ') - MvUseAliasImpl(USE_ALIAS) - PsiElement(as)('as') - PsiWhiteSpace(' ') - PsiElement(IDENTIFIER)('bar') + PsiElement(IDENTIFIER)('bar') PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('foo') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('foo') PsiElement(,)(',') PsiWhiteSpace(' ') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('foo') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('foo') PsiWhiteSpace(' ') MvUseAliasImpl(USE_ALIAS) PsiElement(as)('as') PsiWhiteSpace(' ') PsiElement(IDENTIFIER)('bar') + PsiElement(,)(',') + PsiWhiteSpace(' ') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('foo') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Handle') + PsiElement(})('}') + PsiElement(;)(';') + PsiWhiteSpace('\n\n ') + MvUseStmtImpl(USE_STMT) + PsiElement(use)('use') + PsiWhiteSpace(' ') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('liquidswap') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvUseStmtImpl(USE_STMT) + PsiElement(use)('use') + PsiWhiteSpace(' ') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('liquidswap') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Handle') + PsiElement(;)(';') + PsiWhiteSpace('\n ') + MvUseStmtImpl(USE_STMT) + PsiElement(use)('use') + PsiWhiteSpace(' ') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('liquidswap') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('call') + PsiElement(::)('::') + MvUseGroupImpl(USE_GROUP) + PsiElement({)('{') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Handle1') + PsiElement(,)(',') + PsiWhiteSpace(' ') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Handle2') PsiElement(})('}') PsiElement(;)(';') PsiWhiteSpace('\n\n ') @@ -125,10 +205,11 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(;)(';') @@ -149,10 +230,11 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(;)(';') @@ -180,10 +262,11 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x2') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x2') PsiElement(::)('::') PsiElement(IDENTIFIER)('Mango') PsiElement(;)(';') @@ -210,10 +293,11 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(;)(';') diff --git a/src/test/resources/org/move/lang/parser/complete/vectors.txt b/src/test/resources/org/move/lang/parser/complete/vectors.txt index 4bee53d3f..37492c759 100644 --- a/src/test/resources/org/move/lang/parser/complete/vectors.txt +++ b/src/test/resources/org/move/lang/parser/complete/vectors.txt @@ -13,11 +13,10 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('std') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('std') PsiElement(::)('::') PsiElement(IDENTIFIER)('vector') PsiElement(;)(';') diff --git a/src/test/resources/org/move/lang/parser/partial/module_uses.txt b/src/test/resources/org/move/lang/parser/partial/module_uses.txt index b38731532..640a77f0a 100644 --- a/src/test/resources/org/move/lang/parser/partial/module_uses.txt +++ b/src/test/resources/org/move/lang/parser/partial/module_uses.txt @@ -12,211 +12,209 @@ FILE PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') - PsiErrorElement:
or expected, got 'use' + PsiErrorElement: expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') - PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') - PsiErrorElement:'::' or ';' expected, got 'use' - + PsiWhiteSpace(' ') + PsiElement(DIEM_ADDRESS)('0x0') + PsiErrorElement:'::' expected, got 'use' + PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Std') - PsiErrorElement:'::' or ';' expected, got 'use' + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Std') + PsiErrorElement:'::', ';', or as expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - MvNamedAddressImpl(NAMED_ADDRESS) - PsiElement(IDENTIFIER)('Std') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('Std') PsiElement(::)('::') - PsiErrorElement:'::' or IDENTIFIER expected, got 'use' + PsiErrorElement:< or IDENTIFIER expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') - PsiErrorElement:'::' or IDENTIFIER expected, got 'use' + PsiErrorElement:< or IDENTIFIER expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') - PsiErrorElement:'::', ';' or as expected, got 'use' + PsiErrorElement:'::', ';', or as expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - PsiErrorElement: or '{' expected, got 'use' - + PsiErrorElement:< or IDENTIFIER expected, got 'use' + PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - PsiErrorElement: or '{' expected, got ';' - + PsiErrorElement:< or IDENTIFIER expected, got ';' + PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('create') - PsiErrorElement:';' or as expected, got 'use' + PsiErrorElement:'::', ';', or as expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - PsiErrorElement: expected, got 'use' + PsiErrorElement: expected, got 'use' - PsiWhiteSpace('\n ') - MvUseStmtImpl(USE_STMT) - PsiElement(use)('use') - PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) - PsiElement({)('{') - PsiErrorElement:'}' expected, got ';' - - PsiElement(;)(';') - PsiWhiteSpace('\n ') - MvUseStmtImpl(USE_STMT) - PsiElement(use)('use') - PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') - PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) - PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('create') - PsiElement(,)(',') - PsiErrorElement: expected, got 'use' + PsiWhiteSpace('\n ') + PsiElement(use)('use') + PsiWhiteSpace(' ') + PsiElement(DIEM_ADDRESS)('0x0') + PsiErrorElement: expected, got '::' + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') + PsiElement(::)('::') + PsiElement({)('{') + PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('create') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('create') PsiElement(,)(',') - PsiErrorElement:'}' expected, got ';' + PsiWhiteSpace('\n ') + PsiErrorElement:'use' unexpected + PsiElement(use)('use') + PsiWhiteSpace(' ') + PsiElement(DIEM_ADDRESS)('0x0') + PsiErrorElement: expected, got '::' - PsiElement(;)(';') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') + PsiElement(::)('::') + PsiElement({)('{') + PsiElement(IDENTIFIER)('create') + PsiElement(,)(',') + PsiElement(;)(';') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('create') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('create') PsiElement(,)(',') PsiWhiteSpace(' ') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('modify') - PsiElement(,)(',') - PsiErrorElement: expected, got ',' - + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('modify') PsiElement(,)(',') + PsiErrorElement:',' unexpected + PsiElement(,)(',') PsiElement(})('}') PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - MvUseItemGroupImpl(USE_ITEM_GROUP) + MvUseGroupImpl(USE_GROUP) PsiElement({)('{') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('create') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('create') PsiWhiteSpace(' ') MvUseAliasImpl(USE_ALIAS) PsiElement(as)('as') @@ -225,8 +223,9 @@ FILE PsiWhiteSpace(' ') PsiElement(,)(',') PsiWhiteSpace(' ') - MvUseItemImpl(USE_ITEM) - PsiElement(IDENTIFIER)('update') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('update') PsiElement(})('}') PsiElement(;)(';') PsiWhiteSpace('\n\n ') @@ -242,4 +241,4 @@ FILE PsiElement({)('{') PsiElement(})('}') PsiWhiteSpace('\n') - PsiElement(})('}') + PsiElement(})('}') \ No newline at end of file diff --git a/src/test/resources/org/move/lang/parser/partial/top_level_items.txt b/src/test/resources/org/move/lang/parser/partial/top_level_items.txt index b29aa8325..e9ed5c874 100644 --- a/src/test/resources/org/move/lang/parser/partial/top_level_items.txt +++ b/src/test/resources/org/move/lang/parser/partial/top_level_items.txt @@ -53,7 +53,7 @@ FILE PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') - PsiErrorElement:
or expected, got 'fun' + PsiErrorElement: expected, got 'fun' PsiWhiteSpace('\n ') MvFunctionImpl(FUNCTION) @@ -79,12 +79,13 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') - PsiErrorElement:'::' or IDENTIFIER expected, got '}' + PsiErrorElement:< or IDENTIFIER expected, got '}' PsiWhiteSpace('\n') PsiElement(})('}') @@ -98,12 +99,13 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') - PsiErrorElement:'::' or IDENTIFIER expected, got 'fun' + PsiErrorElement:< or IDENTIFIER expected, got 'fun' PsiWhiteSpace('\n\n ') MvFunctionImpl(FUNCTION) @@ -120,12 +122,13 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvModuleUseSpeckImpl(MODULE_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') PsiElement(::)('::') - PsiErrorElement:'::' or IDENTIFIER expected, got '}' + PsiErrorElement:< or IDENTIFIER expected, got '}' PsiWhiteSpace('\n ') PsiElement(})('}') @@ -141,15 +144,17 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - PsiErrorElement: or '{' expected, got 'fun' - + PsiErrorElement:< or IDENTIFIER expected, got 'fun' + PsiWhiteSpace('\n\n ') MvFunctionImpl(FUNCTION) PsiElement(fun)('fun') @@ -174,16 +179,17 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('create') - PsiErrorElement:';' or as expected, got 'fun' + PsiErrorElement:'::', ';', or as expected, got 'fun' PsiWhiteSpace('\n\n ') MvFunctionImpl(FUNCTION) @@ -209,15 +215,17 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - PsiErrorElement: or '{' expected, got ';' - + PsiErrorElement:< or IDENTIFIER expected, got ';' + PsiElement(;)(';') PsiWhiteSpace('\n\n ') MvFunctionImpl(FUNCTION) @@ -243,29 +251,31 @@ FILE MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('create') - PsiErrorElement:';' or as expected, got 'use' + PsiErrorElement:'::', ';', or as expected, got 'use' PsiWhiteSpace('\n ') MvUseStmtImpl(USE_STMT) PsiElement(use)('use') PsiWhiteSpace(' ') - MvItemUseSpeckImpl(ITEM_USE_SPECK) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x0') + MvUseSpeckImpl(USE_SPECK) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x0') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('Transaction') PsiElement(::)('::') - PsiElement(IDENTIFIER)('Transaction') - PsiElement(::)('::') - MvUseItemImpl(USE_ITEM) PsiElement(IDENTIFIER)('modify') PsiElement(;)(';') PsiWhiteSpace('\n\n ') @@ -283,4 +293,4 @@ FILE PsiWhiteSpace('\n') PsiElement(})('}') PsiWhiteSpace('\n\n') - PsiComment(BLOCK_COMMENT)('/*') + PsiComment(BLOCK_COMMENT)('/*') \ No newline at end of file From edede42cb3f342e81af6758184aa64152aed4ffe Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Sun, 14 Jul 2024 19:14:25 +0300 Subject: [PATCH 05/43] before shadowing --- gradle.properties | 2 +- src/main/grammars/MoveParser.bnf | 26 +- .../RedundantQualifiedPathInspection.kt | 1 + .../ide/inspections/imports/ImportAnalyzer.kt | 12 +- .../move/ide/refactoring/MvImportOptimizer.kt | 6 +- .../MvStructureViewTreeElement.kt | 2 +- .../org/move/ide/utils/imports/ImportUtils.kt | 11 +- .../org/move/lang/core/psi/MvElement.kt | 2 +- .../move/lang/core/psi/ext/MvItemElement.kt | 5 + .../MvItemsOwner.kt} | 40 +- .../org/move/lang/core/psi/ext/MvPath.kt | 91 ++- .../org/move/lang/core/psi/ext/MvUseAlias.kt | 3 + .../org/move/lang/core/psi/ext/MvUseGroup.kt | 6 + .../org/move/lang/core/psi/ext/MvUseSpeck.kt | 11 + .../lang/core/psi/ext/MvVisibilityOwner.kt | 53 ++ .../lang/core/resolve/LexicalDeclarations.kt | 10 +- .../move/lang/core/resolve/NameResolution.kt | 14 +- .../org/move/lang/core/resolve/Processors.kt | 516 ++++++++++++++++++ .../core/resolve/ref/MovePathReferenceImpl.kt | 12 +- .../lang/core/resolve/ref/MoveReference.kt | 25 +- .../core/resolve/ref/MoveReferenceBase.kt | 2 +- .../core/resolve/ref/MoveReferenceElement.kt | 4 + .../move/lang/core/resolve/ref/Namespace.kt | 13 +- .../move/lang/core/resolve2/ItemResolution.kt | 53 ++ .../core/resolve2/LexicalDeclarations2.kt | 309 +++++++++++ .../move/lang/core/resolve2/ModuleItems.kt | 88 +++ .../lang/core/resolve2/NameResolution2.kt | 74 +++ .../move/lang/core/resolve2/Visibility2.kt | 24 + .../core/resolve2/ref/Path2ReferenceImpl.kt | 233 ++++++++ .../core/resolve2/ref/RsPathResolveResult.kt | 19 + .../move/lang/core/resolve2/util/PathUtil.kt | 47 ++ .../lang/core/types/infer/InferenceContext.kt | 25 + src/main/kotlin/org/move/openapiext/utils.kt | 20 +- .../move/lang/resolve/ResolveFunctionTest.kt | 101 +++- .../move/lang/resolve/ResolveModulesTest.kt | 62 ++- 35 files changed, 1803 insertions(+), 119 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvItemElement.kt rename src/main/kotlin/org/move/lang/core/psi/{MvImportsOwner.kt => ext/MvItemsOwner.kt} (68%) create mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt create mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt create mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve/Processors.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveResult.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt diff --git a/gradle.properties b/gradle.properties index c1a5c37d8..89340bddc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,4 @@ jbrVersion=17.0.7b1000.6 propertiesPluginEnvironmentNameProperty=shortPlatformVersion # properties files # pass ORG_GRADLE_PROJECT_shortPlatformVersion environment variable to overwrite -shortPlatformVersion=233 +shortPlatformVersion=241 diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 8a509bfad..686db8877 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -185,7 +185,7 @@ Script ::= SCRIPT_KW ScriptBlock { pin = 1 } ScriptBlock ::= '{' ScriptBlockItems '}' { pin = 1 implements = [ - "org.move.lang.core.psi.MvImportsOwner" + "org.move.lang.core.psi.ext.MvItemsOwner" ] } private ScriptBlockItems ::= ScriptItem* @@ -241,7 +241,7 @@ ModuleBlock ::= '{' ModuleBlockItems '}' { pin = 1 implements = [ - "org.move.lang.core.psi.MvImportsOwner" + "org.move.lang.core.psi.ext.MvItemsOwner" ] } private ModuleBlockItems ::= ModuleItem* @@ -270,8 +270,7 @@ Const ::= Attr* CONST_KW IDENTIFIER TypeAnnotation Initializer ';' pin = "CONST_KW" implements = [ "org.move.lang.core.psi.MvQualNamedElement" - "org.move.lang.core.psi.MvNameIdentifierOwner" - "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" + "org.move.lang.core.psi.ext.MvItemElement" "org.move.lang.core.psi.MvTypeAnnotationOwner" ] mixin = "org.move.lang.core.psi.ext.MvConstMixin" @@ -356,9 +355,8 @@ fake Struct ::= Attr* native? STRUCT_KW IDENTIFIER? TypeParameterList? Abilities { implements = [ "org.move.lang.core.psi.MvQualNamedElement" - "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" "org.move.lang.core.psi.MvTypeParametersOwner" - "org.move.lang.core.psi.MvNameIdentifierOwner" + "org.move.lang.core.psi.ext.MvItemElement" ] mixin = "org.move.lang.core.psi.ext.MvStructMixin" stubClass = "org.move.lang.core.stubs.MvStructStub" @@ -390,6 +388,7 @@ fake Function ::= Attr* native? VisibilityModifier? entry? inline? implements = [ "org.move.lang.core.psi.MvQualNamedElement" "org.move.lang.core.psi.MvFunctionLike" + "org.move.lang.core.psi.ext.MvItemElement" "org.move.lang.core.types.infer.MvInferenceContextOwner" "org.move.lang.core.psi.MvModificationTrackerOwner" ] @@ -769,7 +768,7 @@ CodeBlock ::= '{' CodeBlock_items '}' { pin = 1 implements = [ - "org.move.lang.core.psi.MvImportsOwner" + "org.move.lang.core.psi.ext.MvItemsOwner" "org.move.lang.core.psi.AnyBlock" ] mixin = "org.move.lang.core.psi.ext.MvCodeBlockMixin" @@ -1086,7 +1085,7 @@ RefExpr ::= PathImpl !'{' { fake Path ::= (Path '::')? (PathIdent | PathAddress) TypeArgumentList? { implements = [ - "org.move.lang.core.resolve.ref.MvPathReferenceElement" + "org.move.lang.core.resolve.ref.MvNameAccessChainReferenceElement" "org.move.lang.core.psi.ext.MvMethodOrPath" ] mixin = "org.move.lang.core.psi.ext.MvPathMixin" @@ -1202,7 +1201,7 @@ ModuleSpecBlock ::= '{' ModuleSpecBlock_item_with_recover* '}' { pin = 1 implements = [ - "org.move.lang.core.psi.MvImportsOwner" + "org.move.lang.core.psi.ext.MvItemsOwner" "org.move.lang.core.psi.ScopeMslOnlyElement" "org.move.lang.core.psi.AnyBlock" ] @@ -1282,18 +1281,19 @@ ItemSpecRef ::= IDENTIFIER mixin = "org.move.lang.core.psi.ext.MvItemSpecRefMixin" } -Schema ::= (spec schema) IDENTIFIER TypeParameterList? <> { - pin = 1 +Schema ::= Attr* (spec schema) IDENTIFIER TypeParameterList? <> { + pin = 2 implements = [ "org.move.lang.core.psi.MvTypeParametersOwner" "org.move.lang.core.psi.MvQualNamedElement" - "org.move.lang.core.psi.MvNameIdentifierOwner" "org.move.lang.core.types.infer.MvInferenceContextOwner" "org.move.lang.core.psi.ScopeMslOnlyElement" + "org.move.lang.core.psi.ext.MvItemElement" ] mixin = "org.move.lang.core.psi.ext.MvSchemaMixin" stubClass = "org.move.lang.core.stubs.MvSchemaStub" elementTypeFactory = "org.move.lang.core.stubs.StubsKt.factory" + hooks = [ leftBinder = "ADJACENT_LINE_COMMENTS" ] } ItemSpecBlockExpr ::= spec <> { @@ -1306,7 +1306,7 @@ SpecCodeBlock ::= '{' ItemSpecBlock_items '}' { pin = 1 implements = [ - "org.move.lang.core.psi.MvImportsOwner" + "org.move.lang.core.psi.ext.MvItemsOwner" "org.move.lang.core.psi.AnyBlock" "org.move.lang.core.psi.MslOnlyElement" ] diff --git a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt b/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt index d923a8e1c..64dc484ae 100644 --- a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt @@ -7,6 +7,7 @@ import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.shortestPathText class RedundantQualifiedPathInspection : MvLocalInspectionTool() { diff --git a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt index e9ae838a0..84388f6d6 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt @@ -7,7 +7,7 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.stdext.chain -private val MvImportsOwner.useSpecks: List +private val MvItemsOwner.useSpecks: List get() { val specks = mutableListOf() for (stmt in this.useStmtList) { @@ -16,7 +16,7 @@ private val MvImportsOwner.useSpecks: List return specks } -private val MvImportsOwner.importOwnerWithSiblings: List +private val MvItemsOwner.importOwnerWithSiblings: List get() { return when (this) { is MvModuleBlock -> { @@ -44,12 +44,12 @@ class ImportAnalyzer(val holder: ProblemsHolder): MvVisitor() { override fun visitModuleSpecBlock(o: MvModuleSpecBlock) = analyzeImportsOwner(o) - fun analyzeImportsOwner(importsOwner: MvImportsOwner) { + fun analyzeImportsOwner(importsOwner: MvItemsOwner) { analyzeUseStmtsForScope(importsOwner, NamedItemScope.TEST) analyzeUseStmtsForScope(importsOwner, NamedItemScope.MAIN) } - private fun analyzeUseStmtsForScope(rootImportOwner: MvImportsOwner, itemScope: NamedItemScope) { + private fun analyzeUseStmtsForScope(rootImportOwner: MvItemsOwner, itemScope: NamedItemScope) { val allSpecksHit = mutableSetOf() val rootImportOwnerWithSiblings = rootImportOwner.importOwnerWithSiblings val reachablePaths = @@ -58,7 +58,7 @@ class ImportAnalyzer(val holder: ProblemsHolder): MvVisitor() { .mapNotNull { path -> path.pathStart?.let { Pair(path, it) } } .filter { it.second.usageScope == itemScope } for ((path, start) in reachablePaths) { - for (importOwner in path.ancestorsOfType()) { + for (importOwner in path.ancestorsOfType()) { val useSpecks = importOwner.importOwnerWithSiblings .flatMap { it.useSpecks } @@ -85,7 +85,7 @@ class ImportAnalyzer(val holder: ProblemsHolder): MvVisitor() { } // includes self - val reachableImportOwners = rootImportOwner.descendantsOfTypeOrSelf() + val reachableImportOwners = rootImportOwner.descendantsOfTypeOrSelf() for (importsOwner in reachableImportOwners) { val scopeUseStmts = importsOwner.useStmtList.filter { it.declaredItemScope == itemScope } for (useStmt in scopeUseStmts) { diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index 7b36293b0..74453fc8e 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -30,7 +30,7 @@ class MvImportOptimizer : ImportOptimizer { val importVisitor = ImportAnalyzer(holder) object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { - if (element is MvImportsOwner) { + if (element is MvItemsOwner) { importVisitor.analyzeImportsOwner(element) } else { super.visitElement(element) @@ -77,7 +77,7 @@ class MvImportOptimizer : ImportOptimizer { } } - private fun mergeItemGroups(useStmtOwner: MvImportsOwner) { + private fun mergeItemGroups(useStmtOwner: MvItemsOwner) { val psiFactory = useStmtOwner.project.psiFactory val leftBrace = useStmtOwner.findFirstChildByType(L_BRACE) ?: return @@ -130,7 +130,7 @@ class MvImportOptimizer : ImportOptimizer { useSpeck.replace(newUseSpeck) } - private fun reorderUseStmtsIntoGroups(useScope: MvImportsOwner) { + private fun reorderUseStmtsIntoGroups(useScope: MvItemsOwner) { val useStmts = useScope.useStmtList val first = useScope.childrenOfType() .firstOrNull { it !is MvAttr && it !is PsiComment } ?: return diff --git a/src/main/kotlin/org/move/ide/structureView/MvStructureViewTreeElement.kt b/src/main/kotlin/org/move/ide/structureView/MvStructureViewTreeElement.kt index 1ab179473..14b48bca5 100644 --- a/src/main/kotlin/org/move/ide/structureView/MvStructureViewTreeElement.kt +++ b/src/main/kotlin/org/move/ide/structureView/MvStructureViewTreeElement.kt @@ -16,7 +16,7 @@ class MvStructureViewTreeElement(val element: NavigatablePsiElement): StructureV val isPublic: Boolean get() { return when (element) { - is MvFunction -> element.visibility != FunctionVisibility.PRIVATE + is MvFunction -> element.isPublic is MvConst -> false else -> true } diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index c9e09fb60..a6ec9ed27 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -1,10 +1,7 @@ package org.move.ide.utils.imports import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.childrenOfType -import org.move.lang.core.psi.ext.hasTestOnlyAttr -import org.move.lang.core.psi.ext.itemUseSpeck -import org.move.lang.core.psi.ext.names +import org.move.lang.core.psi.ext.* import org.move.lang.core.types.ItemQualName import org.move.openapiext.checkWriteAccessAllowed @@ -23,7 +20,7 @@ fun ImportCandidate.import(context: MvElement) { insertionScope.insertUseItem(qualName, insertTestOnly) } -private fun MvImportsOwner.insertUseItem(usePath: ItemQualName, testOnly: Boolean) { +private fun MvItemsOwner.insertUseItem(usePath: ItemQualName, testOnly: Boolean) { if (tryInsertingIntoExistingUseStmt(this, usePath, testOnly)) return @@ -42,7 +39,7 @@ private fun MvImportsOwner.insertUseItem(usePath: ItemQualName, testOnly: Boolea } private fun tryInsertingIntoExistingUseStmt( - mod: MvImportsOwner, + mod: MvItemsOwner, usePath: ItemQualName, testOnly: Boolean ): Boolean { @@ -97,7 +94,7 @@ private fun tryGroupWithItemSpeck( private val List.lastElement: T? get() = maxByOrNull { it.textOffset } -private fun insertUseStmtAtTheCorrectLocation(mod: MvImportsOwner, useStmt: MvUseStmt): Boolean { +private fun insertUseStmtAtTheCorrectLocation(mod: MvItemsOwner, useStmt: MvUseStmt): Boolean { val psiFactory = MvPsiFactory(mod.project) val newline = psiFactory.createNewline() val useStmts = mod.childrenOfType().map(::UseStmtWrapper) diff --git a/src/main/kotlin/org/move/lang/core/psi/MvElement.kt b/src/main/kotlin/org/move/lang/core/psi/MvElement.kt index 7e7c4e4a8..c807607b8 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvElement.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvElement.kt @@ -37,7 +37,7 @@ val MvElement.containingModule: MvModule? get() = ancestorStrict() val MvElement.containingModuleSpec: MvModuleSpec? get() = ancestorStrict() -val MvElement.containingImportsOwner get() = ancestorOrSelf() +val MvElement.containingImportsOwner get() = ancestorOrSelf() //val MvElement.containingModuleOrScript: MvElement? // get() { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemElement.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemElement.kt new file mode 100644 index 000000000..64a4b9329 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemElement.kt @@ -0,0 +1,5 @@ +package org.move.lang.core.psi.ext + +import org.move.lang.core.psi.MvNameIdentifierOwner + +interface MvItemElement: MvVisibilityOwner, MvDocAndAttributeOwner, MvNameIdentifierOwner \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt similarity index 68% rename from src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt rename to src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index ea750ad7d..8e5309fb6 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvImportsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -1,22 +1,26 @@ -package org.move.lang.core.psi +package org.move.lang.core.psi.ext import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache -import org.move.lang.core.psi.ext.addressRef -import org.move.lang.core.psi.ext.isSelf -import org.move.lang.core.psi.ext.itemUseSpeck -import org.move.lang.core.psi.ext.moduleUseSpeck +import org.move.lang.core.psi.* -interface MvImportsOwner: MvElement { +interface MvItemsOwner: MvElement { val useStmtList: List get() = emptyList() } -fun MvImportsOwner.items(): Sequence { +fun MvItemsOwner.items(): Sequence { return generateSequence(firstChild) { it.nextSibling } .filterIsInstance() .filter { it !is MvAttr } } -fun MvImportsOwner.moduleUseItems(): List = +val MvItemsOwner.visibleItems: Sequence + get() { + return this.items() + .filterIsInstance() + .filterNot { (it as? MvFunction)?.hasTestAttr ?: false } + } + +fun MvItemsOwner.moduleUseItems(): List = listOf( moduleUseSpecksNoAliases(), moduleUseSpecksAliases(), @@ -24,21 +28,21 @@ fun MvImportsOwner.moduleUseItems(): List = selfModuleUseItemAliases(), ).flatten() -fun MvImportsOwner.moduleUseSpecksNoAliases(): List = +fun MvItemsOwner.moduleUseSpecksNoAliases(): List = moduleUseSpecks() .filter { it.useAlias == null } -fun MvImportsOwner.moduleUseSpecksAliases(): List = +fun MvItemsOwner.moduleUseSpecksAliases(): List = moduleUseSpecks().mapNotNull { it.useAlias } -private fun MvImportsOwner.moduleUseSpecks(): List { +private fun MvItemsOwner.moduleUseSpecks(): List { return getProjectPsiDependentCache(this) { useStmtList.mapNotNull { it.moduleUseSpeck } } } -fun MvImportsOwner.psiUseItems(): List { +fun MvItemsOwner.psiUseItems(): List { return getProjectPsiDependentCache(this) { importsOwner -> importsOwner .useStmtList @@ -54,32 +58,32 @@ fun MvImportsOwner.psiUseItems(): List { } } -fun MvImportsOwner.allUseItems(): List = +fun MvItemsOwner.allUseItems(): List = listOf( useItemsNoAliases(), useItemsAliases(), ).flatten() -fun MvImportsOwner.useItemsNoAliases(): List = +fun MvItemsOwner.useItemsNoAliases(): List = psiUseItems() .filter { !it.isSelf } .filter { it.useAlias == null } -fun MvImportsOwner.useItemsAliases(): List = +fun MvItemsOwner.useItemsAliases(): List = psiUseItems() .filter { !it.isSelf } .mapNotNull { it.useAlias } -fun MvImportsOwner.selfModuleUseItemNoAliases(): List = +fun MvItemsOwner.selfModuleUseItemNoAliases(): List = psiUseItems() .filter { it.isSelf && it.useAlias == null } -fun MvImportsOwner.selfModuleUseItemAliases(): List = +fun MvItemsOwner.selfModuleUseItemAliases(): List = psiUseItems() .filter { it.isSelf } .mapNotNull { it.useAlias } -fun MvImportsOwner.shortestPathText(item: MvNamedElement): String? { +fun MvItemsOwner.shortestPathText(item: MvNamedElement): String? { val itemName = item.name ?: return null // local if (this == item.containingImportsOwner) return itemName diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 171a53294..b1e6843c0 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -6,10 +6,26 @@ import org.move.ide.annotator.BUILTIN_TYPE_IDENTIFIERS import org.move.ide.annotator.PRIMITIVE_TYPE_IDENTIFIERS import org.move.ide.annotator.SPEC_ONLY_PRIMITIVE_TYPES import org.move.lang.core.psi.* -import org.move.lang.core.resolve.ref.MvPathReference -import org.move.lang.core.resolve.ref.MvPathReferenceImpl +import org.move.lang.core.resolve.ref.MvPath2Reference import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.Path2ReferenceImpl +import java.util.* + +/** For `Foo::bar::baz::quux` path returns `Foo` */ +tailrec fun T.basePath(): T { + @Suppress("UNCHECKED_CAST") + val qualifier = path as T? + return if (qualifier === null) this else qualifier.basePath() +} + +/** For `Foo::bar` in `Foo::bar::baz::quux` returns `Foo::bar::baz::quux` */ +tailrec fun MvPath.rootPath(): MvPath { + // Use `parent` instead of `context` because of better performance. + // Assume nobody set a context for a part of a path + val parent = parent + return if (parent is MvPath) parent.rootPath() else this +} fun MvPath.isPrimitiveType(): Boolean = this.parent is MvPathType @@ -51,31 +67,72 @@ val MvPath.maybeStruct get() = reference?.resolveWithAliases() as? MvStruct val MvPath.maybeSchema get() = reference?.resolveWithAliases() as? MvSchema -fun MvPath.namespaces(): Set { +fun MvPath.allowedNamespaces(): Set { val parent = this.parent +// return when (parent) { +// is MvPath, +// is MvPathType -> TYPES +// else -> VALUES +// } + return if (parent is MvPath) EnumSet.of(Namespace.MODULE) else rootNamespace(this) +// return when { +// parent is MvSchemaLit || parent is MvSchemaRef -> setOf(Namespace.SCHEMA) +// parent is MvPathType -> setOf(Namespace.TYPE) +// parent is MvCallExpr -> setOf(Namespace.FUNCTION) +// parent is MvRefExpr && parent.isAbortCodeConst() -> setOf(Namespace.CONST) +// parent is MvRefExpr -> setOf(Namespace.NAME) +//// parent is MvRefExpr && this.nullModuleRef -> setOf(Namespace.NAME) +//// parent is MvRefExpr && !this.nullModuleRef -> setOf(Namespace.NAME, Namespace.MODULE) +// // TODO: it's own namespace? +// parent is MvStructLitExpr || parent is MvStructPat -> setOf(Namespace.NAME) +// parent is MvAccessSpecifier -> setOf(Namespace.TYPE) +// parent is MvAddressSpecifierArg -> setOf(Namespace.FUNCTION) +// parent is MvAddressSpecifierCallParam -> setOf(Namespace.NAME) +// else -> debugErrorOrFallback( +// "Cannot build path namespaces: unhandled parent type ${parent.elementType}", +// setOf(Namespace.NAME) +// ) +// } +} + +private fun rootNamespace(rootPath: MvPath): Set { + val parent = rootPath.parent + check(parent !is MvPath) return when { - parent is MvSchemaLit || parent is MvSchemaRef -> setOf(Namespace.SCHEMA) - parent is MvPathType -> setOf(Namespace.TYPE) - parent is MvCallExpr -> setOf(Namespace.FUNCTION) - parent is MvRefExpr && parent.isAbortCodeConst() -> setOf(Namespace.CONST) - parent is MvRefExpr -> setOf(Namespace.NAME) + parent is MvSchemaLit || parent is MvSchemaRef -> EnumSet.of(Namespace.SCHEMA) + parent is MvPathType -> EnumSet.of(Namespace.TYPE) + parent is MvCallExpr -> EnumSet.of(Namespace.FUNCTION) + parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) + parent is MvRefExpr -> EnumSet.of(Namespace.NAME) // parent is MvRefExpr && this.nullModuleRef -> setOf(Namespace.NAME) // parent is MvRefExpr && !this.nullModuleRef -> setOf(Namespace.NAME, Namespace.MODULE) // TODO: it's own namespace? - parent is MvStructLitExpr || parent is MvStructPat -> setOf(Namespace.NAME) - parent is MvAccessSpecifier -> setOf(Namespace.TYPE) - parent is MvAddressSpecifierArg -> setOf(Namespace.FUNCTION) - parent is MvAddressSpecifierCallParam -> setOf(Namespace.NAME) + parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.NAME) + parent is MvAccessSpecifier -> EnumSet.of(Namespace.TYPE) + parent is MvAddressSpecifierArg -> EnumSet.of(Namespace.FUNCTION) + parent is MvAddressSpecifierCallParam -> EnumSet.of(Namespace.NAME) + parent is MvUseSpeck -> Namespace.all() else -> debugErrorOrFallback( "Cannot build path namespaces: unhandled parent type ${parent.elementType}", - setOf(Namespace.NAME) + EnumSet.of(Namespace.NAME) ) } } -abstract class MvPathMixin(node: ASTNode) : MvElementImpl(node), MvPath { +val MvPath.qualifier: MvPath? + get() { + path?.let { return it } + var ctx = context + while (ctx is MvPath) { + ctx = ctx.context + } + // returns the base qualifier, if it's inside the MvUseGroup + return (ctx as? MvUseSpeck)?.qualifier + } - override fun getReference(): MvPathReference? = MvPathReferenceImpl(this) +abstract class MvPathMixin(node: ASTNode): MvElementImpl(node), MvPath { + + override fun getReference(): MvPath2Reference? = Path2ReferenceImpl(this) } fun MvReferenceElement.importCandidateNamespaces(): Set { @@ -92,4 +149,6 @@ fun MvReferenceElement.importCandidateNamespaces(): Set { } } -val MvPath.moduleRef: MvModuleRef? get() = error("stub") \ No newline at end of file +val MvPath.moduleRef: MvModuleRef? get() = error("unimplemented") + +val MvPath.hasColonColon: Boolean get() = colonColon != null \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt index 095e92ae3..7f68f4003 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt @@ -4,10 +4,13 @@ import com.intellij.lang.ASTNode import org.move.lang.core.psi.MvModuleUseSpeck import org.move.lang.core.psi.MvUseAlias import org.move.lang.core.psi.MvUseItem +import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.impl.MvNameIdentifierOwnerImpl val MvUseAlias.useItem: MvUseItem? get() = this.parent as? MvUseItem +val MvUseAlias.parentUseSpeck: MvUseSpeck get() = this.parent as MvUseSpeck + val MvUseAlias.moduleUseSpeck: MvModuleUseSpeck? get() = this.parent as? MvModuleUseSpeck abstract class MvUseAliasMixin(node: ASTNode) : MvNameIdentifierOwnerImpl(node), diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt new file mode 100644 index 000000000..af26397b8 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt @@ -0,0 +1,6 @@ +package org.move.lang.core.psi.ext + +import org.move.lang.core.psi.MvUseGroup +import org.move.lang.core.psi.MvUseSpeck + +val MvUseGroup.parentUseSpeck: MvUseSpeck get() = parent as MvUseSpeck \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt new file mode 100644 index 000000000..554821f59 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt @@ -0,0 +1,11 @@ +package org.move.lang.core.psi.ext + +import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.MvUseGroup +import org.move.lang.core.psi.MvUseSpeck + +val MvUseSpeck.qualifier: MvPath? get() { + val parentUseSpeck = (context as? MvUseGroup)?.parentUseSpeck ?: return null + return parentUseSpeck.pathOrQualifier +} +val MvUseSpeck.pathOrQualifier: MvPath? get() = path ?: qualifier \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt new file mode 100644 index 000000000..2ba2990b3 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -0,0 +1,53 @@ +package org.move.lang.core.psi.ext + +import com.intellij.psi.util.PsiTreeUtil +import org.move.cli.containingMovePackage +import org.move.lang.core.psi.MvConst +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvVisibilityModifier +import org.move.lang.core.psi.containingModule +import org.move.lang.core.psi.ext.VisKind.* +import org.move.lang.core.resolve.ref.Visibility + +interface MvVisibilityOwner: MvElement { + val visibilityModifier: MvVisibilityModifier? + get() = PsiTreeUtil.getStubChildOfType(this, MvVisibilityModifier::class.java) + + val visibility2: Visibility + get() = visibilityModifier?.visibility ?: Visibility.Internal + + // restricted visibility considered as public + val isPublic: Boolean get() = visibilityModifier != null +} + +// todo: add VisibilityModifier to stubs, rename this one to VisStubKind +enum class VisKind { +// PRIVATE, + PUBLIC, + FRIEND, + PACKAGE, + SCRIPT; +} + +val MvVisibilityModifier.stubKind: VisKind + get() = when { + this.isPublicFriend -> FRIEND + this.isPublicPackage -> PACKAGE + this.isPublicScript -> SCRIPT + this.isPublic -> PUBLIC + else -> error("unreachable") + } + +val MvVisibilityModifier.visibility: Visibility + get() = when (stubKind) { + SCRIPT -> Visibility.PublicScript + PACKAGE -> containingMovePackage?.let { Visibility.PublicPackage(it) } ?: Visibility.Public + FRIEND -> + containingModule?.let { Visibility.PublicFriend(it.asSmartPointer()) } ?: Visibility.Public + PUBLIC -> Visibility.Public + } + + + + + diff --git a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt b/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt index d1be1e506..7d035063c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt @@ -27,7 +27,7 @@ fun processItemsInScope( else -> false } if (!found) { - if (scope is MvImportsOwner) { + if (scope is MvItemsOwner) { if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true } } @@ -133,7 +133,7 @@ fun processItemsInScope( else -> false } if (!found) { - if (scope is MvImportsOwner) { + if (scope is MvItemsOwner) { if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true } } @@ -186,7 +186,7 @@ fun processItemsInScope( else -> false } if (!found) { - if (scope is MvImportsOwner) { + if (scope is MvItemsOwner) { if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true } } @@ -224,7 +224,7 @@ fun processItemsInScope( else -> false } if (!found) { - if (scope is MvImportsOwner) { + if (scope is MvItemsOwner) { if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true } } @@ -247,7 +247,7 @@ fun processItemsInScope( } Namespace.MODULE -> when (scope) { - is MvImportsOwner -> + is MvItemsOwner -> processor.matchAll(contextScopeInfo, scope.moduleUseItems()) else -> false } diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt index 3f3cbe4ec..737924017 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt @@ -23,13 +23,15 @@ data class ContextScopeInfo( val refItemScopes: Set, val letStmtScope: LetStmtScope, ) { - val isMslScope get() = letStmtScope != LetStmtScope.NONE + val isMslScope get() = letStmtScope != NONE fun matches(itemElement: MvNamedElement): Boolean { if ( !this.isMslScope && itemElement.isMslOnlyItem ) return false - if (!itemElement.isVisibleInContext(this.refItemScopes)) return false + if ( + !itemElement.isVisibleInContext(this.refItemScopes) + ) return false return true } @@ -37,6 +39,13 @@ data class ContextScopeInfo( /// really does not affect anything, created just to allow creating CompletionContext everywhere fun default(): ContextScopeInfo = ContextScopeInfo(setOf(MAIN), NONE) fun msl(): ContextScopeInfo = ContextScopeInfo(setOf(VERIFY), EXPR_STMT) + + fun from(element: MvElement): ContextScopeInfo { + return ContextScopeInfo( + refItemScopes = element.itemScopes, + letStmtScope = element.letStmtScope, + ) + } } } @@ -218,7 +227,6 @@ fun processFQModuleRef( processor.match(entry) } - // search modules in the current file first val currentFile = moduleRef.containingMoveFile ?: return val stopped = processModulesInFile(currentFile, matchModule) diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt new file mode 100644 index 000000000..b147a3ad7 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -0,0 +1,516 @@ +package org.move.lang.core.resolve + +import com.intellij.util.SmartList +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvModule +import org.move.lang.core.psi.MvNamedElement +import org.move.lang.core.psi.MvPath +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.RsPathResolveResult + +/** + * ScopeEntry is some PsiElement visible in some code scope. + * + * [SimpleScopeEntry] handles the two cases: + * * aliases (that's why we need a [name] property) + * * lazy resolving of actual elements (that's why [element] can return `null`) - unused for now + */ +interface ScopeEntry { + val name: String + val element: MvElement +// val namespaces: Set +// fun doCopyWithNs(namespaces: Set): ScopeEntry +} + +//@Suppress("UNCHECKED_CAST") +//private fun T.copyWithNs(namespaces: Set): T = doCopyWithNs(namespaces) as T + +typealias RsProcessor = (T) -> Boolean + +interface RsResolveProcessorBase { + /** + * Return `true` to stop further processing, + * return `false` to continue search + */ + fun process(entry: T): Boolean + + /** + * Indicates that processor is interested only in [ScopeEntry]s with specified [names]. + * Improves performance for Resolve2. + * `null` in completion + */ + val names: Set? + + fun acceptsName(name: String): Boolean { + val names = names + return names == null || name in names + } +} + +//interface RsResolveProcessor { +// /** +// * Return `true` to stop further processing, +// * return `false` to continue search +// */ +// fun process(entry: SimpleScopeEntry): Boolean +// +// /** +// * Indicates that processor is interested only in [SimpleScopeEntry]s with specified [names]. +// * Improves performance for Resolve2. +// * `null` in completion +// */ +// val names: Set? +// +// fun acceptsName(name: String): Boolean { +// val names = names +// return names == null || name in names +// } +//} + +typealias RsResolveProcessor = RsResolveProcessorBase + +fun createStoppableProcessor(processor: (ScopeEntry) -> Boolean): RsResolveProcessor { + return object: RsResolveProcessorBase { + override fun process(entry: ScopeEntry): Boolean = processor(entry) + override val names: Set? get() = null + } +} + +fun createProcessor(processor: (ScopeEntry) -> Unit): RsResolveProcessor { + return object: RsResolveProcessorBase { + override fun process(entry: ScopeEntry): Boolean { + processor(entry) + return false + } + + override val names: Set? get() = null + } +} + +fun RsResolveProcessorBase.wrapWithMapper( + mapper: (U) -> T +): RsResolveProcessorBase { + return MappingProcessor(this, mapper) +} + +private class MappingProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val mapper: (U) -> T, +): RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: U): Boolean { + val mapped = mapper(entry) + return originalProcessor.process(mapped) + } + + override fun toString(): String = "MappingProcessor($originalProcessor, mapper = $mapper)" +} + +fun RsResolveProcessorBase.wrapWithNonNullMapper( + mapper: (U) -> T? +): RsResolveProcessorBase { + return NonNullMappingProcessor(this, mapper) +} + +private class NonNullMappingProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val mapper: (U) -> T?, +): RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: U): Boolean { + val mapped = mapper(entry) + return if (mapped == null) { + false + } else { + originalProcessor.process(mapped) + } + } + + override fun toString(): String = "MappingProcessor($originalProcessor, mapper = $mapper)" +} + +fun RsResolveProcessorBase.wrapWithFilter( + filter: (T) -> Boolean +): RsResolveProcessorBase { + return FilteringProcessor(this, filter) +} + +private class FilteringProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val filter: (T) -> Boolean, +): RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: T): Boolean { + return if (filter(entry)) { + originalProcessor.process(entry) + } else { + false + } + } + + override fun toString(): String = "FilteringProcessor($originalProcessor, filter = $filter)" +} + +fun RsResolveProcessorBase.wrapWithBeforeProcessingHandler( + handler: (T) -> Unit +): RsResolveProcessorBase { + return BeforeProcessingProcessor(this, handler) +} + +private class BeforeProcessingProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val handler: (T) -> Unit, +): RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: T): Boolean { + handler(entry) + return originalProcessor.process(entry) + } + + override fun toString(): String = "BeforeProcessingProcessor($originalProcessor, handler = $handler)" +} + + +//fun RsResolveProcessorBase.wrapWithShadowingProcessor( +// prevScope: Map>, +// ns: Set, +//): RsResolveProcessorBase { +// return ShadowingProcessor(this, prevScope, ns) +//} +// +//private class ShadowingProcessor( +// private val originalProcessor: RsResolveProcessorBase, +// private val prevScope: Map>, +// private val ns: Set, +//) : RsResolveProcessorBase { +// override val names: Set? = originalProcessor.names +// override fun process(entry: T): Boolean { +// val prevNs = prevScope[entry.name] +// if (entry.name == "_" || prevNs == null) return originalProcessor.process(entry) +// val restNs = entry.namespaces.minus(prevNs) +// return ns.intersects(restNs) && originalProcessor.process(entry.copyWithNs(restNs)) +// } +// override fun toString(): String = "ShadowingProcessor($originalProcessor, ns = $ns)" +//} + +//fun RsResolveProcessor.wrapWithShadowingProcessorAndUpdateScope( +// prevScope: Map>, +// currScope: MutableMap>, +// ns: Set, +//): RsResolveProcessor { +// return ShadowingAndUpdateScopeProcessor(this, prevScope, currScope, ns) +//} + +//private class ShadowingAndUpdateScopeProcessor( +// private val originalProcessor: RsResolveProcessor, +// private val prevScope: Map>, +// private val currScope: MutableMap>, +// private val ns: Set, +//): RsResolveProcessor { +// override val names: Set? = originalProcessor.names +// override fun process(entry: T): Boolean { +// if (!originalProcessor.acceptsName(entry.name) || entry.name == "_") { +// return originalProcessor.process(entry) +// } +// val prevNs = prevScope[entry.name] +// val newNs = entry.namespaces +// val entryWithIntersectedNs = if (prevNs != null) { +// val restNs = newNs.minus(prevNs) +// if (ns.intersects(restNs)) { +// entry.copyWithNs(restNs) +// } else { +// return false +// } +// } else { +// entry +// } +// currScope[entry.name] = prevNs?.let { it + newNs } ?: newNs +// return originalProcessor.process(entryWithIntersectedNs) +// } +// +// override fun toString(): String = "ShadowingAndUpdateScopeProcessor($originalProcessor, ns = $ns)" +//} + +//fun RsResolveProcessor.wrapWithShadowingProcessorAndImmediatelyUpdateScope( +// prevScope: MutableMap>, +// ns: Set, +//): RsResolveProcessor { +// return ShadowingAndImmediatelyUpdateScopeProcessor(this, prevScope, ns) +//} + +//private class ShadowingAndImmediatelyUpdateScopeProcessor( +// private val originalProcessor: RsResolveProcessor, +// private val prevScope: MutableMap>, +// private val ns: Set, +//): RsResolveProcessor { +// override val names: Set? = originalProcessor.names +// override fun process(entry: T): Boolean { +// if (entry.name in prevScope) return false +// val result = originalProcessor.process(entry) +// if (originalProcessor.acceptsName(entry.name)) { +// prevScope[entry.name] = ns +// } +// return result +// } +// +// override fun toString(): String = +// "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" +//} + +fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Unit): List { + if (referenceName == null) return emptyList() + val processor = ResolveVariantsCollector(referenceName) + f(processor) + return processor.result +} + +private class ResolveVariantsCollector( + private val referenceName: String, + val result: MutableList = SmartList(), +): RsResolveProcessorBase { + override val names: Set = setOf(referenceName) + + override fun process(entry: ScopeEntry): Boolean { + if (entry.name == referenceName) { + val element = entry.element +// if (element !is RsDocAndAttributeOwner || element.existsAfterExpansionSelf) { + result += element +// } + } + return false + } +} + +fun collectResolveVariantsAsScopeEntries( + referenceName: String?, + f: (RsResolveProcessorBase) -> Unit +): List { + if (referenceName == null) return emptyList() + val processor = ResolveVariantsAsScopeEntriesCollector(referenceName) + f(processor) + return processor.result +} + +private class ResolveVariantsAsScopeEntriesCollector( + private val referenceName: String, + val result: MutableList = mutableListOf(), +): RsResolveProcessorBase { + override val names: Set = setOf(referenceName) + + override fun process(entry: T): Boolean { + if (entry.name == referenceName) { +// val element = entry.element +// if (element !is RsDocAndAttributeOwner || element.existsAfterExpansionSelf) { + result += entry +// } + } + return false + } +} + +fun collectPathResolveVariants( + ctx: PathResolutionContext, + path: MvPath, + f: (RsResolveProcessor) -> Unit +): List> { + val referenceName = path.referenceName ?: return emptyList() + val processor = SinglePathResolveVariantsCollector(ctx, referenceName) + f(processor) + return processor.result +} + +private class SinglePathResolveVariantsCollector( + private val ctx: PathResolutionContext, + private val referenceName: String, + val result: MutableList> = SmartList(), +): RsResolveProcessorBase { + override val names: Set = setOf(referenceName) + + override fun process(entry: ScopeEntry): Boolean { + if (entry.name == referenceName) { + collectPathScopeEntry(ctx, result, entry) + } + return false + } +} + +private fun collectPathScopeEntry( + ctx: PathResolutionContext, + result: MutableList>, + e: ScopeEntry +) { + val element = e.element + val visibilityStatus = e.getVisibilityStatusFrom(ctx.context, ctx.lazyContainingModInfo) +// if (visibilityStatus != VisibilityStatus.CfgDisabled) { + val isVisible = visibilityStatus == VisibilityStatus.Visible + // Canonicalize namespaces to consume less memory by the resolve cache +// val namespaces = when (e.namespaces) { +// TYPES -> TYPES +// VALUES -> VALUES +// TYPES_N_VALUES -> TYPES_N_VALUES +// else -> e.namespaces +// } +// result += element + result += RsPathResolveResult(element, isVisible) +// } +} + +fun pickFirstResolveVariant(referenceName: String?, f: (RsResolveProcessor) -> Unit): MvElement? = + pickFirstResolveEntry(referenceName, f)?.element + +fun pickFirstResolveEntry(referenceName: String?, f: (RsResolveProcessor) -> Unit): ScopeEntry? { + if (referenceName == null) return null + val processor = PickFirstScopeEntryCollector(referenceName) + f(processor) + return processor.result +} + +private class PickFirstScopeEntryCollector( + private val referenceName: String, + var result: ScopeEntry? = null, +): RsResolveProcessorBase { + override val names: Set = setOf(referenceName) + + override fun process(entry: ScopeEntry): Boolean { + if (entry.name == referenceName) { +// val element = entry.element +// if (element !is RsDocAndAttributeOwner || element.existsAfterExpansionSelf) { + result = entry + return true +// } + } + return false + } +} + +//fun collectNames(f: (RsResolveProcessor) -> Unit): Set { +// val processor = NamesCollector() +// f(processor) +// return processor.result +//} + +//private class NamesCollector( +// val result: MutableSet = mutableSetOf(), +//): RsResolveProcessor { +// override val names: Set? get() = null +// +// override fun process(entry: SimpleScopeEntry): Boolean { +// if (entry.name != "_") { +// result += entry.name +// } +// return false +// } +//} + +data class SimpleScopeEntry( + override val name: String, + override val element: MvElement, +// override val namespaces: Set, +// override val subst: Substitution = emptySubstitution +): ScopeEntry { +// override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) +} + +data class ModInfo( +// val movePackage: MovePackage?, + val module: MvModule, +// val isScript: Boolean, +) + +fun Map.entriesWithNames(names: Set?): Map { + return if (names.isNullOrEmpty()) { + this + } else if (names.size == 1) { + val single = names.single() + val value = this[single] ?: return emptyMap() + mapOf(single to value) + } else { + names.mapNotNull { name -> this[name]?.let { name to it } }.toMap() + } +} + +typealias VisibilityFilter = (MvElement, Lazy?) -> VisibilityStatus + +fun ScopeEntry.getVisibilityStatusFrom(context: MvElement, lazyModInfo: Lazy?): VisibilityStatus = + if (this is ScopeEntryWithVisibility) { + visibilityFilter(context, lazyModInfo) + } else { + VisibilityStatus.Visible + } + + +fun ScopeEntry.isVisibleFrom(context: MvElement): Boolean = + getVisibilityStatusFrom(context, null) == VisibilityStatus.Visible + +enum class VisibilityStatus { + Visible, + Invisible, +} + +data class ScopeEntryWithVisibility( + override val name: String, + override val element: MvElement, + val namespaces: Set, + /** Given a [MvElement] (usually [MvPath]) checks if this item is visible in `containingMod` of that element */ + val visibilityFilter: VisibilityFilter, +// override val subst: Substitution = emptySubstitution, +): ScopeEntry { +// override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) +} + +fun RsResolveProcessor.process( + name: String, + e: MvElement, + namespaces: Set, + visibilityFilter: VisibilityFilter +): Boolean = process(ScopeEntryWithVisibility(name, e, namespaces, visibilityFilter)) + + +fun RsResolveProcessor.process( + name: String, +// namespaces: Set, + e: MvElement +): Boolean = + process(SimpleScopeEntry(name, e)) +// process(ScopeEntry(name, e, namespaces)) + +inline fun RsResolveProcessor.lazy( + name: String, +// namespaces: Set, + e: () -> MvElement? +): Boolean { + if (!acceptsName(name)) return false + val element = e() ?: return false + return process(name, element) +} + +fun RsResolveProcessor.process( + e: MvNamedElement, +// namespaces: Set +): Boolean { + val name = e.name ?: return false + return process(name, e) +} + +fun RsResolveProcessor.processAll( + elements: List, +// namespaces: Set +): Boolean { + return elements.any { process(it) } +} + +fun RsResolveProcessor.processAll( + vararg collections: Iterable, +// namespaces: Set +): Boolean { + return sequenceOf(*collections).flatten().any { process(it) } +} + +fun processAllScopeEntries(elements: List, processor: RsResolveProcessor): Boolean { + return elements.any { processor.process(it) } +} + + + + diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt index d186c25e8..d2926f47c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt @@ -11,7 +11,7 @@ class MvPathReferenceImpl( override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE override fun multiResolveInner(): List { - val pathNamespaces = element.namespaces() + val ns = element.allowedNamespaces() val vs = Visibility.visibilityScopesForElement(element) val contextScopeInfo = ContextScopeInfo( @@ -25,7 +25,7 @@ class MvPathReferenceImpl( if (moduleRef is MvFQModuleRef) { // TODO: can be replaced with index call val module = moduleRef.reference?.resolve() as? MvModule ?: return emptyList() - return resolveModuleItem(module, refName, pathNamespaces, vs, contextScopeInfo) + return resolveModuleItem(module, refName, ns, vs, contextScopeInfo) } // second, // if it's MODULE::NAME -> resolve MODULE into corresponding FQModuleRef using imports @@ -35,7 +35,7 @@ class MvPathReferenceImpl( return resolveModuleItem( containingModule, refName, - pathNamespaces, + ns, setOf(Visibility.Internal), contextScopeInfo ) @@ -43,14 +43,14 @@ class MvPathReferenceImpl( val useSpeckFQModuleRef = resolveIntoFQModuleRefInUseSpeck(moduleRef) ?: return emptyList() val useSpeckModule = useSpeckFQModuleRef.reference?.resolve() as? MvModule ?: return emptyList() - return resolveModuleItem(useSpeckModule, refName, pathNamespaces, vs, contextScopeInfo) + return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) } else { // if it's NAME // special case second argument of update_field function in specs if (element.isUpdateFieldArg2) return emptyList() // try local names - val item = resolveLocalItem(element, pathNamespaces).firstOrNull() ?: return emptyList() + val item = resolveLocalItem(element, ns).firstOrNull() ?: return emptyList() // local name -> return return when (item) { // item import @@ -60,7 +60,7 @@ class MvPathReferenceImpl( val useSpeckModule = item.itemUseSpeck.fqModuleRef.reference?.resolve() as? MvModule ?: return emptyList() - return resolveModuleItem(useSpeckModule, refName, pathNamespaces, vs, contextScopeInfo) + return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) } // module import is MvModuleUseSpeck -> { diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt index dfa94ef3d..16733e351 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt @@ -5,7 +5,9 @@ import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvUseAlias import org.move.lang.core.psi.ext.moduleUseSpeck +import org.move.lang.core.psi.ext.parentUseSpeck import org.move.lang.core.psi.ext.useItem +import org.move.lang.core.resolve2.ref.RsPathResolveResult interface MvPolyVariantReference : PsiPolyVariantReference { @@ -29,6 +31,25 @@ interface MvPolyVariantReference : PsiPolyVariantReference { } interface MvPathReference : MvPolyVariantReference { -// fun advancedResolve(): BoundElement? = -// resolveWithAliases()?.let { BoundElement(it) } + +// fun multiResolveIfVisible(): List = multiResolve() +// +// fun rawMultiResolve(): List> = +// multiResolve().map { RsPathResolveResult(it, isVisible = true) } +} + +interface MvPath2Reference: MvPolyVariantReference { + fun multiResolveIfVisible(): List = multiResolve() + + fun rawMultiResolve(): List> = + multiResolve().map { RsPathResolveResult(it, isVisible = true) } + + fun resolveFollowingAliases(): MvNamedElement? { + val resolved = this.resolve() + if (resolved is MvUseAlias) { + val aliasedPath = resolved.parentUseSpeck.path + return aliasedPath.reference?.resolve() + } + return resolved + } } diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceBase.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceBase.kt index 1500fc1f8..6e9b46c1c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceBase.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceBase.kt @@ -39,7 +39,7 @@ abstract class MvPolyVariantReferenceBase(element: T): return element } - final override fun resolve(): MvNamedElement? = super.resolve() as? MvNamedElement + override fun resolve(): MvNamedElement? = super.resolve() as? MvNamedElement override fun multiResolve(incompleteCode: Boolean): Array = multiResolve().map { PsiElementResolveResult(it) }.toTypedArray() diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt index d23a1b321..959ef6bd7 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt @@ -57,6 +57,10 @@ interface MvPathReferenceElement : MvReferenceElement { override fun getReference(): MvPathReference? } +interface MvNameAccessChainReferenceElement : MvReferenceElement { + override fun getReference(): MvPath2Reference? +} + interface MvFQModuleReferenceElement : MvReferenceElement { override fun getReference(): MvFQModuleReference? } diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index d6de0eb66..6db3656a9 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -10,13 +10,14 @@ import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.FunctionVisibility import org.move.lang.core.psi.ext.asSmartPointer import org.move.lang.core.psi.ext.visibility +import java.util.* sealed class Visibility { - object Public : Visibility() - object PublicScript : Visibility() - class PublicFriend(val currentModule: SmartPsiElementPointer) : Visibility() - data class PublicPackage(val originPackage: MovePackage) : Visibility() - object Internal : Visibility() + object Public: Visibility() + object PublicScript: Visibility() + class PublicFriend(val currentModule: SmartPsiElementPointer): Visibility() + data class PublicPackage(val originPackage: MovePackage): Visibility() + object Internal: Visibility() companion object { fun local(): Set = setOf(Public, Internal) @@ -53,7 +54,7 @@ enum class Namespace { companion object { fun all(): Set { - return setOf(NAME, FUNCTION, TYPE, SCHEMA, MODULE, CONST) + return EnumSet.of(NAME, FUNCTION, TYPE, SCHEMA, MODULE, CONST) } fun none(): Set = setOf() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt new file mode 100644 index 000000000..6f4921987 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -0,0 +1,53 @@ +package org.move.lang.core.resolve2 + +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.process +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve.ref.Visibility +import java.util.* + +val MvNamedElement.namespaces: Set + get() = when (this) { + is MvFunction -> EnumSet.of(Namespace.FUNCTION) + is MvStruct -> EnumSet.of(Namespace.TYPE) + is MvConst -> EnumSet.of(Namespace.CONST) + is MvSchema -> EnumSet.of(Namespace.SCHEMA) + is MvModule -> EnumSet.of(Namespace.MODULE) + else -> EnumSet.of(Namespace.NAME) + } + +val MvNamedElement.namespace + get() = when (this) { + is MvFunction -> Namespace.FUNCTION + is MvStruct -> Namespace.TYPE + is MvConst -> Namespace.CONST + is MvSchema -> Namespace.SCHEMA + is MvModule -> Namespace.MODULE + else -> error("when should be exhaustive") + } + +fun processItemDeclarations( + itemsOwner: MvItemsOwner, + ns: Set, + processor: RsResolveProcessor +): Boolean { + + // todo: + // 1. loop over all items in module (item is anything accessible with MODULE:: ) + // 2. for every item, use it's .visibility to create VisibilityFilter, even it's just a { false } + + for (item in itemsOwner.visibleItems) { + val name = item.name ?: continue + + val namespace = item.namespace + if (namespace !in ns) continue + + val visibility = (item as? MvVisibilityOwner)?.visibility2 ?: Visibility.Internal + val visibilityFilter = visibility.createFilter() + if (processor.process(name, item, EnumSet.of(namespace), visibilityFilter)) return true + } + + return false +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt new file mode 100644 index 000000000..70b706328 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -0,0 +1,309 @@ +package org.move.lang.core.resolve2 + +import com.intellij.psi.util.PsiTreeUtil +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.LetStmtScope.* +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.util.forEachLeafSpeck + +fun processItemsInScope( + scope: MvElement, + cameFrom: MvElement, + namespaces: Set, + contextScopeInfo: ContextScopeInfo, + processor: RsResolveProcessor, +): Boolean { + for (namespace in namespaces) { + val stop = when (namespace) { + + Namespace.CONST -> { + val found = when (scope) { + is MvModuleBlock -> { + val module = scope.parent as MvModule + processor.processAll( +// contextScopeInfo, + module.consts(), + ) + } + else -> false + } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (processor.processAll(scope.allUseItems())) return true +// } +// } + found + } + + Namespace.NAME -> { + val found = when (scope) { + is MvModuleBlock -> { + val module = scope.parent as MvModule + processor.processAll( +// contextScopeInfo, + module.structs(), + module.consts(), + ) + } + is MvModuleSpecBlock -> processor.processAll(scope.schemaList) + is MvScript -> processor.processAll(scope.consts()) + is MvFunctionLike -> processor.processAll(scope.allParamsAsBindings) + is MvLambdaExpr -> processor.processAll(scope.bindingPatList) + is MvForExpr -> { + val iterConditionBindingPat = scope.forIterCondition?.bindingPat + if (iterConditionBindingPat != null) { + processor.process(iterConditionBindingPat) + } else { + false + } + } + is MvItemSpec -> { + val item = scope.item + when (item) { + is MvFunction -> { + processor.processAll( +// contextScopeInfo, + item.valueParamsAsBindings, + item.specResultParameters.map { it.bindingPat }, + ) + } + is MvStruct -> processor.processAll(item.fields) + else -> false + } + } + is MvSchema -> processor.processAll(scope.fieldBindings) + is MvQuantBindingsOwner -> processor.processAll(scope.bindings) + is MvCodeBlock, + is MvSpecCodeBlock -> { + val visibleLetStmts = when (scope) { + is MvCodeBlock -> { + scope.letStmts + // drops all let-statements after the current position + .filter { it.cameBefore(cameFrom) } + // drops let-statement that is ancestors of ref (on the same statement, at most one) + .filter { + cameFrom != it + && !PsiTreeUtil.isAncestor(cameFrom, it, true) + } + } + is MvSpecCodeBlock -> { + when (contextScopeInfo.letStmtScope) { + EXPR_STMT -> scope.allLetStmts + LET_STMT, LET_POST_STMT -> { + val letDecls = + if (contextScopeInfo.letStmtScope == LET_POST_STMT) { + scope.allLetStmts + } else { + scope.letStmts(false) + } + letDecls + // drops all let-statements after the current position + .filter { it.cameBefore(cameFrom) } + // drops let-statement that is ancestors of ref (on the same statement, at most one) + .filter { + cameFrom != it + && !PsiTreeUtil.isAncestor(cameFrom, it, true) + } + } + NONE -> emptyList() + } + } + else -> error("unreachable") + } + // shadowing support (look at latest first) + val namedElements = visibleLetStmts + .asReversed() + .flatMap { it.pat?.bindings.orEmpty() } + + // skip shadowed (already visited) elements + val visited = mutableSetOf() + val shadowingProcessor = processor.wrapWithFilter { + val isVisited = it.name in visited + if (!isVisited) { + visited += it.name + } + !isVisited + } +// val processorWithShadowing = MatchingProcessor { entry -> +// ((entry.name !in visited) +// && processor.process(entry).also { visited += entry.name }) +// } + var found = shadowingProcessor.processAll(namedElements) + if (!found && scope is MvSpecCodeBlock) { + // if inside SpecCodeBlock, process also with builtin spec consts and global variables + found = shadowingProcessor.processAll( +// contextScopeInfo, + scope.builtinSpecConsts(), + scope.globalVariables() + ) + } + found + } + else -> false + } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (scope.processUseSpeckElements(namespaces, processor)) return true +// } +// } + found + } + Namespace.FUNCTION -> { + val found = when (scope) { + is MvModuleBlock -> { + val module = scope.parent as MvModule + val specFunctions = if (contextScopeInfo.isMslScope) { + listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() + } else { + emptyList() + } + val specInlineFunctions = if (contextScopeInfo.isMslScope) { + module.moduleItemSpecs().flatMap { it.specInlineFunctions() } + } else { + emptyList() + } + processor.processAll( +// contextScopeInfo, + module.allNonTestFunctions(), + module.builtinFunctions(), + specFunctions, + specInlineFunctions + ) + } + is MvModuleSpecBlock -> { + val specFunctions = scope.specFunctionList + val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } + processor.processAll( +// contextScopeInfo, + specFunctions, + specInlineFunctions + ) + } + is MvFunctionLike -> processor.processAll(scope.lambdaParamsAsBindings) + is MvLambdaExpr -> processor.processAll(scope.bindingPatList) + is MvItemSpec -> { + val item = scope.item + when (item) { + is MvFunction -> processor.processAll(item.lambdaParamsAsBindings) + else -> false + } + } + is MvSpecCodeBlock -> { + val inlineFunctions = scope.specInlineFunctions().asReversed() + return processor.processAll(inlineFunctions) + } + else -> false + } +// if (!found) { +// +// } + found + } + + Namespace.TYPE -> { + if (scope is MvTypeParametersOwner) { + if (processor.processAll(scope.typeParameters)) return true + } + val found = when (scope) { + is MvItemSpec -> { + val funcItem = scope.funcItem + if (funcItem != null) { + processor.processAll(funcItem.typeParameters) + } else { + false + } + } + is MvModuleBlock -> { + val module = scope.parent as MvModule + processor.processAll( +// contextScopeInfo, + scope.allUseItems(), + module.structs() + ) + } + is MvApplySchemaStmt -> { + val toPatterns = scope.applyTo?.functionPatternList.orEmpty() + val patternTypeParams = + toPatterns.flatMap { it.typeParameterList?.typeParameterList.orEmpty() } + processor.processAll(patternTypeParams) + } + + else -> false + } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (scope.processUseSpeckElements(namespaces, processor)) return true +// } +// } + found + } + + Namespace.SCHEMA -> when (scope) { + is MvModuleBlock -> processor.processAll( +// contextScopeInfo, + scope.allUseItems(), + scope.schemaList + ) + is MvModuleSpecBlock -> processor.processAll( +// contextScopeInfo, + scope.allUseItems(), + scope.schemaList, + scope.specFunctionList + ) + else -> false + } + + Namespace.MODULE -> when (scope) { + is MvItemsOwner -> + processor.processAll(scope.moduleUseItems()) + else -> false + } + } + if (!stop && scope is MvItemsOwner) { + if (scope.processUseSpeckElements(namespaces, processor)) return true + } + if (stop) return true + } + + return false +} + +private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: RsResolveProcessor): Boolean { + var stop = false + for (useStmt in this.useStmtList) { + useStmt.forEachLeafSpeck { path, alias -> + val name = if (alias != null) { + alias.name ?: return@forEachLeafSpeck false + } else { + var n = path.referenceName ?: return@forEachLeafSpeck false + // 0x1::m::Self -> 0x1::m + if (n == "Self") { + n = path.qualifier?.referenceName ?: return@forEachLeafSpeck false + } + n + } + val namedElement = path.reference?.resolve() + if (namedElement == null) { + if (alias != null) { + // aliased element cannot be resolved, but alias itself is valid, resolve to it + if (processor.process(name, alias)) return@forEachLeafSpeck true + } + // todo: should it be resolved to import anyway? + return@forEachLeafSpeck false + } + + val element = alias ?: namedElement + val namespace = namedElement.namespace + + if (namespace in ns && processor.process(name, element)) { + stop = true + return@forEachLeafSpeck true + } + false + } + if (stop) return true + } + return stop +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt b/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt new file mode 100644 index 000000000..9e1a4b136 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt @@ -0,0 +1,88 @@ +package org.move.lang.core.resolve2 + +import com.intellij.openapi.util.Key +import com.intellij.psi.util.CachedValue +import org.move.lang.core.psi.MvModule +import org.move.lang.core.psi.MvNamedElement +import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.ref.Visibility + +private val MODULE_ITEMS_KEY: Key>> = Key.create("MODULE_ITEMS_KEY") + +data class VisItem( + val name: String, + val item: MvNamedElement, + val visibility: Visibility, + val isFromNamedImport: Boolean +) + +//val MvItemsOwner.visibleItems: List +// get() = +// CachedValuesManager.getCachedValue(this, MODULE_ITEMS_KEY) { +// val declaredItems = buildList { +// if (this is MvModule) { +// addAll(allNonTestFunctions()) +// addAll(consts()) +// addAll(structs()) +// addAll(schemas()) +// } +// } +// .mapNotNull { +// val visibility = (it as? MvItemElement)?.visibility2 ?: Visibility.Internal +// it.name?.let { name -> +// VisItem(name, it, visibility, false) +// } +// } +// +// val speckItems = this.useSpeckVisibleItems +// +// CachedValueProvider.Result.create( +// declaredItems + speckItems, +// listOf(moveStructureOrAnyPsiModificationTracker) +// ) +// } + +val MvModule.declaredItems: List + get() { + return buildList { + addAll(allNonTestFunctions()) + addAll(consts()) + addAll(structs()) + addAll(schemas()) + } + } + +//val MvItemsOwner.useSpeckVisibleItems: List +// get() { +// val visibleItems = mutableListOf() +// for (useStmt in this.useStmtList) { +// useStmt.forEachLeafSpeck { basePath, speckPath, alias -> +// val qualifier = basePath ?: speckPath.path +// if (qualifier == null) { +// // in a form of `use NAME;`, invalid +// return@forEachLeafSpeck +// } +// +// +//// val ctx = PathResolutionContext(speckPath, ContextScopeInfo.from(speckPath)) +//// processQualifiedPathResolveVariants( +//// ctx, +//// Namespace.all(), +//// speckPath, +//// qualifier, +//// createStoppableProcessor { e -> +//// val visItem = VisItem(alias ?: e.name, e.element, ) +//// }) +//// val qualifierModule = qualifier.reference?.resolve() as? MvModule ?: return@forEachLeafSpeck +//// processItemDeclarations(qualifierModule, Namespace.all()) { +//// +//// } +//// val visItem = VisItem( +//// resolvedPath, +//// visibility = Visibility.Internal, +//// isFromNamedImport = true) +//// visibleItems.add(visItem) +// } +// } +// return visibleItems +// } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt new file mode 100644 index 000000000..ad55239e0 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -0,0 +1,74 @@ +package org.move.lang.core.resolve2 + +import com.intellij.psi.search.GlobalSearchScope +import org.move.cli.MoveProject +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvModule +import org.move.lang.core.psi.containingMoveFile +import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.types.address +import org.move.lang.index.MvNamedElementIndex + +fun processNestedScopesUpwards( + scopeStart: MvElement, + ns: Set, + ctx: PathResolutionContext, + processor: RsResolveProcessor +): Boolean { + return walkUpThroughScopes( + scopeStart, + stopAfter = { it is MvModule } + ) { cameFrom, scope -> + processItemsInScope( + scope, cameFrom, ns, ctx.contextScopeInfo, processor + ) +// if (scope !is MvCodeBlock && scope is MvItemsOwner) { +// if (processItemDeclarations(scope, ns, addImports = true, processor)) return@walkUpThroughScopes true +// false +// } else { +// +// } + } +} + +fun processAddressPathResolveVariants( + element: MvElement, + moveProject: MoveProject?, + address: String, + processor: RsResolveProcessor, +): Boolean { + // if no project, cannot use the index + if (moveProject == null) return false + + val equalAddressProcessor = processor.wrapWithFilter { e -> + val candidate = e.element as? MvModule ?: return@wrapWithFilter false + val candidateAddress = candidate.address(moveProject)?.canonicalValue(moveProject) + address == candidateAddress + } + + // search modules in the current file first + val currentFile = element.containingMoveFile ?: return false + for (module in currentFile.modules()) { + if (equalAddressProcessor.process(module)) return true + } + + val project = element.project + val currentFileScope = GlobalSearchScope.fileScope(currentFile) + val searchScope = + moveProject.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) + + var stop = false + for (name in processor.names.orEmpty()) { + MvNamedElementIndex + .processElementsByName(project, name, searchScope) { + stop = equalAddressProcessor.process(it) + // true to continue processing, if .process does not find anything, it returns false + !stop + } + if (stop) return true + } + + return false +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt new file mode 100644 index 000000000..71c28bfde --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -0,0 +1,24 @@ +package org.move.lang.core.resolve2 + +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvModule +import org.move.lang.core.resolve.ModInfo +import org.move.lang.core.resolve.VisibilityFilter +import org.move.lang.core.resolve.VisibilityStatus +import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve.ref.Visibility.Public + +fun getModInfo(module: MvModule): ModInfo { + return ModInfo(module = module) +} + +/** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ +fun Visibility.createFilter(): VisibilityFilter = + if (this !is Public) { + fun(context: MvElement, lazyModInfo: Lazy?): VisibilityStatus { + val modInfo = lazyModInfo?.value ?: return VisibilityStatus.Invisible + return VisibilityStatus.Visible + } + } else { + { _, _ -> VisibilityStatus.Visible } + } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt new file mode 100644 index 000000000..6ba56a507 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -0,0 +1,233 @@ +package org.move.lang.core.resolve2.ref + +import com.intellij.psi.ResolveResult +import org.move.cli.MoveProject +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.allowedNamespaces +import org.move.lang.core.psi.ext.qualifier +import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.ref.* +import org.move.lang.core.resolve2.* +import org.move.lang.core.resolve2.ref.RsPathResolveKind.* +import org.move.lang.core.types.Address +import org.move.lang.moveProject +import kotlin.LazyThreadSafetyMode.NONE + +class Path2ReferenceImpl(element: MvPath): + MvPolyVariantReferenceBase(element), MvPath2Reference { + +// private fun rawMultiResolveUsingInferenceCache(): List>? { +// val msl = element.isMsl() +// return element.inference(msl)?.getResolvedPath(element)?.map { result -> +// RsPathResolveResult(result.element, result.isVisible) +// } +// } + +// override fun multiResolveInner(): List { +// val referenceName = element.referenceName ?: return emptyList() +// val resolveVariants = collectResolveVariantsAsScopeEntries(referenceName) { +// processPathResolveVariants(element, it) +// } +// return resolveVariants.mapNotNull { it.element as? MvNamedElement } +// } + + override fun resolve(): MvNamedElement? = rawMultiResolve().singleOrNull()?.element as? MvNamedElement + + override fun multiResolve(incompleteCode: Boolean): Array = + rawMultiResolve().toTypedArray() + + override fun multiResolve(): List = + rawMultiResolve().mapNotNull { it.element as? MvNamedElement } + + override fun multiResolveIfVisible(): List = + rawMultiResolve().mapNotNull { + if (!it.isVisible) return@mapNotNull null + it.element + } + + override fun rawMultiResolve(): List> = Resolver.invoke(this.element) +// override fun rawMultiResolve(): List> = rawCachedMultiResolve() + + private fun rawCachedMultiResolve(): List> { + val rawResult = MvResolveCache.getInstance(element.project) + .resolveWithCaching(element, ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE, Resolver) + return rawResult.orEmpty() + } + + private object Resolver: (MvElement) -> List> { + override fun invoke(path: MvElement): List> { + // should not really happen + if (path !is MvPath) return emptyList() + + val ctx = PathResolutionContext( + context = path, + contextScopeInfo = ContextScopeInfo.from(path) + ) + val result = resolvePath(ctx, path, ctx.classifyPath(path)) + return result + } + } +} + +fun processPathResolveVariants( + ctx: PathResolutionContext, + pathKind: RsPathResolveKind, + processor: RsResolveProcessor +): Boolean { + val contextScopeAwareProcessor = processor.wrapWithFilter { + val element = it.element + element is MvNamedElement && ctx.contextScopeInfo.matches(element) + } + return when (pathKind) { + is UnqualifiedPath -> { + // Self:: + if (processor.lazy("Self") { ctx.containingModule }) return true + // local + processNestedScopesUpwards(ctx.context, pathKind.ns, ctx, contextScopeAwareProcessor) + } + is AddressPath -> { + // 0x1::bar + processAddressPathResolveVariants( + ctx.context, + ctx.moveProject, + pathKind.canonicalAddress, + contextScopeAwareProcessor + ) + } + is QualifiedPath -> { + // foo::bar + processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) + } + } +} + +fun processPathResolveVariants( + path: MvPath, + processor: RsResolveProcessor, +): Boolean { + val ctx = PathResolutionContext(path, contextScopeInfo = ContextScopeInfo.from(path)) + val pathKind = ctx.classifyPath(path) + return processPathResolveVariants(ctx, pathKind, processor) +} + +/** + * foo::bar + * | | + * | [path] + * [qualifier] + */ +fun processQualifiedPathResolveVariants( + ctx: PathResolutionContext, + ns: Set, + path: MvPath, + qualifier: MvPath, + processor: RsResolveProcessor +): Boolean { + val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() + if (resolvedQualifier != null) { + val result = + processQualifiedPathResolveVariants1(ctx, ns, qualifier, resolvedQualifier, path, processor) + if (result) return true + } + return false +} + +private fun processQualifiedPathResolveVariants1( + ctx: PathResolutionContext, + ns: Set, + qualifier: MvPath, + resolvedQualifier: MvElement, + path: MvPath, + processor: RsResolveProcessor +): Boolean { + if (resolvedQualifier is MvModule) { + if (processor.process("Self", resolvedQualifier)) return true + + val block = resolvedQualifier.moduleBlock + if (block != null) { + if (processItemDeclarations(block, ns, processor)) return true + } + } + return false +} + +sealed class RsPathResolveKind { + /** A path consist of a single identifier, e.g. `foo` */ + data class UnqualifiedPath(val ns: Set): RsPathResolveKind() + + /** `bar` in `foo::bar` or `use foo::{bar}` */ + class QualifiedPath( + val path: MvPath, + val qualifier: MvPath, + val ns: Set, + ): RsPathResolveKind() + + /** bar in `0x1::bar` */ + class AddressPath( + val path: MvPath, + val canonicalAddress: String, + ): RsPathResolveKind() +} + +class PathResolutionContext( + val context: MvElement, + val contextScopeInfo: ContextScopeInfo, +) { + private var lazyContainingMoveProject: Lazy = lazy(NONE) { + context.moveProject + } + val moveProject: MoveProject? get() = lazyContainingMoveProject.value + + private var lazyContainingModule: Lazy = lazy(NONE) { + context.containingModule + } + val containingModule: MvModule? get() = lazyContainingModule.value + var lazyContainingModInfo: Lazy = lazy(NONE) { + containingModule?.let { getModInfo(it) } + } + + fun classifyPath(path: MvPath): RsPathResolveKind { + val qualifier = path.qualifier + val ns = path.allowedNamespaces() + if (qualifier == null) { + return UnqualifiedPath(ns) + } + + val pathAddress = qualifier.pathAddress + return when { + pathAddress != null -> { + val address = Address.Value(pathAddress.text) + val canonical = address.addressLit().canonical() + AddressPath(path, canonical) + } + else -> QualifiedPath(path, qualifier, ns) + } + } +} + +//// todo: use in inference later +//fun resolvePathRaw(path: MvPath): List { +// return collectResolveVariantsAsScopeEntries(path.referenceName) { +// processPathResolveVariants(path, it) +// } +//} + +private fun resolvePath( + ctx: PathResolutionContext, + path: MvPath, + kind: RsPathResolveKind +): List> { + val result = + // matches resolve variants against referenceName from path + collectPathResolveVariants(ctx, path) { + // actually emits resolve variants + processPathResolveVariants(ctx, kind, it) + } + return result +// return when (result.size) { +// 0 -> emptyList() +// 1 -> listOf(result.single()) +// else -> result +// } +} + diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveResult.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveResult.kt new file mode 100644 index 000000000..1021cf5d3 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveResult.kt @@ -0,0 +1,19 @@ +package org.move.lang.core.resolve2.ref + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveResult +import org.move.lang.core.psi.MvElement + +/** + * Used as a resolve result in [org.rust.lang.core.resolve.ref.RsPathReferenceImpl] + */ +data class RsPathResolveResult( + val element: T, +// val resolvedSubst: Substitution = emptySubstitution, + val isVisible: Boolean, +// val namespaces: Set = emptySet(), +): ResolveResult { + override fun getElement(): PsiElement = element + + override fun isValidResult(): Boolean = true +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt new file mode 100644 index 000000000..5f72099ef --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt @@ -0,0 +1,47 @@ +package org.move.lang.core.resolve2.util + +import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.MvUseAlias +import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.MvUseStmt +import org.move.lang.core.psi.ext.childOfType +import org.move.lang.core.psi.ext.childrenOfType +import org.move.lang.core.psi.ext.hasColonColon + +fun interface LeafUseSpeckConsumer { + fun consume(path: MvPath, useAlias: MvUseAlias?): Boolean +} + +fun MvUseStmt.forEachLeafSpeck(consumer: LeafUseSpeckConsumer) { + val rootUseSpeck = this.childOfType() ?: return + val useGroup = rootUseSpeck.useGroup + if (useGroup == null) { + // basePath is null, path is full path of useSpeck + val alias = rootUseSpeck.useAlias + if (!consumer.consume(rootUseSpeck.path, alias)) return + } else { + for (childSpeck in useGroup.childrenOfType()) { + val alias = childSpeck.useAlias + if (!consumer.consume(childSpeck.path, alias)) return + } + } +} + + + + +///** return false if path is incomplete (has empty segments), e.g. `use std::;` */ +//private fun addPathSegments(path: MvPath, segments: ArrayList): Boolean { +// val subpath = path.path +// if (subpath != null) { +// if (!addPathSegments(subpath, segments)) return false +// } else if (path.hasColonColon) { +// // absolute path: `::foo::bar` +// // ~~~~~ this +// segments += "" +// } +// +// val segment = path.referenceName ?: return false +// segments += segment +// return true +//} diff --git a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt index 22dfb50b6..d28a124f9 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt @@ -9,6 +9,8 @@ import org.move.cli.settings.isDebugModeEnabled import org.move.ide.formatter.impl.location import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.ScopeEntry +import org.move.lang.core.resolve.isVisibleFrom import org.move.lang.core.types.ty.* import org.move.lang.core.types.ty.TyReference.Companion.coerceMutability import org.move.lang.toNioPathOrNull @@ -72,6 +74,7 @@ data class InferenceResult( private val exprTypes: Map, private val exprExpectedTypes: Map, private val methodOrPathTypes: Map, + private val resolvedPaths: Map>, private val resolvedFields: Map, private val resolvedMethodCalls: Map, val callableTypes: Map, @@ -90,6 +93,9 @@ data class InferenceResult( fun getCallableType(callable: MvCallable): Ty? = callableTypes[callable] fun getMethodOrPathType(methodOrPath: MvMethodOrPath): Ty? = methodOrPathTypes[methodOrPath] + fun getResolvedPath(path: MvPath): List = + resolvedPaths[path] ?: emptyList() + fun getResolvedField(field: MvStructDotField): MvNamedElement? = resolvedFields[field] fun getResolvedMethod(methodCall: MvMethodCall): MvNamedElement? = resolvedMethodCalls[methodCall] } @@ -136,6 +142,19 @@ fun MvElement.inference(msl: Boolean): InferenceResult? { return contextOwner.inference(msl) } +data class ResolvedPath(val element: MvElement, val isVisible: Boolean) { + companion object { + fun from(entry: ScopeEntry, context: MvElement): ResolvedPath { +// return if (entry is AssocItemScopeEntry) { +// AssocItem(entry.element, entry.source) +// } else { +// val isVisible = entry.isVisibleFrom(context.containingModule) + return ResolvedPath(entry.element, true) +// } + } + } +} + class InferenceContext( var msl: Boolean, private val skipUnification: Boolean = false @@ -150,6 +169,7 @@ class InferenceContext( // private val pathTypes = mutableMapOf() private val methodOrPathTypes = mutableMapOf() + val resolvedPaths = mutableMapOf>() val resolvedFields = mutableMapOf() val resolvedMethodCalls = mutableMapOf() @@ -209,6 +229,7 @@ class InferenceContext( exprTypes, exprExpectedTypes, methodOrPathTypes, + resolvedPaths, resolvedFields, resolvedMethodCalls, callableTypes, @@ -256,6 +277,10 @@ class InferenceContext( this.callableTypes[callable] = ty } + fun writePath(path: MvPath, resolved: List) { + resolvedPaths[path] = resolved + } + @Suppress("UNCHECKED_CAST") fun instantiateMethodOrPath( methodOrPath: MvMethodOrPath, diff --git a/src/main/kotlin/org/move/openapiext/utils.kt b/src/main/kotlin/org/move/openapiext/utils.kt index 5783a65e6..fcd12d210 100644 --- a/src/main/kotlin/org/move/openapiext/utils.kt +++ b/src/main/kotlin/org/move/openapiext/utils.kt @@ -102,13 +102,6 @@ fun saveAllDocumentsAsTheyAre() { // } } -inline fun testAssert(action: () -> Boolean, lazyMessage: () -> Any) { - if (isUnitTestMode && !action()) { - val message = lazyMessage() - throw AssertionError(message) - } -} - val DataContext.psiFile: PsiFile? get() = getData(CommonDataKeys.PSI_FILE) @@ -242,4 +235,15 @@ fun joinPathArray(segments: Array) = segments.joinTo(StringBuilder(), Platform.current().fileSeparator.toString()).toString() fun joinPath(vararg segments: String) = - segments.joinTo(StringBuilder(), Platform.current().fileSeparator.toString()).toString() \ No newline at end of file + segments.joinTo(StringBuilder(), Platform.current().fileSeparator.toString()).toString() + +inline fun testAssert(action: () -> Boolean) { + testAssert(action) { "Assertion failed" } +} + +inline fun testAssert(action: () -> Boolean, lazyMessage: () -> Any) { + if (isUnitTestMode && !action()) { + val message = lazyMessage() + throw AssertionError(message) + } +} diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 087757088..fdb445171 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -5,7 +5,7 @@ import org.move.utils.tests.resolve.ResolveTestCase class ResolveFunctionTest: ResolveTestCase() { fun `test resolve reference to function`() = checkByCode( """ - module M { + module 0x1::m { fun call(): u8 { //X 1 @@ -21,7 +21,7 @@ class ResolveFunctionTest: ResolveTestCase() { fun `test resolve reference to native function`() = checkByCode( """ - module M { + module 0x1::m { native fun call(): u8; //X @@ -208,8 +208,11 @@ class ResolveFunctionTest: ResolveTestCase() { fun `test resolve function to import alias`() = checkByCode( """ - module M { - use 0x1::Original::call as mycall; + module 0x1::original { + public fun call() {} + } + module 0x1::m { + use 0x1::original::call as mycall; //X fun main() { mycall(); @@ -242,7 +245,7 @@ class ResolveFunctionTest: ResolveTestCase() { fun `test resolve reference to function via Self`() = checkByCode( """ - module M { + module 0x1::m { fun call(): u8 { //X 1 @@ -457,13 +460,13 @@ class ResolveFunctionTest: ResolveTestCase() { #[test_only] module 0x1::M1 { #[test] - public(script) fun test_a() {} + entry fun test_a() {} } #[test_only] module 0x1::M2 { use 0x1::M1; - public(script) fun main() { + entry fun main() { M1::test_a(); //^ unresolved } @@ -523,6 +526,19 @@ module 0x1::main { """ ) + fun `test resolve use item`() = checkByCode( + """ +module 0x1::string { + public fun utf8() {} + //X +} +module 0x1::main { + use 0x1::string::utf8; + //^ +} + """ + ) + fun `test resolve with self alias`() = checkByCode( """ module 0x1::string { @@ -635,6 +651,36 @@ module 0x1::mod { """ ) + fun `test resolve local function when module with same name is imported`() = checkByCode( + """ + module 0x1::royalty {} + module 0x1::m { + use 0x1::royalty; + public fun royalty() {} + //X + public fun main() { + royalty(); + //^ + } + } + """ + ) + + fun `test resolve local function when module imported with the same alias`() = checkByCode( + """ + module 0x1::myroyalty {} + module 0x1::m { + use 0x1::myroyalty as royalty; + public fun royalty() {} + //X + public fun main() { + royalty(); + //^ + } + } + """ + ) + fun `test resolve local function when module with same name is imported as Self`() = checkByCode( """ module 0x1::royalty {} @@ -650,7 +696,7 @@ module 0x1::mod { """ ) - fun `test resolve local function when function with the same name imported`() = checkByCode( + fun `test cannot resolve local function when duplicate function is imported`() = checkByCode( """ module 0x1::royalty { public fun royalty() {} @@ -658,10 +704,9 @@ module 0x1::mod { module 0x1::m { use 0x1::royalty::royalty; public fun royalty() {} - //X public fun main() { royalty(); - //^ + //^ unresolved } } """ @@ -831,4 +876,40 @@ module 0x1::mod { } """ ) + + fun `test test function is not available in name resolution`() = checkByCode( + """ + module 0x1::main { + public fun call() { test_main(); } + //^ unresolved + #[test] + fun test_main() {} + } + """ + ) + + fun `test resolve function from use group in use`() = checkByCode(""" + module 0x1::m { + public fun call() {} + //X + } + module 0x1::main { + use 0x1::m::{call}; + //^ + } + """) + + fun `test resolve function from use group`() = checkByCode(""" + module 0x1::m { + public fun call() {} + //X + } + module 0x1::main { + use 0x1::m::{call}; + public fun main() { + call(); + //^ + } + } + """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index a3530487b..8bb95b180 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -3,6 +3,30 @@ package org.move.lang.resolve import org.move.utils.tests.resolve.ResolveTestCase class ResolveModulesTest : ResolveTestCase() { + fun `test use module Self`() = checkByCode( + """ + module 0x1::transaction { + //X + } + module 0x1::main { + use 0x1::transaction::Self; + //^ + } + """ + ) + + fun `test use module Self in use group`() = checkByCode( + """ + module 0x1::transaction { + //X + } + module 0x1::main { + use 0x1::transaction::{Self}; + //^ + } + """ + ) + fun `test import module itself with Self import`() = checkByCode( """ address 0x1 { @@ -22,11 +46,30 @@ class ResolveModulesTest : ResolveTestCase() { """ ) - fun `test resolve Self to current module`() = checkByCode( + fun `test import module itself with Self group import`() = checkByCode( """ + address 0x1 { module Transaction { //X fun create() {} + } + + module M { + use 0x1::Transaction::{Self}; + fun main() { + let a = Transaction::create(); + //^ + } + } + } + """ + ) + + fun `test resolve Self to current module`() = checkByCode( + """ + module 0x1::transaction { + //X + fun create() {} fun main() { let a = Self::create(); //^ @@ -37,7 +80,7 @@ class ResolveModulesTest : ResolveTestCase() { fun `test resolve module to imported module with alias`() = checkByCode( """ - module M { + module 0x1::m { use 0x1::Transaction as MyTransaction; //X fun main() { @@ -50,16 +93,11 @@ class ResolveModulesTest : ResolveTestCase() { fun `test cannot resolve module if imported one has different address`() = checkByCode( """ - address 0x1 { - module Transaction {} - } - - address 0x2 { - module M { - fun main() { - let a = 0x3::Transaction::create(); - //^ unresolved - } + module 0x1::transaction {} + module 0x1::m { + fun main() { + let a = 0x3::transaction::create(); + //^ unresolved } } """ From adb671e4269618876d86eb314ecd007572dc3fad Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Sun, 14 Jul 2024 19:47:08 +0300 Subject: [PATCH 06/43] implement shadowing --- .../org/move/lang/core/resolve/Processors.kt | 178 +++++++++--------- .../lang/core/resolve2/NameResolution2.kt | 34 +++- .../utils/tests/resolve/ResolveTestCase.kt | 3 +- .../utils/tests/resolve/ResolveTestUtils.kt | 14 +- 4 files changed, 133 insertions(+), 96 deletions(-) diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index b147a3ad7..b69819074 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -8,6 +8,7 @@ import org.move.lang.core.psi.MvPath import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.ref.RsPathResolveResult +import org.move.stdext.intersects /** * ScopeEntry is some PsiElement visible in some code scope. @@ -19,12 +20,12 @@ import org.move.lang.core.resolve2.ref.RsPathResolveResult interface ScopeEntry { val name: String val element: MvElement -// val namespaces: Set -// fun doCopyWithNs(namespaces: Set): ScopeEntry + val namespaces: Set + fun doCopyWithNs(namespaces: Set): ScopeEntry } -//@Suppress("UNCHECKED_CAST") -//private fun T.copyWithNs(namespaces: Set): T = doCopyWithNs(namespaces) as T +@Suppress("UNCHECKED_CAST") +private fun T.copyWithNs(namespaces: Set): T = doCopyWithNs(namespaces) as T typealias RsProcessor = (T) -> Boolean @@ -172,91 +173,88 @@ private class BeforeProcessingProcessor( } -//fun RsResolveProcessorBase.wrapWithShadowingProcessor( -// prevScope: Map>, -// ns: Set, -//): RsResolveProcessorBase { -// return ShadowingProcessor(this, prevScope, ns) -//} -// -//private class ShadowingProcessor( -// private val originalProcessor: RsResolveProcessorBase, -// private val prevScope: Map>, -// private val ns: Set, -//) : RsResolveProcessorBase { -// override val names: Set? = originalProcessor.names -// override fun process(entry: T): Boolean { -// val prevNs = prevScope[entry.name] -// if (entry.name == "_" || prevNs == null) return originalProcessor.process(entry) -// val restNs = entry.namespaces.minus(prevNs) -// return ns.intersects(restNs) && originalProcessor.process(entry.copyWithNs(restNs)) -// } -// override fun toString(): String = "ShadowingProcessor($originalProcessor, ns = $ns)" -//} +fun RsResolveProcessorBase.wrapWithShadowingProcessor( + prevScope: Map>, + ns: Set, +): RsResolveProcessorBase { + return ShadowingProcessor(this, prevScope, ns) +} -//fun RsResolveProcessor.wrapWithShadowingProcessorAndUpdateScope( -// prevScope: Map>, -// currScope: MutableMap>, -// ns: Set, -//): RsResolveProcessor { -// return ShadowingAndUpdateScopeProcessor(this, prevScope, currScope, ns) -//} +private class ShadowingProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val prevScope: Map>, + private val ns: Set, +) : RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: T): Boolean { + val prevNs = prevScope[entry.name] + if (entry.name == "_" || prevNs == null) return originalProcessor.process(entry) + val restNs = entry.namespaces.minus(prevNs) + return ns.intersects(restNs) && originalProcessor.process(entry.copyWithNs(restNs)) + } + override fun toString(): String = "ShadowingProcessor($originalProcessor, ns = $ns)" +} -//private class ShadowingAndUpdateScopeProcessor( -// private val originalProcessor: RsResolveProcessor, -// private val prevScope: Map>, -// private val currScope: MutableMap>, -// private val ns: Set, -//): RsResolveProcessor { -// override val names: Set? = originalProcessor.names -// override fun process(entry: T): Boolean { -// if (!originalProcessor.acceptsName(entry.name) || entry.name == "_") { -// return originalProcessor.process(entry) -// } -// val prevNs = prevScope[entry.name] -// val newNs = entry.namespaces -// val entryWithIntersectedNs = if (prevNs != null) { -// val restNs = newNs.minus(prevNs) -// if (ns.intersects(restNs)) { -// entry.copyWithNs(restNs) -// } else { -// return false -// } -// } else { -// entry -// } -// currScope[entry.name] = prevNs?.let { it + newNs } ?: newNs -// return originalProcessor.process(entryWithIntersectedNs) -// } -// -// override fun toString(): String = "ShadowingAndUpdateScopeProcessor($originalProcessor, ns = $ns)" -//} +fun RsResolveProcessorBase.wrapWithShadowingProcessorAndUpdateScope( + prevScope: Map>, + currScope: MutableMap>, + ns: Set, +): RsResolveProcessorBase { + return ShadowingAndUpdateScopeProcessor(this, prevScope, currScope, ns) +} -//fun RsResolveProcessor.wrapWithShadowingProcessorAndImmediatelyUpdateScope( -// prevScope: MutableMap>, -// ns: Set, -//): RsResolveProcessor { -// return ShadowingAndImmediatelyUpdateScopeProcessor(this, prevScope, ns) -//} +private class ShadowingAndUpdateScopeProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val prevScope: Map>, + private val currScope: MutableMap>, + private val ns: Set, +) : RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: T): Boolean { + if (!originalProcessor.acceptsName(entry.name) || entry.name == "_") { + return originalProcessor.process(entry) + } + val prevNs = prevScope[entry.name] + val newNs = entry.namespaces + val entryWithIntersectedNs = if (prevNs != null) { + val restNs = newNs.minus(prevNs) + if (ns.intersects(restNs)) { + entry.copyWithNs(restNs) + } else { + return false + } + } else { + entry + } + currScope[entry.name] = prevNs?.let { it + newNs } ?: newNs + return originalProcessor.process(entryWithIntersectedNs) + } + override fun toString(): String = "ShadowingAndUpdateScopeProcessor($originalProcessor, ns = $ns)" +} -//private class ShadowingAndImmediatelyUpdateScopeProcessor( -// private val originalProcessor: RsResolveProcessor, -// private val prevScope: MutableMap>, -// private val ns: Set, -//): RsResolveProcessor { -// override val names: Set? = originalProcessor.names -// override fun process(entry: T): Boolean { -// if (entry.name in prevScope) return false -// val result = originalProcessor.process(entry) -// if (originalProcessor.acceptsName(entry.name)) { -// prevScope[entry.name] = ns -// } -// return result -// } -// -// override fun toString(): String = -// "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" -//} +fun RsResolveProcessorBase.wrapWithShadowingProcessorAndImmediatelyUpdateScope( + prevScope: MutableMap>, + ns: Set, +): RsResolveProcessorBase { + return ShadowingAndImmediatelyUpdateScopeProcessor(this, prevScope, ns) +} + +private class ShadowingAndImmediatelyUpdateScopeProcessor( + private val originalProcessor: RsResolveProcessorBase, + private val prevScope: MutableMap>, + private val ns: Set, +) : RsResolveProcessorBase { + override val names: Set? = originalProcessor.names + override fun process(entry: T): Boolean { + if (entry.name in prevScope) return false + val result = originalProcessor.process(entry) + if (originalProcessor.acceptsName(entry.name)) { + prevScope[entry.name] = ns + } + return result + } + override fun toString(): String = "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" +} fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Unit): List { if (referenceName == null) return emptyList() @@ -406,10 +404,10 @@ private class PickFirstScopeEntryCollector( data class SimpleScopeEntry( override val name: String, override val element: MvElement, -// override val namespaces: Set, + override val namespaces: Set, // override val subst: Substitution = emptySubstitution ): ScopeEntry { -// override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) + override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) } data class ModInfo( @@ -451,12 +449,12 @@ enum class VisibilityStatus { data class ScopeEntryWithVisibility( override val name: String, override val element: MvElement, - val namespaces: Set, + override val namespaces: Set, /** Given a [MvElement] (usually [MvPath]) checks if this item is visible in `containingMod` of that element */ val visibilityFilter: VisibilityFilter, // override val subst: Substitution = emptySubstitution, ): ScopeEntry { -// override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) + override fun doCopyWithNs(namespaces: Set): ScopeEntry = copy(namespaces = namespaces) } fun RsResolveProcessor.process( @@ -472,7 +470,7 @@ fun RsResolveProcessor.process( // namespaces: Set, e: MvElement ): Boolean = - process(SimpleScopeEntry(name, e)) + process(SimpleScopeEntry(name, e, Namespace.none())) // process(ScopeEntry(name, e, namespaces)) inline fun RsResolveProcessor.lazy( diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index ad55239e0..2b0415f52 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -17,13 +17,16 @@ fun processNestedScopesUpwards( ctx: PathResolutionContext, processor: RsResolveProcessor ): Boolean { + val prevScope = hashMapOf>() return walkUpThroughScopes( scopeStart, stopAfter = { it is MvModule } ) { cameFrom, scope -> - processItemsInScope( - scope, cameFrom, ns, ctx.contextScopeInfo, processor - ) + processWithShadowingAndUpdateScope(prevScope, ns, processor) { shadowingProcessor -> + processItemsInScope( + scope, cameFrom, ns, ctx.contextScopeInfo, shadowingProcessor + ) + } // if (scope !is MvCodeBlock && scope is MvItemsOwner) { // if (processItemDeclarations(scope, ns, addImports = true, processor)) return@walkUpThroughScopes true // false @@ -72,3 +75,28 @@ fun processAddressPathResolveVariants( return false } + +inline fun processWithShadowingAndUpdateScope( + prevScope: MutableMap>, + ns: Set, + processor: RsResolveProcessor, + f: (RsResolveProcessor) -> Boolean +): Boolean { + val currScope = mutableMapOf>() + val shadowingProcessor = processor.wrapWithShadowingProcessorAndUpdateScope(prevScope, currScope, ns) + return try { + f(shadowingProcessor) + } finally { + prevScope.putAll(currScope) + } +} + +inline fun processWithShadowing( + prevScope: Map>, + ns: Set, + processor: RsResolveProcessor, + f: (RsResolveProcessor) -> Boolean +): Boolean { + val shadowingProcessor = processor.wrapWithShadowingProcessor(prevScope, ns) + return f(shadowingProcessor) +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestCase.kt b/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestCase.kt index 5eb31cc40..8d66993f8 100644 --- a/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestCase.kt +++ b/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestCase.kt @@ -13,7 +13,8 @@ abstract class ResolveTestCase : MvTestBase() { ) { InlineFile(code, "main.move") - val (refElement, data, offset) = myFixture.findElementWithDataAndOffsetInEditor("^") + val (refElement, data, offset) = + myFixture.findElementWithDataAndOffsetInEditor("^") if (data == "unresolved") { val resolved = refElement.reference?.resolve() diff --git a/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestUtils.kt b/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestUtils.kt index 35a0de95e..1fff73ede 100644 --- a/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestUtils.kt +++ b/src/main/kotlin/org/move/utils/tests/resolve/ResolveTestUtils.kt @@ -3,6 +3,8 @@ package org.move.utils.tests.resolve import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement import com.intellij.psi.PsiReference +import org.move.lang.core.resolve.ref.MvPathReference +import org.move.lang.core.resolve.ref.MvPolyVariantReference fun checkResolvedFile( actualResolveFile: VirtualFile, @@ -31,9 +33,17 @@ sealed class TestResolveResult { fun PsiElement.findReference(offset: Int): PsiReference? = findReferenceAt(offset - textRange.startOffset) -fun PsiElement.checkedResolve(offset: Int): PsiElement { +fun PsiElement.checkedResolve(offset: Int, errorMessagePrefix: String = ""): PsiElement { val reference = findReference(offset) ?: error("element doesn't have reference") - val resolved = reference.resolve() ?: error("Failed to resolve `$text`") + val resolved = reference.resolve() ?: run { + val multiResolve = (reference as? MvPolyVariantReference)?.multiResolve().orEmpty() + check(multiResolve.size != 1) + if (multiResolve.isEmpty()) { + error("${errorMessagePrefix}Failed to resolve $text") + } else { + error("${errorMessagePrefix}Failed to resolve $text, multiple variants:\n${multiResolve.joinToString()}") + } + } check(reference.isReferenceTo(resolved)) { "Incorrect `isReferenceTo` implementation in `${reference.javaClass.name}`" From 31de334df5f97011efb250d91fa9df22675e3ad4 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Sun, 14 Jul 2024 22:56:34 +0300 Subject: [PATCH 07/43] visibility rules --- .../org/move/lang/core/psi/NamedItemScope.kt | 2 + .../org/move/lang/core/psi/ext/MvAttrItem.kt | 2 + .../org/move/lang/core/psi/ext/MvFunction.kt | 3 + .../move/lang/core/psi/ext/MvItemsOwner.kt | 4 +- .../org/move/lang/core/psi/ext/MvPath.kt | 6 +- .../org/move/lang/core/psi/ext/MvRefExpr.kt | 2 +- .../lang/core/psi/ext/MvVisibilityOwner.kt | 20 ++++- .../org/move/lang/core/resolve/Processors.kt | 31 +++---- .../lang/core/resolve/ref/MoveReference.kt | 6 +- .../move/lang/core/resolve/ref/Namespace.kt | 12 +++ .../move/lang/core/resolve2/ItemResolution.kt | 18 ++-- .../move/lang/core/resolve2/Visibility2.kt | 88 +++++++++++++++---- .../core/resolve2/ref/Path2ReferenceImpl.kt | 62 ++++++------- .../org/move/lang/core/types/Address.kt | 2 + .../move/lang/resolve/ResolveFunctionTest.kt | 32 ++++--- 15 files changed, 193 insertions(+), 97 deletions(-) diff --git a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt index 82f78e395..e7b3be545 100644 --- a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt +++ b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt @@ -11,6 +11,8 @@ enum class NamedItemScope { TEST, VERIFY; + val isTest get() = this == TEST + companion object { fun all(): Set = setOf(MAIN, TEST, VERIFY) } 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 eb771539c..f76b354a7 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 @@ -8,6 +8,8 @@ import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached val MvAttrItem.attr: MvAttr? get() = this.parent as? MvAttr +val MvAttrItem.isAbortCode: Boolean get() = this.identifier.textMatches("abort_code") + class AttrItemReferenceImpl( element: MvAttrItem, val ownerFunction: MvFunction diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvFunction.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvFunction.kt index 73baf52ef..1cdc86d74 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvFunction.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvFunction.kt @@ -50,6 +50,9 @@ val MvFunction.isEntry: Boolean return stub?.isEntry ?: this.isChildExists(MvElementTypes.ENTRY) } +val MvFunction.isPublicScript: Boolean + get() = this.visibilityModifier?.isPublicScript ?: false + val MvFunction.isInline: Boolean get() = this.isChildExists(MvElementTypes.INLINE) val MvFunction.isView: Boolean diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index 8e5309fb6..efd814e62 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -13,10 +13,10 @@ fun MvItemsOwner.items(): Sequence { .filter { it !is MvAttr } } -val MvItemsOwner.visibleItems: Sequence +val MvItemsOwner.visibleItems: Sequence get() { return this.items() - .filterIsInstance() + .filterIsInstance() .filterNot { (it as? MvFunction)?.hasTestAttr ?: false } } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index b1e6843c0..2e28142c6 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -104,10 +104,8 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvCallExpr -> EnumSet.of(Namespace.FUNCTION) parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) parent is MvRefExpr -> EnumSet.of(Namespace.NAME) -// parent is MvRefExpr && this.nullModuleRef -> setOf(Namespace.NAME) -// parent is MvRefExpr && !this.nullModuleRef -> setOf(Namespace.NAME, Namespace.MODULE) - // TODO: it's own namespace? - parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.NAME) + parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.TYPE) +// parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.NAME) parent is MvAccessSpecifier -> EnumSet.of(Namespace.TYPE) parent is MvAddressSpecifierArg -> EnumSet.of(Namespace.FUNCTION) parent is MvAddressSpecifierCallParam -> EnumSet.of(Namespace.NAME) 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 06a7dba1f..e54cdf537 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 @@ -8,7 +8,7 @@ import org.move.lang.core.psi.MvRefExpr fun MvRefExpr.isAbortCodeConst(): Boolean { val abortCodeItem = (this.parent.parent as? MvAttrItem) - ?.takeIf { it.identifier.text == "abort_code" } + ?.takeIf { it.isAbortCode } ?: 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/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt index 2ba2990b3..1de41a5d7 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -2,19 +2,18 @@ package org.move.lang.core.psi.ext import com.intellij.psi.util.PsiTreeUtil import org.move.cli.containingMovePackage -import org.move.lang.core.psi.MvConst import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvVisibilityModifier import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.VisKind.* import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve.ref.Visibility2 interface MvVisibilityOwner: MvElement { val visibilityModifier: MvVisibilityModifier? get() = PsiTreeUtil.getStubChildOfType(this, MvVisibilityModifier::class.java) - val visibility2: Visibility - get() = visibilityModifier?.visibility ?: Visibility.Internal +// val visibility2: Visibility2 get() = this.visibility22 // restricted visibility considered as public val isPublic: Boolean get() = visibilityModifier != null @@ -47,6 +46,21 @@ val MvVisibilityModifier.visibility: Visibility PUBLIC -> Visibility.Public } +val MvVisibilityOwner.visibility2: Visibility2 + get() { + val kind = this.visibilityModifier?.stubKind ?: return Visibility2.Private + return when (kind) { + PACKAGE -> containingMovePackage?.let { Visibility2.Restricted.Package(it) } ?: Visibility2.Public + FRIEND -> { + val module = this.containingModule ?: return Visibility2.Private + // todo: make lazy + val friendModules = module.declaredFriendModules + Visibility2.Restricted.Friend(friendModules) + } + SCRIPT -> Visibility2.Restricted.Script + PUBLIC -> Visibility2.Public + } + } diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index b69819074..f78a3a045 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -339,17 +339,8 @@ private fun collectPathScopeEntry( e: ScopeEntry ) { val element = e.element - val visibilityStatus = e.getVisibilityStatusFrom(ctx.context, ctx.lazyContainingModInfo) -// if (visibilityStatus != VisibilityStatus.CfgDisabled) { + val visibilityStatus = e.getVisibilityStatusFrom(ctx.path) val isVisible = visibilityStatus == VisibilityStatus.Visible - // Canonicalize namespaces to consume less memory by the resolve cache -// val namespaces = when (e.namespaces) { -// TYPES -> TYPES -// VALUES -> VALUES -// TYPES_N_VALUES -> TYPES_N_VALUES -// else -> e.namespaces -// } -// result += element result += RsPathResolveResult(element, isVisible) // } } @@ -412,9 +403,10 @@ data class SimpleScopeEntry( data class ModInfo( // val movePackage: MovePackage?, - val module: MvModule, + val module: MvModule?, // val isScript: Boolean, -) +) { +} fun Map.entriesWithNames(names: Set?): Map { return if (names.isNullOrEmpty()) { @@ -428,18 +420,23 @@ fun Map.entriesWithNames(names: Set?): Map { } } -typealias VisibilityFilter = (MvElement, Lazy?) -> VisibilityStatus +fun interface VisibilityFilter { + fun filter(path: MvPath, ns: Set): VisibilityStatus +} + +//typealias VisibilityFilter = (MvPath, Set) -> VisibilityStatus +//typealias VisibilityFilter = (MvElement, Lazy?) -> VisibilityStatus -fun ScopeEntry.getVisibilityStatusFrom(context: MvElement, lazyModInfo: Lazy?): VisibilityStatus = +fun ScopeEntry.getVisibilityStatusFrom(path: MvPath): VisibilityStatus = if (this is ScopeEntryWithVisibility) { - visibilityFilter(context, lazyModInfo) + visibilityFilter.filter(path, this.namespaces) } else { VisibilityStatus.Visible } -fun ScopeEntry.isVisibleFrom(context: MvElement): Boolean = - getVisibilityStatusFrom(context, null) == VisibilityStatus.Visible +fun ScopeEntry.isVisibleFrom(context: MvPath): Boolean = + getVisibilityStatusFrom(context) == VisibilityStatus.Visible enum class VisibilityStatus { Visible, diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt index 16733e351..5009ec9f7 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt @@ -39,10 +39,10 @@ interface MvPathReference : MvPolyVariantReference { } interface MvPath2Reference: MvPolyVariantReference { - fun multiResolveIfVisible(): List = multiResolve() +// fun multiResolveIfVisible(): List = multiResolve() - fun rawMultiResolve(): List> = - multiResolve().map { RsPathResolveResult(it, isVisible = true) } +// fun rawMultiResolve(): List> +// multiResolve().map { RsPathResolveResult(it, isVisible = true) } fun resolveFollowingAliases(): MvNamedElement? { val resolved = this.resolve() diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index 6db3656a9..290aa983f 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -7,11 +7,23 @@ import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.containingFunction import org.move.lang.core.psi.containingModule +import org.move.lang.core.psi.ext.FQModule import org.move.lang.core.psi.ext.FunctionVisibility import org.move.lang.core.psi.ext.asSmartPointer import org.move.lang.core.psi.ext.visibility import java.util.* +sealed class Visibility2 { + data object Public: Visibility2() + data object Private: Visibility2() + sealed class Restricted: Visibility2() { + class Friend(val friendModules: Set): Restricted() + class Package(val originPackage: MovePackage): Restricted() + data object Script: Restricted() + } + +} + sealed class Visibility { object Public: Visibility() object PublicScript: Visibility() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 6f4921987..cc9c3d275 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -5,7 +5,9 @@ import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.RsResolveProcessor import org.move.lang.core.resolve.process import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve.ref.Namespace.NAME +import org.move.lang.core.resolve.ref.Namespace.TYPE +import org.move.stdext.intersects import java.util.* val MvNamedElement.namespaces: Set @@ -41,12 +43,16 @@ fun processItemDeclarations( for (item in itemsOwner.visibleItems) { val name = item.name ?: continue - val namespace = item.namespace - if (namespace !in ns) continue + val namespaces = mutableSetOf(item.namespace) +// if (namespaces.contains(TYPE) && ns.contains(NAME)) { +// // struct lit / pat +// namespaces.add(NAME) +// } + if (!namespaces.intersects(ns)) continue - val visibility = (item as? MvVisibilityOwner)?.visibility2 ?: Visibility.Internal - val visibilityFilter = visibility.createFilter() - if (processor.process(name, item, EnumSet.of(namespace), visibilityFilter)) return true + val itemVisibility = ItemVisibility(item, isTestOnly = item.hasTestOnlyAttr, vis = item.visibility2) + val visibilityFilter = itemVisibility.createFilter() + if (processor.process(name, item, namespaces, visibilityFilter)) return true } return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 71c28bfde..8a0fbf9d9 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -1,24 +1,82 @@ package org.move.lang.core.resolve2 -import org.move.lang.core.psi.MvElement -import org.move.lang.core.psi.MvModule +import org.move.ide.inspections.imports.pathUsageScope +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ModInfo import org.move.lang.core.resolve.VisibilityFilter -import org.move.lang.core.resolve.VisibilityStatus -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.resolve.ref.Visibility.Public +import org.move.lang.core.resolve.VisibilityStatus.Invisible +import org.move.lang.core.resolve.VisibilityStatus.Visible +import org.move.lang.core.resolve.ref.Namespace.CONST +import org.move.lang.core.resolve.ref.Namespace.TYPE +import org.move.lang.core.resolve.ref.Visibility2 +import org.move.lang.core.resolve.ref.Visibility2.* -fun getModInfo(module: MvModule): ModInfo { - return ModInfo(module = module) -} +data class ItemVisibility( + val item: MvItemElement, + val isTestOnly: Boolean, + val vis: Visibility2, +) /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ -fun Visibility.createFilter(): VisibilityFilter = - if (this !is Public) { - fun(context: MvElement, lazyModInfo: Lazy?): VisibilityStatus { - val modInfo = lazyModInfo?.value ?: return VisibilityStatus.Invisible - return VisibilityStatus.Visible +fun ItemVisibility.createFilter(): VisibilityFilter { + val (item, isTestOnly, vis) = this + return VisibilityFilter { path, namespaces -> + + // inside msl + if (path.isMsl()) return@VisibilityFilter Visible + + // types are always visible + if (namespaces.contains(TYPE)) return@VisibilityFilter Visible + + // if inside MvAttrItem like abort_code= + val attrItem = path.ancestorStrict() + if (attrItem != null) return@VisibilityFilter Visible + + val pathUsageScope = path.pathUsageScope + val useSpeck = path.ancestorStrict() + if (useSpeck != null) { + // inside import, all visibilities except for private work + if (vis is Restricted) return@VisibilityFilter Visible + + // consts are importable in tests + if (pathUsageScope.isTest && namespaces.contains(CONST)) return@VisibilityFilter Visible + } + + // #[test_only] items in non-test-only scope + if (isTestOnly && !pathUsageScope.isTest) return@VisibilityFilter Invisible + + // Self::method + val itemModule = item.containingModule + val pathModule = path.containingModule + if (itemModule == pathModule) return@VisibilityFilter Visible + + when (vis) { + is Restricted -> { + when (vis) { + is Restricted.Friend -> { + val friends = vis.friendModules + val modInfo = pathModule?.fqModule() + if (modInfo in friends) Visible else Invisible + } + is Restricted.Script -> { + val containingFunction = path.containingFunction + if (containingFunction != null) { + if (containingFunction.isEntry + || containingFunction.isPublicScript + ) return@VisibilityFilter Visible + } + if (path.containingScript != null) return@VisibilityFilter Visible + Invisible + } + is Restricted.Package -> { + // todo + Visible + } + } + } + is Public -> Visible + is Private -> Invisible } - } else { - { _, _ -> VisibilityStatus.Visible } } +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 6ba56a507..9a148c8a7 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -7,7 +7,9 @@ import org.move.lang.core.psi.ext.allowedNamespaces import org.move.lang.core.psi.ext.qualifier import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* -import org.move.lang.core.resolve2.* +import org.move.lang.core.resolve2.processAddressPathResolveVariants +import org.move.lang.core.resolve2.processItemDeclarations +import org.move.lang.core.resolve2.processNestedScopesUpwards import org.move.lang.core.resolve2.ref.RsPathResolveKind.* import org.move.lang.core.types.Address import org.move.lang.moveProject @@ -16,36 +18,25 @@ import kotlin.LazyThreadSafetyMode.NONE class Path2ReferenceImpl(element: MvPath): MvPolyVariantReferenceBase(element), MvPath2Reference { -// private fun rawMultiResolveUsingInferenceCache(): List>? { -// val msl = element.isMsl() -// return element.inference(msl)?.getResolvedPath(element)?.map { result -> -// RsPathResolveResult(result.element, result.isVisible) -// } -// } - -// override fun multiResolveInner(): List { -// val referenceName = element.referenceName ?: return emptyList() -// val resolveVariants = collectResolveVariantsAsScopeEntries(referenceName) { -// processPathResolveVariants(element, it) -// } -// return resolveVariants.mapNotNull { it.element as? MvNamedElement } -// } + override fun resolve(): MvNamedElement? = + rawMultiResolveIfVisible().singleOrNull()?.element as? MvNamedElement - override fun resolve(): MvNamedElement? = rawMultiResolve().singleOrNull()?.element as? MvNamedElement + override fun multiResolve(): List = + rawMultiResolveIfVisible().mapNotNull { it.element as? MvNamedElement } override fun multiResolve(incompleteCode: Boolean): Array = rawMultiResolve().toTypedArray() - override fun multiResolve(): List = - rawMultiResolve().mapNotNull { it.element as? MvNamedElement } +// fun multiResolveIfVisible(): List = +// rawMultiResolve().mapNotNull { +// if (!it.isVisible) return@mapNotNull null +// it.element +// } - override fun multiResolveIfVisible(): List = - rawMultiResolve().mapNotNull { - if (!it.isVisible) return@mapNotNull null - it.element - } + fun rawMultiResolveIfVisible(): List> = + rawMultiResolve().filter { it.isVisible } - override fun rawMultiResolve(): List> = Resolver.invoke(this.element) + fun rawMultiResolve(): List> = Resolver.invoke(this.element) // override fun rawMultiResolve(): List> = rawCachedMultiResolve() private fun rawCachedMultiResolve(): List> { @@ -60,11 +51,10 @@ class Path2ReferenceImpl(element: MvPath): if (path !is MvPath) return emptyList() val ctx = PathResolutionContext( - context = path, + path = path, contextScopeInfo = ContextScopeInfo.from(path) ) - val result = resolvePath(ctx, path, ctx.classifyPath(path)) - return result + return resolvePath(ctx, path, ctx.classifyPath(path)) } } } @@ -83,12 +73,12 @@ fun processPathResolveVariants( // Self:: if (processor.lazy("Self") { ctx.containingModule }) return true // local - processNestedScopesUpwards(ctx.context, pathKind.ns, ctx, contextScopeAwareProcessor) + processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextScopeAwareProcessor) } is AddressPath -> { // 0x1::bar processAddressPathResolveVariants( - ctx.context, + ctx.path, ctx.moveProject, pathKind.canonicalAddress, contextScopeAwareProcessor @@ -170,21 +160,23 @@ sealed class RsPathResolveKind { } class PathResolutionContext( - val context: MvElement, + val path: MvPath, val contextScopeInfo: ContextScopeInfo, ) { private var lazyContainingMoveProject: Lazy = lazy(NONE) { - context.moveProject + path.moveProject } val moveProject: MoveProject? get() = lazyContainingMoveProject.value private var lazyContainingModule: Lazy = lazy(NONE) { - context.containingModule + path.containingModule } val containingModule: MvModule? get() = lazyContainingModule.value - var lazyContainingModInfo: Lazy = lazy(NONE) { - containingModule?.let { getModInfo(it) } - } + +// var lazyContainingModInfo: Lazy = lazy(NONE) { +// val module = containingModule +// getModInfo(module) +// } fun classifyPath(path: MvPath): RsPathResolveKind { val qualifier = path.qualifier diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index caa0ea60a..168c9b8ee 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -58,6 +58,8 @@ sealed class Address { } override fun hashCode(): Int = normalizeValue(value).hashCode() + + override fun toString(): String = "Address.Value($value)" } class Named( diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index fdb445171..b0baa096e 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -319,22 +319,18 @@ class ResolveFunctionTest: ResolveTestCase() { fun `test friend function is unresolved in scripts`() = checkByCode( """ - address 0x1 { - module Original { - friend 0x1::M; + module 0x1::original { + friend 0x1::m; public(friend) fun call() {} } - - module M {} - } - - script { - use 0x1::Original; + module 0x1::m {} + script { + use 0x1::original; fun main() { - Original::call(); + original::call(); //^ unresolved } - } + } """ ) @@ -371,6 +367,20 @@ class ResolveFunctionTest: ResolveTestCase() { """ ) + fun `test public script function can be resolved from import`() = checkByCode( + """ + module 0x1::M { + public(script) fun call() {} + //X + } + #[test_only] + module 0x1::Tests { + use 0x1::M::call; + //^ + } + """ + ) + fun `test public script function available in test`() = checkByCode( """ module 0x1::M { From 976d00e362dec9741f287c3238f9fbed7d19f93e Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Mon, 15 Jul 2024 01:18:01 +0300 Subject: [PATCH 08/43] almost finish name resolution --- src/main/grammars/MoveParser.bnf | 7 +- .../completion/CommonCompletionContributor.kt | 2 +- .../providers/MvPathCompletionProvider.kt | 98 +++++++++++++------ .../move/lang/core/psi/ext/MvItemsOwner.kt | 18 +++- .../org/move/lang/core/psi/ext/MvPath.kt | 4 +- .../lang/core/psi/ext/MvVisibilityOwner.kt | 2 + .../org/move/lang/core/resolve/Processors.kt | 75 ++++++++++++++ .../move/lang/core/resolve2/ItemResolution.kt | 57 +++++++---- .../core/resolve2/LexicalDeclarations2.kt | 3 +- .../lang/core/resolve2/NameResolution2.kt | 11 +-- .../move/lang/core/resolve2/Visibility2.kt | 17 ++-- .../core/resolve2/ref/Path2ReferenceImpl.kt | 44 ++++++--- .../org/move/lang/core/types/Address.kt | 6 +- .../docs/MoveNamedAddressDocumentationTest.kt | 2 +- ...st.kt => FindUsagesNamedModulePathTest.kt} | 2 +- ...esTest.kt => NamedModulePathValuesTest.kt} | 2 +- .../move/lang/resolve/ResolveFunctionTest.kt | 36 +++++++ .../move/lang/resolve/ResolveModulesTest.kt | 23 +++++ ... ResolveNamedModulePathTreeProjectTest.kt} | 2 +- .../org/move/lang/resolve/ResolveSpecsTest.kt | 13 +++ 20 files changed, 335 insertions(+), 89 deletions(-) rename src/test/kotlin/org/move/ide/search/{FindUsagesNamedAddressTest.kt => FindUsagesNamedModulePathTest.kt} (97%) rename src/test/kotlin/org/move/lang/{NamedAddressValuesTest.kt => NamedModulePathValuesTest.kt} (98%) rename src/test/kotlin/org/move/lang/resolve/{ResolveNamedAddressTreeProjectTest.kt => ResolveNamedModulePathTreeProjectTest.kt} (98%) diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 686db8877..7d026cbe1 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -289,6 +289,7 @@ fake SpecFunction ::= Attr* spec native? fun IDENTIFIER? TypeParameterList? implements = [ "org.move.lang.core.psi.MvQualNamedElement" "org.move.lang.core.psi.MvFunctionLike" + "org.move.lang.core.psi.ext.MvItemElement" "org.move.lang.core.types.infer.MvInferenceContextOwner" "org.move.lang.core.psi.ScopeMslOnlyElement" ] @@ -320,6 +321,7 @@ fake SpecInlineFunction ::= Attr* native? fun IDENTIFIER? TypeParameterList? implements = [ "org.move.lang.core.psi.MvFunctionLike" "org.move.lang.core.types.infer.MvInferenceContextOwner" + "org.move.lang.core.psi.ext.MvItemElement" "org.move.lang.core.psi.ScopeMslOnlyElement" ] mixin = "org.move.lang.core.psi.ext.MvSpecInlineFunctionMixin" @@ -1348,13 +1350,14 @@ SchemaFieldStmt_local ::= local BindingPat TypeAnnotation ';' { elementType = SchemaFieldStmt } -GlobalVariableStmt ::= global IDENTIFIER TypeParameterList? TypeAnnotation ('=' Expr)? ';' +GlobalVariableStmt ::= Attr* global IDENTIFIER TypeParameterList? TypeAnnotation ('=' Expr)? ';' { - pin = 1 + pin = 2 implements = [ "org.move.lang.core.psi.MvNameIdentifierOwner" "org.move.lang.core.psi.MvTypeAnnotationOwner" "org.move.lang.core.psi.MslOnlyElement" + "org.move.lang.core.psi.ext.MvItemElement" ] mixin = "org.move.lang.core.psi.ext.MvGlobalVariableMixin" } diff --git a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt index 90626d122..683d5bb80 100644 --- a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt +++ b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt @@ -18,7 +18,7 @@ class CommonCompletionContributor : CompletionContributor() { extend(CompletionType.BASIC, AddressInModuleDeclCompletionProvider) extend(CompletionType.BASIC, TypesCompletionProvider) extend(CompletionType.BASIC, ImportsCompletionProvider) - extend(CompletionType.BASIC, ModulesCompletionProvider) +// extend(CompletionType.BASIC, ModulesCompletionProvider) extend(CompletionType.BASIC, FQModuleCompletionProvider) extend(CompletionType.BASIC, StructFieldsCompletionProvider) extend(CompletionType.BASIC, StructPatCompletionProvider) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index e0cfb2591..ec5c940fe 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -17,6 +17,9 @@ import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve2.processItemDeclarations +import org.move.lang.core.resolve2.processNestedScopesUpwards +import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.types.infer.inferExpectedTy import org.move.lang.core.types.infer.inference import org.move.lang.core.types.ty.Ty @@ -42,51 +45,84 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { if (parameters.position !== pathElement.referenceNameElement) return - val moduleRef = pathElement.moduleRef + val qualifier = pathElement.qualifier + val namespaces = setOf(this.namespace) - val pathScopeInfo = pathScopeInfo(pathElement) + val contextScopeInfo = pathScopeInfo(pathElement) val msl = pathElement.isMslScope val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) - val structAsType = this.namespace == Namespace.TYPE - val ctx = CompletionContext( + + val completionContext = CompletionContext( pathElement, - pathScopeInfo, + contextScopeInfo, expectedTy ) - if (moduleRef != null) { - val module = moduleRef.reference?.resolveWithAliases() as? MvModule - ?: return - val vs = when { - moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) - else -> Visibility.visibilityScopesForElement(pathElement) - } - processModuleItems(module, namespaces, vs, pathScopeInfo) { - val lookup = - it.element.createLookupElement(ctx, structAsType = structAsType) - result.addElement(lookup) - false + var completionCollector = createProcessor { e -> + val element = e.element as? MvNamedElement ?: return@createProcessor + val lookup = + element.createLookupElement( + completionContext, + structAsType = structAsType, + priority = element.completionPriority + ) + result.addElement(lookup) + } + + if (qualifier != null) { + val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() + if (resolvedQualifier is MvItemsOwner) { + processItemDeclarations(resolvedQualifier, namespaces, completionCollector) } return } +// if (moduleRef != null) { +// val module = moduleRef.reference?.resolveWithAliases() as? MvModule +// ?: return +// val vs = when { +// moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) +// else -> Visibility.visibilityScopesForElement(pathElement) +// } +// processModuleItems(module, namespaces, vs, contextScopeInfo) { +// val lookup = +// it.element.createLookupElement(ctx, structAsType = structAsType) +// result.addElement(lookup) +// false +// } +// return +// } + val processedNames = mutableSetOf() - processItems(pathElement, namespaces, pathScopeInfo) { (name, element) -> - if (processedNames.contains(name)) { - return@processItems false +// completionCollector = +// completionCollector.wrapWithBeforeProcessingHandler { processedNames.add(it.name) } + completionCollector = completionCollector.wrapWithFilter { e -> + if (processedNames.contains(e.name)) { + return@wrapWithFilter false } - processedNames.add(name) - result.addElement( - element.createLookupElement( - ctx, - structAsType = structAsType, - priority = element.completionPriority - ) - ) - false + processedNames.add(e.name) + true } + val ctx = PathResolutionContext(pathElement, contextScopeInfo) + processNestedScopesUpwards(pathElement, namespaces, ctx, completionCollector) + +// processItems(pathElement, namespaces, contextScopeInfo) { (name, element) -> +// if (processedNames.contains(name)) { +// return@processItems false +// } +// processedNames.add(name) +// result.addElement( +// element.createLookupElement( +// completionContext, +// structAsType = structAsType, +// priority = element.completionPriority +// ) +// ) +// false +// } + // disable auto-import in module specs for now if (pathElement.containingModuleSpec != null) return @@ -96,7 +132,7 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { originalPathElement, namespaces, setOf(Visibility.Public), - pathScopeInfo + contextScopeInfo ) val candidates = getImportCandidates( parameters, @@ -106,7 +142,7 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { ) candidates.forEach { candidate -> val lookupElement = candidate.element.createLookupElement( - ctx, + completionContext, structAsType = structAsType, priority = UNIMPORTED_ITEM_PRIORITY, insertHandler = ImportInsertHandler(parameters, candidate) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index efd814e62..2945c7519 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -2,6 +2,7 @@ package org.move.lang.core.psi.ext import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache import org.move.lang.core.psi.* +import org.move.stdext.buildList interface MvItemsOwner: MvElement { val useStmtList: List get() = emptyList() @@ -13,11 +14,26 @@ fun MvItemsOwner.items(): Sequence { .filter { it !is MvAttr } } -val MvItemsOwner.visibleItems: Sequence +val MvItemsOwner.visibleItems: List get() { return this.items() .filterIsInstance() .filterNot { (it as? MvFunction)?.hasTestAttr ?: false } + .toList() + } + +val MvModule.innerSpecItems: List + get() { + val module = this + return buildList { + addAll(module.allModuleSpecs() + .map { + it.moduleItemSpecs() + .flatMap { spec -> spec.itemSpecBlock?.globalVariables().orEmpty() } + } + .flatten()) + addAll(module.specInlineFunctions()) + } } fun MvItemsOwner.moduleUseItems(): List = diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 2e28142c6..fa04ca103 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -102,8 +102,8 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvSchemaLit || parent is MvSchemaRef -> EnumSet.of(Namespace.SCHEMA) parent is MvPathType -> EnumSet.of(Namespace.TYPE) parent is MvCallExpr -> EnumSet.of(Namespace.FUNCTION) - parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) - parent is MvRefExpr -> EnumSet.of(Namespace.NAME) +// parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) + parent is MvRefExpr -> EnumSet.of(Namespace.NAME, Namespace.CONST) parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.TYPE) // parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.NAME) parent is MvAccessSpecifier -> EnumSet.of(Namespace.TYPE) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt index 1de41a5d7..86f3d6b27 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -4,6 +4,7 @@ import com.intellij.psi.util.PsiTreeUtil import org.move.cli.containingMovePackage import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvVisibilityModifier +import org.move.lang.core.psi.ScopeMslOnlyElement import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.VisKind.* import org.move.lang.core.resolve.ref.Visibility @@ -49,6 +50,7 @@ val MvVisibilityModifier.visibility: Visibility val MvVisibilityOwner.visibility2: Visibility2 get() { val kind = this.visibilityModifier?.stubKind ?: return Visibility2.Private + return when (kind) { PACKAGE -> containingMovePackage?.let { Visibility2.Restricted.Package(it) } ?: Visibility2.Public FRIEND -> { diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index f78a3a045..28be3f0c6 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -1,6 +1,9 @@ package org.move.lang.core.resolve +import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.util.SmartList +import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvNamedElement @@ -373,6 +376,78 @@ private class PickFirstScopeEntryCollector( } } + +fun collectCompletionVariants( + result: CompletionResultSet, + context: CompletionContext, + f: (RsResolveProcessor) -> Unit +) { + val processor = CompletionVariantsCollector(result, context) + f(processor) +} + +private class CompletionVariantsCollector( + private val result: CompletionResultSet, + private val context: CompletionContext, +) : RsResolveProcessorBase { + override val names: Set? get() = null + + override fun process(entry: ScopeEntry): Boolean { +// addEnumVariantsIfNeeded(entry) +// addAssociatedItemsIfNeeded(entry) + +// (entry.element as? MvNamedElement)?.let { +// it.createLookupElement(context) +// } +// result.addElement(createLookupElement( +// context = context +// )) + return false + } + +// private fun addEnumVariantsIfNeeded(entry: ScopeEntry) { +// val element = entry.element as? RsEnumItem ?: return +// +// val expectedType = (context.expectedTy?.ty?.stripReferences() as? TyAdt)?.item +// val actualType = (element.declaredType as? TyAdt)?.item +// +// val parent = context.context +// val contextPat = if (parent is RsPath) parent.context else parent +// val contextIsPat = contextPat is RsPatBinding || contextPat is RsPatStruct || contextPat is RsPatTupleStruct +// +// if (expectedType == actualType || contextIsPat) { +// val variants = collectVariantsForEnumCompletion(element, context, entry.subst) +// val filtered = when (contextPat) { +// is RsPatStruct -> variants.filter { (it.psiElement as? RsEnumVariant)?.blockFields != null } +// is RsPatTupleStruct -> variants.filter { (it.psiElement as? RsEnumVariant)?.tupleFields != null } +// else -> variants +// } +// result.addAllElements(filtered) +// } +// } + +// private fun addAssociatedItemsIfNeeded(entry: ScopeEntry) { +// if (entry.name != "Self") return +// val entryTrait = when (val traitOrImpl = entry.element as? RsTraitOrImpl) { +// is RsTraitItem -> traitOrImpl as? RsTraitItem ?: return +// is RsImplItem -> traitOrImpl.traitRef?.path?.reference?.resolve() as? RsTraitItem ?: return +// else -> return +// } +// +// val associatedTypes = entryTrait +// .associatedTypesTransitively +// .mapNotNull { type -> +// val name = type.name ?: return@mapNotNull null +// val typeAlias = type.superItem ?: type +// createLookupElement( +// SimpleScopeEntry("Self::$name", typeAlias, TYPES), +// context, +// ) +// } +// result.addAllElements(associatedTypes) +// } +} + //fun collectNames(f: (RsResolveProcessor) -> Unit): Set { // val processor = NamesCollector() // f(processor) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index cc9c3d275..776a5a8bb 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -2,12 +2,9 @@ package org.move.lang.core.resolve2 import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.RsResolveProcessor -import org.move.lang.core.resolve.process +import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.NAME -import org.move.lang.core.resolve.ref.Namespace.TYPE -import org.move.stdext.intersects import java.util.* val MvNamedElement.namespaces: Set @@ -22,12 +19,13 @@ val MvNamedElement.namespaces: Set val MvNamedElement.namespace get() = when (this) { - is MvFunction -> Namespace.FUNCTION + is MvFunctionLike -> Namespace.FUNCTION is MvStruct -> Namespace.TYPE is MvConst -> Namespace.CONST is MvSchema -> Namespace.SCHEMA is MvModule -> Namespace.MODULE - else -> error("when should be exhaustive") + is MvGlobalVariableStmt -> Namespace.NAME + else -> error("when should be exhaustive, $this is not covered") } fun processItemDeclarations( @@ -36,24 +34,49 @@ fun processItemDeclarations( processor: RsResolveProcessor ): Boolean { - // todo: // 1. loop over all items in module (item is anything accessible with MODULE:: ) // 2. for every item, use it's .visibility to create VisibilityFilter, even it's just a { false } - - for (item in itemsOwner.visibleItems) { + val items = itemsOwner.visibleItems + + (itemsOwner as? MvModuleBlock)?.module?.innerSpecItems.orEmpty() + + (itemsOwner as? MvModuleBlock)?.let { getItemsFromModuleSpecs(it.module, ns) }.orEmpty() + for (item in items) { val name = item.name ?: continue - val namespaces = mutableSetOf(item.namespace) -// if (namespaces.contains(TYPE) && ns.contains(NAME)) { -// // struct lit / pat -// namespaces.add(NAME) -// } - if (!namespaces.intersects(ns)) continue + val namespace = item.namespace + if (namespace !in ns) continue val itemVisibility = ItemVisibility(item, isTestOnly = item.hasTestOnlyAttr, vis = item.visibility2) val visibilityFilter = itemVisibility.createFilter() - if (processor.process(name, item, namespaces, visibilityFilter)) return true + if (processor.process(name, item, EnumSet.of(namespace), visibilityFilter)) return true } return false -} \ No newline at end of file +} + +fun getItemsFromModuleSpecs(module: MvModule, ns: Set): List { + val c = mutableListOf() + processItemsFromModuleSpecs(module, ns, createProcessor { c.add(it.element as MvItemElement) }) + return c +} + +fun processItemsFromModuleSpecs( + module: MvModule, + namespaces: Set, + processor: RsResolveProcessor, +): Boolean { + for (namespace in namespaces) { + for (moduleSpec in module.allModuleSpecs()) { + val matched = when (namespace) { + Namespace.FUNCTION -> + processor.processAll( + moduleSpec.specFunctions(), + moduleSpec.specInlineFunctions(), + ) + Namespace.SCHEMA -> processor.processAll(moduleSpec.schemas()) + else -> false + } + if (matched) return true + } + } + return false +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 70b706328..8e6923952 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -257,7 +257,8 @@ fun processItemsInScope( Namespace.MODULE -> when (scope) { is MvItemsOwner -> - processor.processAll(scope.moduleUseItems()) + processor.processAll(emptyList()) +// processor.processAll(scope.moduleUseItems()) else -> false } } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 2b0415f52..2c938aebd 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -8,6 +8,7 @@ import org.move.lang.core.psi.containingMoveFile import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.types.Address import org.move.lang.core.types.address import org.move.lang.index.MvNamedElementIndex @@ -27,19 +28,13 @@ fun processNestedScopesUpwards( scope, cameFrom, ns, ctx.contextScopeInfo, shadowingProcessor ) } -// if (scope !is MvCodeBlock && scope is MvItemsOwner) { -// if (processItemDeclarations(scope, ns, addImports = true, processor)) return@walkUpThroughScopes true -// false -// } else { -// -// } } } fun processAddressPathResolveVariants( element: MvElement, moveProject: MoveProject?, - address: String, + address: Address, processor: RsResolveProcessor, ): Boolean { // if no project, cannot use the index @@ -47,7 +42,7 @@ fun processAddressPathResolveVariants( val equalAddressProcessor = processor.wrapWithFilter { e -> val candidate = e.element as? MvModule ?: return@wrapWithFilter false - val candidateAddress = candidate.address(moveProject)?.canonicalValue(moveProject) + val candidateAddress = candidate.address(moveProject) address == candidateAddress } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 8a0fbf9d9..a60717446 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -20,13 +20,13 @@ data class ItemVisibility( /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ fun ItemVisibility.createFilter(): VisibilityFilter { - val (item, isTestOnly, vis) = this + val (item, isTestOnly, visibility) = this return VisibilityFilter { path, namespaces -> - // inside msl + // inside msl everything is visible if (path.isMsl()) return@VisibilityFilter Visible - // types are always visible + // types are always visible, their correct usage is checked in a separate inspection if (namespaces.contains(TYPE)) return@VisibilityFilter Visible // if inside MvAttrItem like abort_code= @@ -37,7 +37,10 @@ fun ItemVisibility.createFilter(): VisibilityFilter { val useSpeck = path.ancestorStrict() if (useSpeck != null) { // inside import, all visibilities except for private work - if (vis is Restricted) return@VisibilityFilter Visible + if (visibility is Restricted) return@VisibilityFilter Visible + + // msl-only items are available from imports + if (item.isMslOnlyItem) return@VisibilityFilter Visible // consts are importable in tests if (pathUsageScope.isTest && namespaces.contains(CONST)) return@VisibilityFilter Visible @@ -51,11 +54,11 @@ fun ItemVisibility.createFilter(): VisibilityFilter { val pathModule = path.containingModule if (itemModule == pathModule) return@VisibilityFilter Visible - when (vis) { + when (visibility) { is Restricted -> { - when (vis) { + when (visibility) { is Restricted.Friend -> { - val friends = vis.friendModules + val friends = visibility.friendModules val modInfo = pathModule?.fqModule() if (modInfo in friends) Visible else Invisible } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 9a148c8a7..5102196bc 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -5,6 +5,7 @@ import org.move.cli.MoveProject import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.allowedNamespaces import org.move.lang.core.psi.ext.qualifier +import org.move.lang.core.psi.ext.rootPath import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* import org.move.lang.core.resolve2.processAddressPathResolveVariants @@ -75,12 +76,12 @@ fun processPathResolveVariants( // local processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextScopeAwareProcessor) } - is AddressPath -> { + is ModulePath -> { // 0x1::bar processAddressPathResolveVariants( ctx.path, ctx.moveProject, - pathKind.canonicalAddress, + pathKind.address, contextScopeAwareProcessor ) } @@ -88,14 +89,18 @@ fun processPathResolveVariants( // foo::bar processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) } + is NamedAddressPath -> { + return false + } } } fun processPathResolveVariants( path: MvPath, + contextScopeInfo: ContextScopeInfo = ContextScopeInfo.from(path), processor: RsResolveProcessor, ): Boolean { - val ctx = PathResolutionContext(path, contextScopeInfo = ContextScopeInfo.from(path)) + val ctx = PathResolutionContext(path, contextScopeInfo = contextScopeInfo) val pathKind = ctx.classifyPath(path) return processPathResolveVariants(ctx, pathKind, processor) } @@ -153,10 +158,13 @@ sealed class RsPathResolveKind { ): RsPathResolveKind() /** bar in `0x1::bar` */ - class AddressPath( + class ModulePath( val path: MvPath, - val canonicalAddress: String, + val address: Address, ): RsPathResolveKind() + + /** aptos_framework in `use aptos_framework::bar`*/ + object NamedAddressPath: RsPathResolveKind() } class PathResolutionContext( @@ -181,17 +189,31 @@ class PathResolutionContext( fun classifyPath(path: MvPath): RsPathResolveKind { val qualifier = path.qualifier val ns = path.allowedNamespaces() +// if (qualifier == null) { +// return UnqualifiedPath(ns) +// } + val isUseSpeck = path.rootPath().parent is MvUseSpeck if (qualifier == null) { - return UnqualifiedPath(ns) + // left-most path + if (isUseSpeck) { + // use aptos_framework:: + // //^ + return NamedAddressPath + } else { + return UnqualifiedPath(ns) + } } + val qualifierPath = qualifier.path val pathAddress = qualifier.pathAddress + val qualifierName = qualifier.referenceName + return when { - pathAddress != null -> { - val address = Address.Value(pathAddress.text) - val canonical = address.addressLit().canonical() - AddressPath(path, canonical) - } + qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text)) + qualifierPath == null && isUseSpeck && qualifierName != null -> + ModulePath(path, Address.Named(qualifierName, null, qualifier.moveProject)) +// qualifier.parent is MvUseSpeck && qualifierName != null -> +// AddressPath(path, Address.Named(qualifierName, null, qualifier.moveProject)) else -> QualifiedPath(path, qualifier, ns) } } diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index 168c9b8ee..fedf0aad0 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -100,9 +100,7 @@ sealed class Address { return when { left is Value && right is Value -> left.addressLit().canonical() == right.addressLit().canonical() left is Named && right is Named -> - Pair(left.name, normalizeValue(left.value())) == Pair( - right.name, - normalizeValue(right.value()) + Pair(left.name, normalizeValue(left.value())) == Pair(right.name, normalizeValue(right.value()) ) else -> false } @@ -129,7 +127,7 @@ sealed class StubAddress { if (moveProject == null) { Address.Named(this.name, null, null) } else { - moveProject.getNamedAddress(this.name) + moveProject.getNamedAddress(this.name) ?: Address.Named(this.name, null, moveProject) } } is Value -> Address.Value(this.value) diff --git a/src/test/kotlin/org/move/ide/docs/MoveNamedAddressDocumentationTest.kt b/src/test/kotlin/org/move/ide/docs/MoveNamedAddressDocumentationTest.kt index 3edb5a727..b561dd80e 100644 --- a/src/test/kotlin/org/move/ide/docs/MoveNamedAddressDocumentationTest.kt +++ b/src/test/kotlin/org/move/ide/docs/MoveNamedAddressDocumentationTest.kt @@ -2,7 +2,7 @@ package org.move.ide.docs import org.move.utils.tests.MvDocumentationProviderProjectTestCase -class MvNamedAddressDocumentationTest : MvDocumentationProviderProjectTestCase() { +class MvNamedModulePathDocumentationTest : MvDocumentationProviderProjectTestCase() { fun `test value of named address accessible from documentation`() = doTestByFileTree( { moveToml( diff --git a/src/test/kotlin/org/move/ide/search/FindUsagesNamedAddressTest.kt b/src/test/kotlin/org/move/ide/search/FindUsagesNamedModulePathTest.kt similarity index 97% rename from src/test/kotlin/org/move/ide/search/FindUsagesNamedAddressTest.kt rename to src/test/kotlin/org/move/ide/search/FindUsagesNamedModulePathTest.kt index 5be8e27f6..787b30c41 100644 --- a/src/test/kotlin/org/move/ide/search/FindUsagesNamedAddressTest.kt +++ b/src/test/kotlin/org/move/ide/search/FindUsagesNamedModulePathTest.kt @@ -8,7 +8,7 @@ import org.move.utils.tests.MvProjectTestBase import org.move.utils.tests.base.findElementWithDataAndOffsetInEditor import org.toml.lang.psi.TomlKeySegment -class FindUsagesNamedAddressTest : MvProjectTestBase() { +class FindUsagesNamedModulePathTest : MvProjectTestBase() { fun `test resolve toml to move usage`() = doTestByText( """ //- Move.toml diff --git a/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt b/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt similarity index 98% rename from src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt rename to src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt index 64a3c25b5..d1fc77930 100644 --- a/src/test/kotlin/org/move/lang/NamedAddressValuesTest.kt +++ b/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt @@ -6,7 +6,7 @@ import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.MvProjectTestBase import org.move.utils.tests.base.findElementAndDataInEditor -class NamedAddressValuesTest : MvProjectTestBase() { +class NamedModulePathValuesTest : MvProjectTestBase() { fun `test named address`() = checkByFileTree { moveToml(""" [addresses] diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index b0baa096e..a21a43e83 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -722,6 +722,42 @@ module 0x1::mod { """ ) + fun `test resolve spec fun from import`() = checkByCode( + """ + module 0x1::m { + } + spec 0x1::m { + spec module { + fun spec_sip_hash(); + //X + } + } + module 0x1::main { + use 0x1::m::spec_sip_hash; + //^ + } + """ + ) + + fun `test cannot resolve spec fun main scope`() = checkByCode( + """ + module 0x1::m { + } + spec 0x1::m { + spec module { + fun spec_sip_hash(); + } + } + module 0x1::main { + use 0x1::m::spec_sip_hash; + fun main() { + spec_sip_hash(); + //^ unresolved + } + } + """ + ) + fun `test resolve spec fun defined in module spec`() = checkByCode( """ module 0x1::m { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 8bb95b180..988f76b41 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -365,4 +365,27 @@ module 0x1::string_tests { } } """) + + fun `test unresolved named address`() = checkByCode(""" + module 0x1::m { + use aptos_framework::account; + //^ unresolved + } + """) + + fun `test unresolved value address`() = checkByCode(""" + module 0x1::m { + use 0x1::account; + //^ unresolved + } + """) + + fun `test resolve module from import with unknown named address`() = checkByCode(""" + module aptos_framework::m1 {} + //X + module 0x1::m { + use aptos_framework::m1; + //^ + } + """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveNamedAddressTreeProjectTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt similarity index 98% rename from src/test/kotlin/org/move/lang/resolve/ResolveNamedAddressTreeProjectTest.kt rename to src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt index f93e5baef..ef1b8b3f9 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveNamedAddressTreeProjectTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt @@ -5,7 +5,7 @@ import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.resolve.ResolveProjectTestCase import org.toml.lang.psi.TomlKeySegment -class ResolveNamedAddressTreeProjectTest : ResolveProjectTestCase() { +class ResolveNamedModulePathTreeProjectTest : ResolveProjectTestCase() { fun `test resolve named address to address`() = checkByFileTree { moveToml(""" [addresses] diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt index 042994812..df7d9365b 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt @@ -257,6 +257,19 @@ class ResolveSpecsTest: ResolveTestCase() { } """) + fun `test another module consts are not accessible from non-msl`() = checkByCode(""" + module 0x1::M { + const MY_CONST: u8 = 1; + } + module 0x1::M2 { + use 0x1::M; + fun main() { + M::MY_CONST; + //^ unresolved + } + } + """) + fun `test another module consts are accessible from msl`() = checkByCode(""" module 0x1::M { const MY_CONST: u8 = 1; From cc7337fce6bd84dc9610aa17f8ea7e410e4d4a90 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 14:50:27 +0300 Subject: [PATCH 09/43] fix import optimizer --- .../ide/annotator/HighlightingAnnotator.kt | 2 +- .../move/ide/annotator/MvErrorAnnotator.kt | 2 +- .../MvUnresolvedReferenceInspection.kt | 27 +++- .../inspections/MvUnusedImportInspection.kt | 7 +- .../ide/inspections/imports/AutoImportFix.kt | 2 +- .../ide/inspections/imports/BasePathType.kt | 72 +++++++++ .../ide/inspections/imports/ImportAnalyzer.kt | 140 ++++++++---------- .../move/ide/inspections/imports/PathStart.kt | 82 ---------- .../move/ide/inspections/imports/UseItem.kt | 54 +++++++ .../move/ide/refactoring/MvImportOptimizer.kt | 5 +- .../org/move/lang/core/psi/ext/MvPath.kt | 11 +- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 4 +- .../move/lang/core/resolve2/ItemResolution.kt | 5 +- .../core/resolve2/LexicalDeclarations2.kt | 29 ++-- .../move/lang/core/resolve2/Visibility2.kt | 5 +- .../core/resolve2/ref/Path2ReferenceImpl.kt | 60 +------- .../core/resolve2/ref/RsPathResolveKind.kt | 63 ++++++++ .../move/lang/core/resolve2/util/PathUtil.kt | 11 +- .../MvUnresolvedReferenceInspectionTest.kt | 4 +- .../MvUnusedImportInspectionTest.kt | 8 +- 20 files changed, 331 insertions(+), 262 deletions(-) create mode 100644 src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt delete mode 100644 src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt create mode 100644 src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt diff --git a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt index 4a7e757f8..746f63126 100644 --- a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt @@ -107,7 +107,7 @@ class HighlightingAnnotator: MvAnnotatorBase() { private fun highlightPathElement(path: MvPath): MvColor? { // any qual :: access is not highlighted - if (path.isQualPath) return null + if (path.qualifier != null) return null val identifierName = path.identifierName val pathOwner = path.parent diff --git a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt index 769940a48..cb11f7fad 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt @@ -199,7 +199,7 @@ class MvErrorAnnotator: MvAnnotatorBase() { val parent = methodOrPath.parent if (item == null && methodOrPath is MvPath - && methodOrPath.nullModuleRef && methodOrPath.identifierName == "vector" + && methodOrPath.qualifier == null && methodOrPath.identifierName == "vector" ) { val expectedCount = 1 if (realCount != expectedCount) { diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt index 358fc92cf..b89b664e6 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt @@ -11,7 +11,7 @@ import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.types.infer.inference import org.move.lang.core.types.ty.TyUnknown -class MvUnresolvedReferenceInspection : MvLocalInspectionTool() { +class MvUnresolvedReferenceInspection: MvLocalInspectionTool() { var ignoreWithoutQuickFix: Boolean = false @@ -42,7 +42,7 @@ class MvUnresolvedReferenceInspection : MvLocalInspectionTool() { ) } - override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : MvVisitor() { + override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object: MvVisitor() { override fun visitModuleRef(moduleRef: MvModuleRef) { if (moduleRef.isMslScope && !isDebugModeEnabled()) { return @@ -73,17 +73,30 @@ class MvUnresolvedReferenceInspection : MvLocalInspectionTool() { if (path.textMatches("_") && path.isInsideAssignmentLhs()) return // assert macro if (path.text == "assert") return + // attribute values are special case if (path.hasAncestor()) return - val moduleRef = path.moduleRef - if (moduleRef != null) { - if (moduleRef is MvFQModuleRef) return - if (moduleRef.unresolved) { - holder.registerUnresolvedReferenceError(moduleRef) + val qualifier = path.qualifier + if (qualifier != null + // AddressPath, should be checked here + && qualifier.pathAddress == null + ) { + if (qualifier.reference?.resolve() == null) { return } } +// val qualifier = path.qualifier +// if (qualifier) + +// val moduleRef = path.moduleRef +// if (moduleRef != null) { +// if (moduleRef is MvFQModuleRef) return +// if (moduleRef.unresolved) { +// holder.registerUnresolvedReferenceError(moduleRef) +// return +// } +// } if (path.unresolved) { holder.registerUnresolvedReferenceError(path) } diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt index 8248ca887..fa8d1da7f 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt @@ -4,11 +4,12 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey import com.intellij.codeInspection.ProblemsHolder import com.intellij.openapi.project.Project import com.intellij.profile.codeInspection.InspectionProjectProfileManager -import org.move.ide.inspections.imports.ImportAnalyzer +import org.move.ide.inspections.imports.ImportAnalyzer2 -class MvUnusedImportInspection : MvLocalInspectionTool() { +class MvUnusedImportInspection: MvLocalInspectionTool() { - override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = ImportAnalyzer(holder) + override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = ImportAnalyzer2(holder) +// override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = ImportAnalyzer(holder) @Suppress("CompanionObjectInExtension") companion object { diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index d2113131e..ab6621576 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -76,7 +76,7 @@ class AutoImportFix(element: MvReferenceElement): DiagnosticFix() != null) return null - if (refElement is MvPath && refElement.moduleRef != null) return null + if (refElement is MvPath && refElement.qualifier != null) return null // TODO: no auto-import if name in scope, but cannot be resolved diff --git a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt new file mode 100644 index 000000000..ad39e4f4c --- /dev/null +++ b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt @@ -0,0 +1,72 @@ +package org.move.ide.inspections.imports + +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.* + +// classifies foo of `foo::bar::baz` +sealed class BasePathType { + data object Address: BasePathType() + data class Module(val moduleName: String): BasePathType() + data class Item(val itemName: String): BasePathType() +} + +fun MvPath.basePathType(): BasePathType? { + val rootPath = this.rootPath() + val qualifier = rootPath.qualifier + // foo + if (qualifier == null) { + return rootPath.referenceName?.let { BasePathType.Item(it) } + } + + // 0x1::m + if (qualifier.pathAddress != null) return BasePathType.Address + + val qualifierBase = qualifier.qualifier + // aptos_framework::m::foo + if (qualifierBase != null) { + return BasePathType.Address + } + + // todo: `aptos_framework::m`, + // first resolve aptos_framework into the NamedAddress, then return the BasePathType.Address + + // m::foo + return qualifier.referenceName?.let { BasePathType.Module(it) } +} + +// only Main/Test for now +val MvPath.pathUsageScope: NamedItemScope + get() { + var parentElement = this.parent + while (parentElement != null) { +// if (parentElement is MslOnlyElement) return ItemScope.MAIN + if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { + return NamedItemScope.TEST + } + if (parentElement is MvFunction && parentElement.hasTestAttr) { + return NamedItemScope.TEST + } + parentElement = parentElement.parent + } + return NamedItemScope.MAIN + } + +// only Main/Test for now +val MvUseStmt.declaredItemScope: NamedItemScope + get() { + if (this.hasTestOnlyAttr) { + return NamedItemScope.TEST + } + var parentElement = this.parent + while (parentElement != null) { +// if (parentElement is MslOnlyElement) return ItemScope.MAIN + if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { + return NamedItemScope.TEST + } + if (parentElement is MvFunction && parentElement.hasTestAttr) { + return NamedItemScope.TEST + } + parentElement = parentElement.parent + } + return NamedItemScope.MAIN + } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt index 84388f6d6..0c8ad9bbe 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt @@ -2,46 +2,15 @@ package org.move.ide.inspections.imports import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder -import org.move.ide.inspections.imports.PathStart.Companion.pathStart +import org.move.ide.inspections.imports.UseItemType.* import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.stdext.chain -private val MvItemsOwner.useSpecks: List - get() { - val specks = mutableListOf() - for (stmt in this.useStmtList) { - specks.addAll(stmt.useSpecks) - } - return specks - } - -private val MvItemsOwner.importOwnerWithSiblings: List - get() { - return when (this) { - is MvModuleBlock -> { - // add all module spec blocks - listOf(this).chain(this.module.allModuleSpecBlocks()).toList() - } - is MvModuleSpecBlock -> { - // add module block - val moduleBlock = this.moduleSpec.moduleItem?.moduleBlock - if (moduleBlock != null) { - listOf(moduleBlock, this) - } else { - listOf(this) - } - } - else -> listOf(this) - } - } - -class ImportAnalyzer(val holder: ProblemsHolder): MvVisitor() { +class ImportAnalyzer2(val holder: ProblemsHolder): MvVisitor() { override fun visitModuleBlock(o: MvModuleBlock) = analyzeImportsOwner(o) - override fun visitScriptBlock(o: MvScriptBlock) = analyzeImportsOwner(o) - override fun visitModuleSpecBlock(o: MvModuleSpecBlock) = analyzeImportsOwner(o) fun analyzeImportsOwner(importsOwner: MvItemsOwner) { @@ -49,56 +18,61 @@ class ImportAnalyzer(val holder: ProblemsHolder): MvVisitor() { analyzeUseStmtsForScope(importsOwner, NamedItemScope.MAIN) } - private fun analyzeUseStmtsForScope(rootImportOwner: MvItemsOwner, itemScope: NamedItemScope) { - val allSpecksHit = mutableSetOf() - val rootImportOwnerWithSiblings = rootImportOwner.importOwnerWithSiblings - val reachablePaths = - rootImportOwnerWithSiblings - .flatMap { it.descendantsOfType() } - .mapNotNull { path -> path.pathStart?.let { Pair(path, it) } } - .filter { it.second.usageScope == itemScope } - for ((path, start) in reachablePaths) { - for (importOwner in path.ancestorsOfType()) { - val useSpecks = - importOwner.importOwnerWithSiblings - .flatMap { it.useSpecks } - .filter { it.scope == itemScope } - val speckHit = - when (start) { - is PathStart.Module -> - useSpecks - .filter { it is UseSpeck.Module || it is UseSpeck.SelfModule } + private fun analyzeUseStmtsForScope(rootItemsOwner: MvItemsOwner, itemScope: NamedItemScope) { + val allUseItemsHit = mutableSetOf() + val rootItemOwnerWithSiblings = rootItemsOwner.itemsOwnerWithSiblings + + val paths = rootItemOwnerWithSiblings + .flatMap { it.descendantsOfType() } + .filter { it.basePath() == it } + .filter { it.pathUsageScope == itemScope } + .filter { !it.hasAncestor() } + + for (path in paths) { + val basePathType = path.basePathType() + for (itemsOwner in path.ancestorsOfType()) { + val useItems = + itemsOwner.itemsOwnerWithSiblings + .flatMap { it.useItems }.filter { it.scope == itemScope } + + val useItemHit = + when (basePathType) { + is BasePathType.Item -> { + useItems.filter { it.type == ITEM } // only hit first encountered to remove duplicates - .firstOrNull { it.nameOrAlias == start.modName } - is PathStart.Item -> - useSpecks.filterIsInstance() + .firstOrNull { it.nameOrAlias == basePathType.itemName } + } + is BasePathType.Module -> { + useItems.filter { it.type == MODULE || it.type == SELF_MODULE } // only hit first encountered to remove duplicates - .firstOrNull { it.nameOrAlias == start.itemName } - // PathStart.Address is fq path, and doesn't participate in imports + .firstOrNull { it.nameOrAlias == basePathType.moduleName } + } + // BasePathType.Address is fq path, and doesn't participate in imports else -> null } - if (speckHit != null) { - allSpecksHit.add(speckHit) + + if (useItemHit != null) { + allUseItemsHit.add(useItemHit) break } } } // includes self - val reachableImportOwners = rootImportOwner.descendantsOfTypeOrSelf() - for (importsOwner in reachableImportOwners) { - val scopeUseStmts = importsOwner.useStmtList.filter { it.declaredItemScope == itemScope } + val reachableItemsOwners = rootItemsOwner.descendantsOfTypeOrSelf() + for (itemsOwner in reachableItemsOwners) { + val scopeUseStmts = itemsOwner.useStmtList.filter { it.declaredItemScope == itemScope } for (useStmt in scopeUseStmts) { - val unusedSpecks = useStmt.useSpecks.toSet() - allSpecksHit - holder.registerStmtSpeckError(useStmt, unusedSpecks) + val unusedUseItems = useStmt.useItems.toSet() - allUseItemsHit + holder.registerStmtSpeckError2(useStmt, unusedUseItems) } } } } -private fun ProblemsHolder.registerStmtSpeckError(useStmt: MvUseStmt, specks: Set) { - val moduleSpecks = specks.filterIsInstance() - if (moduleSpecks.isNotEmpty()) { +fun ProblemsHolder.registerStmtSpeckError2(useStmt: MvUseStmt, useItems: Set) { + val moduleUseItems = useItems.filter { it.type == MODULE } + if (moduleUseItems.isNotEmpty()) { this.registerProblem( useStmt, "Unused use item", @@ -107,8 +81,7 @@ private fun ProblemsHolder.registerStmtSpeckError(useStmt: MvUseStmt, specks: Se return } - val itemSpecks = specks - if (useStmt.useSpecks.size == itemSpecks.size) { + if (useStmt.useItems.size == useItems.size) { // all inner speck types are covered, highlight complete useStmt this.registerProblem( useStmt, @@ -116,14 +89,9 @@ private fun ProblemsHolder.registerStmtSpeckError(useStmt: MvUseStmt, specks: Se ProblemHighlightType.LIKE_UNUSED_SYMBOL ) } else { - for (itemUseSpeck in itemSpecks) { - val useItem = when (itemUseSpeck) { - is UseSpeck.SelfModule -> itemUseSpeck.useItem - is UseSpeck.Item -> itemUseSpeck.useItem - else -> continue - } + for (useItem in useItems) { this.registerProblem( - useItem, + useItem.useSpeck, "Unused use item", ProblemHighlightType.LIKE_UNUSED_SYMBOL ) @@ -131,3 +99,23 @@ private fun ProblemsHolder.registerStmtSpeckError(useStmt: MvUseStmt, specks: Se } } +val MvItemsOwner.itemsOwnerWithSiblings: List + get() { + return when (this) { + is MvModuleBlock -> { + // add all module spec blocks + listOf(this).chain(this.module.allModuleSpecBlocks()).toList() + } + is MvModuleSpecBlock -> { + // add module block + val moduleBlock = this.moduleSpec.moduleItem?.moduleBlock + if (moduleBlock != null) { + listOf(moduleBlock, this) + } else { + listOf(this) + } + } + else -> listOf(this) + } + } + diff --git a/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt b/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt deleted file mode 100644 index e7e4a4a7a..000000000 --- a/src/main/kotlin/org/move/ide/inspections/imports/PathStart.kt +++ /dev/null @@ -1,82 +0,0 @@ -package org.move.ide.inspections.imports - -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.MvDocAndAttributeOwner -import org.move.lang.core.psi.ext.hasTestAttr -import org.move.lang.core.psi.ext.hasTestOnlyAttr -import org.move.lang.core.psi.ext.moduleRef - -// only Main/Test for now -val MvPath.pathUsageScope: NamedItemScope - get() { - var parentElement = this.parent - while (parentElement != null) { -// if (parentElement is MslOnlyElement) return ItemScope.MAIN - if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - if (parentElement is MvFunction && parentElement.hasTestAttr) { - return NamedItemScope.TEST - } - parentElement = parentElement.parent - } - return NamedItemScope.MAIN - } - -// only Main/Test for now -val MvUseStmt.declaredItemScope: NamedItemScope - get() { - if (this.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - var parentElement = this.parent - while (parentElement != null) { -// if (parentElement is MslOnlyElement) return ItemScope.MAIN - if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - if (parentElement is MvFunction && parentElement.hasTestAttr) { - return NamedItemScope.TEST - } - parentElement = parentElement.parent - } - return NamedItemScope.MAIN - } - -sealed class PathStart(open val usageScope: NamedItemScope) { - data class Address( - val addressRef: MvAddressRef, - override val usageScope: NamedItemScope - ): PathStart(usageScope) - - data class Module( - val modName: String, - val moduleRef: MvModuleRef, - override val usageScope: NamedItemScope - ): PathStart(usageScope) - - data class Item( - val itemName: String, - override val usageScope: NamedItemScope - ): PathStart(usageScope) - - companion object { - val MvPath.pathStart: PathStart? - get() { - val usageScope = this.pathUsageScope - val pathModuleRef = this.moduleRef - if (pathModuleRef != null) { - if (pathModuleRef is MvFQModuleRef) { - return Address(pathModuleRef.addressRef, usageScope) - } else { - val modName = pathModuleRef.referenceName ?: return null - return Module(modName, pathModuleRef, usageScope) - } - } else { - val itemName = this.referenceName ?: return null - return Item(itemName, usageScope) - } - } - } -} - diff --git a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt new file mode 100644 index 000000000..5a507b541 --- /dev/null +++ b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt @@ -0,0 +1,54 @@ +package org.move.ide.inspections.imports + +import org.move.ide.inspections.imports.UseItemType.* +import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.MvUseStmt +import org.move.lang.core.psi.NamedItemScope +import org.move.lang.core.psi.ext.MvItemsOwner +import org.move.lang.core.resolve2.ref.RsPathResolveKind.ModulePath +import org.move.lang.core.resolve2.ref.RsPathResolveKind.QualifiedPath +import org.move.lang.core.resolve2.ref.classifyPath +import org.move.lang.core.resolve2.util.forEachLeafSpeck + +enum class UseItemType { + MODULE, SELF_MODULE, ITEM; +} + +data class UseItem( + val useSpeck: MvUseSpeck, + val nameOrAlias: String, + val type: UseItemType, + val scope: NamedItemScope +) + +val MvItemsOwner.useItems: List + get() = this.useStmtList.flatMap { it.useItems } + +val MvUseStmt.useItems: List + get() { + val items = mutableListOf() + val stmtItemScope = this.declaredItemScope + this.forEachLeafSpeck { path, useAlias -> + val useSpeck = path.parent as MvUseSpeck + val nameOrAlias = useAlias?.name ?: path.referenceName ?: return@forEachLeafSpeck false + val kind = classifyPath(path) + when (kind) { + is ModulePath -> { + items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) + } + is QualifiedPath -> { + if (kind.path.referenceName == "Self") { + val moduleName = + useAlias?.name ?: kind.qualifier.referenceName ?: return@forEachLeafSpeck false + items.add(UseItem(useSpeck, moduleName, SELF_MODULE, stmtItemScope)) + } else { + items.add(UseItem(useSpeck, nameOrAlias, ITEM, stmtItemScope)) + } + } + else -> {} + } + false + } + + return items + } diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index 74453fc8e..53bba66db 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -5,7 +5,7 @@ import com.intellij.codeInspection.ProblemsHolder import com.intellij.lang.ImportOptimizer import com.intellij.psi.* import org.move.ide.inspections.MvUnusedImportInspection -import org.move.ide.inspections.imports.ImportAnalyzer +import org.move.ide.inspections.imports.ImportAnalyzer2 import org.move.ide.utils.imports.COMPARATOR_FOR_ITEMS_IN_USE_GROUP import org.move.ide.utils.imports.UseStmtWrapper import org.move.lang.MoveFile @@ -27,7 +27,8 @@ class MvImportOptimizer : ImportOptimizer { } val holder = ProblemsHolder(InspectionManager.getInstance(file.project), file, false) - val importVisitor = ImportAnalyzer(holder) + val importVisitor = ImportAnalyzer2(holder) +// val importVisitor = ImportAnalyzer(holder) object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { if (element is MvItemsOwner) { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index fa04ca103..db3cb9e94 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -57,11 +57,9 @@ val MvPath.isUpdateFieldArg2: Boolean val MvPath.identifierName: String? get() = identifier?.text -val MvPath.nullModuleRef: Boolean - get() = - identifier != null && this.moduleRef == null - -val MvPath.isQualPath: Boolean get() = !this.nullModuleRef +//val MvPath.nullModuleRef: Boolean +// get() = +// identifier != null && this.moduleRef == null val MvPath.maybeStruct get() = reference?.resolveWithAliases() as? MvStruct @@ -103,7 +101,8 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvPathType -> EnumSet.of(Namespace.TYPE) parent is MvCallExpr -> EnumSet.of(Namespace.FUNCTION) // parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) - parent is MvRefExpr -> EnumSet.of(Namespace.NAME, Namespace.CONST) + parent is MvRefExpr -> EnumSet.of(Namespace.NAME) +// parent is MvRefExpr -> EnumSet.of(Namespace.NAME, Namespace.CONST) parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.TYPE) // parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.NAME) parent is MvAccessSpecifier -> EnumSet.of(Namespace.TYPE) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index 221d18b7b..5b64b684b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -1,6 +1,5 @@ package org.move.lang.core.psi.ext -import com.intellij.lang.ASTNode import org.move.ide.inspections.imports.declaredItemScope import org.move.lang.core.psi.* import org.move.stdext.wrapWithList @@ -74,6 +73,7 @@ val MvItemUseSpeck.useItems: List return this.useItem.wrapWithList() } + sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemScope) { data class Module( override val nameOrAlias: String, @@ -94,6 +94,7 @@ sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemSco ): UseSpeck(nameOrAlias, scope) } + val MvUseStmt.useSpecks: List get() { val stmtItemScope = this.declaredItemScope @@ -121,6 +122,7 @@ val MvUseStmt.useSpecks: List } } + val MvUseStmt.useSpeckText: String get() { val moduleUseSpeck = this.moduleUseSpeck diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 776a5a8bb..32fb3ac8f 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -11,7 +11,8 @@ val MvNamedElement.namespaces: Set get() = when (this) { is MvFunction -> EnumSet.of(Namespace.FUNCTION) is MvStruct -> EnumSet.of(Namespace.TYPE) - is MvConst -> EnumSet.of(Namespace.CONST) + is MvConst -> EnumSet.of(Namespace.NAME) +// is MvConst -> EnumSet.of(Namespace.CONST) is MvSchema -> EnumSet.of(Namespace.SCHEMA) is MvModule -> EnumSet.of(Namespace.MODULE) else -> EnumSet.of(Namespace.NAME) @@ -21,7 +22,7 @@ val MvNamedElement.namespace get() = when (this) { is MvFunctionLike -> Namespace.FUNCTION is MvStruct -> Namespace.TYPE - is MvConst -> Namespace.CONST + is MvConst -> Namespace.NAME is MvSchema -> Namespace.SCHEMA is MvModule -> Namespace.MODULE is MvGlobalVariableStmt -> Namespace.NAME diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 8e6923952..4c8854618 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -19,22 +19,23 @@ fun processItemsInScope( val stop = when (namespace) { Namespace.CONST -> { - val found = when (scope) { - is MvModuleBlock -> { - val module = scope.parent as MvModule - processor.processAll( -// contextScopeInfo, - module.consts(), - ) - } - else -> false - } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (processor.processAll(scope.allUseItems())) return true + false +// val found = when (scope) { +// is MvModuleBlock -> { +// val module = scope.parent as MvModule +// processor.processAll( +//// contextScopeInfo, +// module.consts(), +// ) // } +// else -> false // } - found +//// if (!found) { +//// if (scope is MvItemsOwner) { +//// if (processor.processAll(scope.allUseItems())) return true +//// } +//// } +// found } Namespace.NAME -> { diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index a60717446..22fd8509c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -7,8 +7,7 @@ import org.move.lang.core.resolve.ModInfo import org.move.lang.core.resolve.VisibilityFilter import org.move.lang.core.resolve.VisibilityStatus.Invisible import org.move.lang.core.resolve.VisibilityStatus.Visible -import org.move.lang.core.resolve.ref.Namespace.CONST -import org.move.lang.core.resolve.ref.Namespace.TYPE +import org.move.lang.core.resolve.ref.Namespace.* import org.move.lang.core.resolve.ref.Visibility2 import org.move.lang.core.resolve.ref.Visibility2.* @@ -43,7 +42,7 @@ fun ItemVisibility.createFilter(): VisibilityFilter { if (item.isMslOnlyItem) return@VisibilityFilter Visible // consts are importable in tests - if (pathUsageScope.isTest && namespaces.contains(CONST)) return@VisibilityFilter Visible + if (pathUsageScope.isTest && namespaces.contains(NAME)) return@VisibilityFilter Visible } // #[test_only] items in non-test-only scope diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 5102196bc..ac4d6e484 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -37,8 +37,8 @@ class Path2ReferenceImpl(element: MvPath): fun rawMultiResolveIfVisible(): List> = rawMultiResolve().filter { it.isVisible } - fun rawMultiResolve(): List> = Resolver.invoke(this.element) -// override fun rawMultiResolve(): List> = rawCachedMultiResolve() +// fun rawMultiResolve(): List> = Resolver.invoke(this.element) + fun rawMultiResolve(): List> = rawCachedMultiResolve() private fun rawCachedMultiResolve(): List> { val rawResult = MvResolveCache.getInstance(element.project) @@ -55,7 +55,7 @@ class Path2ReferenceImpl(element: MvPath): path = path, contextScopeInfo = ContextScopeInfo.from(path) ) - return resolvePath(ctx, path, ctx.classifyPath(path)) + return resolvePath(ctx, path, classifyPath(path)) } } } @@ -101,7 +101,7 @@ fun processPathResolveVariants( processor: RsResolveProcessor, ): Boolean { val ctx = PathResolutionContext(path, contextScopeInfo = contextScopeInfo) - val pathKind = ctx.classifyPath(path) + val pathKind = classifyPath(path) return processPathResolveVariants(ctx, pathKind, processor) } @@ -146,27 +146,6 @@ private fun processQualifiedPathResolveVariants1( return false } -sealed class RsPathResolveKind { - /** A path consist of a single identifier, e.g. `foo` */ - data class UnqualifiedPath(val ns: Set): RsPathResolveKind() - - /** `bar` in `foo::bar` or `use foo::{bar}` */ - class QualifiedPath( - val path: MvPath, - val qualifier: MvPath, - val ns: Set, - ): RsPathResolveKind() - - /** bar in `0x1::bar` */ - class ModulePath( - val path: MvPath, - val address: Address, - ): RsPathResolveKind() - - /** aptos_framework in `use aptos_framework::bar`*/ - object NamedAddressPath: RsPathResolveKind() -} - class PathResolutionContext( val path: MvPath, val contextScopeInfo: ContextScopeInfo, @@ -186,37 +165,6 @@ class PathResolutionContext( // getModInfo(module) // } - fun classifyPath(path: MvPath): RsPathResolveKind { - val qualifier = path.qualifier - val ns = path.allowedNamespaces() -// if (qualifier == null) { -// return UnqualifiedPath(ns) -// } - val isUseSpeck = path.rootPath().parent is MvUseSpeck - if (qualifier == null) { - // left-most path - if (isUseSpeck) { - // use aptos_framework:: - // //^ - return NamedAddressPath - } else { - return UnqualifiedPath(ns) - } - } - - val qualifierPath = qualifier.path - val pathAddress = qualifier.pathAddress - val qualifierName = qualifier.referenceName - - return when { - qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text)) - qualifierPath == null && isUseSpeck && qualifierName != null -> - ModulePath(path, Address.Named(qualifierName, null, qualifier.moveProject)) -// qualifier.parent is MvUseSpeck && qualifierName != null -> -// AddressPath(path, Address.Named(qualifierName, null, qualifier.moveProject)) - else -> QualifiedPath(path, qualifier, ns) - } - } } //// todo: use in inference later diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt new file mode 100644 index 000000000..d3e59d835 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt @@ -0,0 +1,63 @@ +package org.move.lang.core.resolve2.ref + +import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.ext.allowedNamespaces +import org.move.lang.core.psi.ext.qualifier +import org.move.lang.core.psi.ext.rootPath +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.RsPathResolveKind.* +import org.move.lang.core.types.Address +import org.move.lang.moveProject + +sealed class RsPathResolveKind { + /** A path consist of a single identifier, e.g. `foo` */ + data class UnqualifiedPath(val ns: Set): RsPathResolveKind() + + /** `bar` in `foo::bar` or `use foo::{bar}` */ + class QualifiedPath( + val path: MvPath, + val qualifier: MvPath, + val ns: Set, + ): RsPathResolveKind() + + /** bar in `0x1::bar` */ + class ModulePath( + val path: MvPath, + val address: Address, + ): RsPathResolveKind() + + /** aptos_framework in `use aptos_framework::bar`*/ + data object NamedAddressPath: RsPathResolveKind() +} + +fun classifyPath(path: MvPath): RsPathResolveKind { + val qualifier = path.qualifier + val ns = path.allowedNamespaces() +// if (qualifier == null) { +// return UnqualifiedPath(ns) +// } + val isUseSpeck = path.rootPath().parent is MvUseSpeck + if (qualifier == null) { + // left-most path + if (isUseSpeck) { + // use aptos_framework:: + // //^ + return NamedAddressPath + } + return UnqualifiedPath(ns) + } + + val qualifierPath = qualifier.path + val pathAddress = qualifier.pathAddress + val qualifierName = qualifier.referenceName + + return when { + qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text)) + qualifierPath == null && isUseSpeck && qualifierName != null -> + ModulePath(path, Address.Named(qualifierName, null, qualifier.moveProject)) +// qualifier.parent is MvUseSpeck && qualifierName != null -> +// AddressPath(path, Address.Named(qualifierName, null, qualifier.moveProject)) + else -> QualifiedPath(path, qualifier, ns) + } +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt index 5f72099ef..9bb3683ec 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt @@ -22,11 +22,20 @@ fun MvUseStmt.forEachLeafSpeck(consumer: LeafUseSpeckConsumer) { } else { for (childSpeck in useGroup.childrenOfType()) { val alias = childSpeck.useAlias - if (!consumer.consume(childSpeck.path, alias)) return + if (!consumer.consume(childSpeck.path, alias)) continue } } } +fun MvUseStmt.leafSpecks(): List { + val specks = mutableListOf() + forEachLeafSpeck { path, useAlias -> + val useSpeck = path.parent as MvUseSpeck + specks.add(useSpeck) + } + return specks +} + diff --git a/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt index 45bb1f498..2ae9d8ff6 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt @@ -133,11 +133,11 @@ class MvUnresolvedReferenceInspectionTest : InspectionTestBase(MvUnresolvedRefer """ ) - fun `test no unresolved reference for fully qualified module`() = checkByText( + fun `test unresolved reference for fully qualified module`() = checkByText( """ module 0x1::M { fun main() { - 0x1::Debug::print(1); + 0x1::Debug::print(1); } } """ diff --git a/src/test/kotlin/org/move/ide/inspections/MvUnusedImportInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvUnusedImportInspectionTest.kt index 3da95a71e..67dc2298f 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvUnusedImportInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvUnusedImportInspectionTest.kt @@ -184,13 +184,13 @@ module 0x1::M2 { } """) - fun `test skip analyzing for incomplete self item alias`() = checkWarnings(""" + fun `test incomplete alias considered absent for module`() = checkWarnings(""" module 0x1::coin { struct Coin {} public fun get_coin(): Coin {} } module 0x1::Main { - use 0x1::coin::{Self as, Self, Coin}; + use 0x1::coin::{Self as, Self, Coin}; fun call(): Coin { coin::get_coin(); @@ -198,13 +198,13 @@ module 0x1::M2 { } """) - fun `test skip analyzing for incomplete item alias`() = checkWarnings(""" + fun `test incomplete alias considered absent for item`() = checkWarnings(""" module 0x1::coin { struct Coin {} public fun get_coin(): Coin {} } module 0x1::Main { - use 0x1::coin::{Coin as, Coin}; + use 0x1::coin::{Coin as, Coin}; fun call(): Coin { } From 3f1c293fe95fe080d98ab9c4d3971c1b1cf4f6ec Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 14:52:48 +0300 Subject: [PATCH 10/43] fix spec tests --- .../resources/org/move/lang/parser/specs/conditions.txt | 4 ++-- src/test/resources/org/move/lang/parser/specs/pragma.txt | 7 ++++--- .../resources/org/move/lang/parser/specs/spec_file.txt | 6 +++--- .../org/move/lang/parser/specs/spec_statements.txt | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/test/resources/org/move/lang/parser/specs/conditions.txt b/src/test/resources/org/move/lang/parser/specs/conditions.txt index df84f53f6..9c7962f1c 100644 --- a/src/test/resources/org/move/lang/parser/specs/conditions.txt +++ b/src/test/resources/org/move/lang/parser/specs/conditions.txt @@ -417,7 +417,7 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Error') PsiElement(::)('::') PsiElement(IDENTIFIER)('MY_ERROR') @@ -723,7 +723,7 @@ FILE MvBinaryExprImpl(BINARY_EXPR[==]) MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Self') PsiElement(::)('::') PsiElement(IDENTIFIER)('generic') diff --git a/src/test/resources/org/move/lang/parser/specs/pragma.txt b/src/test/resources/org/move/lang/parser/specs/pragma.txt index eebc4e82f..e50b2c66e 100644 --- a/src/test/resources/org/move/lang/parser/specs/pragma.txt +++ b/src/test/resources/org/move/lang/parser/specs/pragma.txt @@ -94,9 +94,10 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvFQModuleRefImpl(FQ_MODULE_REF) - MvAddressRefImpl(ADDRESS_REF) - PsiElement(DIEM_ADDRESS)('0x1') + MvPathImpl(PATH) + MvPathImpl(PATH) + MvPathAddressImpl(PATH_ADDRESS) + PsiElement(DIEM_ADDRESS)('0x1') PsiElement(::)('::') PsiElement(IDENTIFIER)('m') PsiElement(::)('::') diff --git a/src/test/resources/org/move/lang/parser/specs/spec_file.txt b/src/test/resources/org/move/lang/parser/specs/spec_file.txt index 652d032c3..27d6f97ee 100644 --- a/src/test/resources/org/move/lang/parser/specs/spec_file.txt +++ b/src/test/resources/org/move/lang/parser/specs/spec_file.txt @@ -76,9 +76,9 @@ FILE PsiWhiteSpace('\n ') PsiElement(})('}') PsiWhiteSpace('\n\n ') - PsiComment(EOL_DOC_COMMENT)('/// Helper schema to specify that a function aborts if not in genesis.') - PsiWhiteSpace('\n ') MvSchemaImpl(SCHEMA) + PsiComment(EOL_DOC_COMMENT)('/// Helper schema to specify that a function aborts if not in genesis.') + PsiWhiteSpace('\n ') PsiElement(spec)('spec') PsiWhiteSpace(' ') PsiElement(schema_kw)('schema') @@ -106,7 +106,7 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('error') PsiElement(::)('::') PsiElement(IDENTIFIER)('INVALID_STATE') diff --git a/src/test/resources/org/move/lang/parser/specs/spec_statements.txt b/src/test/resources/org/move/lang/parser/specs/spec_statements.txt index 6cd89f60a..8486c183f 100644 --- a/src/test/resources/org/move/lang/parser/specs/spec_statements.txt +++ b/src/test/resources/org/move/lang/parser/specs/spec_statements.txt @@ -260,7 +260,7 @@ FILE MvValueArgumentImpl(VALUE_ARGUMENT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Signer') PsiElement(::)('::') PsiElement(IDENTIFIER)('spec_address_of') @@ -293,7 +293,7 @@ FILE MvValueArgumentImpl(VALUE_ARGUMENT) MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Signer') PsiElement(::)('::') PsiElement(IDENTIFIER)('spec_address_of') @@ -336,7 +336,7 @@ FILE PsiWhiteSpace(' ') MvRefExprImpl(REF_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Errors') PsiElement(::)('::') PsiElement(IDENTIFIER)('NOT_PUBLISHED') @@ -493,7 +493,7 @@ FILE PsiWhiteSpace(' ') MvCallExprImpl(CALL_EXPR) MvPathImpl(PATH) - MvModuleRefImpl(MODULE_REF) + MvPathImpl(PATH) PsiElement(IDENTIFIER)('Signer') PsiElement(::)('::') PsiElement(IDENTIFIER)('address_of') From 4199874589e8463cd4b290323d896230127a801d Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 16:08:26 +0300 Subject: [PATCH 11/43] fix auto imports --- .../ide/annotator/HighlightingAnnotator.kt | 2 +- .../ide/hints/TypeParameterInfoHandler.kt | 2 +- .../MvUnresolvedReferenceInspection.kt | 45 ++++++----- .../PhantomTypeParameterInspection.kt | 2 +- .../RedundantQualifiedPathInspection.kt | 2 +- .../ReplaceWithMethodCallInspection.kt | 2 +- .../ReplaceWithIndexExprInspection.kt | 2 +- .../ide/inspections/imports/AutoImportFix.kt | 49 ++++++------ .../intentions/RemoveCurlyBracesIntention.kt | 2 +- .../org/move/ide/utils/FunctionSignature.kt | 2 +- .../org/move/ide/utils/imports/ImportUtils.kt | 76 +++++++++++++------ .../move/ide/utils/imports/UseStmtWrapper.kt | 16 ++++ .../org/move/lang/core/psi/MvPsiFactory.kt | 17 ++++- .../move/lang/core/psi/ext/MvAddressRef.kt | 15 ---- .../org/move/lang/core/psi/ext/MvCallExpr.kt | 5 +- .../org/move/lang/core/psi/ext/MvPath.kt | 19 +++-- .../org/move/lang/core/psi/ext/MvSchemaLit.kt | 2 +- .../org/move/lang/core/psi/ext/MvStructPat.kt | 2 +- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 10 +-- .../lang/core/types/infer/ExpectedType.kt | 2 +- .../move/lang/core/types/infer/TyLowering.kt | 2 +- .../core/types/infer/TypeInferenceWalker.kt | 4 +- .../imports/ImportCandidatesTest.kt | 6 +- 23 files changed, 163 insertions(+), 123 deletions(-) diff --git a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt index 746f63126..b299caeed 100644 --- a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt @@ -128,7 +128,7 @@ class HighlightingAnnotator: MvAnnotatorBase() { } } is MvCallExpr -> { - val item = path.reference?.resolveWithAliases() + val item = path.reference?.resolveFollowingAliases() when { item is MvSpecFunction && item.isNative diff --git a/src/main/kotlin/org/move/ide/hints/TypeParameterInfoHandler.kt b/src/main/kotlin/org/move/ide/hints/TypeParameterInfoHandler.kt index ef4a0eb34..d5b42e2a6 100644 --- a/src/main/kotlin/org/move/ide/hints/TypeParameterInfoHandler.kt +++ b/src/main/kotlin/org/move/ide/hints/TypeParameterInfoHandler.kt @@ -19,7 +19,7 @@ class TypeParameterInfoHandler : override fun calculateParameterInfo(element: MvTypeArgumentList): Array? { val parentPath = element.parent as? MvPath ?: return null - val owner = parentPath.reference?.resolveWithAliases() ?: return null + val owner = parentPath.reference?.resolveFollowingAliases() ?: return null // if zero type parameters if (owner !is MvTypeParametersOwner) return null diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt index b89b664e6..83ed790d0 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt @@ -7,7 +7,6 @@ import org.move.cli.settings.isDebugModeEnabled import org.move.ide.inspections.imports.AutoImportFix import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.types.infer.inference import org.move.lang.core.types.ty.TyUnknown @@ -17,23 +16,23 @@ class MvUnresolvedReferenceInspection: MvLocalInspectionTool() { override val isSyntaxOnly get() = false - private fun ProblemsHolder.registerUnresolvedReferenceError(element: MvReferenceElement) { + private fun ProblemsHolder.registerUnresolvedReferenceError(path: MvPath) { // no errors in pragmas - if (element.hasAncestor()) return + if (path.hasAncestor()) return - val candidates = AutoImportFix.findApplicableContext(element)?.candidates.orEmpty() + val candidates = AutoImportFix.findApplicableContext(path)?.candidates.orEmpty() if (candidates.isEmpty() && ignoreWithoutQuickFix) return - val referenceName = element.referenceName ?: return - val parent = element.parent + val referenceName = path.referenceName ?: return + val parent = path.parent val description = when (parent) { is MvPathType -> "Unresolved type: `$referenceName`" is MvCallExpr -> "Unresolved function: `$referenceName`" else -> "Unresolved reference: `$referenceName`" } - val highlightedElement = element.referenceNameElement ?: element - val fix = if (candidates.isNotEmpty()) AutoImportFix(element) else null + val highlightedElement = path.referenceNameElement ?: path + val fix = if (candidates.isNotEmpty()) AutoImportFix(path) else null registerProblem( highlightedElement, description, @@ -43,21 +42,21 @@ class MvUnresolvedReferenceInspection: MvLocalInspectionTool() { } override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object: MvVisitor() { - override fun visitModuleRef(moduleRef: MvModuleRef) { - if (moduleRef.isMslScope && !isDebugModeEnabled()) { - return - } - // skip this check, as it will be checked in MvPath visitor - if (moduleRef.ancestorStrict() != null) return - - // skip those two, checked in UseSpeck checks later - if (moduleRef.ancestorStrict() != null) return - if (moduleRef is MvFQModuleRef) return - - if (moduleRef.unresolved) { - holder.registerUnresolvedReferenceError(moduleRef) - } - } +// override fun visitModuleRef(moduleRef: MvModuleRef) { +// if (moduleRef.isMslScope && !isDebugModeEnabled()) { +// return +// } +// // skip this check, as it will be checked in MvPath visitor +// if (moduleRef.ancestorStrict() != null) return +// +// // skip those two, checked in UseSpeck checks later +// if (moduleRef.ancestorStrict() != null) return +// if (moduleRef is MvFQModuleRef) return +// +// if (moduleRef.unresolved) { +// holder.registerUnresolvedReferenceError(moduleRef) +// } +// } override fun visitPath(path: MvPath) { // skip specs in non-dev mode, too many false-positives diff --git a/src/main/kotlin/org/move/ide/inspections/PhantomTypeParameterInspection.kt b/src/main/kotlin/org/move/ide/inspections/PhantomTypeParameterInspection.kt index 67fb91632..6fa282567 100644 --- a/src/main/kotlin/org/move/ide/inspections/PhantomTypeParameterInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/PhantomTypeParameterInspection.kt @@ -31,7 +31,7 @@ class PhantomTypeParameterInspection : MvLocalInspectionTool() { // stop if empty if (path.typeArguments.isEmpty()) continue // determine phantom status of every argument, drop if phantom - val outerStruct = path.reference?.resolveWithAliases() as? MvStruct ?: continue + val outerStruct = path.reference?.resolveFollowingAliases() as? MvStruct ?: continue for ((i, typeArg) in path.typeArguments.withIndex()) { val outerTypeParam = outerStruct.typeParameters.getOrNull(i) ?: continue if (outerTypeParam.isPhantom) { diff --git a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt b/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt index 64dc484ae..e4a1a331a 100644 --- a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt @@ -19,7 +19,7 @@ class RedundantQualifiedPathInspection : MvLocalInspectionTool() { val pathText = path.text .replace(path.typeArgumentList?.text.orEmpty(), "") .replace(Regex("\\s"), "") - val item = path.reference?.resolveWithAliases() ?: return + val item = path.reference?.resolveFollowingAliases() ?: return val importsOwner = path.containingScript?.scriptBlock ?: path.containingModule?.moduleBlock diff --git a/src/main/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspection.kt b/src/main/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspection.kt index 02a500a5f..714c96e7d 100644 --- a/src/main/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspection.kt @@ -18,7 +18,7 @@ class ReplaceWithMethodCallInspection: MvLocalInspectionTool() { override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): MvVisitor { return object: MvVisitor() { override fun visitCallExpr(callExpr: MvCallExpr) { - val function = callExpr.path.reference?.resolveWithAliases() as? MvFunction ?: return + val function = callExpr.path.reference?.resolveFollowingAliases() as? MvFunction ?: return val msl = callExpr.isMsl() val inference = callExpr.inference(msl) ?: return diff --git a/src/main/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithIndexExprInspection.kt b/src/main/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithIndexExprInspection.kt index 20127d940..887f66f83 100644 --- a/src/main/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithIndexExprInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithIndexExprInspection.kt @@ -16,7 +16,7 @@ class ReplaceWithIndexExprInspection: MvLocalInspectionTool() { override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): MvVisitor { return object: MvVisitor() { override fun visitCallExpr(callExpr: MvCallExpr) { - val function = callExpr.path.reference?.resolveWithAliases() as? MvFunction ?: return + val function = callExpr.path.reference?.resolveFollowingAliases() as? MvFunction ?: return val module = function.module ?: return val moveProject = function.moveProject ?: return val msl = callExpr.isMsl() diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index ab6621576..517548488 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -18,8 +18,8 @@ import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Visibility import org.move.openapiext.runWriteCommandAction -class AutoImportFix(element: MvReferenceElement): DiagnosticFix(element), - HighPriorityAction { +class AutoImportFix(element: MvPath): DiagnosticFix(element), + HighPriorityAction { private var isConsumed: Boolean = false @@ -29,11 +29,11 @@ class AutoImportFix(element: MvReferenceElement): DiagnosticFix()) return @@ -72,16 +72,16 @@ class AutoImportFix(element: MvReferenceElement): DiagnosticFix() != null) return null - if (refElement is MvPath && refElement.qualifier != null) return null + fun findApplicableContext(path: MvPath): Context? { + if (path.reference == null) return null + if (path.resolvable) return null + if (path.ancestorStrict() != null) return null + if (path.qualifier != null) return null // TODO: no auto-import if name in scope, but cannot be resolved - val refName = refElement.referenceName ?: return null - val importContext = ImportContext.from(refElement) + val refName = path.referenceName ?: return null + val importContext = ImportContext.from(path) val candidates = ImportCandidateCollector.getImportCandidates(importContext, refName) return Context(candidates) @@ -106,23 +106,24 @@ data class ImportContext private constructor( return ImportContext(contextElement, namespaces, visibilities, contextScopeInfo) } - fun from(refElement: MvReferenceElement): ImportContext { - val ns = refElement.importCandidateNamespaces() - val vs = if (refElement.containingScript != null) { - setOf(Visibility.Public, Visibility.PublicScript) - } else { - val module = refElement.containingModule - if (module != null) { - setOf(Visibility.Public, Visibility.PublicFriend(module.asSmartPointer())) + fun from(path: MvPath): ImportContext { + val ns = path.importCandidateNamespaces() + val vs = + if (path.containingScript != null) { + setOf(Visibility.Public, Visibility.PublicScript) } else { - setOf(Visibility.Public) + val module = path.containingModule + if (module != null) { + setOf(Visibility.Public, Visibility.PublicFriend(module.asSmartPointer())) + } else { + setOf(Visibility.Public) + } } - } val contextScopeInfo = ContextScopeInfo( - letStmtScope = refElement.letStmtScope, - refItemScopes = refElement.refItemScopes, + letStmtScope = path.letStmtScope, + refItemScopes = path.refItemScopes, ) - return ImportContext(refElement, ns, vs, contextScopeInfo) + return ImportContext(path, ns, vs, contextScopeInfo) } } } diff --git a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt index 7fec55559..bfb249c62 100644 --- a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt +++ b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt @@ -49,6 +49,6 @@ private fun MvUseItemGroup.removeCurlyBraces() { if (aliasName != null) { newText += " as $aliasName" } - val newItemUse = psiFactory.useItem(newText) + val newItemUse = psiFactory.useSpeckForGroup(newText) this.replace(newItemUse) } diff --git a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt index 7b6796aeb..b06933e68 100644 --- a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt +++ b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt @@ -44,7 +44,7 @@ data class FunctionSignature( fun resolve(callable: MvCallable): FunctionSignature? = when (callable) { is MvCallExpr -> { - val function = callable.path.reference?.resolveWithAliases() as? MvFunction + val function = callable.path.reference?.resolveFollowingAliases() as? MvFunction function?.getSignature() } is MvMethodCall -> { diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index a6ec9ed27..23fb9cb63 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -1,5 +1,7 @@ package org.move.ide.utils.imports +import org.move.ide.inspections.imports.UseItemType.MODULE +import org.move.ide.inspections.imports.useItems import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.types.ItemQualName @@ -45,49 +47,73 @@ private fun tryInsertingIntoExistingUseStmt( ): Boolean { if (usePath.moduleName == null) return false val psiFactory = mod.project.psiFactory - return mod - .useStmtList - .filter { it.hasTestOnlyAttr == testOnly } - .mapNotNull { it.itemUseSpeck } + val useStmts = mod.useStmtList.filter { it.hasTestOnlyAttr == testOnly } + return useStmts +// .mapNotNull { it.itemUseSpeck } .any { tryGroupWithItemSpeck(psiFactory, it, usePath) } } private fun tryGroupWithItemSpeck( - psiFactory: MvPsiFactory, itemUseSpeck: MvItemUseSpeck, usePath: ItemQualName + psiFactory: MvPsiFactory, useStmt: MvUseStmt, usePath: ItemQualName ): Boolean { + // module imports do not support groups for now + val useItems = useStmt.useItems + if (useItems.all { it.type == MODULE }) return false + + val itemUseItem = useItems.firstOrNull() ?: return false + val itemUseSpeck = itemUseItem.useSpeck + val qualifier = itemUseSpeck.qualifier ?: itemUseSpeck.path.qualifier ?: return false + val fqModuleName = usePath.editorModuleFqName() ?: error("checked in the upper level") - if (!itemUseSpeck.fqModuleRef.textMatches(fqModuleName)) return false + if (!qualifier.textMatches(fqModuleName)) return false val itemName = usePath.itemName - if (itemName in itemUseSpeck.names()) return true + val useStmtNames = useItems.map { it.nameOrAlias } + if (itemName in useStmtNames) return true - val useItem = psiFactory.useItem(itemName) - val useItemGroup = itemUseSpeck.useItemGroup - if (useItemGroup != null) { + val useGroup = itemUseSpeck.useGroup + val useSpeck = psiFactory.useSpeckForGroup(itemName) + if (useGroup != null) { // add after the last item - val itemList = useItemGroup.useItemList - if (itemList.isEmpty()) { + val useSpeckList = useGroup.useSpeckList + if (useSpeckList.isEmpty()) { // use 0x1::m::{}; - useItemGroup.addAfter(useItem, useItemGroup.lBrace) + useGroup.addAfter(useSpeck, useGroup.lBrace) } else { // use 0x1::m::{item1} -> use 0x1::m::{item1, item2} - val lastItem = itemList.last() - useItemGroup.addAfter( - useItem, - useItemGroup.addAfter(psiFactory.createComma(), lastItem) + val lastItem = useSpeckList.last() + useGroup.addAfter( + useSpeck, + useGroup.addAfter(psiFactory.createComma(), lastItem) ) } } else { - val existingItem = itemUseSpeck.useItem ?: return true + // 0x1::dummy::{} + val newRootUseSpeck = psiFactory.useSpeckWithEmptyUseGroup() + + // 0x1::dummy::{} -> 0x1::m::{} + newRootUseSpeck.path.replace(qualifier) + + // 0x1::m::{} -> 0x1::m::{item} + val existingItemName = itemUseSpeck.path.referenceName ?: return false + val newItemUseSpeck = psiFactory.useSpeckForGroup(existingItemName) + val newUseGroup = newRootUseSpeck.useGroup ?: error("created with use group") + newUseGroup.addAfter(newItemUseSpeck, newUseGroup.lBrace) + + // 0x1::m::{item} -> 0x1::m::{item as myitem} + val existingUseAlias = itemUseSpeck.useAlias + if (existingUseAlias != null) { + newItemUseSpeck.add(existingUseAlias) + } + + // 0x1::m::{item as myitem} -> 0x1::m::{item as myitem, } + val comma = newUseGroup.addBefore(psiFactory.createComma(), newUseGroup.rBrace) - val existingItemCopy = existingItem.copy() - val itemGroup = existingItem.replace(psiFactory.useItemGroup(listOf())) as MvUseItemGroup + // 0x1::m::{item as myitem, } -> 0x1::m::{item as myitem, item2} + newUseGroup.addAfter(useSpeck, comma) - val comma = itemGroup.addAfter( - psiFactory.createComma(), - itemGroup.addAfter(existingItemCopy, itemGroup.lBrace) - ) - itemGroup.addAfter(useItem, comma) + newRootUseSpeck.useGroup?.replace(newUseGroup) + useStmt.useSpeck?.replace(newRootUseSpeck) } return true } diff --git a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt index 556e61464..c15ebc78d 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt @@ -9,6 +9,7 @@ import org.move.lang.core.psi.MvAddressRef import org.move.lang.core.psi.MvUseItem import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.* +import org.move.lang.moveProject class UseStmtWrapper(val useStmt: MvUseStmt) : Comparable { private val addr: MvAddressRef? get() = this.useStmt.addressRef @@ -56,3 +57,18 @@ class UseStmtWrapper(val useStmt: MvUseStmt) : Comparable { val COMPARATOR_FOR_ITEMS_IN_USE_GROUP: Comparator = compareBy { !it.isSelf }.thenBy { it.referenceName.lowercase() } + +private val MvAddressRef.useGroupLevel: Int + get() { + // sort to the end if not a named address + if (this.namedAddress == null) return 4 + + val name = this.namedAddress?.text.orEmpty().lowercase() + val currentPackageAddresses = + this.moveProject?.currentPackageAddresses()?.keys.orEmpty().map { it.lowercase() } + return when (name) { + "std", "aptos_std", "aptos_framework", "aptos_token" -> 1 + !in currentPackageAddresses -> 2 + else -> 3 + } + } diff --git a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt index e3df70df8..9ead25f56 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt @@ -129,15 +129,26 @@ class MvPsiFactory(val project: Project) { } } - fun useItemGroup(items: List): MvUseItemGroup { + fun useGroup(items: List): MvUseItemGroup { val allItemsText = items.joinToString(", ") return createFromText("module 0x1::_DummyModule { use 0x1::Module::{$allItemsText}; }") ?: error("Failed to create an item import from text: `$allItemsText`") } - fun useItem(text: String): MvUseItem { - return createFromText("module 0x1::_DummyModule { use 0x1::Module::$text; }") + fun useSpeckWithEmptyUseGroup(): MvUseSpeck { + return createFromText("module 0x1::_DummyModule { use 0x1::dummy::{}; }") + ?: error("Failed to create a use speck") + } + + fun useSpeck(text: String): MvUseSpeck { + return createFromText("module 0x1::_DummyModule { use $text; }") + ?: error("Failed to create an item import from text: `$text`") + } + + fun useSpeckForGroup(text: String): MvUseSpeck { + val useGroup = createFromText("module 0x1::_DummyModule { use 0x1::Module::{$text}; }") ?: error("Failed to create an item import from text: `$text`") + return useGroup.useSpeckList.first() } fun acquires(text: String): MvAcquiresType { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt index 281e5cde7..6c15b1eaf 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt @@ -4,18 +4,3 @@ import org.move.lang.core.psi.MvAddressRef import org.move.lang.moveProject val MvAddressRef.normalizedText: String get() = this.text.lowercase() - -val MvAddressRef.useGroupLevel: Int - get() { - // sort to the end if not a named address - if (this.namedAddress == null) return 4 - - val name = this.namedAddress?.text.orEmpty().lowercase() - val currentPackageAddresses = - this.moveProject?.currentPackageAddresses()?.keys.orEmpty().map { it.lowercase() } - return when (name) { - "std", "aptos_std", "aptos_framework", "aptos_token" -> 1 - !in currentPackageAddresses -> 2 - else -> 3 - } - } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt index aabe3ee09..12d74289b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt @@ -1,9 +1,6 @@ package org.move.lang.core.psi.ext -import org.move.lang.core.psi.MvElement -import org.move.lang.core.psi.MvExpr -import org.move.lang.core.psi.MvValueArgument -import org.move.lang.core.psi.MvValueArgumentList +import org.move.lang.core.psi.* interface MvCallable: MvElement { val valueArgumentList: MvValueArgumentList? diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index db3cb9e94..868c59da2 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -5,6 +5,8 @@ import org.move.cli.settings.debugErrorOrFallback import org.move.ide.annotator.BUILTIN_TYPE_IDENTIFIERS import org.move.ide.annotator.PRIMITIVE_TYPE_IDENTIFIERS import org.move.ide.annotator.SPEC_ONLY_PRIMITIVE_TYPES +import org.move.ide.inspections.imports.BasePathType +import org.move.ide.inspections.imports.basePathType import org.move.lang.core.psi.* import org.move.lang.core.resolve.ref.MvPath2Reference import org.move.lang.core.resolve.ref.MvReferenceElement @@ -61,9 +63,9 @@ val MvPath.identifierName: String? get() = identifier?.text // get() = // identifier != null && this.moduleRef == null -val MvPath.maybeStruct get() = reference?.resolveWithAliases() as? MvStruct +val MvPath.maybeStruct get() = reference?.resolveFollowingAliases() as? MvStruct -val MvPath.maybeSchema get() = reference?.resolveWithAliases() as? MvSchema +val MvPath.maybeSchema get() = reference?.resolveFollowingAliases() as? MvSchema fun MvPath.allowedNamespaces(): Set { val parent = this.parent @@ -132,17 +134,18 @@ abstract class MvPathMixin(node: ASTNode): MvElementImpl(node), MvPath { override fun getReference(): MvPath2Reference? = Path2ReferenceImpl(this) } -fun MvReferenceElement.importCandidateNamespaces(): Set { +fun MvPath.importCandidateNamespaces(): Set { val parent = this.parent return when (parent) { is MvPathType -> setOf(Namespace.TYPE) is MvSchemaLit, is MvSchemaRef -> setOf(Namespace.SCHEMA) - else -> - when (this) { - is MvModuleRef -> setOf(Namespace.MODULE) - is MvPath -> setOf(Namespace.NAME, Namespace.FUNCTION) - else -> Namespace.all() + else -> { + val baseBaseType = this.basePathType() + when (baseBaseType) { + is BasePathType.Module -> EnumSet.of(Namespace.MODULE) + else -> EnumSet.of(Namespace.NAME, Namespace.FUNCTION) } + } } } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt index 80cfbc99c..dccc85505 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt @@ -4,7 +4,7 @@ import org.move.lang.core.psi.MvSchema import org.move.lang.core.psi.MvSchemaLit import org.move.lang.core.psi.MvSchemaLitField -val MvSchemaLit.schema: MvSchema? get() = this.path.reference?.resolveWithAliases() as? MvSchema +val MvSchemaLit.schema: MvSchema? get() = this.path.reference?.resolveFollowingAliases() as? MvSchema val MvSchemaLit.fields: List get() = schemaFieldsBlock?.schemaLitFieldList.orEmpty() diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt index bf42ba952..c97d7fed9 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt @@ -12,4 +12,4 @@ val MvStructPat.patFieldNames: List get() = patFields.map { it.referenceName } -val MvStructPat.structItem: MvStruct? get() = this.path.reference?.resolveWithAliases() as? MvStruct +val MvStructPat.structItem: MvStruct? get() = this.path.reference?.resolveFollowingAliases() as? MvStruct diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index 5b64b684b..bcc4eb281 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -25,11 +25,11 @@ val MvUseStmt.addressRef: MvAddressRef? return null } -val MvUseStmt.useGroupLevel: Int - get() { - if (this.hasTestOnlyAttr) return 5 - return this.addressRef?.useGroupLevel ?: -1 - } +//val MvUseStmt.useGroupLevel: Int +// get() { +// if (this.hasTestOnlyAttr) return 5 +// return this.addressRef?.useGroupLevel ?: -1 +// } val MvUseStmt.fqModuleText: String? get() { diff --git a/src/main/kotlin/org/move/lang/core/types/infer/ExpectedType.kt b/src/main/kotlin/org/move/lang/core/types/infer/ExpectedType.kt index d675bf4b6..fbc26f792 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/ExpectedType.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/ExpectedType.kt @@ -27,7 +27,7 @@ fun inferExpectedTypeArgumentTy(typeArgument: MvTypeArgument): Ty? { if (paramIndex == -1) return null val path = typeArgumentList.parent as MvPath - val genericItem = path.reference?.resolveWithAliases() as? MvTypeParametersOwner ?: return null + val genericItem = path.reference?.resolveFollowingAliases() as? MvTypeParametersOwner ?: return null genericItem.typeParameters .getOrNull(paramIndex) ?.let { TyInfer.TyVar(TyTypeParameter(it)) } diff --git a/src/main/kotlin/org/move/lang/core/types/infer/TyLowering.kt b/src/main/kotlin/org/move/lang/core/types/infer/TyLowering.kt index 4ff23777c..5f1e16336 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/TyLowering.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/TyLowering.kt @@ -13,7 +13,7 @@ class TyLowering { fun lowerTy(moveType: MvType, msl: Boolean): Ty { return when (moveType) { is MvPathType -> { - val genericItem = moveType.path.reference?.resolveWithAliases() + val genericItem = moveType.path.reference?.resolveFollowingAliases() lowerPath(moveType.path, genericItem, msl) } is MvRefType -> { diff --git a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt index c1a345bba..19a912080 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt @@ -291,7 +291,7 @@ class TypeInferenceWalker( return funcItem.rawReturnType(true) } } - val item = refExpr.path.reference?.resolveWithAliases() ?: return TyUnknown + val item = refExpr.path.reference?.resolveFollowingAliases() ?: return TyUnknown val ty = when (item) { is MvBindingPat -> ctx.getPatType(item) is MvConst -> item.type?.loweredType(msl) ?: TyUnknown @@ -353,7 +353,7 @@ class TypeInferenceWalker( private fun inferCallExprTy(callExpr: MvCallExpr, expected: Expectation): Ty { val path = callExpr.path - val item = path.reference?.resolveWithAliases() + val item = path.reference?.resolveFollowingAliases() val baseTy = when (item) { is MvFunctionLike -> { diff --git a/src/test/kotlin/org/move/ide/inspections/imports/ImportCandidatesTest.kt b/src/test/kotlin/org/move/ide/inspections/imports/ImportCandidatesTest.kt index 4872f7341..d3ee311a9 100644 --- a/src/test/kotlin/org/move/ide/inspections/imports/ImportCandidatesTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/imports/ImportCandidatesTest.kt @@ -1,6 +1,7 @@ package org.move.ide.inspections.imports import org.move.ide.utils.imports.ImportCandidateCollector +import org.move.lang.core.psi.MvPath import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.MvProjectTestBase @@ -221,11 +222,12 @@ module 0x1::main { val refClass = MvReferenceElement::class.java val (refElement, data, _) = myFixture.findElementWithDataAndOffsetInEditor(refClass, "^") - val targetName = refElement.referenceName ?: error("No name for reference element") + val path = refElement as? MvPath ?: error("no path at caret") + val targetName = path.referenceName ?: error("No name for reference element") val candidates = ImportCandidateCollector - .getImportCandidates(ImportContext.Companion.from(refElement), targetName) + .getImportCandidates(ImportContext.Companion.from(path), targetName) .map { it.qualName.editorText() } if (data == "[]") { check(candidates.isEmpty()) { "Non-empty candidates: $candidates" } From a4e3e4770b5a7ebdf5de26ca3f74c9d6df9585f8 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 17:34:14 +0300 Subject: [PATCH 12/43] fix import optimizer --- src/main/grammars/MoveParser.bnf | 2 +- .../ide/annotator/HighlightingAnnotator.kt | 6 +- .../move/ide/refactoring/MvImportOptimizer.kt | 37 +++++---- .../org/move/ide/utils/imports/ImportUtils.kt | 1 + .../move/ide/utils/imports/UseStmtWrapper.kt | 75 +++++++++---------- .../org/move/lang/core/psi/MvPsiFactory.kt | 5 -- .../org/move/lang/core/psi/ext/MvUseItem.kt | 1 + .../move/lang/core/psi/ext/MvUseItemGroup.kt | 8 +- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 14 ---- .../annotator/HighlightingAnnotatorTest.kt | 11 ++- .../optimizeImports/OptimizeImportsTest.kt | 4 +- .../compilerV2/ReceiverStyleFunctionTest.kt | 11 +++ 12 files changed, 91 insertions(+), 84 deletions(-) diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 7d026cbe1..f66030bb3 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -529,7 +529,7 @@ UseStmt ::= Attr* use UseSpeck ';' { extends = Stmt implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] } -UseSpeck ::= PathWithoutTypeArgs ( UseAlias | ('::' UseSpeckProjection) )? +UseSpeck ::= PathImpl ( UseAlias | ('::' UseSpeckProjection) )? private UseSpeckProjection ::= UseGroup diff --git a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt index b299caeed..fc9d91517 100644 --- a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt @@ -62,8 +62,6 @@ class HighlightingAnnotator: MvAnnotatorBase() { if (element is MvAbility) return MvColor.ABILITY if (element is MvTypeParameter) return MvColor.TYPE_PARAMETER if (element is MvItemSpecTypeParameter) return MvColor.TYPE_PARAMETER - if (element is MvModuleRef && element.isSelfModuleRef) return MvColor.KEYWORD - if (element is MvUseItem && element.text == "Self") return MvColor.KEYWORD if (element is MvFunction) return when { element.isInline -> MvColor.INLINE_FUNCTION @@ -106,10 +104,12 @@ class HighlightingAnnotator: MvAnnotatorBase() { } private fun highlightPathElement(path: MvPath): MvColor? { + val identifierName = path.identifierName + if (identifierName == "Self") return MvColor.KEYWORD + // any qual :: access is not highlighted if (path.qualifier != null) return null - val identifierName = path.identifierName val pathOwner = path.parent return when (pathOwner) { is MvPathType -> { diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index 53bba66db..d20941e98 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -46,11 +46,11 @@ class MvImportOptimizer : ImportOptimizer { (useElement.nextSibling as? PsiWhiteSpace)?.delete() useElement.delete() } - is MvUseItem -> { + is MvUseSpeck -> { // remove whitespace following comma, if first position in a group - val useItemGroup = useElement.parent as? MvUseItemGroup - if (useItemGroup != null - && useItemGroup.useItemList.firstOrNull() == useElement + val useGroup = useElement.parent as? MvUseGroup + if (useGroup != null + && useGroup.useSpeckList.firstOrNull() == useElement ) { val followingComma = useElement.getNextNonCommentSibling() followingComma?.rightSiblings @@ -67,9 +67,9 @@ class MvImportOptimizer : ImportOptimizer { val useStmtsWithOwner = file.descendantsOfType().groupBy { it.parent } for ((stmtOwner, useStmts) in useStmtsWithOwner.entries) { useStmts.forEach { useStmt -> - useStmt.itemUseSpeck?.let { + useStmt.useSpeck?.let { removeCurlyBracesIfPossible(it, psiFactory) - it.useItemGroup?.sortUseItems() + it.useGroup?.sortUseSpecks() } } if (stmtOwner is MvModuleBlock) { @@ -116,19 +116,28 @@ class MvImportOptimizer : ImportOptimizer { } companion object { - fun MvUseItemGroup.sortUseItems() { - val sortedList = useItemList + private fun MvUseGroup.sortUseSpecks() { + val sortedList = useSpeckList .sortedWith(COMPARATOR_FOR_ITEMS_IN_USE_GROUP) .map { it.copy() } - useItemList.zip(sortedList).forEach { it.first.replace(it.second) } + useSpeckList.zip(sortedList).forEach { it.first.replace(it.second) } } /** Returns true if successfully removed, e.g. `use aaa::{bbb};` -> `use aaa::bbb;` */ - private fun removeCurlyBracesIfPossible(useSpeck: MvItemUseSpeck, psiFactory: MvPsiFactory) { - val useItemText = useSpeck.useItemGroup?.asTrivial?.text ?: return - val fqModuleText = useSpeck.fqModuleRef.text - val newUseSpeck = psiFactory.itemUseSpeck(fqModuleText, useItemText) - useSpeck.replace(newUseSpeck) + private fun removeCurlyBracesIfPossible(rootUseSpeck: MvUseSpeck, psiFactory: MvPsiFactory) { + val itemUseSpeck = rootUseSpeck.useGroup?.asTrivial ?: return + + val newUseSpeck = psiFactory.useSpeck("0x1::dummy::call") + val newUseSpeckPath = newUseSpeck.path + newUseSpeckPath.path?.replace(rootUseSpeck.path) + itemUseSpeck.path.identifier?.let { newUseSpeckPath.identifier?.replace(it) } + + val useAlias = itemUseSpeck.useAlias + if (useAlias != null) { + newUseSpeck.add(useAlias) + } + + rootUseSpeck.replace(newUseSpeck) } private fun reorderUseStmtsIntoGroups(useScope: MvItemsOwner) { diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index 23fb9cb63..d421dccd5 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -120,6 +120,7 @@ private fun tryGroupWithItemSpeck( private val List.lastElement: T? get() = maxByOrNull { it.textOffset } +@Suppress("SameReturnValue") private fun insertUseStmtAtTheCorrectLocation(mod: MvItemsOwner, useStmt: MvUseStmt): Boolean { val psiFactory = MvPsiFactory(mod.project) val newline = psiFactory.createNewline() diff --git a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt index c15ebc78d..ada827a6c 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt @@ -5,14 +5,22 @@ package org.move.ide.utils.imports +import org.move.cli.MoveProject import org.move.lang.core.psi.MvAddressRef import org.move.lang.core.psi.MvUseItem +import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.* import org.move.lang.moveProject -class UseStmtWrapper(val useStmt: MvUseStmt) : Comparable { - private val addr: MvAddressRef? get() = this.useStmt.addressRef +class UseStmtWrapper(val useStmt: MvUseStmt): Comparable { + private val namedAddress: String? + get() { + val useSpeck = useStmt.useSpeck ?: return null + val base = useSpeck.path.basePath() + if (base.pathAddress != null) return null + return base.identifier?.text + } // `use` order: // 1. Standard library (stdlib) @@ -25,50 +33,41 @@ class UseStmtWrapper(val useStmt: MvUseStmt) : Comparable { val packageGroupLevel: Int = when { this.useStmt.hasTestOnlyAttr -> 5 this.useStmt.hasVerifyOnlyAttr -> 6 - else -> this.addr?.useGroupLevel ?: -1 + else -> getBetweenGroupsLevel(this.namedAddress, useStmt.moveProject) } - val addressLevel: Int = when (this.addr?.namedAddress?.referenceName?.lowercase()) { + override fun compareTo(other: UseStmtWrapper): Int = + compareValuesBy( + this, + other, + { it.packageGroupLevel }, + { getWithinGroupLevel(it.namedAddress) }, + { it.useStmt.useSpeck?.text ?: "" } + ) +} + +val COMPARATOR_FOR_ITEMS_IN_USE_GROUP: Comparator = + compareBy { !it.isSelf }.thenBy { it.path.referenceName?.lowercase() } + +private fun getWithinGroupLevel(namedAddress: String?): Int = + when (namedAddress?.lowercase()) { "std" -> 0 "aptos_std" -> 1 "aptos_framework" -> 2 "aptos_token" -> 3 else -> 4 } -// val packageGroupLevel: Int = when { -// -// basePath?.self != null -> 6 -// basePath?.`super` != null -> 5 -// basePath?.crate != null -> 4 -// else -> when (basePath?.reference?.resolve()?.containingCrate?.origin) { -// PackageOrigin.WORKSPACE -> 3 -// PackageOrigin.DEPENDENCY -> 2 -// PackageOrigin.STDLIB, PackageOrigin.STDLIB_DEPENDENCY -> 1 -// null -> 3 -// } -// } - override fun compareTo(other: UseStmtWrapper): Int = - compareValuesBy( - this, other, - { it.packageGroupLevel }, { it.addressLevel }, { it.useStmt.useSpeckText } - ) -} - -val COMPARATOR_FOR_ITEMS_IN_USE_GROUP: Comparator = - compareBy { !it.isSelf }.thenBy { it.referenceName.lowercase() } +private fun getBetweenGroupsLevel(namedAddress: String?, moveProject: MoveProject?): Int { + // sort to the end if not a named address + if (namedAddress == null) return 4 -private val MvAddressRef.useGroupLevel: Int - get() { - // sort to the end if not a named address - if (this.namedAddress == null) return 4 - - val name = this.namedAddress?.text.orEmpty().lowercase() - val currentPackageAddresses = - this.moveProject?.currentPackageAddresses()?.keys.orEmpty().map { it.lowercase() } - return when (name) { - "std", "aptos_std", "aptos_framework", "aptos_token" -> 1 - !in currentPackageAddresses -> 2 - else -> 3 - } + val name = namedAddress.lowercase() + val currentPackageAddresses = + moveProject?.currentPackageAddresses()?.keys.orEmpty().map { it.lowercase() } + return when (name) { + "std", "aptos_std", "aptos_framework", "aptos_token" -> 1 + !in currentPackageAddresses -> 2 + else -> 3 } +} diff --git a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt index 9ead25f56..c26736258 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt @@ -53,11 +53,6 @@ class MvPsiFactory(val project: Project) { createFromText("module $text {}")?.nameIdentifier ?: error("Failed to create identifier: `$text`") -// fun createColon(): PsiElement = -// const("const C: u8 = 1;") -// .descendantOfTypeStrict()!! -// .getChild(MvElementTypes.COLON)!! - fun createComma(): PsiElement = createFromText( """ diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt index 66eaa052e..34028915e 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt @@ -41,6 +41,7 @@ val MvUseItem.moduleName: String } val MvUseItem.isSelf: Boolean get() = this.identifier.textMatches("Self") +val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false class MvUseItemReferenceElement( element: MvUseItem diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt index f6b2ccb1e..dcb6e3ab2 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt @@ -3,16 +3,18 @@ package org.move.lang.core.psi.ext import com.intellij.psi.PsiComment import com.intellij.psi.SyntaxTraverser import org.move.lang.core.psi.MvItemUseSpeck +import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseItem import org.move.lang.core.psi.MvUseItemGroup +import org.move.lang.core.psi.MvUseSpeck val MvUseItemGroup.names get() = this.useItemList.mapNotNull { it.identifier.text } -val MvUseItemGroup.parentUseSpeck: MvItemUseSpeck get() = parent as MvItemUseSpeck +//val MvUseItemGroup.parentUseSpeck: MvItemUseSpeck get() = parent as MvItemUseSpeck -val MvUseItemGroup.asTrivial: MvUseItem? +val MvUseGroup.asTrivial: MvUseSpeck? get() { - val speck = useItemList.singleOrNull() ?: return null + val speck = useSpeckList.singleOrNull() ?: return null // Do not change use-groups with comments if (SyntaxTraverser.psiTraverser(this).traverse().any { it is PsiComment }) return null return speck diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index bcc4eb281..9df6704c7 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -121,17 +121,3 @@ val MvUseStmt.useSpecks: List } } } - - -val MvUseStmt.useSpeckText: String - get() { - val moduleUseSpeck = this.moduleUseSpeck - if (moduleUseSpeck != null) { - return moduleUseSpeck.text - } - val itemUseSpeck = this.itemUseSpeck - if (itemUseSpeck != null) { - return itemUseSpeck.text - } - return "" - } diff --git a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt index 378da39d8..b8276196e 100644 --- a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt @@ -174,17 +174,20 @@ class HighlightingAnnotatorTest: AnnotatorTestCase(HighlightingAnnotator::class) """ ) - fun `test imported Self as keyword`() = checkHighlighting( + fun `test Self as keyword`() = checkHighlighting( """ - module M { - use 0x1::Transaction::Self + module 0x1::m { + use 0x1::Transaction::Self; + fun main() { + Self::call(); + } } """ ) fun `test copy is keyword`() = checkHighlighting( """ - module M { + module 0x1::m { struct S has copy {} fun main() { let a = copy 1; diff --git a/src/test/kotlin/org/move/ide/refactoring/optimizeImports/OptimizeImportsTest.kt b/src/test/kotlin/org/move/ide/refactoring/optimizeImports/OptimizeImportsTest.kt index 65652b370..4a6f9fc81 100644 --- a/src/test/kotlin/org/move/ide/refactoring/optimizeImports/OptimizeImportsTest.kt +++ b/src/test/kotlin/org/move/ide/refactoring/optimizeImports/OptimizeImportsTest.kt @@ -180,13 +180,13 @@ class OptimizeImportsTest : OptimizeImportsTestBase() { use BBB::M2::S2; use AAA::M1::S1; use AAA::M1::SS1; - use Std::Signer; - use std::signature; use aptos_std::table; use aptos_std::iter_table; use aptos_framework::coin; #[test_only] use Std::Errors; + use Std::Signer; + use std::signature; fun call(a: S1, b: S2, c: SS1) { Signer::address_of(); diff --git a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt index 4c24c29db..0e22a3683 100644 --- a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt @@ -21,6 +21,17 @@ class ReceiverStyleFunctionTest: ResolveTestCase() { } """) + fun `test resolve self parameter`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(self: S, y: u64): u64 { + //X + self.x + y + //^ + } + } + """) + fun `test resolve receiver function with reference`() = checkByCode(""" module 0x1::main { struct S { x: u64 } From 185ca992f767b28c5fe78790343b59d45fbdc7bb Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 17:38:13 +0300 Subject: [PATCH 13/43] aliases fixes --- .../move/ide/annotator/MvErrorAnnotator.kt | 2 +- .../org/move/ide/utils/FunctionSignature.kt | 2 +- .../lang/core/resolve/ref/MoveReference.kt | 22 ++++--------------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt index cb11f7fad..b4dad2b2b 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt @@ -193,7 +193,7 @@ class MvErrorAnnotator: MvAnnotatorBase() { } private fun checkMethodOrPath(methodOrPath: MvMethodOrPath, holder: MvAnnotationHolder) { - val item = methodOrPath.reference?.resolveWithAliases() + val item = methodOrPath.reference?.resolveFollowingAliases() val msl = methodOrPath.isMslScope val realCount = methodOrPath.typeArguments.size diff --git a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt index b06933e68..1232b1d52 100644 --- a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt +++ b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt @@ -48,7 +48,7 @@ data class FunctionSignature( function?.getSignature() } is MvMethodCall -> { - val function = callable.reference.resolveWithAliases() as? MvFunction + val function = callable.reference.resolveFollowingAliases() as? MvFunction function?.getSignature() } else -> null diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt index 5009ec9f7..75bda53ff 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReference.kt @@ -4,10 +4,7 @@ import com.intellij.psi.PsiPolyVariantReference import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvUseAlias -import org.move.lang.core.psi.ext.moduleUseSpeck import org.move.lang.core.psi.ext.parentUseSpeck -import org.move.lang.core.psi.ext.useItem -import org.move.lang.core.resolve2.ref.RsPathResolveResult interface MvPolyVariantReference : PsiPolyVariantReference { @@ -15,14 +12,11 @@ interface MvPolyVariantReference : PsiPolyVariantReference { override fun resolve(): MvNamedElement? - fun resolveWithAliases(): MvNamedElement? { + fun resolveFollowingAliases(): MvNamedElement? { val resolved = this.resolve() if (resolved is MvUseAlias) { - val useItem = resolved.useItem - if (useItem != null) { - return useItem.reference.resolve() - } - return resolved.moduleUseSpeck?.fqModuleRef?.reference?.resolve() + val aliasedPath = resolved.parentUseSpeck.path + return aliasedPath.reference?.resolve() } return resolved } @@ -43,13 +37,5 @@ interface MvPath2Reference: MvPolyVariantReference { // fun rawMultiResolve(): List> // multiResolve().map { RsPathResolveResult(it, isVisible = true) } - - fun resolveFollowingAliases(): MvNamedElement? { - val resolved = this.resolve() - if (resolved is MvUseAlias) { - val aliasedPath = resolved.parentUseSpeck.path - return aliasedPath.reference?.resolve() - } - return resolved - } + } From c0c0d416c84ff78249dd921ef93fd0df38c21989 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 22:43:36 +0300 Subject: [PATCH 14/43] fix completions --- .../completion/CommonCompletionContributor.kt | 13 +- .../lang/core/completion/LookupElements.kt | 6 +- .../providers/ModulesCompletionProvider.kt | 2 +- .../providers/MvPathCompletionProvider.kt | 97 +++++----- .../providers/MvPathCompletionProvider2.kt | 168 ++++++++++++++++++ .../org/move/lang/core/psi/ext/MvPath.kt | 6 +- .../move/lang/core/psi/ext/MvUseItemGroup.kt | 2 + .../core/resolve2/ref/Path2ReferenceImpl.kt | 10 +- .../core/resolve2/ref/RsPathResolveKind.kt | 10 +- .../completion/MoveCompletionTestFixture.kt | 1 + .../completion/names/ModulesCompletionTest.kt | 6 +- 11 files changed, 262 insertions(+), 59 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt diff --git a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt index 683d5bb80..0b818ecf2 100644 --- a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt +++ b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt @@ -10,19 +10,20 @@ import org.move.lang.core.psi.MvModule class CommonCompletionContributor : CompletionContributor() { init { extend(CompletionType.BASIC, PrimitiveTypesCompletionProvider) - extend(CompletionType.BASIC, NamesCompletionProvider) - extend(CompletionType.BASIC, FunctionsCompletionProvider) - extend(CompletionType.BASIC, SchemasCompletionProvider) +// extend(CompletionType.BASIC, NamesCompletionProvider) +// extend(CompletionType.BASIC, FunctionsCompletionProvider) +// extend(CompletionType.BASIC, SchemasCompletionProvider) extend(CompletionType.BASIC, SpecItemCompletionProvider) extend(CompletionType.BASIC, AddressesCompletionProvider) extend(CompletionType.BASIC, AddressInModuleDeclCompletionProvider) - extend(CompletionType.BASIC, TypesCompletionProvider) - extend(CompletionType.BASIC, ImportsCompletionProvider) +// extend(CompletionType.BASIC, TypesCompletionProvider) +// extend(CompletionType.BASIC, ImportsCompletionProvider) // extend(CompletionType.BASIC, ModulesCompletionProvider) - extend(CompletionType.BASIC, FQModuleCompletionProvider) +// extend(CompletionType.BASIC, FQModuleCompletionProvider) extend(CompletionType.BASIC, StructFieldsCompletionProvider) extend(CompletionType.BASIC, StructPatCompletionProvider) extend(CompletionType.BASIC, SchemaFieldsCompletionProvider) + extend(CompletionType.BASIC, MvPathCompletionProvider2) extend( CompletionType.BASIC, MvPsiPatterns.ability(), diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index d9a48df98..b9c3a6500 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -12,6 +12,7 @@ import org.move.ide.presentation.text import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ContextScopeInfo +import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.types.infer.* import org.move.lang.core.types.ty.Ty import org.move.lang.core.types.ty.TyUnknown @@ -142,6 +143,7 @@ data class CompletionContext( val contextElement: MvElement, val contextScopeInfo: ContextScopeInfo, val expectedTy: Ty? = null, + val resolutionCtx: PathResolutionContext? = null ) { fun isMsl(): Boolean = contextScopeInfo.isMslScope } @@ -226,9 +228,11 @@ open class DefaultInsertHandler(val completionCtx: CompletionContext? = null): I item: LookupElement ) { val document = context.document - when (element) { is MvFunctionLike -> { + // no suffix for imports + if (completionCtx?.resolutionCtx?.isUseSpeck ?: false) return + val isMethodCall = context.getElementOfType() != null val requiresExplicitTypes = element.requiresExplicitlyProvidedTypeArguments(completionCtx) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt index ff3de5481..776c67d88 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt @@ -23,7 +23,7 @@ import org.move.lang.core.resolve.processItems import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Visibility -object ModulesCompletionProvider: MvCompletionProvider() { +object ModulesCompletionProvider2: MvCompletionProvider() { override val elementPattern: ElementPattern get() = MvPsiPatterns.path() diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index ec5c940fe..0296ea9b3 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -24,10 +24,17 @@ import org.move.lang.core.types.infer.inferExpectedTy import org.move.lang.core.types.infer.inference import org.move.lang.core.types.ty.Ty import org.move.lang.core.types.ty.TyUnknown +import java.util.* + +fun interface CompletionFilter { + fun removeEntry(entry: ScopeEntry, ctx: PathResolutionContext): Boolean +} abstract class MvPathCompletionProvider: MvCompletionProvider() { - abstract val namespace: Namespace + abstract val namespaces: Set + + open val completionFilters: List = emptyList() open fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo = ContextScopeInfo( @@ -47,16 +54,15 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { val qualifier = pathElement.qualifier - val namespaces = setOf(this.namespace) val contextScopeInfo = pathScopeInfo(pathElement) val msl = pathElement.isMslScope val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) - val structAsType = this.namespace == Namespace.TYPE + val structAsType = Namespace.TYPE in this.namespaces val completionContext = CompletionContext( pathElement, contextScopeInfo, - expectedTy + expectedTy, ) var completionCollector = createProcessor { e -> @@ -72,8 +78,13 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { if (qualifier != null) { val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() - if (resolvedQualifier is MvItemsOwner) { - processItemDeclarations(resolvedQualifier, namespaces, completionCollector) + when (resolvedQualifier) { + is MvModule -> { + val moduleBlock = resolvedQualifier.moduleBlock + if (moduleBlock != null) { + processItemDeclarations(moduleBlock, this.namespaces, completionCollector) + } + } } return } @@ -95,8 +106,6 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { // } val processedNames = mutableSetOf() -// completionCollector = -// completionCollector.wrapWithBeforeProcessingHandler { processedNames.add(it.name) } completionCollector = completionCollector.wrapWithFilter { e -> if (processedNames.contains(e.name)) { return@wrapWithFilter false @@ -105,8 +114,18 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { true } + val resolutionCtx = PathResolutionContext(pathElement, contextScopeInfo) + + // custom filters + completionCollector = completionCollector.wrapWithFilter { + for (completionFilter in this.completionFilters) { + if (!completionFilter.removeEntry(it, resolutionCtx)) return@wrapWithFilter false + } + true + } + val ctx = PathResolutionContext(pathElement, contextScopeInfo) - processNestedScopesUpwards(pathElement, namespaces, ctx, completionCollector) + processNestedScopesUpwards(pathElement, this.namespaces, ctx, completionCollector) // processItems(pathElement, namespaces, contextScopeInfo) { (name, element) -> // if (processedNames.contains(name)) { @@ -130,7 +149,7 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { val importContext = ImportContext.from( originalPathElement, - namespaces, + this.namespaces, setOf(Visibility.Public), contextScopeInfo ) @@ -141,6 +160,10 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { importContext, ) candidates.forEach { candidate -> + val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, namespaces) + for (completionFilter in completionFilters) { + if (!completionFilter.removeEntry(entry, resolutionCtx)) return@forEach + } val lookupElement = candidate.element.createLookupElement( completionContext, structAsType = structAsType, @@ -159,16 +182,7 @@ object NamesCompletionProvider: MvPathCompletionProvider() { .andNot(MvPsiPatterns.pathType()) .andNot(MvPsiPatterns.schemaLit()) - override val namespace: Namespace get() = Namespace.NAME - -// override fun itemVis(pathElement: MvPath): ItemVis { -// return ItemVis( -// setOf(Namespace.NAME), -// Visibility.none(), -// mslLetScope = pathElement.mslLetScope, -// itemScopes = pathElement.itemScopes, -// ) -// } + override val namespaces: Set get() = EnumSet.of(Namespace.NAME) } object FunctionsCompletionProvider: MvPathCompletionProvider() { @@ -178,32 +192,14 @@ object FunctionsCompletionProvider: MvPathCompletionProvider() { .andNot(MvPsiPatterns.pathType()) .andNot(MvPsiPatterns.schemaLit()) - override val namespace: Namespace get() = Namespace.FUNCTION - -// override fun itemVis(pathElement: MvPath): ItemVis { -// return ItemVis( -// setOf(Namespace.FUNCTION), -// Visibility.none(), -// mslLetScope = pathElement.mslLetScope, -// itemScopes = pathElement.itemScopes, -// ) -// } + override val namespaces: Set get() = EnumSet.of(Namespace.FUNCTION) } object TypesCompletionProvider: MvPathCompletionProvider() { override val elementPattern: ElementPattern get() = MvPsiPatterns.pathType() - override val namespace: Namespace get() = Namespace.TYPE - -// override fun itemVis(pathElement: MvPath): ItemVis { -// return ItemVis( -// setOf(Namespace.TYPE), -// Visibility.none(), -// mslLetScope = pathElement.mslLetScope, -// itemScopes = pathElement.itemScopes, -// ) -// } + override val namespaces: Set get() = EnumSet.of(Namespace.TYPE) } object SchemasCompletionProvider: MvPathCompletionProvider() { @@ -213,7 +209,7 @@ object SchemasCompletionProvider: MvPathCompletionProvider() { MvPsiPatterns.schemaLit(), MvPsiPatterns.pathInsideIncludeStmt() ) - override val namespace: Namespace get() = Namespace.SCHEMA + override val namespaces: Set get() = EnumSet.of(Namespace.SCHEMA) override fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo { return ContextScopeInfo( @@ -223,6 +219,25 @@ object SchemasCompletionProvider: MvPathCompletionProvider() { } } +object ModulesCompletionProvider: MvPathCompletionProvider() { + override val elementPattern: ElementPattern + get() = + MvPsiPatterns.path() + .andNot(MvPsiPatterns.pathType()) + .andNot(MvPsiPatterns.schemaLit()) + + override val namespaces: Set get() = EnumSet.of(Namespace.MODULE) + + override val completionFilters: List + get() = listOf( + // filter out the current module + CompletionFilter { e, ctx -> + if (e.element is MvModule) + return@CompletionFilter ctx.containingModule?.let { e.element.equalsTo(it) } ?: true + true + }) +} + fun getExpectedTypeForEnclosingPathOrDotExpr(element: MvReferenceElement, msl: Boolean): Ty? { for (ancestor in element.ancestors) { if (element.endOffset < ancestor.endOffset) continue diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt new file mode 100644 index 000000000..547e6a84f --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -0,0 +1,168 @@ +package org.move.lang.core.completion.providers + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.patterns.ElementPattern +import com.intellij.psi.PsiElement +import com.intellij.util.ProcessingContext +import org.move.ide.inspections.imports.ImportContext +import org.move.lang.core.MvPsiPatterns.path +import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY +import org.move.lang.core.completion.createLookupElement +import org.move.lang.core.completion.getOriginalOrSelf +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.equalsTo +import org.move.lang.core.psi.ext.isMslScope +import org.move.lang.core.psi.ext.names +import org.move.lang.core.psi.ext.rootPath +import org.move.lang.core.resolve.ContextScopeInfo +import org.move.lang.core.resolve.LetStmtScope.EXPR_STMT +import org.move.lang.core.resolve.SimpleScopeEntry +import org.move.lang.core.resolve.createProcessor +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve.ref.Namespace.* +import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve.wrapWithFilter +import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.classifyPath +import org.move.lang.core.resolve2.ref.processPathResolveVariants +import java.util.* + +object MvPathCompletionProvider2: MvCompletionProvider() { + override val elementPattern: ElementPattern get() = path() + + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + val maybePath = parameters.position.parent + val pathElement = maybePath as? MvPath ?: maybePath.parent as MvPath + if (parameters.position !== pathElement.referenceNameElement) return + + val parentElement = pathElement.rootPath().parent + val contextScopeInfo = + if (parentElement is MvSchemaLit) + ContextScopeInfo( + refItemScopes = pathElement.itemScopes, + letStmtScope = EXPR_STMT + ) else ContextScopeInfo.from(pathElement) + val resolutionCtx = PathResolutionContext(pathElement, contextScopeInfo) + val msl = pathElement.isMslScope + val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) + + val completionContext = CompletionContext( + pathElement, + contextScopeInfo, + expectedTy, + resolutionCtx = resolutionCtx + ) + + // 0x1::m::{a, b, Self} + // //^ + if (resolutionCtx.isUseSpeck) { + val useGroup = resolutionCtx.useSpeck?.parent as? MvUseGroup + if (useGroup != null && "Self" !in useGroup.names) { + result.addElement(createSelfLookup()) + } + } + + val ns = + when (parentElement) { + is MvPathType -> EnumSet.of(MODULE, TYPE) + is MvSchemaLit -> EnumSet.of(MODULE, SCHEMA) + else -> EnumSet.of(MODULE, NAME, FUNCTION) + } + + addVariants( + pathElement, parameters, completionContext, ns, result, + listOf( + CompletionFilter { e, ctx -> + // filter out current module, skips processing if true + val element = e.element.getOriginalOrSelf() + if (element is MvModule) { + val containingModule = ctx.containingModule?.getOriginalOrSelf() + if (containingModule != null) { + return@CompletionFilter containingModule.equalsTo(element) + } + } + false + }) + ) + } + + fun addVariants( + pathElement: MvPath, + parameters: CompletionParameters, + completionContext: CompletionContext, + ns: Set, + result: CompletionResultSet, + completionFilters: List = emptyList() + ) { +// val qualifier = pathElement.qualifier + val structAsType = TYPE in ns + val resolutionCtx = completionContext.resolutionCtx ?: error("always non-null in path completion") + + var completionCollector = createProcessor { e -> + val element = e.element as? MvNamedElement ?: return@createProcessor + val lookup = + element.createLookupElement( + completionContext, + structAsType = structAsType, + priority = element.completionPriority + ) + result.addElement(lookup) + } + + val processedNames = mutableSetOf() + completionCollector = completionCollector.wrapWithFilter { e -> + // custom filters + for (completionFilter in completionFilters) { + if (completionFilter.removeEntry(e, resolutionCtx)) return@wrapWithFilter false + } + + if (processedNames.contains(e.name)) return@wrapWithFilter false + processedNames.add(e.name) + + true + } + + val pathKind = classifyPath(pathElement, overwriteNs = ns) + processPathResolveVariants(resolutionCtx, pathKind, completionCollector) + + // disable auto-import in module specs for now + if (pathElement.containingModuleSpec != null) return + + val originalPathElement = parameters.originalPosition?.parent as? MvPath ?: return + val importContext = + ImportContext.from( + originalPathElement, + ns, + setOf(Visibility.Public), + completionContext.contextScopeInfo + ) + val candidates = getImportCandidates( + parameters, + result, + processedNames, + importContext, + ) + candidates.forEach { candidate -> + val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, ns) + for (completionFilter in completionFilters) { + if (completionFilter.removeEntry(entry, resolutionCtx)) return@forEach + } + val lookupElement = candidate.element.createLookupElement( + completionContext, + structAsType = structAsType, + priority = UNIMPORTED_ITEM_PRIORITY, + insertHandler = ImportInsertHandler(parameters, candidate) + ) + result.addElement(lookupElement) + } + } + + private fun createSelfLookup() = LookupElementBuilder.create("Self").bold() +} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 868c59da2..aa633f648 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -151,4 +151,8 @@ fun MvPath.importCandidateNamespaces(): Set { val MvPath.moduleRef: MvModuleRef? get() = error("unimplemented") -val MvPath.hasColonColon: Boolean get() = colonColon != null \ No newline at end of file +val MvPath.hasColonColon: Boolean get() = colonColon != null + +val MvPath.useSpeck: MvUseSpeck? get() = this.rootPath().parent as? MvUseSpeck + +val MvPath.isUseSpeck get() = useSpeck != null \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt index dcb6e3ab2..fb965f772 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt @@ -10,6 +10,8 @@ import org.move.lang.core.psi.MvUseSpeck val MvUseItemGroup.names get() = this.useItemList.mapNotNull { it.identifier.text } +val MvUseGroup.names get() = this.useSpeckList.mapNotNull { it.path.identifier?.text } + //val MvUseItemGroup.parentUseSpeck: MvItemUseSpeck get() = parent as MvItemUseSpeck val MvUseGroup.asTrivial: MvUseSpeck? diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index ac4d6e484..ae0c6e4bd 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -3,9 +3,7 @@ package org.move.lang.core.resolve2.ref import com.intellij.psi.ResolveResult import org.move.cli.MoveProject import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.allowedNamespaces -import org.move.lang.core.psi.ext.qualifier -import org.move.lang.core.psi.ext.rootPath +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* import org.move.lang.core.resolve2.processAddressPathResolveVariants @@ -160,6 +158,12 @@ class PathResolutionContext( } val containingModule: MvModule? get() = lazyContainingModule.value + private var lazyUseSpeck: Lazy = lazy(NONE) { + path.useSpeck + } + val useSpeck: MvUseSpeck? get() = lazyUseSpeck.value + val isUseSpeck: Boolean get() = useSpeck != null + // var lazyContainingModInfo: Lazy = lazy(NONE) { // val module = containingModule // getModInfo(module) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt index d3e59d835..b022ecdee 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt @@ -1,10 +1,9 @@ package org.move.lang.core.resolve2.ref import org.move.lang.core.psi.MvPath -import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.ext.allowedNamespaces +import org.move.lang.core.psi.ext.isUseSpeck import org.move.lang.core.psi.ext.qualifier -import org.move.lang.core.psi.ext.rootPath import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.RsPathResolveKind.* import org.move.lang.core.types.Address @@ -31,13 +30,14 @@ sealed class RsPathResolveKind { data object NamedAddressPath: RsPathResolveKind() } -fun classifyPath(path: MvPath): RsPathResolveKind { +fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResolveKind { val qualifier = path.qualifier - val ns = path.allowedNamespaces() + + val ns = overwriteNs ?: path.allowedNamespaces() // if (qualifier == null) { // return UnqualifiedPath(ns) // } - val isUseSpeck = path.rootPath().parent is MvUseSpeck + val isUseSpeck = path.isUseSpeck if (qualifier == null) { // left-most path if (isUseSpeck) { diff --git a/src/main/kotlin/org/move/utils/tests/completion/MoveCompletionTestFixture.kt b/src/main/kotlin/org/move/utils/tests/completion/MoveCompletionTestFixture.kt index da310f82f..6fff39ebe 100644 --- a/src/main/kotlin/org/move/utils/tests/completion/MoveCompletionTestFixture.kt +++ b/src/main/kotlin/org/move/utils/tests/completion/MoveCompletionTestFixture.kt @@ -16,6 +16,7 @@ class MvCompletionTestFixture( fun invokeCompletion(@Language("Move") code: String): List { prepare(code) val completions = myFixture.completeBasic() + check(completions != null) { "Only a single completion item" } return completions.toList() } diff --git a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt index a90a849b0..f3b43f108 100644 --- a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt @@ -5,6 +5,7 @@ import org.move.utils.tests.completion.CompletionTestCase class ModulesCompletionTest : CompletionTestCase() { fun `test autocomplete imported modules in name position`() = doSingleCompletion( """ + module 0x1::Transaction {} script { use 0x1::Transaction; @@ -13,6 +14,7 @@ class ModulesCompletionTest : CompletionTestCase() { } } """, """ + module 0x1::Transaction {} script { use 0x1::Transaction; @@ -25,12 +27,14 @@ class ModulesCompletionTest : CompletionTestCase() { fun `test autocomplete imported modules in type position`() = doSingleCompletion( """ + module 0x1::Transaction {} script { use 0x1::Transaction; fun main(a: Tra/*caret*/) {} } """, """ + module 0x1::Transaction {} script { use 0x1::Transaction; @@ -46,7 +50,7 @@ class ModulesCompletionTest : CompletionTestCase() { } script { - use 0x01::/*caret*/ + use 0x1::/*caret*/ } """ ) From 62d63fc801218bac1b5f1a8fc4b5dc1186678d37 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 16 Jul 2024 23:33:19 +0300 Subject: [PATCH 15/43] addresses resolution --- .../core/resolve2/ref/Path2ReferenceImpl.kt | 23 +++---- .../core/resolve2/ref/RsPathResolveKind.kt | 25 +++++-- .../org/move/lang/core/types/Address.kt | 15 ++-- .../move/lang/NamedModulePathValuesTest.kt | 68 ++++++++++++------- .../resolve/ResolveItemsTreeProjectTest.kt | 2 +- .../ResolveNamedModulePathTreeProjectTest.kt | 5 +- .../move/lang/resolve/ResolveVariablesTest.kt | 38 +++++------ 7 files changed, 106 insertions(+), 70 deletions(-) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index ae0c6e4bd..c6c511d12 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -87,21 +87,20 @@ fun processPathResolveVariants( // foo::bar processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) } - is NamedAddressPath -> { - return false - } + is NamedAddressPath -> return false + is ValueAddressPath -> return false } } -fun processPathResolveVariants( - path: MvPath, - contextScopeInfo: ContextScopeInfo = ContextScopeInfo.from(path), - processor: RsResolveProcessor, -): Boolean { - val ctx = PathResolutionContext(path, contextScopeInfo = contextScopeInfo) - val pathKind = classifyPath(path) - return processPathResolveVariants(ctx, pathKind, processor) -} +//fun processPathResolveVariants( +// path: MvPath, +// contextScopeInfo: ContextScopeInfo = ContextScopeInfo.from(path), +// processor: RsResolveProcessor, +//): Boolean { +// val ctx = PathResolutionContext(path, contextScopeInfo = contextScopeInfo) +// val pathKind = classifyPath(path) +// return processPathResolveVariants(ctx, pathKind, processor) +//} /** * foo::bar diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt index b022ecdee..58d931435 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt @@ -27,7 +27,8 @@ sealed class RsPathResolveKind { ): RsPathResolveKind() /** aptos_framework in `use aptos_framework::bar`*/ - data object NamedAddressPath: RsPathResolveKind() + data class NamedAddressPath(val address: Address.Named): RsPathResolveKind() + data class ValueAddressPath(val address: Address.Value): RsPathResolveKind() } fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResolveKind { @@ -43,7 +44,16 @@ fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResol if (isUseSpeck) { // use aptos_framework:: // //^ - return NamedAddressPath + val moveProject = path.moveProject + val pathName = path.referenceName + if (pathName == null) { + val value = path.pathAddress!!.text + return ValueAddressPath(Address.Value(value)) + } else { + val namedAddress = + moveProject?.getNamedAddress(pathName) ?: Address.Named(pathName, null, moveProject) + return NamedAddressPath(namedAddress) + } } return UnqualifiedPath(ns) } @@ -54,10 +64,13 @@ fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResol return when { qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text)) - qualifierPath == null && isUseSpeck && qualifierName != null -> - ModulePath(path, Address.Named(qualifierName, null, qualifier.moveProject)) -// qualifier.parent is MvUseSpeck && qualifierName != null -> -// AddressPath(path, Address.Named(qualifierName, null, qualifier.moveProject)) + qualifierPath == null && isUseSpeck && qualifierName != null -> { + val moveProject = qualifier.moveProject + val namedAddress = + moveProject?.getNamedAddress(qualifierName) + ?: Address.Named(qualifierName, null, moveProject) + ModulePath(path, namedAddress) + } else -> QualifiedPath(path, qualifier, ns) } } diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index fedf0aad0..82877539a 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -64,7 +64,7 @@ sealed class Address { class Named( val name: String, - private val value: String?, + val value: String?, private val declMoveProject: MoveProject? ) : Address() { fun value(moveProject: MoveProject? = null): String { @@ -84,7 +84,7 @@ sealed class Address { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Named) return false - if (this.hashCode() != other.hashCode()) return false +// if (this.hashCode() != other.hashCode()) return false return eq(this, other) } @@ -99,9 +99,14 @@ sealed class Address { if (left == null && right == null) return true return when { left is Value && right is Value -> left.addressLit().canonical() == right.addressLit().canonical() - left is Named && right is Named -> - Pair(left.name, normalizeValue(left.value())) == Pair(right.name, normalizeValue(right.value()) - ) + left is Named && right is Named -> { + val leftValue = left.value?.let { normalizeValue(it) } + val rightValue = right.value?.let { normalizeValue(it) } + if (leftValue == null && rightValue == null) { + return left.name == right.name + } + return leftValue == rightValue + } else -> false } } diff --git a/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt b/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt index d1fc77930..c02a92486 100644 --- a/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt +++ b/src/test/kotlin/org/move/lang/NamedModulePathValuesTest.kt @@ -2,53 +2,68 @@ package org.move.lang import org.move.cli.moveProjectsService import org.move.lang.core.psi.MvNamedAddress +import org.move.lang.core.psi.MvPath import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.MvProjectTestBase import org.move.utils.tests.base.findElementAndDataInEditor -class NamedModulePathValuesTest : MvProjectTestBase() { +class NamedModulePathValuesTest: MvProjectTestBase() { fun `test named address`() = checkByFileTree { - moveToml(""" + moveToml( + """ [addresses] Std = "0x1" - """) + """ + ) sources { - move("main.move", """ + move( + "main.move", """ module Std::Module {} //^ Std = 0x1 - """) + """ + ) } } fun `test placeholder address`() = checkByFileTree { - moveToml(""" + moveToml( + """ [addresses] Std = "_" - """) + """ + ) sources { - move("main.move", """ + move( + "main.move", """ module Std::Module {} //^ Std = _ - """) + """ + ) } } fun `test dependency address`() = checkByFileTree { - moveToml(""" + moveToml( + """ [dependencies] Stdlib = { local = "./stdlib" } - """) + """ + ) dir("stdlib") { - moveToml(""" + moveToml( + """ [addresses] Std = "0x1" - """) + """ + ) } sources { - move("main.move", """ + move( + "main.move", """ module Std::Module {} //^ Std = 0x1 - """) + """ + ) } } @@ -129,9 +144,8 @@ class NamedModulePathValuesTest : MvProjectTestBase() { sources { move( "main.move", """ - module 0x1::M { - use Std::Reflect; - //^ Std = 0x2 + module Std::M { + //^ Std = 0x2 } """ ) @@ -157,27 +171,33 @@ class NamedModulePathValuesTest : MvProjectTestBase() { fun `test named address from git dependency`() = checkByFileTree { dotMove { git("https://github.com/pontem-network/move-stdlib.git", "main") { - moveToml(""" + moveToml( + """ [package] name = "Stdlib" [addresses] Std = "0x2" - """) + """ + ) } } - moveToml(""" + moveToml( + """ [package] name = "Module" [dependencies] Stdlib = { git = "https://github.com/pontem-network/move-stdlib.git", rev = "main"} - """) + """ + ) sources { - move("main.move", """ + move( + "main.move", """ module Std::Module {} //^ Std = 0x2 - """) + """ + ) } } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt index b10298c30..515b1e8cd 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt @@ -346,7 +346,7 @@ class ResolveItemsTreeProjectTest : ResolveProjectTestCase() { } } - fun `test resolve module by address value`() = checkByFileTree { + fun `test resolve module by address value with different address name`() = checkByFileTree { moveToml( """ [package] diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt index ef1b8b3f9..dfd9d296e 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveNamedModulePathTreeProjectTest.kt @@ -128,9 +128,8 @@ class ResolveNamedModulePathTreeProjectTest : ResolveProjectTestCase() { ) sources { move("main.move", """ - module 0x1::M { - use Std::Reflect; - //^ + module Std::M { + //^ } """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt index 62aa4e187..86f94d903 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt @@ -290,25 +290,25 @@ module 0x1::string_tests { } """) - fun `test resolve const item with same name imported expected failure`() = checkByCode(""" -module 0x1::string { - const ERR_ADMIN: u64 = 1; -} -#[test_only] -module 0x1::string_tests { - use 0x1::string::ERR_ADMIN; - - const ERR_ADMIN: u64 = 1; - //X - - #[test] - #[expected_failure(abort_code = ERR_ADMIN)] - //^ - fun test_abort() { - - } -} - """) +// fun `test resolve const item with same name imported expected failure`() = checkByCode(""" +//module 0x1::string { +// const ERR_ADMIN: u64 = 1; +//} +//#[test_only] +//module 0x1::string_tests { +// use 0x1::string::ERR_ADMIN; +// +// const ERR_ADMIN: u64 = 1; +// //X +// +// #[test] +// #[expected_failure(abort_code = ERR_ADMIN)] +// //^ +// fun test_abort() { +// +// } +//} +// """) fun `test resolve const item same module expected failure`() = checkByCode(""" #[test_only] From f5bc73ce16f665bc03537a1d46001a5a7609aecb Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 17 Jul 2024 00:20:23 +0300 Subject: [PATCH 16/43] finish resolution tests --- .../move/lang/core/resolve2/ItemResolution.kt | 4 +- .../core/resolve2/LexicalDeclarations2.kt | 5 +- .../move/lang/core/resolve2/ModuleItems.kt | 88 ----------- .../move/lang/core/resolve2/Visibility2.kt | 21 ++- .../move/lang/resolve/ResolveFunctionTest.kt | 47 ++++++ .../move/lang/resolve/ResolveStubOnlyTest.kt | 140 +++++++++--------- 6 files changed, 136 insertions(+), 169 deletions(-) delete mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 32fb3ac8f..15bc7777c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -4,7 +4,6 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Namespace.NAME import java.util.* val MvNamedElement.namespaces: Set @@ -46,8 +45,7 @@ fun processItemDeclarations( val namespace = item.namespace if (namespace !in ns) continue - val itemVisibility = ItemVisibility(item, isTestOnly = item.hasTestOnlyAttr, vis = item.visibility2) - val visibilityFilter = itemVisibility.createFilter() + val visibilityFilter = item.visInfo.createFilter() if (processor.process(name, item, EnumSet.of(namespace), visibilityFilter)) return true } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 4c8854618..67df3b809 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -5,6 +5,7 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.* +import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.util.forEachLeafSpeck @@ -298,8 +299,10 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val element = alias ?: namedElement val namespace = namedElement.namespace + val visibilityFilter = + (namedElement as? MvItemElement)?.visInfo?.createFilter() ?: VisibilityFilter { _, _ -> Visible } - if (namespace in ns && processor.process(name, element)) { + if (namespace in ns && processor.process(name, element, ns, visibilityFilter)) { stop = true return@forEachLeafSpeck true } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt b/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt deleted file mode 100644 index 9e1a4b136..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve2/ModuleItems.kt +++ /dev/null @@ -1,88 +0,0 @@ -package org.move.lang.core.resolve2 - -import com.intellij.openapi.util.Key -import com.intellij.psi.util.CachedValue -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ref.Visibility - -private val MODULE_ITEMS_KEY: Key>> = Key.create("MODULE_ITEMS_KEY") - -data class VisItem( - val name: String, - val item: MvNamedElement, - val visibility: Visibility, - val isFromNamedImport: Boolean -) - -//val MvItemsOwner.visibleItems: List -// get() = -// CachedValuesManager.getCachedValue(this, MODULE_ITEMS_KEY) { -// val declaredItems = buildList { -// if (this is MvModule) { -// addAll(allNonTestFunctions()) -// addAll(consts()) -// addAll(structs()) -// addAll(schemas()) -// } -// } -// .mapNotNull { -// val visibility = (it as? MvItemElement)?.visibility2 ?: Visibility.Internal -// it.name?.let { name -> -// VisItem(name, it, visibility, false) -// } -// } -// -// val speckItems = this.useSpeckVisibleItems -// -// CachedValueProvider.Result.create( -// declaredItems + speckItems, -// listOf(moveStructureOrAnyPsiModificationTracker) -// ) -// } - -val MvModule.declaredItems: List - get() { - return buildList { - addAll(allNonTestFunctions()) - addAll(consts()) - addAll(structs()) - addAll(schemas()) - } - } - -//val MvItemsOwner.useSpeckVisibleItems: List -// get() { -// val visibleItems = mutableListOf() -// for (useStmt in this.useStmtList) { -// useStmt.forEachLeafSpeck { basePath, speckPath, alias -> -// val qualifier = basePath ?: speckPath.path -// if (qualifier == null) { -// // in a form of `use NAME;`, invalid -// return@forEachLeafSpeck -// } -// -// -//// val ctx = PathResolutionContext(speckPath, ContextScopeInfo.from(speckPath)) -//// processQualifiedPathResolveVariants( -//// ctx, -//// Namespace.all(), -//// speckPath, -//// qualifier, -//// createStoppableProcessor { e -> -//// val visItem = VisItem(alias ?: e.name, e.element, ) -//// }) -//// val qualifierModule = qualifier.reference?.resolve() as? MvModule ?: return@forEachLeafSpeck -//// processItemDeclarations(qualifierModule, Namespace.all()) { -//// -//// } -//// val visItem = VisItem( -//// resolvedPath, -//// visibility = Visibility.Internal, -//// isFromNamedImport = true) -//// visibleItems.add(visItem) -// } -// } -// return visibleItems -// } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 22fd8509c..1fd3d2201 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -1,5 +1,7 @@ package org.move.lang.core.resolve2 +import org.move.cli.containingMovePackage +import org.move.cli.settings.moveSettings import org.move.ide.inspections.imports.pathUsageScope import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* @@ -11,14 +13,17 @@ import org.move.lang.core.resolve.ref.Namespace.* import org.move.lang.core.resolve.ref.Visibility2 import org.move.lang.core.resolve.ref.Visibility2.* -data class ItemVisibility( +data class ItemVisibilityInfo( val item: MvItemElement, val isTestOnly: Boolean, val vis: Visibility2, ) +val MvItemElement.visInfo: ItemVisibilityInfo get() = + ItemVisibilityInfo(this, isTestOnly = this.hasTestOnlyAttr, vis = this.visibility2) + /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ -fun ItemVisibility.createFilter(): VisibilityFilter { +fun ItemVisibilityInfo.createFilter(): VisibilityFilter { val (item, isTestOnly, visibility) = this return VisibilityFilter { path, namespaces -> @@ -33,7 +38,7 @@ fun ItemVisibility.createFilter(): VisibilityFilter { if (attrItem != null) return@VisibilityFilter Visible val pathUsageScope = path.pathUsageScope - val useSpeck = path.ancestorStrict() + val useSpeck = path.useSpeck if (useSpeck != null) { // inside import, all visibilities except for private work if (visibility is Restricted) return@VisibilityFilter Visible @@ -64,16 +69,18 @@ fun ItemVisibility.createFilter(): VisibilityFilter { is Restricted.Script -> { val containingFunction = path.containingFunction if (containingFunction != null) { - if (containingFunction.isEntry - || containingFunction.isPublicScript + if (containingFunction.isEntry || containingFunction.isPublicScript ) return@VisibilityFilter Visible } if (path.containingScript != null) return@VisibilityFilter Visible Invisible } is Restricted.Package -> { - // todo - Visible + if (!item.project.moveSettings.enablePublicPackage) { + return@VisibilityFilter Invisible + } + val pathPackage = path.containingMovePackage ?: return@VisibilityFilter Invisible + if (visibility.originPackage == pathPackage) Visible else Invisible } } } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index a21a43e83..69c1cc0ca 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -400,6 +400,40 @@ class ResolveFunctionTest: ResolveTestCase() { """ ) + fun `test public script function available in entry function`() = checkByCode( + """ + module 0x1::M { + public(script) fun call() {} + //X + } + module 0x1::main { + use 0x1::M::call; + + entry fun test_1() { + call(); + //^ + } + } + """ + ) + + fun `test public script function available in public script function`() = checkByCode( + """ + module 0x1::M { + public(script) fun call() {} + //X + } + module 0x1::main { + use 0x1::M::call; + + public(script) fun test_1() { + call(); + //^ + } + } + """ + ) + fun `test resolve fun in test_only module from another test_only`() = checkByCode( """ #[test_only] @@ -958,4 +992,17 @@ module 0x1::mod { } } """) + + fun `test cannot resolve function that friend without friend statement`() = checkByCode(""" + module 0x1::m { + public(friend) fun call() {} + } + module 0x1::main { + use 0x1::m::call; + fun main() { + call() + //^ unresolved + } + } + """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveStubOnlyTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveStubOnlyTest.kt index ba2d65af8..052999ae9 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveStubOnlyTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveStubOnlyTest.kt @@ -48,76 +48,76 @@ class ResolveStubOnlyTest : ResolveProjectTestCase() { } } - fun `test stub resolve module function`() = stubOnlyResolve { - namedMoveToml("MyPackage") - sources { - move( - "module.move", """ - module 0x1::Module { - public fun call() {} - //X - } - """ - ) - move( - "main.move", """ - script { - use 0x1::Module; - fun main() { - Module::call(); - //^ - } - } - """ - ) - } - } +// fun `test stub resolve module function`() = stubOnlyResolve { +// namedMoveToml("MyPackage") +// sources { +// move( +// "module.move", """ +// module 0x1::Module { +// public fun call() {} +// //X +// } +// """ +// ) +// move( +// "main.move", """ +// script { +// use 0x1::Module; +// fun main() { +// Module::call(); +// //^ +// } +// } +// """ +// ) +// } +// } - fun `test stub resolve fq module function`() = stubOnlyResolve { - namedMoveToml("MyPackage") - sources { - move( - "module.move", """ - module 0x1::Module { - public fun call() {} - //X - } - """ - ) - move( - "main.move", """ - script { - fun main() { - 0x1::Module::call(); - //^ - } - } - """ - ) - } - } +// fun `test stub resolve fq module function`() = stubOnlyResolve { +// namedMoveToml("MyPackage") +// sources { +// move( +// "module.move", """ +// module 0x1::Module { +// public fun call() {} +// //X +// } +// """ +// ) +// move( +// "main.move", """ +// script { +// fun main() { +// 0x1::Module::call(); +// //^ +// } +// } +// """ +// ) +// } +// } - fun `test stub resolve module struct`() = stubOnlyResolve { - namedMoveToml("MyPackage") - sources { - move( - "module.move", """ - module 0x1::Module { - struct S {} - //X - } - """ - ) - move( - "main.move", """ - script { - use 0x1::Module; - fun main(s: Module::S) { - //^ - } - } - """ - ) - } - } +// fun `test stub resolve module struct`() = stubOnlyResolve { +// namedMoveToml("MyPackage") +// sources { +// move( +// "module.move", """ +// module 0x1::Module { +// struct S {} +// //X +// } +// """ +// ) +// move( +// "main.move", """ +// script { +// use 0x1::Module; +// fun main(s: Module::S) { +// //^ +// } +// } +// """ +// ) +// } +// } } From b281e4f0f00a45ecb96e307f51f81dded613a92a Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 01:19:48 +0300 Subject: [PATCH 17/43] fix import candidates --- src/main/kotlin/org/move/cli/MoveProject.kt | 19 ++- .../ide/inspections/imports/AutoImportFix.kt | 10 +- .../move/ide/utils/imports/ImportCandidate.kt | 100 +++---------- .../utils/imports/ImportCandidateCollector.kt | 92 ++++++++++++ .../org/move/ide/utils/imports/ImportUtils.kt | 134 +++++++++++------- .../providers/ModulesCompletionProvider.kt | 7 +- .../providers/MvCompletionProvider.kt | 23 --- .../providers/MvPathCompletionProvider.kt | 5 +- .../providers/MvPathCompletionProvider2.kt | 28 ++-- .../org/move/lang/core/psi/MvPsiFactory.kt | 6 + .../move/lang/core/psi/ext/MvItemsOwner.kt | 7 +- .../org/move/lang/core/psi/ext/MvPath.kt | 10 ++ .../move/lang/core/resolve/NameResolution.kt | 4 + .../org/move/lang/core/resolve/Processors.kt | 39 ++--- .../move/lang/core/resolve2/ItemResolution.kt | 2 +- .../core/resolve2/LexicalDeclarations2.kt | 7 +- .../lang/core/resolve2/NameResolution2.kt | 2 +- .../move/lang/core/resolve2/Visibility2.kt | 5 +- .../core/resolve2/ref/Path2ReferenceImpl.kt | 40 ++---- .../move/lang/core/resolve2/util/PathUtil.kt | 28 ---- .../annotation/MvAnnotationTestFixture.kt | 8 +- .../inspections/imports/AutoImportFixTest.kt | 2 +- .../completion/lookups/LookupElementTest.kt | 38 ++--- .../completion/names/ModulesCompletionTest.kt | 10 ++ .../completion/names/StructsCompletionTest.kt | 10 +- .../move/lang/resolve/ResolveFunctionTest.kt | 68 +++++++++ .../org/move/lang/resolve/ResolveTypesTest.kt | 13 ++ 27 files changed, 431 insertions(+), 286 deletions(-) create mode 100644 src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt diff --git a/src/main/kotlin/org/move/cli/MoveProject.kt b/src/main/kotlin/org/move/cli/MoveProject.kt index 6fcd74a8b..5a6c8b5c2 100644 --- a/src/main/kotlin/org/move/cli/MoveProject.kt +++ b/src/main/kotlin/org/move/cli/MoveProject.kt @@ -1,5 +1,6 @@ package org.move.cli +import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.util.NlsContexts.Tooltip import com.intellij.openapi.util.UserDataHolderBase @@ -20,6 +21,7 @@ import org.move.lang.index.MvNamedElementIndex import org.move.lang.toMoveFile import org.move.lang.toNioPathOrNull import org.move.openapiext.common.checkUnitTestMode +import org.move.openapiext.common.isUnitTestMode import org.move.openapiext.contentRoots import org.move.stdext.chain import org.move.stdext.iterateMoveVirtualFiles @@ -106,6 +108,16 @@ data class MoveProject( val dirScope = GlobalSearchScopes.directoryScope(project, folder, true) searchScope = searchScope.uniteWith(dirScope) } + if (isUnitTestMode + && searchScope == GlobalSearchScope.EMPTY_SCOPE + ) { + // add current file to the search scope for the tests + val currentFile = + FileEditorManager.getInstance(project).selectedTextEditor?.virtualFile + if (currentFile != null) { + searchScope = searchScope.uniteWith(GlobalSearchScope.fileScope(project, currentFile)) + } + } return searchScope } @@ -134,11 +146,12 @@ data class MoveProject( } sealed class UpdateStatus(private val priority: Int) { -// object UpToDate : UpdateStatus(0) - object NeedsUpdate : UpdateStatus(1) - class UpdateFailed(@Tooltip val reason: String) : UpdateStatus(2) { + // object UpToDate : UpdateStatus(0) + object NeedsUpdate: UpdateStatus(1) + class UpdateFailed(@Tooltip val reason: String): UpdateStatus(2) { override fun toString(): String = reason } + fun merge(status: UpdateStatus): UpdateStatus = if (priority >= status.priority) this else status } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index 517548488..05fa71f71 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -91,19 +91,19 @@ class AutoImportFix(element: MvPath): DiagnosticFix(element), @Suppress("DataClassPrivateConstructor") data class ImportContext private constructor( - val pathElement: MvReferenceElement, - val namespaces: Set, + val pathElement: MvPath, + val ns: Set, val visibilities: Set, val contextScopeInfo: ContextScopeInfo, ) { companion object { fun from( - contextElement: MvReferenceElement, - namespaces: Set, + pathElement: MvPath, + ns: Set, visibilities: Set, contextScopeInfo: ContextScopeInfo ): ImportContext { - return ImportContext(contextElement, namespaces, visibilities, contextScopeInfo) + return ImportContext(pathElement, ns, visibilities, contextScopeInfo) } fun from(path: MvPath): ImportContext { diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt index 8547d8035..76fec0daf 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt @@ -1,88 +1,34 @@ package org.move.ide.utils.imports -import org.move.ide.inspections.imports.ImportContext import org.move.lang.MoveFile -import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvQualNamedElement -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.MatchingProcessor -import org.move.lang.core.resolve.processModuleInnerItems -import org.move.lang.core.resolve.processQualItem +import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.types.ItemQualName -import org.move.lang.index.MvNamedElementIndex -import org.move.lang.moveProject import org.move.openapiext.common.checkUnitTestMode -import org.move.openapiext.common.isUnitTestMode data class ImportCandidate(val element: MvQualNamedElement, val qualName: ItemQualName) -object ImportCandidateCollector { - fun getImportCandidates( - context: ImportContext, - targetName: String, - itemFilter: (MvQualNamedElement) -> Boolean = { true } - ): List { - val (contextElement, namespaces, visibilities, itemVis) = context - - val project = contextElement.project - val moveProject = contextElement.moveProject ?: return emptyList() - val searchScope = moveProject.searchScope() - - val allItems = mutableListOf() - if (isUnitTestMode) { - // always add current file in tests - val currentFile = contextElement.containingFile as? MoveFile ?: return emptyList() - - val items = mutableListOf() - processFileItemsForUnitTests(currentFile, namespaces, visibilities, itemVis) { - if (it.element is MvQualNamedElement && it.name == targetName) { - items.add(it.element) - } - false - } -// return elements - -// val items = currentFile.qualifiedItems(targetName, namespaces, visibilities, itemVis) - allItems.addAll(items) - } - - MvNamedElementIndex - .processElementsByName(project, targetName, searchScope) { element -> - processQualItem(element, namespaces, visibilities, itemVis) { - val entryElement = it.element - if (entryElement !is MvQualNamedElement) return@processQualItem false - if (it.name == targetName) { - allItems.add(entryElement) - } - false - } - true - } - - return allItems - .filter(itemFilter) - .mapNotNull { item -> item.qualName?.let { ImportCandidate(item, it) } } - } -} - -private fun processFileItemsForUnitTests( - file: MoveFile, - namespaces: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - checkUnitTestMode() - for (module in file.modules()) { - if ( - Namespace.MODULE in namespaces - && processor.match(contextScopeInfo, module) - ) { - return true - } - if (processModuleInnerItems(module, namespaces, visibilities, contextScopeInfo, processor)) return true - } - return false -} +//fun processFileItemsForUnitTests( +// file: MoveFile, +// namespaces: Set, +// visibilities: Set, +// contextScopeInfo: ContextScopeInfo, +// processor: RsResolveProcessor, +//): Boolean { +// checkUnitTestMode() +// val contextProcessor = contextScopeInfo.wrapWithContextFilter(processor) +// for (module in file.modules()) { +// if ( +// Namespace.MODULE in namespaces && contextProcessor.process(module) +// ) { +// return true +// } +// val matchProcessor = MatchingProcessor { +// contextProcessor.process(it.name, it.element) +// } +// if (processModuleInnerItems(module, namespaces, visibilities, contextScopeInfo, matchProcessor)) return true +// } +// return false +//} diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt new file mode 100644 index 000000000..c602ac0c1 --- /dev/null +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt @@ -0,0 +1,92 @@ +package org.move.ide.utils.imports + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.PrefixMatcher +import com.intellij.psi.PsiElement +import org.move.ide.inspections.imports.ImportContext +import org.move.lang.core.psi.MvQualNamedElement +import org.move.lang.core.psi.ext.MvItemElement +import org.move.lang.core.resolve.VisibilityFilter +import org.move.lang.core.resolve.VisibilityStatus.Visible +import org.move.lang.core.resolve2.createFilter +import org.move.lang.core.resolve2.namespace +import org.move.lang.core.resolve2.visInfo +import org.move.lang.index.MvNamedElementIndex +import org.move.lang.moveProject + +object ImportCandidateCollector { + + fun getImportCandidates(context: ImportContext, targetName: String): List { + val (pathElement, namespaces, visibilities, itemVis) = context + + val project = pathElement.project + val moveProject = pathElement.moveProject ?: return emptyList() + val searchScope = moveProject.searchScope() + + val allItems = mutableListOf() +// if (isUnitTestMode) { +// // always add current file in tests +// val currentFile = pathElement.containingFile as? MoveFile ?: return emptyList() +// val items = mutableListOf() +// processFileItemsForUnitTests(currentFile, namespaces, visibilities, itemVis, createProcessor { +// val element = it.element +// if (element is MvQualNamedElement && it.name == targetName) { +// items.add(element) +// } +// }) +// allItems.addAll(items) +// } + + MvNamedElementIndex + .processElementsByName(project, targetName, searchScope) { element -> + val elementNs = element.namespace + if (elementNs !in namespaces) return@processElementsByName true + val visibilityFilter = + (element as? MvItemElement)?.visInfo?.createFilter() ?: VisibilityFilter { _, _ -> Visible } + + val visibilityStatus = visibilityFilter.filter(pathElement, namespaces) + if (visibilityStatus != Visible) return@processElementsByName true + + if (element !is MvQualNamedElement) return@processElementsByName true + if (element.name == targetName) { + allItems.add(element) + } + +// processQualItem(element, namespaces, visibilities, itemVis) { +// val entryElement = it.element +// if (entryElement !is MvQualNamedElement) return@processQualItem true +// if (it.name == targetName) { +// allItems.add(entryElement) +// } +// false +// } + true + } + + return allItems +// .filter(itemFilter) + .mapNotNull { item -> item.qualName?.let { ImportCandidate(item, it) } } + } + + fun getCompletionCandidates( + parameters: CompletionParameters, + prefixMatcher: PrefixMatcher, + processedPathNames: Set, + importContext: ImportContext, + itemFilter: (PsiElement) -> Boolean = { true } + ): List { + val project = parameters.position.project + val keys = hashSetOf().apply { + val names = MvNamedElementIndex.getAllKeys(project) + addAll(names) + removeAll(processedPathNames) + } + + return prefixMatcher.sortMatching(keys) + .flatMap { + getImportCandidates(importContext, it) + .distinctBy { it.element } + .filter { itemFilter(it.element) } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index d421dccd5..d890623b9 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -1,9 +1,9 @@ package org.move.ide.utils.imports -import org.move.ide.inspections.imports.UseItemType.MODULE -import org.move.ide.inspections.imports.useItems import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve2.ref.RsPathResolveKind.ModulePath +import org.move.lang.core.resolve2.ref.classifyPath import org.move.lang.core.types.ItemQualName import org.move.openapiext.checkWriteAccessAllowed @@ -42,79 +42,117 @@ private fun MvItemsOwner.insertUseItem(usePath: ItemQualName, testOnly: Boolean) private fun tryInsertingIntoExistingUseStmt( mod: MvItemsOwner, - usePath: ItemQualName, + itemQualName: ItemQualName, testOnly: Boolean ): Boolean { - if (usePath.moduleName == null) return false + if (itemQualName.moduleName == null) return false val psiFactory = mod.project.psiFactory val useStmts = mod.useStmtList.filter { it.hasTestOnlyAttr == testOnly } return useStmts -// .mapNotNull { it.itemUseSpeck } - .any { tryGroupWithItemSpeck(psiFactory, it, usePath) } + .any { tryGroupWithItemSpeck(psiFactory, it, itemQualName) } } private fun tryGroupWithItemSpeck( - psiFactory: MvPsiFactory, useStmt: MvUseStmt, usePath: ItemQualName + psiFactory: MvPsiFactory, useStmt: MvUseStmt, itemQualName: ItemQualName ): Boolean { - // module imports do not support groups for now - val useItems = useStmt.useItems - if (useItems.all { it.type == MODULE }) return false + val rootUseSpeck = useStmt.useSpeck ?: return false - val itemUseItem = useItems.firstOrNull() ?: return false - val itemUseSpeck = itemUseItem.useSpeck - val qualifier = itemUseSpeck.qualifier ?: itemUseSpeck.path.qualifier ?: return false + val useGroup = rootUseSpeck.useGroup + // 0x1::m -> module imports does not support groups, can't insert + if (useGroup == null && rootUseSpeck.path.length < 3) return false - val fqModuleName = usePath.editorModuleFqName() ?: error("checked in the upper level") - if (!qualifier.textMatches(fqModuleName)) return false + // searching for the statement with the same module qualifier + val itemModulePath = itemQualName.editorModuleFqName() ?: error("moduleName cannot be zero") + if (useGroup == null) { + val modulePath = rootUseSpeck.path.qualifier ?: return false + if (!modulePath.textMatches(itemModulePath)) return false + } else { + val modulePath = rootUseSpeck.path + if (!modulePath.textMatches(itemModulePath)) return false + } - val itemName = usePath.itemName - val useStmtNames = useItems.map { it.nameOrAlias } - if (itemName in useStmtNames) return true + val itemName = itemQualName.itemName + val newUseSpeck = psiFactory.useSpeckForGroup(itemName) - val useGroup = itemUseSpeck.useGroup - val useSpeck = psiFactory.useSpeckForGroup(itemName) - if (useGroup != null) { - // add after the last item - val useSpeckList = useGroup.useSpeckList - if (useSpeckList.isEmpty()) { - // use 0x1::m::{}; - useGroup.addAfter(useSpeck, useGroup.lBrace) - } else { - // use 0x1::m::{item1} -> use 0x1::m::{item1, item2} - val lastItem = useSpeckList.last() - useGroup.addAfter( - useSpeck, - useGroup.addAfter(psiFactory.createComma(), lastItem) - ) - } - } else { + if (useGroup == null) { // 0x1::dummy::{} - val newRootUseSpeck = psiFactory.useSpeckWithEmptyUseGroup() + val useSpeckWithGroup = psiFactory.useSpeckWithEmptyUseGroup() + // [0x1::m]::item + // ^ qualifier + val qualifier = rootUseSpeck.path.qualifier ?: return false // 0x1::dummy::{} -> 0x1::m::{} - newRootUseSpeck.path.replace(qualifier) + useSpeckWithGroup.path.replace(qualifier) - // 0x1::m::{} -> 0x1::m::{item} - val existingItemName = itemUseSpeck.path.referenceName ?: return false - val newItemUseSpeck = psiFactory.useSpeckForGroup(existingItemName) - val newUseGroup = newRootUseSpeck.useGroup ?: error("created with use group") - newUseGroup.addAfter(newItemUseSpeck, newUseGroup.lBrace) + // 0x1::m::{} -> 0x1::m::{item as dummy} + val existingItemName = rootUseSpeck.path.referenceName ?: return false + val groupItemUseSpeck = psiFactory.useSpeckForGroupWithDummyAlias(existingItemName) - // 0x1::m::{item} -> 0x1::m::{item as myitem} - val existingUseAlias = itemUseSpeck.useAlias + // 0x1::m::{item as dummy} -> 0x1::m::{item as myitem} + val existingUseAlias = rootUseSpeck.useAlias if (existingUseAlias != null) { - newItemUseSpeck.add(existingUseAlias) + groupItemUseSpeck.useAlias?.replace(existingUseAlias) + } else { + groupItemUseSpeck.useAlias?.delete() } + val newUseGroup = useSpeckWithGroup.useGroup!! + newUseGroup.addAfter(groupItemUseSpeck, newUseGroup.lBrace) + // 0x1::m::{item as myitem} -> 0x1::m::{item as myitem, } val comma = newUseGroup.addBefore(psiFactory.createComma(), newUseGroup.rBrace) // 0x1::m::{item as myitem, } -> 0x1::m::{item as myitem, item2} - newUseGroup.addAfter(useSpeck, comma) + newUseGroup.addAfter(newUseSpeck, comma) - newRootUseSpeck.useGroup?.replace(newUseGroup) - useStmt.useSpeck?.replace(newRootUseSpeck) + useSpeckWithGroup.useGroup?.replace(newUseGroup) + useStmt.useSpeck?.replace(useSpeckWithGroup) + } else { + // add after the last item + val useSpeckList = useGroup.useSpeckList + if (useSpeckList.isEmpty()) { + // use 0x1::m::{}; + useGroup.addAfter(newUseSpeck, useGroup.lBrace) + } else { + // use 0x1::m::{item1} -> use 0x1::m::{item1, item2} + val lastItem = useSpeckList.last() + val newComma = useGroup.addAfter(psiFactory.createComma(), lastItem) + useGroup.addAfter(newUseSpeck, newComma) + } } + +// val useItems = useStmt.useItems +// if (useItems.all { it.type == MODULE }) return false +// +// val itemUseItem = useItems.firstOrNull() ?: return false +// val itemUseSpeck = itemUseItem.useSpeck +// val qualifier = itemUseSpeck.qualifier ?: itemUseSpeck.path.qualifier ?: return false +// +// val fqModuleName = usePath.editorModuleFqName() ?: error("checked in the upper level") +// if (!qualifier.textMatches(fqModuleName)) return false + +// val itemName = usePath.itemName +// val useStmtNames = useItems.map { it.nameOrAlias } +// if (itemName in useStmtNames) return true + +// val useGroup = itemUseSpeck.useGroup +// val useSpeck = psiFactory.useSpeckForGroup(itemName) +// if (useGroup != null) { +// // add after the last item +// val useSpeckList = useGroup.useSpeckList +// if (useSpeckList.isEmpty()) { +// // use 0x1::m::{}; +// useGroup.addAfter(useSpeck, useGroup.lBrace) +// } else { +// // use 0x1::m::{item1} -> use 0x1::m::{item1, item2} +// val lastItem = useSpeckList.last() +// useGroup.addAfter( +// useSpeck, +// useGroup.addAfter(psiFactory.createComma(), lastItem) +// ) +// } +// } else { +// } return true } diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt index 776c67d88..bd7518919 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt @@ -6,6 +6,7 @@ import com.intellij.patterns.ElementPattern import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.ide.inspections.imports.ImportContext +import org.move.ide.utils.imports.ImportCandidateCollector.getCompletionCandidates import org.move.lang.core.MvPsiPatterns import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.IMPORTED_MODULE_PRIORITY @@ -68,8 +69,8 @@ object ModulesCompletionProvider2: MvCompletionProvider() { contextScopeInfo ) val containingMod = path.containingModule - val candidates = getImportCandidates(parameters, result, processedNames, importContext, - itemFilter = { + val candidates = getCompletionCandidates(parameters, result.prefixMatcher, processedNames, importContext, + itemFilter = { containingMod != null && !it.equalsTo( containingMod ) @@ -78,7 +79,7 @@ object ModulesCompletionProvider2: MvCompletionProvider() { val lookupElement = candidate.element.createLookupElement( completionCtx, - structAsType = Namespace.TYPE in importContext.namespaces, + structAsType = Namespace.TYPE in importContext.ns, priority = UNIMPORTED_ITEM_PRIORITY, insertHandler = ImportInsertHandler(parameters, candidate) ) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt index e012e77c4..0f3e177e9 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt @@ -18,29 +18,6 @@ import org.move.lang.index.MvNamedElementIndex abstract class MvCompletionProvider : CompletionProvider() { abstract val elementPattern: ElementPattern - - protected fun getImportCandidates( - parameters: CompletionParameters, - result: CompletionResultSet, - processedPathNames: Set, - importContext: ImportContext, - itemFilter: (PsiElement) -> Boolean = { true } - ): List { - val project = parameters.position.project - val keys = hashSetOf().apply { - val names = MvNamedElementIndex.getAllKeys(project) - addAll(names) - removeAll(processedPathNames) - } - - return result.prefixMatcher.sortMatching(keys) - .flatMap { - ImportCandidateCollector - .getImportCandidates(importContext, it) - .distinctBy { it.element } - .filter { itemFilter(it.element) } - } - } } class ImportInsertHandler( diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index 0296ea9b3..6f90ae883 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -7,6 +7,7 @@ import com.intellij.patterns.StandardPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.ide.inspections.imports.ImportContext +import org.move.ide.utils.imports.ImportCandidateCollector.getCompletionCandidates import org.move.lang.core.MvPsiPatterns import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY @@ -153,9 +154,9 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { setOf(Visibility.Public), contextScopeInfo ) - val candidates = getImportCandidates( + val candidates = getCompletionCandidates( parameters, - result, + result.prefixMatcher, processedNames, importContext, ) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 547e6a84f..e385537a4 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -7,6 +7,7 @@ import com.intellij.patterns.ElementPattern import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.ide.inspections.imports.ImportContext +import org.move.ide.utils.imports.ImportCandidateCollector import org.move.lang.core.MvPsiPatterns.path import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY @@ -28,7 +29,6 @@ import org.move.lang.core.resolve.wrapWithFilter import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.ref.classifyPath import org.move.lang.core.resolve2.ref.processPathResolveVariants -import java.util.* object MvPathCompletionProvider2: MvCompletionProvider() { override val elementPattern: ElementPattern get() = path() @@ -69,12 +69,17 @@ object MvPathCompletionProvider2: MvCompletionProvider() { } } - val ns = + val ns = buildSet { + add(MODULE) when (parentElement) { - is MvPathType -> EnumSet.of(MODULE, TYPE) - is MvSchemaLit -> EnumSet.of(MODULE, SCHEMA) - else -> EnumSet.of(MODULE, NAME, FUNCTION) + is MvPathType -> add(TYPE) + is MvSchemaLit -> add(SCHEMA) + else -> { + add(NAME) + add(FUNCTION) + } } + } addVariants( pathElement, parameters, completionContext, ns, result, @@ -143,12 +148,13 @@ object MvPathCompletionProvider2: MvCompletionProvider() { setOf(Visibility.Public), completionContext.contextScopeInfo ) - val candidates = getImportCandidates( - parameters, - result, - processedNames, - importContext, - ) + val candidates = + ImportCandidateCollector.getCompletionCandidates( + parameters, + result.prefixMatcher, + processedNames, + importContext, + ) candidates.forEach { candidate -> val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, ns) for (completionFilter in completionFilters) { diff --git a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt index c26736258..e8f5e8e72 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt @@ -146,6 +146,12 @@ class MvPsiFactory(val project: Project) { return useGroup.useSpeckList.first() } + fun useSpeckForGroupWithDummyAlias(text: String): MvUseSpeck { + val useGroup = createFromText("module 0x1::_DummyModule { use 0x1::Module::{$text as dummy}; }") + ?: error("Failed to create an item import from text: `$text`") + return useGroup.useSpeckList.first() + } + fun acquires(text: String): MvAcquiresType { return createFromText("module 0x1::_DummyModule { fun main() $text {}}") ?: error("Failed to create a method member from text: `$text`") diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index 2945c7519..b792c0e4b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -14,12 +14,9 @@ fun MvItemsOwner.items(): Sequence { .filter { it !is MvAttr } } -val MvItemsOwner.visibleItems: List +val MvItemsOwner.itemElements: List get() { - return this.items() - .filterIsInstance() - .filterNot { (it as? MvFunction)?.hasTestAttr ?: false } - .toList() + return this.items().filterIsInstance().toList() } val MvModule.innerSpecItems: List diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index aa633f648..e54016b5b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -29,6 +29,16 @@ tailrec fun MvPath.rootPath(): MvPath { return if (parent is MvPath) parent.rootPath() else this } +val MvPath.length: Int get() { + var length = 1 + var currentPath = this + while (currentPath.path != null) { + currentPath = currentPath.path!! + length += 1 + } + return length +} + fun MvPath.isPrimitiveType(): Boolean = this.parent is MvPathType && this.referenceName in PRIMITIVE_TYPE_IDENTIFIERS.union(BUILTIN_TYPE_IDENTIFIERS) diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt index 737924017..1f8f2d6b5 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt @@ -35,6 +35,10 @@ data class ContextScopeInfo( return true } + fun wrapWithContextFilter(processor: RsResolveProcessorBase): RsResolveProcessorBase { + return processor.wrapWithFilter { e: T -> this.matches(e.element) } + } + companion object { /// really does not affect anything, created just to allow creating CompletionContext everywhere fun default(): ContextScopeInfo = ContextScopeInfo(setOf(MAIN), NONE) diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 28be3f0c6..1a65b9ec3 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -3,7 +3,6 @@ package org.move.lang.core.resolve import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.util.SmartList import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvNamedElement @@ -22,7 +21,7 @@ import org.move.stdext.intersects */ interface ScopeEntry { val name: String - val element: MvElement + val element: MvNamedElement val namespaces: Set fun doCopyWithNs(namespaces: Set): ScopeEntry } @@ -176,18 +175,18 @@ private class BeforeProcessingProcessor( } -fun RsResolveProcessorBase.wrapWithShadowingProcessor( +fun RsResolveProcessorBase.wrapWithShadowingProcessor( prevScope: Map>, ns: Set, ): RsResolveProcessorBase { return ShadowingProcessor(this, prevScope, ns) } -private class ShadowingProcessor( +private class ShadowingProcessor( private val originalProcessor: RsResolveProcessorBase, private val prevScope: Map>, private val ns: Set, -) : RsResolveProcessorBase { +): RsResolveProcessorBase { override val names: Set? = originalProcessor.names override fun process(entry: T): Boolean { val prevNs = prevScope[entry.name] @@ -195,10 +194,11 @@ private class ShadowingProcessor( val restNs = entry.namespaces.minus(prevNs) return ns.intersects(restNs) && originalProcessor.process(entry.copyWithNs(restNs)) } + override fun toString(): String = "ShadowingProcessor($originalProcessor, ns = $ns)" } -fun RsResolveProcessorBase.wrapWithShadowingProcessorAndUpdateScope( +fun RsResolveProcessorBase.wrapWithShadowingProcessorAndUpdateScope( prevScope: Map>, currScope: MutableMap>, ns: Set, @@ -206,12 +206,12 @@ fun RsResolveProcessorBase.wrapWithShadowingProcessorAndUpda return ShadowingAndUpdateScopeProcessor(this, prevScope, currScope, ns) } -private class ShadowingAndUpdateScopeProcessor( +private class ShadowingAndUpdateScopeProcessor( private val originalProcessor: RsResolveProcessorBase, private val prevScope: Map>, private val currScope: MutableMap>, private val ns: Set, -) : RsResolveProcessorBase { +): RsResolveProcessorBase { override val names: Set? = originalProcessor.names override fun process(entry: T): Boolean { if (!originalProcessor.acceptsName(entry.name) || entry.name == "_") { @@ -232,21 +232,22 @@ private class ShadowingAndUpdateScopeProcessor( currScope[entry.name] = prevNs?.let { it + newNs } ?: newNs return originalProcessor.process(entryWithIntersectedNs) } + override fun toString(): String = "ShadowingAndUpdateScopeProcessor($originalProcessor, ns = $ns)" } -fun RsResolveProcessorBase.wrapWithShadowingProcessorAndImmediatelyUpdateScope( +fun RsResolveProcessorBase.wrapWithShadowingProcessorAndImmediatelyUpdateScope( prevScope: MutableMap>, ns: Set, ): RsResolveProcessorBase { return ShadowingAndImmediatelyUpdateScopeProcessor(this, prevScope, ns) } -private class ShadowingAndImmediatelyUpdateScopeProcessor( +private class ShadowingAndImmediatelyUpdateScopeProcessor( private val originalProcessor: RsResolveProcessorBase, private val prevScope: MutableMap>, private val ns: Set, -) : RsResolveProcessorBase { +): RsResolveProcessorBase { override val names: Set? = originalProcessor.names override fun process(entry: T): Boolean { if (entry.name in prevScope) return false @@ -256,7 +257,9 @@ private class ShadowingAndImmediatelyUpdateScopeProcessor( } return result } - override fun toString(): String = "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" + + override fun toString(): String = + "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" } fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Unit): List { @@ -389,7 +392,7 @@ fun collectCompletionVariants( private class CompletionVariantsCollector( private val result: CompletionResultSet, private val context: CompletionContext, -) : RsResolveProcessorBase { +): RsResolveProcessorBase { override val names: Set? get() = null override fun process(entry: ScopeEntry): Boolean { @@ -469,7 +472,7 @@ private class CompletionVariantsCollector( data class SimpleScopeEntry( override val name: String, - override val element: MvElement, + override val element: MvNamedElement, override val namespaces: Set, // override val subst: Substitution = emptySubstitution ): ScopeEntry { @@ -520,7 +523,7 @@ enum class VisibilityStatus { data class ScopeEntryWithVisibility( override val name: String, - override val element: MvElement, + override val element: MvNamedElement, override val namespaces: Set, /** Given a [MvElement] (usually [MvPath]) checks if this item is visible in `containingMod` of that element */ val visibilityFilter: VisibilityFilter, @@ -531,7 +534,7 @@ data class ScopeEntryWithVisibility( fun RsResolveProcessor.process( name: String, - e: MvElement, + e: MvNamedElement, namespaces: Set, visibilityFilter: VisibilityFilter ): Boolean = process(ScopeEntryWithVisibility(name, e, namespaces, visibilityFilter)) @@ -540,7 +543,7 @@ fun RsResolveProcessor.process( fun RsResolveProcessor.process( name: String, // namespaces: Set, - e: MvElement + e: MvNamedElement ): Boolean = process(SimpleScopeEntry(name, e, Namespace.none())) // process(ScopeEntry(name, e, namespaces)) @@ -548,7 +551,7 @@ fun RsResolveProcessor.process( inline fun RsResolveProcessor.lazy( name: String, // namespaces: Set, - e: () -> MvElement? + e: () -> MvNamedElement? ): Boolean { if (!acceptsName(name)) return false val element = e() ?: return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 15bc7777c..700b3ffb4 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -36,7 +36,7 @@ fun processItemDeclarations( // 1. loop over all items in module (item is anything accessible with MODULE:: ) // 2. for every item, use it's .visibility to create VisibilityFilter, even it's just a { false } - val items = itemsOwner.visibleItems + + val items = itemsOwner.itemElements + (itemsOwner as? MvModuleBlock)?.module?.innerSpecItems.orEmpty() + (itemsOwner as? MvModuleBlock)?.let { getItemsFromModuleSpecs(it.module, ns) }.orEmpty() for (item in items) { diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 67df3b809..a76b592bb 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -7,13 +7,14 @@ import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.* import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.util.forEachLeafSpeck fun processItemsInScope( scope: MvElement, cameFrom: MvElement, namespaces: Set, - contextScopeInfo: ContextScopeInfo, + ctx: PathResolutionContext, processor: RsResolveProcessor, ): Boolean { for (namespace in namespaces) { @@ -91,11 +92,11 @@ fun processItemsInScope( } } is MvSpecCodeBlock -> { - when (contextScopeInfo.letStmtScope) { + when (ctx.contextScopeInfo.letStmtScope) { EXPR_STMT -> scope.allLetStmts LET_STMT, LET_POST_STMT -> { val letDecls = - if (contextScopeInfo.letStmtScope == LET_POST_STMT) { + if (ctx.contextScopeInfo.letStmtScope == LET_POST_STMT) { scope.allLetStmts } else { scope.letStmts(false) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 2c938aebd..ca0a1f013 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -25,7 +25,7 @@ fun processNestedScopesUpwards( ) { cameFrom, scope -> processWithShadowingAndUpdateScope(prevScope, ns, processor) { shadowingProcessor -> processItemsInScope( - scope, cameFrom, ns, ctx.contextScopeInfo, shadowingProcessor + scope, cameFrom, ns, ctx, shadowingProcessor ) } } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 1fd3d2201..6413dca15 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -41,7 +41,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { val useSpeck = path.useSpeck if (useSpeck != null) { // inside import, all visibilities except for private work - if (visibility is Restricted) return@VisibilityFilter Visible + if (visibility !is Private) return@VisibilityFilter Visible // msl-only items are available from imports if (item.isMslOnlyItem) return@VisibilityFilter Visible @@ -50,6 +50,9 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { if (pathUsageScope.isTest && namespaces.contains(NAME)) return@VisibilityFilter Visible } + // #[test] functions cannot be used from non-imports + if (item is MvFunction && item.hasTestAttr) return@VisibilityFilter Invisible + // #[test_only] items in non-test-only scope if (isTestOnly && !pathUsageScope.isTest) return@VisibilityFilter Invisible diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index c6c511d12..5e5a146e6 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -3,14 +3,13 @@ package org.move.lang.core.resolve2.ref import com.intellij.psi.ResolveResult import org.move.cli.MoveProject import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* +import org.move.lang.core.psi.ext.useSpeck import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* import org.move.lang.core.resolve2.processAddressPathResolveVariants import org.move.lang.core.resolve2.processItemDeclarations import org.move.lang.core.resolve2.processNestedScopesUpwards import org.move.lang.core.resolve2.ref.RsPathResolveKind.* -import org.move.lang.core.types.Address import org.move.lang.moveProject import kotlin.LazyThreadSafetyMode.NONE @@ -35,7 +34,7 @@ class Path2ReferenceImpl(element: MvPath): fun rawMultiResolveIfVisible(): List> = rawMultiResolve().filter { it.isVisible } -// fun rawMultiResolve(): List> = Resolver.invoke(this.element) + // fun rawMultiResolve(): List> = Resolver.invoke(this.element) fun rawMultiResolve(): List> = rawCachedMultiResolve() private fun rawCachedMultiResolve(): List> { @@ -63,16 +62,13 @@ fun processPathResolveVariants( pathKind: RsPathResolveKind, processor: RsResolveProcessor ): Boolean { - val contextScopeAwareProcessor = processor.wrapWithFilter { - val element = it.element - element is MvNamedElement && ctx.contextScopeInfo.matches(element) - } + val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) return when (pathKind) { is UnqualifiedPath -> { // Self:: if (processor.lazy("Self") { ctx.containingModule }) return true // local - processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextScopeAwareProcessor) + processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextProcessor) } is ModulePath -> { // 0x1::bar @@ -80,7 +76,7 @@ fun processPathResolveVariants( ctx.path, ctx.moveProject, pathKind.address, - contextScopeAwareProcessor + contextProcessor ) } is QualifiedPath -> { @@ -117,27 +113,13 @@ fun processQualifiedPathResolveVariants( ): Boolean { val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() if (resolvedQualifier != null) { - val result = - processQualifiedPathResolveVariants1(ctx, ns, qualifier, resolvedQualifier, path, processor) - if (result) return true - } - return false -} - -private fun processQualifiedPathResolveVariants1( - ctx: PathResolutionContext, - ns: Set, - qualifier: MvPath, - resolvedQualifier: MvElement, - path: MvPath, - processor: RsResolveProcessor -): Boolean { - if (resolvedQualifier is MvModule) { - if (processor.process("Self", resolvedQualifier)) return true + if (resolvedQualifier is MvModule) { + if (processor.process("Self", resolvedQualifier)) return true - val block = resolvedQualifier.moduleBlock - if (block != null) { - if (processItemDeclarations(block, ns, processor)) return true + val moduleBlock = resolvedQualifier.moduleBlock + if (moduleBlock != null) { + if (processItemDeclarations(moduleBlock, ns, processor)) return true + } } } return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt index 9bb3683ec..3622ee5ef 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt @@ -26,31 +26,3 @@ fun MvUseStmt.forEachLeafSpeck(consumer: LeafUseSpeckConsumer) { } } } - -fun MvUseStmt.leafSpecks(): List { - val specks = mutableListOf() - forEachLeafSpeck { path, useAlias -> - val useSpeck = path.parent as MvUseSpeck - specks.add(useSpeck) - } - return specks -} - - - - -///** return false if path is incomplete (has empty segments), e.g. `use std::;` */ -//private fun addPathSegments(path: MvPath, segments: ArrayList): Boolean { -// val subpath = path.path -// if (subpath != null) { -// if (!addPathSegments(subpath, segments)) return false -// } else if (path.hasColonColon) { -// // absolute path: `::foo::bar` -// // ~~~~~ this -// segments += "" -// } -// -// val segment = path.referenceName ?: return false -// segments += segment -// return true -//} diff --git a/src/main/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt b/src/main/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt index 1c741ce23..baee22110 100644 --- a/src/main/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt +++ b/src/main/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt @@ -10,10 +10,12 @@ import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile +import com.intellij.testFramework.IndexingTestUtil import com.intellij.testFramework.InspectionTestUtil import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.fixtures.CodeInsightTestFixture import com.intellij.testFramework.fixtures.impl.BaseFixture +import com.intellij.vcs.log.data.index.isIndexingEnabled import junit.framework.TestCase import org.intellij.lang.annotations.Language import org.move.ide.annotator.MvAnnotatorBase @@ -63,7 +65,10 @@ class MvAnnotationTestFixture( checkByText(text, checkWarn = false, checkWeakWarn = false, checkInfo = false) private fun configureByText(text: String): PsiFile { - return codeInsightFixture.configureByText("main.move", replaceCaretMarker(text.trimIndent())) + val psiFile = codeInsightFixture.configureByText("main.move", replaceCaretMarker(text.trimIndent())) + // build indexes + IndexingTestUtil.waitUntilIndexesAreReady(codeInsightFixture.project) + return psiFile } fun checkByText( @@ -131,6 +136,7 @@ class MvAnnotationTestFixture( "No /*caret*/ comment, add it to the place where fix is expected" } val file = configureByText(before) + codeInsightFixture.checkHighlighting(checkWarn, checkInfo, checkWeakWarn) applyQuickFix(fixName) codeInsightFixture.checkResult(replaceCaretMarker(after.trimIndent())) diff --git a/src/test/kotlin/org/move/ide/inspections/imports/AutoImportFixTest.kt b/src/test/kotlin/org/move/ide/inspections/imports/AutoImportFixTest.kt index 3e61ac713..3eb771aff 100644 --- a/src/test/kotlin/org/move/ide/inspections/imports/AutoImportFixTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/imports/AutoImportFixTest.kt @@ -388,7 +388,7 @@ module 0x1::main { } """) - fun `test cannot auto import test function from same file`() = checkAutoImportFixIsUnavailable(""" + fun `test cannot auto import test function from the same file`() = checkAutoImportFixIsUnavailable(""" module 0x1::m1 { #[test] public fun test_a() {} diff --git a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt index 0189e0077..c06a7d84c 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt @@ -157,26 +157,26 @@ class LookupElementTest: MvTestBase() { } """, tailText = "(&mut self)", typeText = "u8" ) +// +// fun `test import module lookup`() = checkNamedItem(""" +// module 0x1::m { +// public fun identity(a: u8): u8 { a } +// } +// module 0x1::main { +// use 0x1::m; +// //^ +// } +// """, tailText = " 0x1", typeText = "main.move") - fun `test import module lookup`() = checkNamedItem(""" - module 0x1::m { - public fun identity(a: u8): u8 { a } - } - module 0x1::main { - use 0x1::m; - //^ - } - """, tailText = " 0x1", typeText = "main.move") - - fun `test import function lookup`() = checkNamedItem(""" - module 0x1::m { - public fun identity(a: u8): u8 { a } - } - module 0x1::main { - use 0x1::m::identity; - //^ - } - """, tailText = "(a: u8): u8", typeText = "main.move") +// fun `test import function lookup`() = checkNamedItem(""" +// module 0x1::m { +// public fun identity(a: u8): u8 { a } +// } +// module 0x1::main { +// use 0x1::m::identity; +// //^ +// } +// """, tailText = "(a: u8): u8", typeText = "main.move") private fun checkNamedItem( @Language("Move") code: String, diff --git a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt index f3b43f108..78043d9f1 100644 --- a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt @@ -164,4 +164,14 @@ class ModulesCompletionTest : CompletionTestCase() { use 0x1::He/*caret*/ } """) + + + fun `test no Self completion for fully qualified path`() = checkNoCompletion(""" + module 0x1::m1 {} + module 0x1::m { + fun main() { + 0x1::m1::Se/*caret*/; + } + } + """) } diff --git a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt index 132019b43..f9923dd76 100644 --- a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt @@ -199,25 +199,21 @@ class StructsCompletionTest: CompletionTestCase() { """) fun `test module struct completion in type position`() = doSingleCompletion(""" - address 0x1 { - module Transaction { + module 0x1::Transaction { struct Type { val: u8 } } - } module 0x1::M { - fun main(a: 0x1::Transaction::/*caret*/) { + fun main(a: 0x1::Transaction::T/*caret*/) { } } """, """ - address 0x1 { - module Transaction { + module 0x1::Transaction { struct Type { val: u8 } } - } module 0x1::M { fun main(a: 0x1::Transaction::Type/*caret*/) { } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 69c1cc0ca..12473cb4b 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -1005,4 +1005,72 @@ module 0x1::mod { } } """) + + fun `test unresolved if main scope and test_only item`() = checkByCode(""" +module 0x1::minter { + struct S {} + public fun mint() {} +} +module 0x1::main { + #[test_only] + use 0x1::minter::{Self, mint}; + + public fun main() { + mint(); + //^ unresolved + } +} + """) + + fun `test unresolved if main scope and verify_only item`() = checkByCode(""" +module 0x1::minter { + struct S {} + public fun mint() {} +} +module 0x1::main { + #[verify_only] + use 0x1::minter::{Self, mint}; + + public fun main() { + mint(); + //^ unresolved + } +} + """) + + fun `test test function can be imported`() = checkByCode(""" +module 0x1::m1 { + #[test] + public fun test_a() {} + //X +} +module 0x1::m2 { + use 0x1::m1::test_a; + //^ +} """) + + fun `test private test function cannot be imported`() = checkByCode(""" +module 0x1::m1 { + #[test] + fun test_a() {} +} +module 0x1::m2 { + use 0x1::m1::test_a; + //^ unresolved +} """) + + fun `test test function cannot be used`() = checkByCode(""" +module 0x1::m1 { + #[test] + public fun test_a() {} +} +module 0x1::m2 { + use 0x1::m1::test_a; + + #[test_only] + fun main() { + test_a(); + //^ unresolved + } +} """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt index bedd9d33e..bc2573a80 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt @@ -351,4 +351,17 @@ module 0x1::m { } } """) + + fun `test module resolution not available on type position`() = checkByCode(""" + module 0x1::Transaction { + struct Type { + val: u8 + } + } + module 0x1::M { + fun main(a: 0x1::Transaction::Transaction) { + //^ unresolved + } + } + """) } From 6df8d76d80b492a147a4e61944246723d558d665 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 01:41:58 +0300 Subject: [PATCH 18/43] adjust places where searchScope() is used as it's now properly supported in tests --- src/main/kotlin/org/move/cli/MoveProject.kt | 6 +++--- .../kotlin/org/move/lang/core/psi/ext/MvModule.kt | 8 +++++--- .../org/move/lang/core/resolve2/ItemResolution.kt | 5 ++++- .../lang/core/resolve2/LexicalDeclarations2.kt | 9 +++++---- .../move/lang/core/resolve2/NameResolution2.kt | 15 ++++++++------- .../org/move/lang/resolve/ResolveFunctionTest.kt | 13 ------------- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/org/move/cli/MoveProject.kt b/src/main/kotlin/org/move/cli/MoveProject.kt index 5a6c8b5c2..0bef66c1e 100644 --- a/src/main/kotlin/org/move/cli/MoveProject.kt +++ b/src/main/kotlin/org/move/cli/MoveProject.kt @@ -44,7 +44,7 @@ data class MoveProject( fun movePackages(): Sequence = currentPackage.wrapWithList().chain(depPackages()) fun depPackages(): List = dependencies.map { it.first }.reversed() - fun sourceFolders(): List { + fun allAccessibleMoveFolders(): List { val folders = currentPackage.moveFolders().toMutableList() val depFolders = dependencies.asReversed().flatMap { it.first.moveFolders() } @@ -104,7 +104,7 @@ data class MoveProject( fun searchScope(): GlobalSearchScope { var searchScope = GlobalSearchScope.EMPTY_SCOPE - for (folder in sourceFolders()) { + for (folder in allAccessibleMoveFolders()) { val dirScope = GlobalSearchScopes.directoryScope(project, folder, true) searchScope = searchScope.uniteWith(dirScope) } @@ -132,7 +132,7 @@ data class MoveProject( val profiles: Set = this.aptosConfigYaml?.profiles.orEmpty() fun processMoveFiles(processFile: (MoveFile) -> Boolean) { - val folders = sourceFolders() + val folders = allAccessibleMoveFolders() var stopped = false for (folder in folders) { if (stopped) break diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index c1a5adb74..d53d6fe1b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -225,11 +225,13 @@ fun MvModule.allModuleSpecs(): List { return getProjectPsiDependentCache(this) { val moveProject = it.moveProject ?: return@getProjectPsiDependentCache emptyList() val moduleName = it.name ?: return@getProjectPsiDependentCache emptyList() - val file = it.containingMoveFile ?: return@getProjectPsiDependentCache emptyList() +// val file = it.containingMoveFile ?: return@getProjectPsiDependentCache emptyList() val searchScope = moveProject.searchScope() - val moduleSpecs = file.moduleSpecs() + - MvModuleSpecIndex.getElementsByModuleName(it.project, moduleName, searchScope) + // all `spec 0x1::m {}` for the current module + val moduleSpecs = MvModuleSpecIndex.getElementsByModuleName(it.project, moduleName, searchScope) +// val moduleSpecs = file.moduleSpecs() + +// MvModuleSpecIndex.getElementsByModuleName(it.project, moduleName, searchScope) if (moduleSpecs.isEmpty()) return@getProjectPsiDependentCache emptyList() val currentModule = it.fqModule() ?: return@getProjectPsiDependentCache emptyList() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 700b3ffb4..79f8d3a3e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -2,7 +2,10 @@ package org.move.lang.core.resolve2 import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.createProcessor +import org.move.lang.core.resolve.process +import org.move.lang.core.resolve.processAll import org.move.lang.core.resolve.ref.Namespace import java.util.* diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index a76b592bb..d8cd2a6df 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -92,11 +92,12 @@ fun processItemsInScope( } } is MvSpecCodeBlock -> { - when (ctx.contextScopeInfo.letStmtScope) { + val letStmtScope = ctx.path.letStmtScope + when (letStmtScope) { EXPR_STMT -> scope.allLetStmts LET_STMT, LET_POST_STMT -> { val letDecls = - if (ctx.contextScopeInfo.letStmtScope == LET_POST_STMT) { + if (letStmtScope == LET_POST_STMT) { scope.allLetStmts } else { scope.letStmts(false) @@ -157,12 +158,12 @@ fun processItemsInScope( val found = when (scope) { is MvModuleBlock -> { val module = scope.parent as MvModule - val specFunctions = if (contextScopeInfo.isMslScope) { + val specFunctions = if (ctx.contextScopeInfo.isMslScope) { listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() } else { emptyList() } - val specInlineFunctions = if (contextScopeInfo.isMslScope) { + val specInlineFunctions = if (ctx.contextScopeInfo.isMslScope) { module.moduleItemSpecs().flatMap { it.specInlineFunctions() } } else { emptyList() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index ca0a1f013..8c772fea0 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -47,15 +47,16 @@ fun processAddressPathResolveVariants( } // search modules in the current file first - val currentFile = element.containingMoveFile ?: return false - for (module in currentFile.modules()) { - if (equalAddressProcessor.process(module)) return true - } +// val currentFile = element.containingMoveFile ?: return false +// for (module in currentFile.modules()) { +// if (equalAddressProcessor.process(module)) return true +// } val project = element.project - val currentFileScope = GlobalSearchScope.fileScope(currentFile) - val searchScope = - moveProject.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) +// val currentFileScope = GlobalSearchScope.fileScope(currentFile) +// val searchScope = +// moveProject.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) + val searchScope = moveProject.searchScope() var stop = false for (name in processor.names.orEmpty()) { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 12473cb4b..98dd10358 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -855,19 +855,6 @@ module 0x1::mod { """ ) - fun `test cannot resolve non-test-only import into test-only item`() = checkByCode( - """ - module 0x1::m { - #[test_only] - public fun call() {} - } - module 0x1::main { - use 0x1::m::call; - //^ unresolved - } - """ - ) - fun `test resolve local test-only import into test-only item`() = checkByCode( """ module 0x1::m { From 205ac4d3c6996c6173399b6d1e4d8e37738be9f1 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 02:30:27 +0300 Subject: [PATCH 19/43] friend declaration as path --- src/main/grammars/MoveParser.bnf | 4 +-- src/main/kotlin/org/move/cli/MoveProject.kt | 3 ++ .../org/move/lang/core/psi/ext/MvModule.kt | 19 +++++++----- .../org/move/lang/core/psi/ext/MvPath.kt | 2 ++ .../core/resolve2/LexicalDeclarations2.kt | 21 +++++++------ .../lang/core/resolve2/NameResolution2.kt | 4 +-- .../core/resolve2/ref/Path2ReferenceImpl.kt | 27 ++++++++++------- .../core/resolve2/ref/RsPathResolveKind.kt | 5 ++-- .../move/lang/resolve/ResolveFunctionTest.kt | 17 +++++++++++ .../move/lang/resolve/ResolveModulesTest.kt | 30 +++++++++++++++++++ .../move/lang/resolve/ResolveVariablesTest.kt | 13 ++++++++ 11 files changed, 112 insertions(+), 33 deletions(-) diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index f66030bb3..d653a3912 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -159,7 +159,7 @@ // * recovery related rules are PascalCase_with_snake_suffix: Item_recover File ::= (NamedAddressDef | Script | AddressDef | Module | ModuleSpec)* -QualPathCodeFragmentElement ::= FQModulePathIdent? TypeArgumentList? +QualPathCodeFragmentElement ::= PathImpl Attr ::= '#' '[' <> ']' { pin = 1 } AttrItem ::= IDENTIFIER (AttrItemList | AttrItemInitializer)? @@ -513,7 +513,7 @@ StructField ::= Attr* IDENTIFIER TypeAnnotation &(',' | '}') hooks = [ leftBinder = "ADJACENT_LINE_COMMENTS" ] } -FriendDecl ::= Attr* friend FQModuleRef ';' +FriendDecl ::= Attr* friend PathImpl ';' { pin = "friend" implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] diff --git a/src/main/kotlin/org/move/cli/MoveProject.kt b/src/main/kotlin/org/move/cli/MoveProject.kt index 0bef66c1e..8891a0a10 100644 --- a/src/main/kotlin/org/move/cli/MoveProject.kt +++ b/src/main/kotlin/org/move/cli/MoveProject.kt @@ -90,6 +90,9 @@ data class MoveProject( return Address.Named(name, value, this) } + fun getNamedAddressOrNotInitialized(name: String): Address.Named = + getNamedAddress(name) ?: Address.Named(name, null, this) + fun getAddressNamesForValue(addressValue: String): List { val addressLit = AddressLit(addressValue) val names = mutableListOf() diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index d53d6fe1b..54570ef3e 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -39,15 +39,20 @@ fun MvModule.fqModule(): FQModule? { val MvModule.declaredFriendModules: Set get() { - val block = this.moduleBlock ?: return emptySet() - val friendModuleRefs = block.friendDeclList.mapNotNull { it.fqModuleRef } - val moveProj = block.moveProject + val moduleBlock = this.moduleBlock ?: return emptySet() + val friendModulePaths = moduleBlock.friendDeclList.mapNotNull { it.path } +// val moveProj = moduleBlock.moveProject val friends = mutableSetOf() - for (moduleRef in friendModuleRefs) { - val address = moduleRef.addressRef.address(moveProj) ?: continue - val identifier = moduleRef.identifier?.text ?: continue - friends.add(FQModule(address, identifier)) + for (modulePath in friendModulePaths) { + val module = modulePath.reference?.resolve() as? MvModule ?: continue + val fqModule = module.fqModule() ?: continue + friends.add(fqModule) +// val pathAddress = modulePath.qualifier?.pathAddress ?: continue +// val address = Address.Value(pathAddress.text) +//// val address = modulePath.addressRef.address(moveProj) ?: continue +// val identifier = modulePath.identifier?.text ?: continue +// friends.add(FQModule(address, identifier)) } return friends } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index e54016b5b..13359ecc8 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -113,6 +113,7 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvPathType -> EnumSet.of(Namespace.TYPE) parent is MvCallExpr -> EnumSet.of(Namespace.FUNCTION) // parent is MvRefExpr && parent.isAbortCodeConst() -> EnumSet.of(Namespace.CONST) + parent is MvRefExpr && rootPath.hasAncestor() -> EnumSet.of(Namespace.NAME, Namespace.MODULE) parent is MvRefExpr -> EnumSet.of(Namespace.NAME) // parent is MvRefExpr -> EnumSet.of(Namespace.NAME, Namespace.CONST) parent is MvStructLitExpr || parent is MvStructPat -> EnumSet.of(Namespace.TYPE) @@ -120,6 +121,7 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvAccessSpecifier -> EnumSet.of(Namespace.TYPE) parent is MvAddressSpecifierArg -> EnumSet.of(Namespace.FUNCTION) parent is MvAddressSpecifierCallParam -> EnumSet.of(Namespace.NAME) + parent is MvFriendDecl -> EnumSet.of(Namespace.MODULE) parent is MvUseSpeck -> Namespace.all() else -> debugErrorOrFallback( "Cannot build path namespaces: unhandled parent type ${parent.elementType}", diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index d8cd2a6df..9137e31e2 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -158,16 +158,19 @@ fun processItemsInScope( val found = when (scope) { is MvModuleBlock -> { val module = scope.parent as MvModule - val specFunctions = if (ctx.contextScopeInfo.isMslScope) { + val specFunctions = listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() - } else { - emptyList() - } - val specInlineFunctions = if (ctx.contextScopeInfo.isMslScope) { - module.moduleItemSpecs().flatMap { it.specInlineFunctions() } - } else { - emptyList() - } +// val specFunctions = if (ctx.contextScopeInfo.isMslScope) { +// listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() +// } else { +// emptyList() +// } + val specInlineFunctions = module.moduleItemSpecs().flatMap { it.specInlineFunctions() } +// val specInlineFunctions = if (ctx.contextScopeInfo.isMslScope) { +// module.moduleItemSpecs().flatMap { it.specInlineFunctions() } +// } else { +// emptyList() +// } processor.processAll( // contextScopeInfo, module.allNonTestFunctions(), diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 8c772fea0..d12461c96 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -1,10 +1,8 @@ package org.move.lang.core.resolve2 -import com.intellij.psi.search.GlobalSearchScope import org.move.cli.MoveProject import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.containingMoveFile import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.PathResolutionContext @@ -31,7 +29,7 @@ fun processNestedScopesUpwards( } } -fun processAddressPathResolveVariants( +fun processModulePathResolveVariants( element: MvElement, moveProject: MoveProject?, address: Address, diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 5e5a146e6..425c07896 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -6,8 +6,8 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.useSpeck import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* -import org.move.lang.core.resolve2.processAddressPathResolveVariants import org.move.lang.core.resolve2.processItemDeclarations +import org.move.lang.core.resolve2.processModulePathResolveVariants import org.move.lang.core.resolve2.processNestedScopesUpwards import org.move.lang.core.resolve2.ref.RsPathResolveKind.* import org.move.lang.moveProject @@ -72,7 +72,7 @@ fun processPathResolveVariants( } is ModulePath -> { // 0x1::bar - processAddressPathResolveVariants( + processModulePathResolveVariants( ctx.path, ctx.moveProject, pathKind.address, @@ -112,14 +112,21 @@ fun processQualifiedPathResolveVariants( processor: RsResolveProcessor ): Boolean { val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() - if (resolvedQualifier != null) { - if (resolvedQualifier is MvModule) { - if (processor.process("Self", resolvedQualifier)) return true - - val moduleBlock = resolvedQualifier.moduleBlock - if (moduleBlock != null) { - if (processItemDeclarations(moduleBlock, ns, processor)) return true - } + if (resolvedQualifier == null) { + if (Namespace.MODULE in ns) { + // can be module, try for named address as a qualifier + val addressName = qualifier.referenceName ?: return false + val address = ctx.moveProject?.getNamedAddressOrNotInitialized(addressName) ?: return false + if (processModulePathResolveVariants(ctx.path, ctx.moveProject, address, processor)) return true + } + return false + } + if (resolvedQualifier is MvModule) { + if (processor.process("Self", resolvedQualifier)) return true + + val moduleBlock = resolvedQualifier.moduleBlock + if (moduleBlock != null) { + if (processItemDeclarations(moduleBlock, ns, processor)) return true } } return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt index 58d931435..48fa46108 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt @@ -24,6 +24,7 @@ sealed class RsPathResolveKind { class ModulePath( val path: MvPath, val address: Address, + val ns: Set, ): RsPathResolveKind() /** aptos_framework in `use aptos_framework::bar`*/ @@ -63,13 +64,13 @@ fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResol val qualifierName = qualifier.referenceName return when { - qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text)) + qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text), ns) qualifierPath == null && isUseSpeck && qualifierName != null -> { val moveProject = qualifier.moveProject val namedAddress = moveProject?.getNamedAddress(qualifierName) ?: Address.Named(qualifierName, null, moveProject) - ModulePath(path, namedAddress) + ModulePath(path, namedAddress, ns) } else -> QualifiedPath(path, qualifier, ns) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 98dd10358..45aa75477 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -279,6 +279,23 @@ class ResolveFunctionTest: ResolveTestCase() { """ ) + fun `test resolve friend function with named address`() = checkByCode( + """ + module aptos_std::original { + friend aptos_std::m; + public(friend) fun call() {} + //X + } + module aptos_std::m { + use aptos_std::original; + fun main() { + original::call(); + //^ + } + } + """ + ) + fun `test script function is unresolved in friend modules`() = checkByCode( """ address 0x1 { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 988f76b41..274c4b269 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -328,6 +328,36 @@ class ResolveModulesTest : ResolveTestCase() { //X """) + fun `test resolve friend module`() = checkByCode(""" + module 0x1::myfriend {} + //X + module 0x1::main { + friend 0x1::myfriend; + //^ + } + """) + + fun `test resolve friend module with named address`() = checkByCode(""" + module aptos_std::myfriend {} + //X + module 0x1::main { + friend aptos_std::myfriend; + //^ + } + """) + + fun `test cannot resolve path inside friend to a function`() = checkByCode(""" + module 0x1::myfriend { + public fun call() {} + } + module 0x1::main { + use 0x1::myfriend; + + friend myfriend::call; + //^ unresolved + } + """) + fun `test friend no module resolution for test_only modules in non test_only case`() = checkByCode(""" module 0x1::M { friend 0x1::MTest; diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt index 86f94d903..65efc5574 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt @@ -370,4 +370,17 @@ module 0x1::string_tests { } } """) + + fun `test resolve attribute location for named address`() = checkByCode(""" + module aptos_std::m { + //X + fun main() { + } + #[test(location=aptos_std::m)] + //^ + fun test_main() { + + } + } + """) } From 095c4419a42ba8b7680433a4867642d8cd88a60b Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 02:44:28 +0300 Subject: [PATCH 20/43] fix multiple item resolution for multiple namespaces --- .../core/resolve2/LexicalDeclarations2.kt | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 9137e31e2..e75a4edd9 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -19,7 +19,6 @@ fun processItemsInScope( ): Boolean { for (namespace in namespaces) { val stop = when (namespace) { - Namespace.CONST -> { false // val found = when (scope) { @@ -160,19 +159,8 @@ fun processItemsInScope( val module = scope.parent as MvModule val specFunctions = listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() -// val specFunctions = if (ctx.contextScopeInfo.isMslScope) { -// listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() -// } else { -// emptyList() -// } val specInlineFunctions = module.moduleItemSpecs().flatMap { it.specInlineFunctions() } -// val specInlineFunctions = if (ctx.contextScopeInfo.isMslScope) { -// module.moduleItemSpecs().flatMap { it.specInlineFunctions() } -// } else { -// emptyList() -// } processor.processAll( -// contextScopeInfo, module.allNonTestFunctions(), module.builtinFunctions(), specFunctions, @@ -269,12 +257,13 @@ fun processItemsInScope( else -> false } } - if (!stop && scope is MvItemsOwner) { - if (scope.processUseSpeckElements(namespaces, processor)) return true - } if (stop) return true } + if (scope is MvItemsOwner) { + if (scope.processUseSpeckElements(namespaces, processor)) return true + } + return false } From 662ac1ec001bc523e2fd81c1bd04a5cba6e70eae Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 16:41:47 +0300 Subject: [PATCH 21/43] new PathKind, named address support for tests --- src/main/grammars/MoveParser.bnf | 4 +- src/main/kotlin/org/move/cli/MoveProject.kt | 13 ++- .../org/move/lang/core/resolve2/PathKind.kt | 106 ++++++++++++++++++ .../core/resolve2/ref/Path2ReferenceImpl.kt | 2 +- .../core/resolve2/ref/RsPathResolveKind.kt | 4 +- .../org/move/lang/core/types/Address.kt | 2 +- .../org/move/utils/tests/MvLightTestBase.kt | 1 + .../kotlin/org/move/utils/tests/MvTestBase.kt | 14 +++ .../move/utils/tests/NamedAddressService.kt | 22 ++++ .../kotlin/org/move/utils/tests/Settings.kt | 4 + .../resources/META-INF/intellij-move-core.xml | 43 +++---- .../completion/names/ModulesCompletionTest.kt | 2 +- .../move/lang/resolve/ResolveFunctionTest.kt | 2 + .../move/lang/resolve/ResolveModulesTest.kt | 2 + 14 files changed, 192 insertions(+), 29 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt create mode 100644 src/main/kotlin/org/move/utils/tests/NamedAddressService.kt diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index d653a3912..edecf65c9 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -529,9 +529,7 @@ UseStmt ::= Attr* use UseSpeck ';' { extends = Stmt implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] } -UseSpeck ::= PathImpl ( UseAlias | ('::' UseSpeckProjection) )? - -private UseSpeckProjection ::= UseGroup +UseSpeck ::= PathImpl ( UseAlias | ('::' UseGroup) )? UseGroup ::= '{' UseSpeck_with_recover* '}' { diff --git a/src/main/kotlin/org/move/cli/MoveProject.kt b/src/main/kotlin/org/move/cli/MoveProject.kt index 8891a0a10..2cb0098c4 100644 --- a/src/main/kotlin/org/move/cli/MoveProject.kt +++ b/src/main/kotlin/org/move/cli/MoveProject.kt @@ -1,5 +1,6 @@ package org.move.cli +import com.intellij.openapi.components.service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.util.NlsContexts.Tooltip @@ -26,6 +27,7 @@ import org.move.openapiext.contentRoots import org.move.stdext.chain import org.move.stdext.iterateMoveVirtualFiles import org.move.stdext.wrapWithList +import org.move.utils.tests.NamedAddressService import org.toml.lang.TomlLanguage import org.toml.lang.psi.TomlFile import java.nio.file.Path @@ -90,8 +92,15 @@ data class MoveProject( return Address.Named(name, value, this) } - fun getNamedAddressOrNotInitialized(name: String): Address.Named = - getNamedAddress(name) ?: Address.Named(name, null, this) + fun getNamedAddressTestAware(name: String): Address.Named? { + val namedAddress = getNamedAddress(name) + if (namedAddress != null) return namedAddress + if (isUnitTestMode) { + val namedAddressService = project.service() + return namedAddressService.getNamedAddress(this, name) + } + return null + } fun getAddressNamesForValue(addressValue: String): List { val addressLit = AddressLit(addressValue) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt new file mode 100644 index 000000000..2685dad20 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt @@ -0,0 +1,106 @@ +package org.move.lang.core.resolve2 + +import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.MvUseGroup +import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.ext.allowedNamespaces +import org.move.lang.core.psi.ext.ancestorStrict +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.types.Address +import org.move.lang.moveProject + +sealed class PathKind { + // aptos_std:: where aptos_std is a existing named address in a project + data class NamedAddress(val address: Address.Named): PathKind() + + // 0x1:: + data class ValueAddress(val address: Address.Value): PathKind() + + // foo + data class UnqualifiedPath(val ns: Set): PathKind() + + // any multi element path + sealed class QualifiedPath: PathKind() { + // `0x1:foo` or `aptos_framework::foo` (where aptos_framework is known named address) + class Module(val path: MvPath, val qualifier: MvPath, val ns: Set, val address: Address): QualifiedPath() + + // bar in foo::bar, where foo is not a named address + class ModuleItem(val path: MvPath, val qualifier: MvPath, val ns: Set): QualifiedPath() + + // bar in `0x1::foo::bar` or `aptos_std::foo::bar` (where aptos_std is known named address) + class FQModuleItem(val path: MvPath, val qualifier: MvPath, val ns: Set): QualifiedPath() + + // use 0x1::m::{item1}; + // ^ + class UseGroupItem(val path: MvPath, val qualifier: MvPath): QualifiedPath() + } +} + +val MvPath.kind: PathKind + get() { + val ns = this.allowedNamespaces() + val qualifierPath = this.path + val moveProject = this.moveProject + + val useGroup = this.ancestorStrict() + if (useGroup != null) { + // use 0x1::m::{item} + // ^ + val qualifier = (useGroup.parent as MvUseSpeck).path + return PathKind.QualifiedPath.UseGroupItem(this, qualifier) + } + + if (qualifierPath == null) { + // left-most path + val parentPath = this.parent as? MvPath + if (parentPath != null) { + // can be an address + val pathAddress = this.pathAddress + val referenceName = this.referenceName + when { + pathAddress != null -> return PathKind.ValueAddress(Address.Value(pathAddress.text)) + moveProject != null && referenceName != null -> { + // try for named address + val namedAddress = moveProject.getNamedAddressTestAware(referenceName) + if (namedAddress != null) { + return PathKind.NamedAddress(namedAddress) + } + } + } + } + + return PathKind.UnqualifiedPath(ns) + } + + val qualifierOfQualifier = qualifierPath.path + + // two-element paths + if (qualifierOfQualifier == null) { + val qualifierPathAddress = qualifierPath.pathAddress + val qualifierItemName = qualifierPath.referenceName + when { + // 0x1::bar + // ^ + qualifierPathAddress != null -> { + val address = Address.Value(qualifierPathAddress.text) + return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) + } + // aptos_framework::bar + // ^ + moveProject != null && qualifierItemName != null -> { + val namedAddress = moveProject.getNamedAddressTestAware(qualifierItemName) + if (namedAddress != null) { + // known named address, can be module path + return PathKind.QualifiedPath.Module(this, qualifierPath, ns, namedAddress) + } + } + else -> { + // module::name + return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) + } + } + } + + // three-element path + return PathKind.QualifiedPath.FQModuleItem(this, qualifierPath, ns) + } \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 425c07896..a322b7bd0 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -116,7 +116,7 @@ fun processQualifiedPathResolveVariants( if (Namespace.MODULE in ns) { // can be module, try for named address as a qualifier val addressName = qualifier.referenceName ?: return false - val address = ctx.moveProject?.getNamedAddressOrNotInitialized(addressName) ?: return false + val address = ctx.moveProject?.getNamedAddressTestAware(addressName) ?: return false if (processModulePathResolveVariants(ctx.path, ctx.moveProject, address, processor)) return true } return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt index 48fa46108..40c584f86 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt @@ -52,7 +52,7 @@ fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResol return ValueAddressPath(Address.Value(value)) } else { val namedAddress = - moveProject?.getNamedAddress(pathName) ?: Address.Named(pathName, null, moveProject) + moveProject?.getNamedAddressTestAware(pathName) ?: Address.Named(pathName, null, moveProject) return NamedAddressPath(namedAddress) } } @@ -68,7 +68,7 @@ fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResol qualifierPath == null && isUseSpeck && qualifierName != null -> { val moveProject = qualifier.moveProject val namedAddress = - moveProject?.getNamedAddress(qualifierName) + moveProject?.getNamedAddressTestAware(qualifierName) ?: Address.Named(qualifierName, null, moveProject) ModulePath(path, namedAddress, ns) } diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index 82877539a..6ec43ea44 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -132,7 +132,7 @@ sealed class StubAddress { if (moveProject == null) { Address.Named(this.name, null, null) } else { - moveProject.getNamedAddress(this.name) ?: Address.Named(this.name, null, moveProject) + moveProject.getNamedAddressTestAware(this.name) ?: Address.Named(this.name, null, moveProject) } } is Value -> Address.Value(this.value) diff --git a/src/main/kotlin/org/move/utils/tests/MvLightTestBase.kt b/src/main/kotlin/org/move/utils/tests/MvLightTestBase.kt index 1aaaf6c31..93e283830 100644 --- a/src/main/kotlin/org/move/utils/tests/MvLightTestBase.kt +++ b/src/main/kotlin/org/move/utils/tests/MvLightTestBase.kt @@ -11,5 +11,6 @@ abstract class MvLightTestBase: BasePlatformTestCase() { setRegistryKey("org.move.debug.enabled", isDebugMode) this.handleCompilerV2Annotations(project) + this.handleNamedAddressAnnotations(project) } } \ No newline at end of file diff --git a/src/main/kotlin/org/move/utils/tests/MvTestBase.kt b/src/main/kotlin/org/move/utils/tests/MvTestBase.kt index 3ae890610..979ebd9ba 100644 --- a/src/main/kotlin/org/move/utils/tests/MvTestBase.kt +++ b/src/main/kotlin/org/move/utils/tests/MvTestBase.kt @@ -6,6 +6,7 @@ package org.move.utils.tests import com.intellij.codeInspection.InspectionProfileEntry +import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.testFramework.UsefulTestCase @@ -36,6 +37,11 @@ annotation class WithEnabledInspections(vararg val inspections: KClass() if (enabledCompilerV2 != null) { @@ -53,6 +59,14 @@ fun UsefulTestCase.handleCompilerV2Annotations(project: Project) { } } +fun UsefulTestCase.handleNamedAddressAnnotations(project: Project) { + val namedAddresses = this.findAnnotationInstances() + val namedAddressService = project.service() as NamedAddressServiceTestImpl + for (namedAddress in namedAddresses) { + namedAddressService.namedAddresses[namedAddress.name] = namedAddress.value + } +} + abstract class MvTestBase: MvLightTestBase(), MvTestCase { protected val fileName: String diff --git a/src/main/kotlin/org/move/utils/tests/NamedAddressService.kt b/src/main/kotlin/org/move/utils/tests/NamedAddressService.kt new file mode 100644 index 000000000..2bb7a9f18 --- /dev/null +++ b/src/main/kotlin/org/move/utils/tests/NamedAddressService.kt @@ -0,0 +1,22 @@ +package org.move.utils.tests + +import org.move.cli.MoveProject +import org.move.lang.core.types.Address +import org.move.lang.core.types.Address.Named + +interface NamedAddressService { + fun getNamedAddress(moveProject: MoveProject, name: String): Named? +} + +class NamedAddressServiceImpl: NamedAddressService { + override fun getNamedAddress(moveProject: MoveProject, name: String): Named? = null +} + +class NamedAddressServiceTestImpl: NamedAddressService { + val namedAddresses: MutableMap = mutableMapOf() + + override fun getNamedAddress(moveProject: MoveProject, name: String): Named? { + val value = namedAddresses[name] ?: return null + return Named(name, value, moveProject) + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/utils/tests/Settings.kt b/src/main/kotlin/org/move/utils/tests/Settings.kt index c5dc5d900..5d0846547 100644 --- a/src/main/kotlin/org/move/utils/tests/Settings.kt +++ b/src/main/kotlin/org/move/utils/tests/Settings.kt @@ -5,3 +5,7 @@ import junit.framework.TestCase /** Tries to find the specified annotation on the current test method and then on the current class */ inline fun TestCase.findAnnotationInstance(): T? = javaClass.getMethod(name).getAnnotation(T::class.java) ?: javaClass.getAnnotation(T::class.java) + +/** Tries to find the specified annotation on the current test method and then on the current class */ +inline fun TestCase.findAnnotationInstances(): Array = + javaClass.getMethod(name).getAnnotationsByType(T::class.java) ?: javaClass.getAnnotationsByType(T::class.java) diff --git a/src/main/resources/META-INF/intellij-move-core.xml b/src/main/resources/META-INF/intellij-move-core.xml index 5cbb61de6..c0eb32f8a 100644 --- a/src/main/resources/META-INF/intellij-move-core.xml +++ b/src/main/resources/META-INF/intellij-move-core.xml @@ -45,6 +45,11 @@ + + + - + @@ -199,7 +204,7 @@ + order="first" /> @@ -292,7 +297,7 @@ + displayName="External linter" /> @@ -312,9 +317,9 @@ - - - + + + - + + description="Enable debug mode for Move" /> + description="Show notification warning if the external linter is running longer than the set value (ms)" /> + description="Force-enable support for pre-compiled bundled Aptos CLI (imitate non-MacOS)" /> + description="Force-disable support for pre-compiled bundled Aptos CLI (imitate MacOS)" /> + topic="org.move.cli.MoveProjectsService$MoveProjectsListener" /> @@ -460,14 +465,14 @@ - - - - - - + + + + + + - + diff --git a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt index 78043d9f1..ebae27aaf 100644 --- a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt @@ -50,7 +50,7 @@ class ModulesCompletionTest : CompletionTestCase() { } script { - use 0x1::/*caret*/ + use 0x1::Tra/*caret*/ } """ ) diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 45aa75477..cfa1b3427 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -1,5 +1,6 @@ package org.move.lang.resolve +import org.move.utils.tests.NamedAddress import org.move.utils.tests.resolve.ResolveTestCase class ResolveFunctionTest: ResolveTestCase() { @@ -279,6 +280,7 @@ class ResolveFunctionTest: ResolveTestCase() { """ ) + @NamedAddress("aptos_std", "0x1") fun `test resolve friend function with named address`() = checkByCode( """ module aptos_std::original { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 274c4b269..335dddc4d 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -1,5 +1,6 @@ package org.move.lang.resolve +import org.move.utils.tests.NamedAddress import org.move.utils.tests.resolve.ResolveTestCase class ResolveModulesTest : ResolveTestCase() { @@ -337,6 +338,7 @@ class ResolveModulesTest : ResolveTestCase() { } """) + @NamedAddress("aptos_std", "0x1") fun `test resolve friend module with named address`() = checkByCode(""" module aptos_std::myfriend {} //X From 605e988924f6de5d3b399a5e7361b02800212a10 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 17:26:04 +0300 Subject: [PATCH 22/43] named address fixes, replace last FqModuleRef usage --- src/main/grammars/MoveParser.bnf | 3 +- .../move/ide/inspections/imports/UseItem.kt | 34 +++-- .../org/move/ide/utils/imports/ImportUtils.kt | 4 +- .../providers/MvPathCompletionProvider2.kt | 5 +- .../org/move/lang/core/psi/ext/MvModule.kt | 4 +- .../org/move/lang/core/psi/ext/MvPath.kt | 3 +- .../org/move/lang/core/resolve2/PathKind.kt | 130 ++++++++++-------- .../core/resolve2/ref/Path2ReferenceImpl.kt | 59 +++++--- .../core/resolve2/ref/RsPathResolveKind.kt | 77 ----------- .../kotlin/org/move/lang/core/stubs/Stubs.kt | 2 +- .../move/lang/resolve/ResolveVariablesTest.kt | 2 + 11 files changed, 144 insertions(+), 179 deletions(-) delete mode 100644 src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index edecf65c9..c444475d3 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -1188,7 +1188,8 @@ private to ::= <> private apply ::= <> private except ::= <> -ModuleSpec ::= Attr* spec FQModuleRef ModuleSpecBlock +ModuleSpec ::= Attr* spec PathImpl ModuleSpecBlock +//ModuleSpec ::= Attr* spec FQModuleRef ModuleSpecBlock { pin = "spec" name = "module spec declaration" diff --git a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt index 5a507b541..50a3c474e 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt @@ -5,9 +5,8 @@ import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.NamedItemScope import org.move.lang.core.psi.ext.MvItemsOwner -import org.move.lang.core.resolve2.ref.RsPathResolveKind.ModulePath -import org.move.lang.core.resolve2.ref.RsPathResolveKind.QualifiedPath -import org.move.lang.core.resolve2.ref.classifyPath +import org.move.lang.core.resolve2.PathKind +import org.move.lang.core.resolve2.pathKind import org.move.lang.core.resolve2.util.forEachLeafSpeck enum class UseItemType { @@ -31,21 +30,36 @@ val MvUseStmt.useItems: List this.forEachLeafSpeck { path, useAlias -> val useSpeck = path.parent as MvUseSpeck val nameOrAlias = useAlias?.name ?: path.referenceName ?: return@forEachLeafSpeck false - val kind = classifyPath(path) - when (kind) { - is ModulePath -> { + val pathKind = path.pathKind() + when (pathKind) { + is PathKind.QualifiedPath.Module -> items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) +// is ModulePath -> { +// items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) +// } + is PathKind.QualifiedPath.ModuleItem -> { + // cannot be + return@forEachLeafSpeck false } - is QualifiedPath -> { - if (kind.path.referenceName == "Self") { + is PathKind.QualifiedPath -> { + if (pathKind.path.referenceName == "Self") { val moduleName = - useAlias?.name ?: kind.qualifier.referenceName ?: return@forEachLeafSpeck false + useAlias?.name ?: pathKind.qualifier.referenceName ?: return@forEachLeafSpeck false items.add(UseItem(useSpeck, moduleName, SELF_MODULE, stmtItemScope)) } else { items.add(UseItem(useSpeck, nameOrAlias, ITEM, stmtItemScope)) } } - else -> {} +// is QualifiedPath -> { +// if (kind.path.referenceName == "Self") { +// val moduleName = +// useAlias?.name ?: kind.qualifier.referenceName ?: return@forEachLeafSpeck false +// items.add(UseItem(useSpeck, moduleName, SELF_MODULE, stmtItemScope)) +// } else { +// items.add(UseItem(useSpeck, nameOrAlias, ITEM, stmtItemScope)) +// } +// } + else -> return@forEachLeafSpeck false } false } diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index d890623b9..5faf7931a 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -2,8 +2,6 @@ package org.move.ide.utils.imports import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve2.ref.RsPathResolveKind.ModulePath -import org.move.lang.core.resolve2.ref.classifyPath import org.move.lang.core.types.ItemQualName import org.move.openapiext.checkWriteAccessAllowed @@ -156,7 +154,7 @@ private fun tryGroupWithItemSpeck( return true } -private val List.lastElement: T? get() = maxByOrNull { it.textOffset } +private val List.lastElement: T? get() = maxByOrNull { it.textOffset } @Suppress("SameReturnValue") private fun insertUseStmtAtTheCorrectLocation(mod: MvItemsOwner, useStmt: MvUseStmt): Boolean { diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index e385537a4..65aa98f4e 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -26,8 +26,8 @@ import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.* import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.resolve.wrapWithFilter +import org.move.lang.core.resolve2.pathKind import org.move.lang.core.resolve2.ref.PathResolutionContext -import org.move.lang.core.resolve2.ref.classifyPath import org.move.lang.core.resolve2.ref.processPathResolveVariants object MvPathCompletionProvider2: MvCompletionProvider() { @@ -134,7 +134,8 @@ object MvPathCompletionProvider2: MvCompletionProvider() { true } - val pathKind = classifyPath(pathElement, overwriteNs = ns) + val pathKind = pathElement.pathKind(overwriteNs = ns) +// val pathKind = classifyPath(pathElement, overwriteNs = ns) processPathResolveVariants(resolutionCtx, pathKind, completionCollector) // disable auto-import in module specs for now diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index 54570ef3e..68803a3f8 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -201,7 +201,7 @@ val MvModuleBlock.module: MvModule get() = this.parent as MvModule //// this.childrenOfType() //// .filter { it.itemSpecRef?.moduleKw != null } -val MvModuleSpec.moduleItem: MvModule? get() = this.fqModuleRef?.reference?.resolve() as? MvModule +val MvModuleSpec.moduleItem: MvModule? get() = this.path?.reference?.resolve() as? MvModule val MvModuleSpecBlock.moduleSpec: MvModuleSpec get() = this.parent as MvModuleSpec @@ -242,7 +242,7 @@ fun MvModule.allModuleSpecs(): List { val currentModule = it.fqModule() ?: return@getProjectPsiDependentCache emptyList() moduleSpecs .filter { moduleSpec -> - val module = moduleSpec.fqModuleRef?.reference?.resolve() as? MvModule ?: return@filter false + val module = moduleSpec.moduleItem ?: return@filter false currentModule == module.fqModule() } .toList() diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 13359ecc8..51a040182 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -122,7 +122,8 @@ private fun rootNamespace(rootPath: MvPath): Set { parent is MvAddressSpecifierArg -> EnumSet.of(Namespace.FUNCTION) parent is MvAddressSpecifierCallParam -> EnumSet.of(Namespace.NAME) parent is MvFriendDecl -> EnumSet.of(Namespace.MODULE) - parent is MvUseSpeck -> Namespace.all() + parent is MvModuleSpec -> EnumSet.of(Namespace.MODULE) + parent is MvUseSpeck -> Namespace.all() else -> debugErrorOrFallback( "Cannot build path namespaces: unhandled parent type ${parent.elementType}", EnumSet.of(Namespace.NAME) diff --git a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt index 2685dad20..2843b95fa 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt @@ -3,6 +3,7 @@ package org.move.lang.core.resolve2 import org.move.lang.core.psi.MvPath import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.allowedNamespaces import org.move.lang.core.psi.ext.ancestorStrict import org.move.lang.core.resolve.ref.Namespace @@ -20,87 +21,94 @@ sealed class PathKind { data class UnqualifiedPath(val ns: Set): PathKind() // any multi element path - sealed class QualifiedPath: PathKind() { + sealed class QualifiedPath(val path: MvPath, val qualifier: MvPath, val ns: Set): PathKind() { // `0x1:foo` or `aptos_framework::foo` (where aptos_framework is known named address) - class Module(val path: MvPath, val qualifier: MvPath, val ns: Set, val address: Address): QualifiedPath() + class Module(path: MvPath, qualifier: MvPath, ns: Set, val address: Address): + QualifiedPath(path, qualifier, ns) // bar in foo::bar, where foo is not a named address - class ModuleItem(val path: MvPath, val qualifier: MvPath, val ns: Set): QualifiedPath() + class ModuleItem(path: MvPath, qualifier: MvPath, ns: Set): + QualifiedPath(path, qualifier, ns) // bar in `0x1::foo::bar` or `aptos_std::foo::bar` (where aptos_std is known named address) - class FQModuleItem(val path: MvPath, val qualifier: MvPath, val ns: Set): QualifiedPath() + class FQModuleItem(path: MvPath, qualifier: MvPath, ns: Set): + QualifiedPath(path, qualifier, ns) // use 0x1::m::{item1}; // ^ - class UseGroupItem(val path: MvPath, val qualifier: MvPath): QualifiedPath() + class UseGroupItem(path: MvPath, qualifier: MvPath, ns: Set): + QualifiedPath(path, qualifier, ns) } } -val MvPath.kind: PathKind - get() { - val ns = this.allowedNamespaces() - val qualifierPath = this.path - val moveProject = this.moveProject +fun MvPath.pathKind(overwriteNs: Set? = null): PathKind { + val ns = overwriteNs ?: this.allowedNamespaces() + val qualifierPath = this.path + val moveProject = this.moveProject - val useGroup = this.ancestorStrict() - if (useGroup != null) { - // use 0x1::m::{item} - // ^ - val qualifier = (useGroup.parent as MvUseSpeck).path - return PathKind.QualifiedPath.UseGroupItem(this, qualifier) - } + val useGroup = this.ancestorStrict() + if (useGroup != null) { + // use 0x1::m::{item} + // ^ + val qualifier = (useGroup.parent as MvUseSpeck).path + return PathKind.QualifiedPath.UseGroupItem(this, qualifier, ns) + } - if (qualifierPath == null) { - // left-most path - val parentPath = this.parent as? MvPath - if (parentPath != null) { - // can be an address - val pathAddress = this.pathAddress - val referenceName = this.referenceName - when { - pathAddress != null -> return PathKind.ValueAddress(Address.Value(pathAddress.text)) - moveProject != null && referenceName != null -> { - // try for named address - val namedAddress = moveProject.getNamedAddressTestAware(referenceName) - if (namedAddress != null) { - return PathKind.NamedAddress(namedAddress) - } + if (qualifierPath == null) { + val parentPath = this.parent as? MvPath + if (parentPath != null) { + // can be an address + val pathAddress = this.pathAddress + val referenceName = this.referenceName + when { + pathAddress != null -> return PathKind.ValueAddress(Address.Value(pathAddress.text)) + moveProject != null && referenceName != null -> { + // try for named address + val namedAddress = moveProject.getNamedAddressTestAware(referenceName) + if (namedAddress != null) { + return PathKind.NamedAddress(namedAddress) + } + // check whether it's a first item in use speck + val speckParent = parentPath.parent as? MvUseSpeck + if (speckParent != null && speckParent.parent is MvUseStmt) { + // always a named address, even if unknown + return PathKind.NamedAddress(Address.Named(referenceName, null, moveProject)) } } } - - return PathKind.UnqualifiedPath(ns) } + return PathKind.UnqualifiedPath(ns) + } - val qualifierOfQualifier = qualifierPath.path + val qualifierOfQualifier = qualifierPath.path - // two-element paths - if (qualifierOfQualifier == null) { - val qualifierPathAddress = qualifierPath.pathAddress - val qualifierItemName = qualifierPath.referenceName - when { - // 0x1::bar - // ^ - qualifierPathAddress != null -> { - val address = Address.Value(qualifierPathAddress.text) - return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) - } - // aptos_framework::bar - // ^ - moveProject != null && qualifierItemName != null -> { - val namedAddress = moveProject.getNamedAddressTestAware(qualifierItemName) - if (namedAddress != null) { - // known named address, can be module path - return PathKind.QualifiedPath.Module(this, qualifierPath, ns, namedAddress) - } - } - else -> { - // module::name - return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) + // two-element paths + if (qualifierOfQualifier == null) { + val qualifierPathAddress = qualifierPath.pathAddress + val qualifierItemName = qualifierPath.referenceName + when { + // 0x1::bar + // ^ + qualifierPathAddress != null -> { + val address = Address.Value(qualifierPathAddress.text) + return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) + } + // aptos_framework::bar + // ^ + moveProject != null && qualifierItemName != null -> { + val namedAddress = moveProject.getNamedAddressTestAware(qualifierItemName) + if (namedAddress != null) { + // known named address, can be module path + return PathKind.QualifiedPath.Module(this, qualifierPath, ns, namedAddress) } } + else -> { + // module::name + return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) + } } + } - // three-element path - return PathKind.QualifiedPath.FQModuleItem(this, qualifierPath, ns) - } \ No newline at end of file + // three-element path + return PathKind.QualifiedPath.FQModuleItem(this, qualifierPath, ns) +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index a322b7bd0..b987fc534 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -6,10 +6,9 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.useSpeck import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* -import org.move.lang.core.resolve2.processItemDeclarations -import org.move.lang.core.resolve2.processModulePathResolveVariants -import org.move.lang.core.resolve2.processNestedScopesUpwards -import org.move.lang.core.resolve2.ref.RsPathResolveKind.* +import org.move.lang.core.resolve2.* +import org.move.lang.core.resolve2.PathKind.NamedAddress +import org.move.lang.core.resolve2.PathKind.ValueAddress import org.move.lang.moveProject import kotlin.LazyThreadSafetyMode.NONE @@ -52,40 +51,57 @@ class Path2ReferenceImpl(element: MvPath): path = path, contextScopeInfo = ContextScopeInfo.from(path) ) - return resolvePath(ctx, path, classifyPath(path)) + return resolvePath(ctx, path) +// return resolvePath(ctx, path, classifyPath(path)) } } } fun processPathResolveVariants( ctx: PathResolutionContext, - pathKind: RsPathResolveKind, + pathKind: PathKind, processor: RsResolveProcessor ): Boolean { val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) return when (pathKind) { - is UnqualifiedPath -> { + is NamedAddress, is ValueAddress -> false + is PathKind.UnqualifiedPath -> { // Self:: if (processor.lazy("Self") { ctx.containingModule }) return true // local processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextProcessor) } - is ModulePath -> { - // 0x1::bar - processModulePathResolveVariants( - ctx.path, - ctx.moveProject, - pathKind.address, - contextProcessor - ) + is PathKind.QualifiedPath.Module -> { + processModulePathResolveVariants(ctx.path, ctx.moveProject, pathKind.address, contextProcessor) } - is QualifiedPath -> { - // foo::bar + is PathKind.QualifiedPath -> { processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) +// processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, contextProcessor) } - is NamedAddressPath -> return false - is ValueAddressPath -> return false } +// return when (pathKind) { +// is UnqualifiedPath -> { +// // Self:: +// if (processor.lazy("Self") { ctx.containingModule }) return true +// // local +// processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextProcessor) +// } +// is ModulePath -> { +// // 0x1::bar +// processModulePathResolveVariants( +// ctx.path, +// ctx.moveProject, +// pathKind.address, +// contextProcessor +// ) +// } +// is QualifiedPath -> { +// // foo::bar +// processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) +// } +// is NamedAddressPath -> return false +// is ValueAddressPath -> return false +// } } //fun processPathResolveVariants( @@ -169,13 +185,14 @@ class PathResolutionContext( private fun resolvePath( ctx: PathResolutionContext, path: MvPath, - kind: RsPathResolveKind +// kind: RsPathResolveKind ): List> { + val pathKind = path.pathKind() val result = // matches resolve variants against referenceName from path collectPathResolveVariants(ctx, path) { // actually emits resolve variants - processPathResolveVariants(ctx, kind, it) + processPathResolveVariants(ctx, pathKind, it) } return result // return when (result.size) { diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt deleted file mode 100644 index 40c584f86..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/RsPathResolveKind.kt +++ /dev/null @@ -1,77 +0,0 @@ -package org.move.lang.core.resolve2.ref - -import org.move.lang.core.psi.MvPath -import org.move.lang.core.psi.ext.allowedNamespaces -import org.move.lang.core.psi.ext.isUseSpeck -import org.move.lang.core.psi.ext.qualifier -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve2.ref.RsPathResolveKind.* -import org.move.lang.core.types.Address -import org.move.lang.moveProject - -sealed class RsPathResolveKind { - /** A path consist of a single identifier, e.g. `foo` */ - data class UnqualifiedPath(val ns: Set): RsPathResolveKind() - - /** `bar` in `foo::bar` or `use foo::{bar}` */ - class QualifiedPath( - val path: MvPath, - val qualifier: MvPath, - val ns: Set, - ): RsPathResolveKind() - - /** bar in `0x1::bar` */ - class ModulePath( - val path: MvPath, - val address: Address, - val ns: Set, - ): RsPathResolveKind() - - /** aptos_framework in `use aptos_framework::bar`*/ - data class NamedAddressPath(val address: Address.Named): RsPathResolveKind() - data class ValueAddressPath(val address: Address.Value): RsPathResolveKind() -} - -fun classifyPath(path: MvPath, overwriteNs: Set? = null): RsPathResolveKind { - val qualifier = path.qualifier - - val ns = overwriteNs ?: path.allowedNamespaces() -// if (qualifier == null) { -// return UnqualifiedPath(ns) -// } - val isUseSpeck = path.isUseSpeck - if (qualifier == null) { - // left-most path - if (isUseSpeck) { - // use aptos_framework:: - // //^ - val moveProject = path.moveProject - val pathName = path.referenceName - if (pathName == null) { - val value = path.pathAddress!!.text - return ValueAddressPath(Address.Value(value)) - } else { - val namedAddress = - moveProject?.getNamedAddressTestAware(pathName) ?: Address.Named(pathName, null, moveProject) - return NamedAddressPath(namedAddress) - } - } - return UnqualifiedPath(ns) - } - - val qualifierPath = qualifier.path - val pathAddress = qualifier.pathAddress - val qualifierName = qualifier.referenceName - - return when { - qualifierPath == null && pathAddress != null -> ModulePath(path, Address.Value(pathAddress.text), ns) - qualifierPath == null && isUseSpeck && qualifierName != null -> { - val moveProject = qualifier.moveProject - val namedAddress = - moveProject?.getNamedAddressTestAware(qualifierName) - ?: Address.Named(qualifierName, null, moveProject) - ModulePath(path, namedAddress, ns) - } - else -> QualifiedPath(path, qualifier, ns) - } -} 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 780a69729..6b57bd873 100644 --- a/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt +++ b/src/main/kotlin/org/move/lang/core/stubs/Stubs.kt @@ -363,7 +363,7 @@ class MvModuleSpecStub( MvModuleSpecImpl(stub, this) override fun createStub(psi: MvModuleSpec, parentStub: StubElement<*>?): MvModuleSpecStub { - return MvModuleSpecStub(parentStub, this, psi.fqModuleRef?.referenceName) + return MvModuleSpecStub(parentStub, this, psi.path?.referenceName) } override fun indexStub(stub: MvModuleSpecStub, sink: IndexSink) = sink.indexModuleSpecStub(stub) diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt index 65efc5574..bfe5f4b72 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt @@ -1,5 +1,6 @@ package org.move.lang.resolve +import org.move.utils.tests.NamedAddress import org.move.utils.tests.resolve.ResolveTestCase class ResolveVariablesTest : ResolveTestCase() { @@ -371,6 +372,7 @@ module 0x1::string_tests { } """) + @NamedAddress("aptos_std", "0x1") fun `test resolve attribute location for named address`() = checkByCode(""" module aptos_std::m { //X From 041bde577793e15647ca23c6e6b429bc6e5cefd1 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 17:57:26 +0300 Subject: [PATCH 23/43] comment out a lot of legacy code --- src/main/grammars/MoveParser.bnf | 22 +- .../org/move/ide/formatter/MoveFmtBlock.kt | 2 +- .../org/move/ide/formatter/impl/utils.kt | 4 +- .../MvUnresolvedReferenceInspection.kt | 69 ++- .../ide/inspections/imports/AutoImportFix.kt | 44 +- .../intentions/RemoveCurlyBracesIntention.kt | 21 +- .../utils/imports/ImportCandidateCollector.kt | 2 +- .../lang/core/completion/LookupElements.kt | 40 +- .../providers/FQModuleCompletionProvider.kt | 92 ++-- .../providers/ImportsCompletionProvider.kt | 116 ++--- .../MethodOrFieldCompletionProvider.kt | 3 +- .../providers/ModulesCompletionProvider.kt | 126 ++--- .../providers/MvPathCompletionProvider.kt | 451 ++++++++---------- .../providers/MvPathCompletionProvider2.kt | 43 +- .../SchemaFieldsCompletionProvider.kt | 8 +- .../StructFieldsCompletionProvider.kt | 3 +- .../providers/StructPatCompletionProvider.kt | 4 +- .../org/move/lang/core/psi/MvElement.kt | 2 +- .../move/lang/core/psi/ext/MvFQModuleRef.kt | 30 +- .../move/lang/core/psi/ext/MvItemsOwner.kt | 115 ++--- .../org/move/lang/core/psi/ext/MvModuleRef.kt | 26 +- .../org/move/lang/core/psi/ext/MvUseItem.kt | 141 +++--- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 52 +- .../lang/core/resolve/LexicalDeclarations.kt | 255 +++++----- .../lang/core/resolve/MatchingProcessor.kt | 8 +- .../lang/core/resolve/ModuleItemResolution.kt | 34 +- .../move/lang/core/resolve/NameResolution.kt | 334 +++++++------ .../resolve/ref/MoveFQModuleReferenceImpl.kt | 48 +- .../resolve/ref/MoveModuleReferenceImpl.kt | 52 +- .../core/resolve/ref/MovePathReferenceImpl.kt | 142 +++--- .../core/resolve/ref/MoveReferenceElement.kt | 6 +- .../core/resolve2/LexicalDeclarations2.kt | 6 +- .../lookups/BuiltInFunctionLookupTest.kt | 4 +- .../completion/lookups/LookupElementTest.kt | 3 +- .../move/lang/resolve/ResolveModulesTest.kt | 11 +- 35 files changed, 1108 insertions(+), 1211 deletions(-) diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index c444475d3..5942e39e4 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -575,11 +575,11 @@ UseItem ::= IDENTIFIER UseAlias? { pin = 1 name = "item name" - implements = [ - "org.move.lang.core.psi.MvNamedElement" - "org.move.lang.core.resolve.ref.MvMandatoryReferenceElement" - ] - mixin = "org.move.lang.core.psi.ext.MvUseItemMixin" +// implements = [ +// "org.move.lang.core.psi.MvNamedElement" +// "org.move.lang.core.resolve.ref.MvMandatoryReferenceElement" +// ] +// mixin = "org.move.lang.core.psi.ext.MvUseItemMixin" } UseAlias ::= as IDENTIFIER { @@ -1125,18 +1125,18 @@ private PATH_MODE_IDENTIFIER ::= (<> IDENTIFIER) ModuleRef ::= PATH_MODE_IDENTIFIER | FQModuleRef { - implements = ["org.move.lang.core.resolve.ref.MvReferenceElement"] - mixin = "org.move.lang.core.psi.ext.MvModuleRefMixin" +// implements = ["org.move.lang.core.resolve.ref.MvReferenceElement"] +// mixin = "org.move.lang.core.psi.ext.MvModuleRefMixin" } FQModuleRef ::= AddressRef '::' PATH_MODE_IDENTIFIER { pin = 2 extends = ModuleRef - implements = [ - "org.move.lang.core.resolve.ref.MvFQModuleReferenceElement" - ] - mixin = "org.move.lang.core.psi.ext.MvFQModuleRefMixin" +// implements = [ +// "org.move.lang.core.resolve.ref.MvFQModuleReferenceElement" +// ] +// mixin = "org.move.lang.core.psi.ext.MvFQModuleRefMixin" } AddressRef ::= NamedAddress diff --git a/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt b/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt index 928bf241a..5754f80dc 100644 --- a/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt +++ b/src/main/kotlin/org/move/ide/formatter/MoveFmtBlock.kt @@ -56,7 +56,7 @@ class MoveFmtBlock( parentType == FUNCTION_PARAMETER_LIST -> chopListWrap parentType == VALUE_ARGUMENT_LIST -> chopListWrap parentType == ATTR_ITEM_LIST -> chopListWrap - parentType == USE_ITEM_GROUP -> chopListWrap + parentType == USE_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 6f62e2283..f31ecc6a2 100644 --- a/src/main/kotlin/org/move/ide/formatter/impl/utils.kt +++ b/src/main/kotlin/org/move/ide/formatter/impl/utils.kt @@ -38,7 +38,7 @@ val BLOCK_LIKE = orSet(STRUCT_LITERAL_BLOCKS, DEF_BLOCKS) val DELIMITED_BLOCKS = orSet( PAREN_DELIMITED_BLOCKS, ANGLE_DELIMITED_BLOCKS, BRACKET_DELIMITED_BLOCKS, BLOCK_LIKE, - ts(USE_ITEM_GROUP) + ts(USE_GROUP) ) fun ASTNode?.isWhitespaceOrEmpty() = this == null || textLength == 0 || elementType == TokenType.WHITE_SPACE @@ -72,7 +72,7 @@ fun ASTNode.isDelimiterOfCurrentBlock(parent: ASTNode?): Boolean { if (parent == null) return false val parentType = parent.elementType return when (elementType) { - L_BRACE, R_BRACE -> parentType in BLOCK_LIKE || parentType == USE_ITEM_GROUP + L_BRACE, R_BRACE -> parentType in BLOCK_LIKE || parentType == USE_GROUP L_BRACK, R_BRACK -> parentType in BRACKET_DELIMITED_BLOCKS L_PAREN, R_PAREN -> parentType in PAREN_DELIMITED_BLOCKS LT, GT -> parentType in ANGLE_DELIMITED_BLOCKS diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt index 83ed790d0..13e576680 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspection.kt @@ -2,7 +2,6 @@ package org.move.ide.inspections import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder -import com.intellij.psi.util.descendantsOfType import org.move.cli.settings.isDebugModeEnabled import org.move.ide.inspections.imports.AutoImportFix import org.move.lang.core.psi.* @@ -196,40 +195,40 @@ class MvUnresolvedReferenceInspection: MvLocalInspectionTool() { } } - override fun visitModuleUseSpeck(o: MvModuleUseSpeck) { - val moduleRef = o.fqModuleRef ?: return - if (!moduleRef.resolvable) { - val refNameElement = moduleRef.referenceNameElement ?: return - holder.registerProblem( - refNameElement, - "Unresolved reference: `${refNameElement.text}`", - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - ) - } - } +// override fun visitModuleUseSpeck(o: MvModuleUseSpeck) { +// val moduleRef = o.fqModuleRef ?: return +// if (!moduleRef.resolvable) { +// val refNameElement = moduleRef.referenceNameElement ?: return +// holder.registerProblem( +// refNameElement, +// "Unresolved reference: `${refNameElement.text}`", +// ProblemHighlightType.LIKE_UNKNOWN_SYMBOL +// ) +// } +// } - override fun visitItemUseSpeck(o: MvItemUseSpeck) { - val moduleRef = o.fqModuleRef - if (!moduleRef.resolvable) { - val refNameElement = moduleRef.referenceNameElement ?: return - holder.registerProblem( - refNameElement, - "Unresolved reference: `${refNameElement.text}`", - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - ) - return - } - val useItems = o.descendantsOfType() - for (useItem in useItems) { - if (!useItem.resolvable) { - val refNameElement = useItem.referenceNameElement - holder.registerProblem( - refNameElement, - "Unresolved reference: `${refNameElement.text}`", - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - ) - } - } - } +// override fun visitItemUseSpeck(o: MvItemUseSpeck) { +// val moduleRef = o.fqModuleRef +// if (!moduleRef.resolvable) { +// val refNameElement = moduleRef.referenceNameElement ?: return +// holder.registerProblem( +// refNameElement, +// "Unresolved reference: `${refNameElement.text}`", +// ProblemHighlightType.LIKE_UNKNOWN_SYMBOL +// ) +// return +// } +// val useItems = o.descendantsOfType() +// for (useItem in useItems) { +// if (!useItem.resolvable) { +// val refNameElement = useItem.referenceNameElement +// holder.registerProblem( +// refNameElement, +// "Unresolved reference: `${refNameElement.text}`", +// ProblemHighlightType.LIKE_UNKNOWN_SYMBOL +// ) +// } +// } +// } } } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index 05fa71f71..64b35303e 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -93,37 +93,39 @@ class AutoImportFix(element: MvPath): DiagnosticFix(element), data class ImportContext private constructor( val pathElement: MvPath, val ns: Set, - val visibilities: Set, - val contextScopeInfo: ContextScopeInfo, +// val visibilities: Set, +// val contextScopeInfo: ContextScopeInfo, ) { companion object { fun from( pathElement: MvPath, ns: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo +// visibilities: Set, +// contextScopeInfo: ContextScopeInfo ): ImportContext { - return ImportContext(pathElement, ns, visibilities, contextScopeInfo) + return ImportContext(pathElement, ns) +// return ImportContext(pathElement, ns, visibilities, contextScopeInfo) } fun from(path: MvPath): ImportContext { val ns = path.importCandidateNamespaces() - val vs = - if (path.containingScript != null) { - setOf(Visibility.Public, Visibility.PublicScript) - } else { - val module = path.containingModule - if (module != null) { - setOf(Visibility.Public, Visibility.PublicFriend(module.asSmartPointer())) - } else { - setOf(Visibility.Public) - } - } - val contextScopeInfo = ContextScopeInfo( - letStmtScope = path.letStmtScope, - refItemScopes = path.refItemScopes, - ) - return ImportContext(path, ns, vs, contextScopeInfo) +// val vs = +// if (path.containingScript != null) { +// setOf(Visibility.Public, Visibility.PublicScript) +// } else { +// val module = path.containingModule +// if (module != null) { +// setOf(Visibility.Public, Visibility.PublicFriend(module.asSmartPointer())) +// } else { +// setOf(Visibility.Public) +// } +// } +// val contextScopeInfo = ContextScopeInfo( +// letStmtScope = path.letStmtScope, +// refItemScopes = path.refItemScopes, +// ) + return ImportContext(path, ns) +// return ImportContext(path, ns, vs, contextScopeInfo) } } } diff --git a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt index bfb249c62..15002c32d 100644 --- a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt +++ b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt @@ -3,29 +3,28 @@ package org.move.ide.intentions import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement -import org.move.lang.core.psi.MvUseItemGroup +import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.ancestorStrict import org.move.lang.core.psi.ext.endOffset -import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.psi.ext.startOffset import org.move.lang.core.psi.psiFactory -class RemoveCurlyBracesIntention : MvElementBaseIntentionAction() { +class RemoveCurlyBracesIntention: MvElementBaseIntentionAction() { override fun getText(): String = "Remove curly braces" override fun getFamilyName(): String = text - data class Context(val itemUseGroup: MvUseItemGroup) + data class Context(val useGroup: MvUseGroup) override fun findApplicableContext(project: Project, editor: Editor, element: PsiElement): Context? { val useStmt = element.ancestorStrict() ?: return null - val useItemGroup = useStmt.itemUseSpeck?.useItemGroup ?: return null - if (useItemGroup.useItemList.size > 1) return null - return Context(useItemGroup) + val useGroup = useStmt.useSpeck?.useGroup ?: return null + if (useGroup.useSpeckList.size > 1) return null + return Context(useGroup) } override fun invoke(project: Project, editor: Editor, ctx: Context) { - val itemUseGroup = ctx.itemUseGroup + val itemUseGroup = ctx.useGroup // Save the cursor position, adjusting for curly brace removal val caret = editor.caretModel.offset @@ -39,10 +38,10 @@ class RemoveCurlyBracesIntention : MvElementBaseIntentionAction { - val (pathElement, namespaces, visibilities, itemVis) = context + val (pathElement, namespaces) = context val project = pathElement.project val moveProject = pathElement.moveProject ?: return emptyList() diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index b9c3a6500..7ebde3e82 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -55,12 +55,12 @@ fun MvNamedElement.createLookupElementWithIcon(): LookupElementBuilder { .withLookupString(this.name ?: "") } -@Suppress("UnusedReceiverParameter") -fun MvModule.createSelfLookup(): LookupElement { - return LookupElementBuilder - .create("Self") - .withBoldness(true) -} +//@Suppress("UnusedReceiverParameter") +//fun MvModule.createSelfLookup(): LookupElement { +// return LookupElementBuilder +// .create("Self") +// .withBoldness(true) +//} fun MvNamedElement.getLookupElementBuilder( completionCtx: CompletionContext, @@ -123,17 +123,17 @@ fun MvNamedElement.getLookupElementBuilder( // we need to do the resolve here and in the next one to get the underlying item, // but it should be cached in the most cases - is MvModuleUseSpeck -> { - this.fqModuleRef?.reference?.resolve() - ?.getLookupElementBuilder(completionCtx, subst, structAsType) - ?: lookupElementBuilder - } - - is MvUseItem -> { - this.reference.resolve() - ?.getLookupElementBuilder(completionCtx, subst, structAsType) - ?: lookupElementBuilder - } +// is MvModuleUseSpeck -> { +// this.fqModuleRef?.reference?.resolve() +// ?.getLookupElementBuilder(completionCtx, subst, structAsType) +// ?: lookupElementBuilder +// } + +// is MvUseItem -> { +// this.reference.resolve() +// ?.getLookupElementBuilder(completionCtx, subst, structAsType) +// ?: lookupElementBuilder +// } else -> lookupElementBuilder } @@ -141,11 +141,13 @@ fun MvNamedElement.getLookupElementBuilder( data class CompletionContext( val contextElement: MvElement, - val contextScopeInfo: ContextScopeInfo, +// val contextScopeInfo: ContextScopeInfo, + val msl: Boolean, val expectedTy: Ty? = null, val resolutionCtx: PathResolutionContext? = null ) { - fun isMsl(): Boolean = contextScopeInfo.isMslScope +// fun isMsl(): Boolean = contextScopeInfo.isMslScope + fun isMsl(): Boolean = msl } diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/FQModuleCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/FQModuleCompletionProvider.kt index e3144266f..22d3b4dd2 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/FQModuleCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/FQModuleCompletionProvider.kt @@ -1,57 +1,39 @@ package org.move.lang.core.completion.providers -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.patterns.ElementPattern -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.util.ProcessingContext -import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.createLookupElement -import org.move.lang.core.psi.MvFQModuleRef -import org.move.lang.core.psi.refItemScopes -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.letStmtScope -import org.move.lang.core.resolve.processFQModuleRef -import org.move.lang.core.types.Address -import org.move.lang.core.types.address -import org.move.lang.core.withParent -import org.move.lang.moveProject - -object FQModuleCompletionProvider: MvCompletionProvider() { - override val elementPattern: ElementPattern - get() = - PlatformPatterns.psiElement() - .withParent() - - override fun addCompletions( - parameters: CompletionParameters, - context: ProcessingContext, - result: CompletionResultSet, - ) { - val directParent = parameters.position.parent - val fqModuleRef = - directParent as? MvFQModuleRef - ?: directParent.parent as MvFQModuleRef - if (parameters.position !== fqModuleRef.referenceNameElement) return - - val contextScopeInfo = ContextScopeInfo( - letStmtScope = fqModuleRef.letStmtScope, - refItemScopes = fqModuleRef.refItemScopes, - ) - val completionContext = CompletionContext(fqModuleRef, contextScopeInfo) - - val moveProj = fqModuleRef.moveProject - val positionAddress = fqModuleRef.addressRef.address(moveProj) - - processFQModuleRef(fqModuleRef) { - val module = it.element - val moduleAddress = module.address(moveProj) - if (Address.eq(positionAddress, moduleAddress)) { - val lookup = module.createLookupElement(completionContext) - result.addElement(lookup) - } - false - } - } -} +//object FQModuleCompletionProvider: MvCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// PlatformPatterns.psiElement() +// .withParent() +// +// override fun addCompletions( +// parameters: CompletionParameters, +// context: ProcessingContext, +// result: CompletionResultSet, +// ) { +// val directParent = parameters.position.parent +// val fqModuleRef = +// directParent as? MvFQModuleRef +// ?: directParent.parent as MvFQModuleRef +// if (parameters.position !== fqModuleRef.referenceNameElement) return +// +// val contextScopeInfo = ContextScopeInfo( +// letStmtScope = fqModuleRef.letStmtScope, +// refItemScopes = fqModuleRef.refItemScopes, +// ) +// val completionContext = CompletionContext(fqModuleRef, contextScopeInfo) +// +// val moveProj = fqModuleRef.moveProject +// val positionAddress = fqModuleRef.addressRef.address(moveProj) +// +// processFQModuleRef(fqModuleRef) { +// val module = it.element +// val moduleAddress = module.address(moveProj) +// if (Address.eq(positionAddress, moduleAddress)) { +// val lookup = module.createLookupElement(completionContext) +// result.addElement(lookup) +// } +// false +// } +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt index a71efc7a9..872455647 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt @@ -1,72 +1,48 @@ package org.move.lang.core.completion.providers -import com.intellij.codeInsight.completion.BasicInsertHandler -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.patterns.ElementPattern -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.util.ProcessingContext -import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.createLookupElement -import org.move.lang.core.completion.createSelfLookup -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvUseItem -import org.move.lang.core.psi.MvUseItemGroup -import org.move.lang.core.psi.ext.isSelfModuleRef -import org.move.lang.core.psi.ext.itemUseSpeck -import org.move.lang.core.psi.ext.names -import org.move.lang.core.psi.refItemScopes -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.letStmtScope -import org.move.lang.core.resolve.processModuleItems -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.withParent - -object ImportsCompletionProvider: MvCompletionProvider() { - override val elementPattern: ElementPattern - get() = PlatformPatterns - .psiElement().withParent() - - override fun addCompletions( - parameters: CompletionParameters, - context: ProcessingContext, - result: CompletionResultSet - ) { - val itemImport = parameters.position.parent as MvUseItem - if (parameters.position !== itemImport.referenceNameElement) return - - val moduleRef = itemImport.itemUseSpeck.fqModuleRef - val referredModule = moduleRef.reference?.resolve() as? MvModule - ?: return - - val p = itemImport.parent - if (p is MvUseItemGroup && "Self" !in p.names) { - result.addElement(referredModule.createSelfLookup()) - } - - val vs = when { - moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) - else -> Visibility.visibilityScopesForElement(itemImport) - } - val ns = setOf(Namespace.NAME, Namespace.TYPE, Namespace.FUNCTION) - val contextScopeInfo = - ContextScopeInfo( - letStmtScope = itemImport.letStmtScope, - refItemScopes = itemImport.refItemScopes, - ) - - val completionContext = CompletionContext(itemImport, contextScopeInfo) - processModuleItems(referredModule, ns, vs, contextScopeInfo) { - result.addElement( - it.element.createLookupElement( - completionContext, - insertHandler = BasicInsertHandler(), - structAsType = true - ) - ) - false - } - } -} +//object ImportsCompletionProvider: MvCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = PlatformPatterns +// .psiElement().withParent() +// +// override fun addCompletions( +// parameters: CompletionParameters, +// context: ProcessingContext, +// result: CompletionResultSet +// ) { +// val itemImport = parameters.position.parent as MvUseItem +// if (parameters.position !== itemImport.referenceNameElement) return +// +// val moduleRef = itemImport.itemUseSpeck.fqModuleRef +// val referredModule = moduleRef.reference?.resolve() as? MvModule +// ?: return +// +// val p = itemImport.parent +// if (p is MvUseItemGroup && "Self" !in p.names) { +// result.addElement(referredModule.createSelfLookup()) +// } +// +// val vs = when { +// moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) +// else -> Visibility.visibilityScopesForElement(itemImport) +// } +// val ns = setOf(Namespace.NAME, Namespace.TYPE, Namespace.FUNCTION) +// val contextScopeInfo = +// ContextScopeInfo( +// letStmtScope = itemImport.letStmtScope, +// refItemScopes = itemImport.refItemScopes, +// ) +// +// val completionContext = CompletionContext(itemImport, contextScopeInfo) +// processModuleItems(referredModule, ns, vs, contextScopeInfo) { +// result.addElement( +// it.element.createLookupElement( +// completionContext, +// insertHandler = BasicInsertHandler(), +// structAsType = true +// ) +// ) +// false +// } +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index de732feb9..bdd5f83c3 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -50,7 +50,8 @@ object MethodOrFieldCompletionProvider: MvCompletionProvider() { ) val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(element, msl) - val ctx = CompletionContext(element, scopeInfo, expectedTy) + val ctx = CompletionContext(element, msl, expectedTy) +// val ctx = CompletionContext(element, scopeInfo, msl, expectedTy) val structTy = receiverTy.derefIfNeeded() as? TyStruct if (structTy != null) { diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt index bd7518919..015f550e6 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt @@ -24,66 +24,66 @@ import org.move.lang.core.resolve.processItems import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Visibility -object ModulesCompletionProvider2: MvCompletionProvider() { - override val elementPattern: ElementPattern - get() = - MvPsiPatterns.path() - - override fun addCompletions( - parameters: CompletionParameters, - context: ProcessingContext, - result: CompletionResultSet, - ) { - val maybePath = parameters.position.parent - val refElement = - maybePath as? MvPath ?: maybePath.parent as MvPath - - if (parameters.position !== refElement.referenceNameElement) return - if (refElement.moduleRef != null) return - - val processedNames = mutableSetOf() - val namespaces = setOf(Namespace.MODULE) - val contextScopeInfo = - ContextScopeInfo( - letStmtScope = refElement.letStmtScope, - refItemScopes = refElement.refItemScopes, - ) - val completionCtx = CompletionContext(refElement, contextScopeInfo) - processItems(refElement, namespaces, contextScopeInfo) { (name, element) -> - result.addElement( - element.createLookupElement(completionCtx, priority = IMPORTED_MODULE_PRIORITY) - ) - processedNames.add(name) - false - } - - // disable auto-import in module specs for now - if (refElement.containingModuleSpec != null) return - - val path = parameters.originalPosition?.parent as? MvPath ?: return - val importContext = - ImportContext.from( - path, - namespaces, - setOf(Visibility.Public), - contextScopeInfo - ) - val containingMod = path.containingModule - val candidates = getCompletionCandidates(parameters, result.prefixMatcher, processedNames, importContext, - itemFilter = { - containingMod != null && !it.equalsTo( - containingMod - ) - }) - candidates.forEach { candidate -> - val lookupElement = - candidate.element.createLookupElement( - completionCtx, - structAsType = Namespace.TYPE in importContext.ns, - priority = UNIMPORTED_ITEM_PRIORITY, - insertHandler = ImportInsertHandler(parameters, candidate) - ) - result.addElement(lookupElement) - } - } -} +//object ModulesCompletionProvider2: MvCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// MvPsiPatterns.path() +// +// override fun addCompletions( +// parameters: CompletionParameters, +// context: ProcessingContext, +// result: CompletionResultSet, +// ) { +// val maybePath = parameters.position.parent +// val refElement = +// maybePath as? MvPath ?: maybePath.parent as MvPath +// +// if (parameters.position !== refElement.referenceNameElement) return +// if (refElement.moduleRef != null) return +// +// val processedNames = mutableSetOf() +// val namespaces = setOf(Namespace.MODULE) +// val contextScopeInfo = +// ContextScopeInfo( +// letStmtScope = refElement.letStmtScope, +// refItemScopes = refElement.refItemScopes, +// ) +// val completionCtx = CompletionContext(refElement, contextScopeInfo) +// processItems(refElement, namespaces, contextScopeInfo) { (name, element) -> +// result.addElement( +// element.createLookupElement(completionCtx, priority = IMPORTED_MODULE_PRIORITY) +// ) +// processedNames.add(name) +// false +// } +// +// // disable auto-import in module specs for now +// if (refElement.containingModuleSpec != null) return +// +// val path = parameters.originalPosition?.parent as? MvPath ?: return +// val importContext = +// ImportContext.from( +// path, +// namespaces, +// setOf(Visibility.Public), +// contextScopeInfo +// ) +// val containingMod = path.containingModule +// val candidates = getCompletionCandidates(parameters, result.prefixMatcher, processedNames, importContext, +// itemFilter = { +// containingMod != null && !it.equalsTo( +// containingMod +// ) +// }) +// candidates.forEach { candidate -> +// val lookupElement = +// candidate.element.createLookupElement( +// completionCtx, +// structAsType = Namespace.TYPE in importContext.ns, +// priority = UNIMPORTED_ITEM_PRIORITY, +// insertHandler = ImportInsertHandler(parameters, candidate) +// ) +// result.addElement(lookupElement) +// } +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index 6f90ae883..0dc7f4228 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -1,256 +1,213 @@ package org.move.lang.core.completion.providers -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.patterns.ElementPattern -import com.intellij.patterns.StandardPatterns -import com.intellij.psi.PsiElement -import com.intellij.util.ProcessingContext -import org.move.ide.inspections.imports.ImportContext -import org.move.ide.utils.imports.ImportCandidateCollector.getCompletionCandidates -import org.move.lang.core.MvPsiPatterns -import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY -import org.move.lang.core.completion.createLookupElement -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.* -import org.move.lang.core.resolve.ref.MvReferenceElement -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.resolve2.processItemDeclarations -import org.move.lang.core.resolve2.processNestedScopesUpwards -import org.move.lang.core.resolve2.ref.PathResolutionContext -import org.move.lang.core.types.infer.inferExpectedTy -import org.move.lang.core.types.infer.inference -import org.move.lang.core.types.ty.Ty -import org.move.lang.core.types.ty.TyUnknown -import java.util.* - -fun interface CompletionFilter { - fun removeEntry(entry: ScopeEntry, ctx: PathResolutionContext): Boolean -} - -abstract class MvPathCompletionProvider: MvCompletionProvider() { - - abstract val namespaces: Set - - open val completionFilters: List = emptyList() - - open fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo = - ContextScopeInfo( - letStmtScope = pathElement.letStmtScope, - refItemScopes = pathElement.refItemScopes, - ) - - final override fun addCompletions( - parameters: CompletionParameters, - context: ProcessingContext, - result: CompletionResultSet - ) { - val maybePath = parameters.position.parent - val pathElement = maybePath as? MvPath ?: maybePath.parent as MvPath - - if (parameters.position !== pathElement.referenceNameElement) return - - val qualifier = pathElement.qualifier - - val contextScopeInfo = pathScopeInfo(pathElement) - val msl = pathElement.isMslScope - val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) - val structAsType = Namespace.TYPE in this.namespaces - - val completionContext = CompletionContext( - pathElement, - contextScopeInfo, - expectedTy, - ) - - var completionCollector = createProcessor { e -> - val element = e.element as? MvNamedElement ?: return@createProcessor - val lookup = - element.createLookupElement( - completionContext, - structAsType = structAsType, - priority = element.completionPriority - ) - result.addElement(lookup) - } - - if (qualifier != null) { - val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() - when (resolvedQualifier) { - is MvModule -> { - val moduleBlock = resolvedQualifier.moduleBlock - if (moduleBlock != null) { - processItemDeclarations(moduleBlock, this.namespaces, completionCollector) - } - } - } - return - } - -// if (moduleRef != null) { -// val module = moduleRef.reference?.resolveWithAliases() as? MvModule -// ?: return -// val vs = when { -// moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) -// else -> Visibility.visibilityScopesForElement(pathElement) -// } -// processModuleItems(module, namespaces, vs, contextScopeInfo) { -// val lookup = -// it.element.createLookupElement(ctx, structAsType = structAsType) -// result.addElement(lookup) -// false -// } -// return -// } - - val processedNames = mutableSetOf() - completionCollector = completionCollector.wrapWithFilter { e -> - if (processedNames.contains(e.name)) { - return@wrapWithFilter false - } - processedNames.add(e.name) - true - } - - val resolutionCtx = PathResolutionContext(pathElement, contextScopeInfo) - - // custom filters - completionCollector = completionCollector.wrapWithFilter { - for (completionFilter in this.completionFilters) { - if (!completionFilter.removeEntry(it, resolutionCtx)) return@wrapWithFilter false - } - true - } - - val ctx = PathResolutionContext(pathElement, contextScopeInfo) - processNestedScopesUpwards(pathElement, this.namespaces, ctx, completionCollector) - -// processItems(pathElement, namespaces, contextScopeInfo) { (name, element) -> -// if (processedNames.contains(name)) { -// return@processItems false -// } -// processedNames.add(name) -// result.addElement( +//fun interface CompletionFilter { +// fun removeEntry(entry: ScopeEntry, ctx: PathResolutionContext): Boolean +//} + +//abstract class MvPathCompletionProvider: MvCompletionProvider() { +// +// abstract val namespaces: Set +// +// open val completionFilters: List = emptyList() +// +// open fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo = +// ContextScopeInfo( +// letStmtScope = pathElement.letStmtScope, +// refItemScopes = pathElement.refItemScopes, +// ) +// +// final override fun addCompletions( +// parameters: CompletionParameters, +// context: ProcessingContext, +// result: CompletionResultSet +// ) { +// val maybePath = parameters.position.parent +// val pathElement = maybePath as? MvPath ?: maybePath.parent as MvPath +// +// if (parameters.position !== pathElement.referenceNameElement) return +// +// val qualifier = pathElement.qualifier +// +// val contextScopeInfo = pathScopeInfo(pathElement) +// val msl = pathElement.isMslScope +// val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) +// val structAsType = Namespace.TYPE in this.namespaces +// +// val completionContext = CompletionContext( +// pathElement, +// contextScopeInfo, +// expectedTy, +// ) +// +// var completionCollector = createProcessor { e -> +// val element = e.element as? MvNamedElement ?: return@createProcessor +// val lookup = // element.createLookupElement( // completionContext, // structAsType = structAsType, // priority = element.completionPriority // ) +// result.addElement(lookup) +// } +// +// if (qualifier != null) { +// val resolvedQualifier = qualifier.reference?.resolveFollowingAliases() +// when (resolvedQualifier) { +// is MvModule -> { +// val moduleBlock = resolvedQualifier.moduleBlock +// if (moduleBlock != null) { +// processItemDeclarations(moduleBlock, this.namespaces, completionCollector) +// } +// } +// } +// return +// } +// +//// if (moduleRef != null) { +//// val module = moduleRef.reference?.resolveWithAliases() as? MvModule +//// ?: return +//// val vs = when { +//// moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) +//// else -> Visibility.visibilityScopesForElement(pathElement) +//// } +//// processModuleItems(module, namespaces, vs, contextScopeInfo) { +//// val lookup = +//// it.element.createLookupElement(ctx, structAsType = structAsType) +//// result.addElement(lookup) +//// false +//// } +//// return +//// } +// +// val processedNames = mutableSetOf() +// completionCollector = completionCollector.wrapWithFilter { e -> +// if (processedNames.contains(e.name)) { +// return@wrapWithFilter false +// } +// processedNames.add(e.name) +// true +// } +// +// val resolutionCtx = PathResolutionContext(pathElement, contextScopeInfo) +// +// // custom filters +// completionCollector = completionCollector.wrapWithFilter { +// for (completionFilter in this.completionFilters) { +// if (!completionFilter.removeEntry(it, resolutionCtx)) return@wrapWithFilter false +// } +// true +// } +// +// val ctx = PathResolutionContext(pathElement, contextScopeInfo) +// processNestedScopesUpwards(pathElement, this.namespaces, ctx, completionCollector) +// +//// processItems(pathElement, namespaces, contextScopeInfo) { (name, element) -> +//// if (processedNames.contains(name)) { +//// return@processItems false +//// } +//// processedNames.add(name) +//// result.addElement( +//// element.createLookupElement( +//// completionContext, +//// structAsType = structAsType, +//// priority = element.completionPriority +//// ) +//// ) +//// false +//// } +// +// // disable auto-import in module specs for now +// if (pathElement.containingModuleSpec != null) return +// +// val originalPathElement = parameters.originalPosition?.parent as? MvPath ?: return +// val importContext = +// ImportContext.from( +// originalPathElement, +// this.namespaces, +// setOf(Visibility.Public), +// contextScopeInfo // ) -// false +// val candidates = getCompletionCandidates( +// parameters, +// result.prefixMatcher, +// processedNames, +// importContext, +// ) +// candidates.forEach { candidate -> +// val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, namespaces) +// for (completionFilter in completionFilters) { +// if (!completionFilter.removeEntry(entry, resolutionCtx)) return@forEach +// } +// val lookupElement = candidate.element.createLookupElement( +// completionContext, +// structAsType = structAsType, +// priority = UNIMPORTED_ITEM_PRIORITY, +// insertHandler = ImportInsertHandler(parameters, candidate) +// ) +// result.addElement(lookupElement) // } - - // disable auto-import in module specs for now - if (pathElement.containingModuleSpec != null) return - - val originalPathElement = parameters.originalPosition?.parent as? MvPath ?: return - val importContext = - ImportContext.from( - originalPathElement, - this.namespaces, - setOf(Visibility.Public), - contextScopeInfo - ) - val candidates = getCompletionCandidates( - parameters, - result.prefixMatcher, - processedNames, - importContext, - ) - candidates.forEach { candidate -> - val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, namespaces) - for (completionFilter in completionFilters) { - if (!completionFilter.removeEntry(entry, resolutionCtx)) return@forEach - } - val lookupElement = candidate.element.createLookupElement( - completionContext, - structAsType = structAsType, - priority = UNIMPORTED_ITEM_PRIORITY, - insertHandler = ImportInsertHandler(parameters, candidate) - ) - result.addElement(lookupElement) - } - } -} - -object NamesCompletionProvider: MvPathCompletionProvider() { - override val elementPattern: ElementPattern - get() = - MvPsiPatterns.path() - .andNot(MvPsiPatterns.pathType()) - .andNot(MvPsiPatterns.schemaLit()) - - override val namespaces: Set get() = EnumSet.of(Namespace.NAME) -} - -object FunctionsCompletionProvider: MvPathCompletionProvider() { - override val elementPattern: ElementPattern - get() = - MvPsiPatterns.path() - .andNot(MvPsiPatterns.pathType()) - .andNot(MvPsiPatterns.schemaLit()) - - override val namespaces: Set get() = EnumSet.of(Namespace.FUNCTION) -} - -object TypesCompletionProvider: MvPathCompletionProvider() { - override val elementPattern: ElementPattern - get() = MvPsiPatterns.pathType() - - override val namespaces: Set get() = EnumSet.of(Namespace.TYPE) -} - -object SchemasCompletionProvider: MvPathCompletionProvider() { - override val elementPattern: ElementPattern - get() = - StandardPatterns.or( - MvPsiPatterns.schemaLit(), MvPsiPatterns.pathInsideIncludeStmt() - ) - - override val namespaces: Set get() = EnumSet.of(Namespace.SCHEMA) - - override fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo { - return ContextScopeInfo( - letStmtScope = LetStmtScope.EXPR_STMT, - refItemScopes = pathElement.refItemScopes, - ) - } -} - -object ModulesCompletionProvider: MvPathCompletionProvider() { - override val elementPattern: ElementPattern - get() = - MvPsiPatterns.path() - .andNot(MvPsiPatterns.pathType()) - .andNot(MvPsiPatterns.schemaLit()) - - override val namespaces: Set get() = EnumSet.of(Namespace.MODULE) - - override val completionFilters: List - get() = listOf( - // filter out the current module - CompletionFilter { e, ctx -> - if (e.element is MvModule) - return@CompletionFilter ctx.containingModule?.let { e.element.equalsTo(it) } ?: true - true - }) -} - -fun getExpectedTypeForEnclosingPathOrDotExpr(element: MvReferenceElement, msl: Boolean): Ty? { - for (ancestor in element.ancestors) { - if (element.endOffset < ancestor.endOffset) continue - if (element.endOffset > ancestor.endOffset) break - when (ancestor) { - is MvPathType, - is MvRefExpr, - is MvDotExpr -> { - val inference = (ancestor as MvElement).inference(msl) ?: return TyUnknown - return inferExpectedTy(ancestor, inference) - } - } - } - return null -} +// } +//} + +//object NamesCompletionProvider: MvPathCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// MvPsiPatterns.path() +// .andNot(MvPsiPatterns.pathType()) +// .andNot(MvPsiPatterns.schemaLit()) +// +// override val namespaces: Set get() = EnumSet.of(Namespace.NAME) +//} + +//object FunctionsCompletionProvider: MvPathCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// MvPsiPatterns.path() +// .andNot(MvPsiPatterns.pathType()) +// .andNot(MvPsiPatterns.schemaLit()) +// +// override val namespaces: Set get() = EnumSet.of(Namespace.FUNCTION) +//} + +//object TypesCompletionProvider: MvPathCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = MvPsiPatterns.pathType() +// +// override val namespaces: Set get() = EnumSet.of(Namespace.TYPE) +//} + +//object SchemasCompletionProvider: MvPathCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// StandardPatterns.or( +// MvPsiPatterns.schemaLit(), MvPsiPatterns.pathInsideIncludeStmt() +// ) +// +// override val namespaces: Set get() = EnumSet.of(Namespace.SCHEMA) +// +// override fun pathScopeInfo(pathElement: MvPath): ContextScopeInfo { +// return ContextScopeInfo( +// letStmtScope = LetStmtScope.EXPR_STMT, +// refItemScopes = pathElement.refItemScopes, +// ) +// } +//} + +//object ModulesCompletionProvider: MvPathCompletionProvider() { +// override val elementPattern: ElementPattern +// get() = +// MvPsiPatterns.path() +// .andNot(MvPsiPatterns.pathType()) +// .andNot(MvPsiPatterns.schemaLit()) +// +// override val namespaces: Set get() = EnumSet.of(Namespace.MODULE) +// +// override val completionFilters: List +// get() = listOf( +// // filter out the current module +// CompletionFilter { e, ctx -> +// if (e.element is MvModule) +// return@CompletionFilter ctx.containingModule?.let { e.element.equalsTo(it) } ?: true +// true +// }) +//} diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 65aa98f4e..c20617bc1 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -14,21 +14,23 @@ import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY import org.move.lang.core.completion.createLookupElement import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.equalsTo -import org.move.lang.core.psi.ext.isMslScope -import org.move.lang.core.psi.ext.names -import org.move.lang.core.psi.ext.rootPath -import org.move.lang.core.resolve.ContextScopeInfo +import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.EXPR_STMT -import org.move.lang.core.resolve.SimpleScopeEntry -import org.move.lang.core.resolve.createProcessor +import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.* -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.resolve.wrapWithFilter import org.move.lang.core.resolve2.pathKind import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.ref.processPathResolveVariants +import org.move.lang.core.types.infer.inferExpectedTy +import org.move.lang.core.types.infer.inference +import org.move.lang.core.types.ty.Ty +import org.move.lang.core.types.ty.TyUnknown + +fun interface CompletionFilter { + fun removeEntry(entry: ScopeEntry, ctx: PathResolutionContext): Boolean +} object MvPathCompletionProvider2: MvCompletionProvider() { override val elementPattern: ElementPattern get() = path() @@ -55,7 +57,8 @@ object MvPathCompletionProvider2: MvCompletionProvider() { val completionContext = CompletionContext( pathElement, - contextScopeInfo, +// contextScopeInfo, + msl, expectedTy, resolutionCtx = resolutionCtx ) @@ -146,8 +149,8 @@ object MvPathCompletionProvider2: MvCompletionProvider() { ImportContext.from( originalPathElement, ns, - setOf(Visibility.Public), - completionContext.contextScopeInfo +// setOf(Visibility.Public), +// completionContext.contextScopeInfo ) val candidates = ImportCandidateCollector.getCompletionCandidates( @@ -173,3 +176,19 @@ object MvPathCompletionProvider2: MvCompletionProvider() { private fun createSelfLookup() = LookupElementBuilder.create("Self").bold() } + +fun getExpectedTypeForEnclosingPathOrDotExpr(element: MvReferenceElement, msl: Boolean): Ty? { + for (ancestor in element.ancestors) { + if (element.endOffset < ancestor.endOffset) continue + if (element.endOffset > ancestor.endOffset) break + when (ancestor) { + is MvPathType, + is MvRefExpr, + is MvDotExpr -> { + val inference = (ancestor as MvElement).inference(msl) ?: return TyUnknown + return inferExpectedTy(ancestor, inference) + } + } + } + return null +} diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt index 0a397bc6f..9107446ca 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt @@ -9,10 +9,7 @@ import com.intellij.util.ProcessingContext import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvSchemaLitField -import org.move.lang.core.psi.ext.fieldBindings -import org.move.lang.core.psi.ext.fieldNames -import org.move.lang.core.psi.ext.schema -import org.move.lang.core.psi.ext.schemaLit +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.withParent @@ -33,7 +30,8 @@ object SchemaFieldsCompletionProvider: MvCompletionProvider() { val schema = schemaLit.schema ?: return val providedFieldNames = schemaLit.fieldNames - val completionCtx = CompletionContext(element, ContextScopeInfo.msl()) + val completionCtx = CompletionContext(element, element.isMsl()) +// val completionCtx = CompletionContext(element, ContextScopeInfo.msl()) for (fieldBinding in schema.fieldBindings.filter { it.name !in providedFieldNames }) { result.addElement( fieldBinding.createLookupElement(completionCtx) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt index 6a5ca8c68..4110edcb0 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt @@ -39,7 +39,8 @@ object StructFieldsCompletionProvider: MvCompletionProvider() { if (element is MvBindingPat) element = element.parent as MvElement - val completionCtx = CompletionContext(element, ContextScopeInfo.default()) + val completionCtx = CompletionContext(element, element.isMsl()) +// val completionCtx = CompletionContext(element, ContextScopeInfo.default()) when (element) { is MvStructPatField -> { val structPat = element.structPat diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt index de0aaf57a..bd9715e66 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt @@ -11,6 +11,7 @@ import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvBindingPat import org.move.lang.core.psi.MvLetStmt import org.move.lang.core.psi.containingModule +import org.move.lang.core.psi.ext.isMsl import org.move.lang.core.psi.namedItemScopes import org.move.lang.core.psiElement import org.move.lang.core.resolve.ContextScopeInfo @@ -41,7 +42,8 @@ object StructPatCompletionProvider: MvCompletionProvider() { letStmtScope = LetStmtScope.NONE, refItemScopes = bindingPat.namedItemScopes, ) - val completionCtx = CompletionContext(bindingPat, contextScopeInfo) + val completionCtx = CompletionContext(bindingPat, bindingPat.isMsl()) +// val completionCtx = CompletionContext(bindingPat, contextScopeInfo) processModuleItems(module, namespaces, setOf(Visibility.Internal), contextScopeInfo) { val lookup = it.element.createLookupElement(completionCtx) diff --git a/src/main/kotlin/org/move/lang/core/psi/MvElement.kt b/src/main/kotlin/org/move/lang/core/psi/MvElement.kt index c807607b8..0c32b2801 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvElement.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvElement.kt @@ -37,7 +37,7 @@ val MvElement.containingModule: MvModule? get() = ancestorStrict() val MvElement.containingModuleSpec: MvModuleSpec? get() = ancestorStrict() -val MvElement.containingImportsOwner get() = ancestorOrSelf() +val MvElement.containingItemsOwner get() = ancestorOrSelf() //val MvElement.containingModuleOrScript: MvElement? // get() { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvFQModuleRef.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvFQModuleRef.kt index 5167ed1e7..291e055b2 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvFQModuleRef.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvFQModuleRef.kt @@ -1,21 +1,13 @@ package org.move.lang.core.psi.ext -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiElement -import org.move.lang.MvElementTypes -import org.move.lang.core.psi.MvElementImpl -import org.move.lang.core.psi.MvFQModuleRef -import org.move.lang.core.resolve.ref.MvFQModuleReference -import org.move.lang.core.resolve.ref.MvFQModuleReferenceImpl - -abstract class MvFQModuleRefMixin(node: ASTNode) : MvElementImpl(node), - MvFQModuleRef { - override val identifier: PsiElement? - get() = findChildByType(MvElementTypes.IDENTIFIER) - - override fun getReference(): MvFQModuleReference { - return MvFQModuleReferenceImpl(this) - } - - override fun getMul(): PsiElement? = null -} +//abstract class MvFQModuleRefMixin(node: ASTNode) : MvElementImpl(node), +// MvFQModuleRef { +// override val identifier: PsiElement? +// get() = findChildByType(MvElementTypes.IDENTIFIER) +// +// override fun getReference(): MvFQModuleReference { +// return MvFQModuleReferenceImpl(this) +// } +// +// override fun getMul(): PsiElement? = null +//} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index b792c0e4b..7b65e0a41 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -33,20 +33,21 @@ val MvModule.innerSpecItems: List } } -fun MvItemsOwner.moduleUseItems(): List = - listOf( - moduleUseSpecksNoAliases(), - moduleUseSpecksAliases(), - selfModuleUseItemNoAliases(), - selfModuleUseItemAliases(), - ).flatten() +//fun MvItemsOwner.moduleUseItems(): List = +// listOf( +//// moduleUseSpecksNoAliases(), +//// moduleUseSpecksAliases(), +//// selfModuleUseItemNoAliases(), +//// selfModuleUseItemAliases(), +// ) +// ).flatten() fun MvItemsOwner.moduleUseSpecksNoAliases(): List = moduleUseSpecks() .filter { it.useAlias == null } -fun MvItemsOwner.moduleUseSpecksAliases(): List = - moduleUseSpecks().mapNotNull { it.useAlias } +//fun MvItemsOwner.moduleUseSpecksAliases(): List = +// moduleUseSpecks().mapNotNull { it.useAlias } private fun MvItemsOwner.moduleUseSpecks(): List { @@ -55,58 +56,58 @@ private fun MvItemsOwner.moduleUseSpecks(): List { } } -fun MvItemsOwner.psiUseItems(): List { - return getProjectPsiDependentCache(this) { importsOwner -> - importsOwner - .useStmtList - .mapNotNull { it.itemUseSpeck } - .flatMap { - val item = it.useItem - if (item != null) { - listOf(item) - } else - it.useItemGroup?.useItemList.orEmpty() - } - - } -} - -fun MvItemsOwner.allUseItems(): List = - listOf( - useItemsNoAliases(), - useItemsAliases(), - ).flatten() - -fun MvItemsOwner.useItemsNoAliases(): List = - psiUseItems() - .filter { !it.isSelf } - .filter { it.useAlias == null } - -fun MvItemsOwner.useItemsAliases(): List = - psiUseItems() - .filter { !it.isSelf } - .mapNotNull { it.useAlias } - -fun MvItemsOwner.selfModuleUseItemNoAliases(): List = - psiUseItems() - .filter { it.isSelf && it.useAlias == null } - -fun MvItemsOwner.selfModuleUseItemAliases(): List = - psiUseItems() - .filter { it.isSelf } - .mapNotNull { it.useAlias } +//fun MvItemsOwner.psiUseItems(): List { +// return getProjectPsiDependentCache(this) { importsOwner -> +// importsOwner +// .useStmtList +// .mapNotNull { it.itemUseSpeck } +// .flatMap { +// val item = it.useItem +// if (item != null) { +// listOf(item) +// } else +// it.useItemGroup?.useItemList.orEmpty() +// } +// +// } +//} + +fun MvItemsOwner.allUseItems(): List = emptyList() +// listOf( +// useItemsNoAliases(), +// useItemsAliases(), +// ).flatten() + +//fun MvItemsOwner.useItemsNoAliases(): List = +// psiUseItems() +// .filter { !it.isSelf } +// .filter { it.useAlias == null } + +//fun MvItemsOwner.useItemsAliases(): List = +// psiUseItems() +// .filter { !it.isSelf } +// .mapNotNull { it.useAlias } + +//fun MvItemsOwner.selfModuleUseItemNoAliases(): List = +// psiUseItems() +// .filter { it.isSelf && it.useAlias == null } + +//fun MvItemsOwner.selfModuleUseItemAliases(): List = +// psiUseItems() +// .filter { it.isSelf } +// .mapNotNull { it.useAlias } fun MvItemsOwner.shortestPathText(item: MvNamedElement): String? { val itemName = item.name ?: return null // local - if (this == item.containingImportsOwner) return itemName - - for (useItem in this.useItemsNoAliases()) { - val importedItem = useItem.reference.resolve() ?: continue - if (importedItem == item) { - return itemName - } - } + if (this == item.containingItemsOwner) return itemName + +// for (useItem in this.useItemsNoAliases()) { +// val importedItem = useItem.reference.resolve() ?: continue +// if (importedItem == item) { +// return itemName +// } +// } val module = item.containingModule ?: return null val moduleName = module.name ?: return null for (moduleImport in this.moduleUseSpecksNoAliases()) { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt index f4623a808..e9ab788f5 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt @@ -1,23 +1,15 @@ package org.move.lang.core.psi.ext -import com.intellij.lang.ASTNode -import org.move.lang.core.psi.MvElementImpl -import org.move.lang.core.psi.MvFQModuleRef -import org.move.lang.core.psi.MvModuleRef -import org.move.lang.core.psi.containingModule -import org.move.lang.core.resolve.ref.MvModuleReferenceImpl -import org.move.lang.core.resolve.ref.MvPolyVariantReference +//val MvModuleRef.isSelfModuleRef: Boolean +// get() = +// this !is MvFQModuleRef +// && this.referenceName == "Self" +// && this.containingModule != null -val MvModuleRef.isSelfModuleRef: Boolean - get() = - this !is MvFQModuleRef - && this.referenceName == "Self" - && this.containingModule != null - -abstract class MvModuleRefMixin(node: ASTNode) : MvElementImpl(node), MvModuleRef { - - override fun getReference(): MvPolyVariantReference? = MvModuleReferenceImpl(this) -} +//abstract class MvModuleRefMixin(node: ASTNode) : MvElementImpl(node), MvModuleRef { +// +// override fun getReference(): MvPolyVariantReference? = MvModuleReferenceImpl(this) +//} //abstract class MvImportedModuleRefMixin(node: ASTNode) : MvReferenceElementImpl(node), // MvImportedModuleRef { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt index 34028915e..6555aa387 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt @@ -1,15 +1,6 @@ package org.move.lang.core.psi.ext -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiElement import org.move.lang.core.psi.* -import org.move.lang.core.psi.impl.MvNamedElementImpl -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.LetStmtScope -import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.resolve.resolveModuleItem val MvUseItem.itemUseSpeck: MvItemUseSpeck get() = ancestorStrict() ?: error("MvUseItem outside MvItemUseSpeck") @@ -34,73 +25,73 @@ val MvUseItem.nameOrAlias: String? return this.identifier.text } -val MvUseItem.moduleName: String - get() { - val useStmt = this.ancestorStrict() - return useStmt?.itemUseSpeck?.fqModuleRef?.referenceName.orEmpty() - } +//val MvUseItem.moduleName: String +// get() { +// val useStmt = this.ancestorStrict() +// return useStmt?.itemUseSpeck?.fqModuleRef?.referenceName.orEmpty() +// } val MvUseItem.isSelf: Boolean get() = this.identifier.textMatches("Self") val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false -class MvUseItemReferenceElement( - element: MvUseItem -): MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner(): List { - val fqModuleRef = element.itemUseSpeck.fqModuleRef - val module = - fqModuleRef.reference?.resolve() as? MvModule ?: return emptyList() - if ((element.useAlias == null && element.text == "Self") - || (element.useAlias != null && element.text.startsWith("Self as")) - ) { - return listOf(module) - } - - val ns = setOf( - Namespace.TYPE, - Namespace.NAME, - Namespace.FUNCTION, - Namespace.SCHEMA, - Namespace.CONST - ) - val vs = Visibility.visibilityScopesForElement(fqModuleRef) - - // import has MAIN+VERIFY, and TEST if it or any of the parents has test - val useItemScopes = mutableSetOf(NamedItemScope.MAIN, NamedItemScope.VERIFY) - - // gather scopes for all parents up to MvUseStmt - var scopedElement: MvElement? = element - while (scopedElement != null) { - useItemScopes.addAll(scopedElement.itemScopes) - scopedElement = scopedElement.parent as? MvElement - } - - val contextScopeInfo = - ContextScopeInfo( - letStmtScope = LetStmtScope.EXPR_STMT, - refItemScopes = useItemScopes, - ) - return resolveModuleItem( - module, - element.referenceName, - ns, - vs, - contextScopeInfo - ) - } - -} - -abstract class MvUseItemMixin(node: ASTNode): MvNamedElementImpl(node), - MvUseItem { - override fun getName(): String? { - val name = super.getName() - if (name != "Self") return name - return ancestorStrict()?.fqModuleRef?.referenceName ?: name - } - - override val referenceNameElement: PsiElement get() = identifier - - override fun getReference() = MvUseItemReferenceElement(this) -} +//class MvUseItemReferenceElement( +// element: MvUseItem +//): MvPolyVariantReferenceCached(element) { +// +// override fun multiResolveInner(): List { +// val fqModuleRef = element.itemUseSpeck.fqModuleRef +// val module = +// fqModuleRef.reference?.resolve() as? MvModule ?: return emptyList() +// if ((element.useAlias == null && element.text == "Self") +// || (element.useAlias != null && element.text.startsWith("Self as")) +// ) { +// return listOf(module) +// } +// +// val ns = setOf( +// Namespace.TYPE, +// Namespace.NAME, +// Namespace.FUNCTION, +// Namespace.SCHEMA, +// Namespace.CONST +// ) +// val vs = Visibility.visibilityScopesForElement(fqModuleRef) +// +// // import has MAIN+VERIFY, and TEST if it or any of the parents has test +// val useItemScopes = mutableSetOf(NamedItemScope.MAIN, NamedItemScope.VERIFY) +// +// // gather scopes for all parents up to MvUseStmt +// var scopedElement: MvElement? = element +// while (scopedElement != null) { +// useItemScopes.addAll(scopedElement.itemScopes) +// scopedElement = scopedElement.parent as? MvElement +// } +// +// val contextScopeInfo = +// ContextScopeInfo( +// letStmtScope = LetStmtScope.EXPR_STMT, +// refItemScopes = useItemScopes, +// ) +// return resolveModuleItem( +// module, +// element.referenceName, +// ns, +// vs, +// contextScopeInfo +// ) +// } +// +//} + +//abstract class MvUseItemMixin(node: ASTNode): MvNamedElementImpl(node), +// MvUseItem { +// override fun getName(): String? { +// val name = super.getName() +// if (name != "Self") return name +// return ancestorStrict()?.fqModuleRef?.referenceName ?: name +// } +// +// override val referenceNameElement: PsiElement get() = identifier +// +// override fun getReference() = MvUseItemReferenceElement(this) +//} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index 9df6704c7..8f109ec4a 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -95,29 +95,29 @@ sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemSco } -val MvUseStmt.useSpecks: List - get() { - val stmtItemScope = this.declaredItemScope - val moduleUseSpeck = this.moduleUseSpeck - if (moduleUseSpeck != null) { - val nameOrAlias = moduleUseSpeck.nameElement?.text ?: return emptyList() - return listOf(UseSpeck.Module(nameOrAlias, stmtItemScope, moduleUseSpeck)) - } - return this.itemUseSpeck?.useItems.orEmpty() - .mapNotNull { - if (it.isSelf) { - val useAlias = it.useAlias - val nameOrAlias = - if (useAlias != null) { - val aliasName = useAlias.name ?: return@mapNotNull null - aliasName - } else { - it.moduleName - } - UseSpeck.SelfModule(nameOrAlias, stmtItemScope, it) - } else { - val nameOrAlias = it.nameOrAlias ?: return@mapNotNull null - UseSpeck.Item(nameOrAlias, stmtItemScope, it) - } - } - } +//val MvUseStmt.useSpecks: List +// get() { +// val stmtItemScope = this.declaredItemScope +// val moduleUseSpeck = this.moduleUseSpeck +// if (moduleUseSpeck != null) { +// val nameOrAlias = moduleUseSpeck.nameElement?.text ?: return emptyList() +// return listOf(UseSpeck.Module(nameOrAlias, stmtItemScope, moduleUseSpeck)) +// } +// return this.itemUseSpeck?.useItems.orEmpty() +// .mapNotNull { +// if (it.isSelf) { +// val useAlias = it.useAlias +// val nameOrAlias = +// if (useAlias != null) { +// val aliasName = useAlias.name ?: return@mapNotNull null +// aliasName +// } else { +// it.moduleName +// } +// UseSpeck.SelfModule(nameOrAlias, stmtItemScope, it) +// } else { +// val nameOrAlias = it.nameOrAlias ?: return@mapNotNull null +// UseSpeck.Item(nameOrAlias, stmtItemScope, it) +// } +// } +// } diff --git a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt b/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt index 7d035063c..12ea230ec 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt @@ -15,24 +15,24 @@ fun processItemsInScope( for (namespace in namespaces) { val stop = when (namespace) { - Namespace.CONST -> { - val found = when (scope) { - is MvModuleBlock -> { - val module = scope.parent as MvModule - processor.matchAll( - contextScopeInfo, - module.consts(), - ) - } - else -> false - } - if (!found) { - if (scope is MvItemsOwner) { - if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true - } - } - found - } +// Namespace.CONST -> { +// val found = when (scope) { +// is MvModuleBlock -> { +// val module = scope.parent as MvModule +// processor.matchAll( +// contextScopeInfo, +// module.consts(), +// ) +// } +// else -> false +// } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true +// } +// } +// found +// } Namespace.NAME -> { val found = when (scope) { @@ -139,118 +139,119 @@ fun processItemsInScope( } found } - Namespace.FUNCTION -> { - val found = when (scope) { - is MvModuleBlock -> { - val module = scope.parent as MvModule - val specFunctions = if (contextScopeInfo.isMslScope) { - listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() - } else { - emptyList() - } - val specInlineFunctions = if (contextScopeInfo.isMslScope) { - module.moduleItemSpecs().flatMap { it.specInlineFunctions() } - } else { - emptyList() - } - processor.matchAll( - contextScopeInfo, - module.allNonTestFunctions(), - module.builtinFunctions(), - specFunctions, - specInlineFunctions - ) - } - is MvModuleSpecBlock -> { - val specFunctions = scope.specFunctionList - val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } - processor.matchAll( - contextScopeInfo, - specFunctions, - specInlineFunctions - ) - } - is MvFunctionLike -> processor.matchAll(contextScopeInfo, scope.lambdaParamsAsBindings) - is MvLambdaExpr -> processor.matchAll(contextScopeInfo, scope.bindingPatList) - is MvItemSpec -> { - val item = scope.item - when (item) { - is MvFunction -> processor.matchAll(contextScopeInfo, item.lambdaParamsAsBindings) - else -> false - } - } - is MvSpecCodeBlock -> { - val inlineFunctions = scope.specInlineFunctions().asReversed() - return processor.matchAll(contextScopeInfo, inlineFunctions) - } - else -> false - } - if (!found) { - if (scope is MvItemsOwner) { - if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true - } - } - found - } - - Namespace.TYPE -> { - if (scope is MvTypeParametersOwner) { - if (processor.matchAll(contextScopeInfo, scope.typeParameters)) return true - } - val found = when (scope) { - is MvItemSpec -> { - val funcItem = scope.funcItem - if (funcItem != null) { - processor.matchAll(contextScopeInfo, funcItem.typeParameters) - } else { - false - } - } - is MvModuleBlock -> { - val module = scope.parent as MvModule - processor.matchAll( - contextScopeInfo, - scope.allUseItems(), - module.structs() - ) - } - is MvApplySchemaStmt -> { - val toPatterns = scope.applyTo?.functionPatternList.orEmpty() - val patternTypeParams = - toPatterns.flatMap { it.typeParameterList?.typeParameterList.orEmpty() } - processor.matchAll(contextScopeInfo, patternTypeParams) - } +// Namespace.FUNCTION -> { +// val found = when (scope) { +// is MvModuleBlock -> { +// val module = scope.parent as MvModule +// val specFunctions = if (contextScopeInfo.isMslScope) { +// listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() +// } else { +// emptyList() +// } +// val specInlineFunctions = if (contextScopeInfo.isMslScope) { +// module.moduleItemSpecs().flatMap { it.specInlineFunctions() } +// } else { +// emptyList() +// } +// processor.matchAll( +// contextScopeInfo, +// module.allNonTestFunctions(), +// module.builtinFunctions(), +// specFunctions, +// specInlineFunctions +// ) +// } +// is MvModuleSpecBlock -> { +// val specFunctions = scope.specFunctionList +// val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } +// processor.matchAll( +// contextScopeInfo, +// specFunctions, +// specInlineFunctions +// ) +// } +// is MvFunctionLike -> processor.matchAll(contextScopeInfo, scope.lambdaParamsAsBindings) +// is MvLambdaExpr -> processor.matchAll(contextScopeInfo, scope.bindingPatList) +// is MvItemSpec -> { +// val item = scope.item +// when (item) { +// is MvFunction -> processor.matchAll(contextScopeInfo, item.lambdaParamsAsBindings) +// else -> false +// } +// } +// is MvSpecCodeBlock -> { +// val inlineFunctions = scope.specInlineFunctions().asReversed() +// return processor.matchAll(contextScopeInfo, inlineFunctions) +// } +// else -> false +// } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true +// } +// } +// found +// } - else -> false - } - if (!found) { - if (scope is MvItemsOwner) { - if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true - } - } - found - } +// Namespace.TYPE -> { +// if (scope is MvTypeParametersOwner) { +// if (processor.matchAll(contextScopeInfo, scope.typeParameters)) return true +// } +// val found = when (scope) { +// is MvItemSpec -> { +// val funcItem = scope.funcItem +// if (funcItem != null) { +// processor.matchAll(contextScopeInfo, funcItem.typeParameters) +// } else { +// false +// } +// } +// is MvModuleBlock -> { +// val module = scope.parent as MvModule +// processor.matchAll( +// contextScopeInfo, +// scope.allUseItems(), +// module.structs() +// ) +// } +// is MvApplySchemaStmt -> { +// val toPatterns = scope.applyTo?.functionPatternList.orEmpty() +// val patternTypeParams = +// toPatterns.flatMap { it.typeParameterList?.typeParameterList.orEmpty() } +// processor.matchAll(contextScopeInfo, patternTypeParams) +// } +// +// else -> false +// } +// if (!found) { +// if (scope is MvItemsOwner) { +// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true +// } +// } +// found +// } - Namespace.SCHEMA -> when (scope) { - is MvModuleBlock -> processor.matchAll( - contextScopeInfo, - scope.allUseItems(), - scope.schemaList - ) - is MvModuleSpecBlock -> processor.matchAll( - contextScopeInfo, - scope.allUseItems(), - scope.schemaList, - scope.specFunctionList - ) - else -> false - } +// Namespace.SCHEMA -> when (scope) { +// is MvModuleBlock -> processor.matchAll( +// contextScopeInfo, +// scope.allUseItems(), +// scope.schemaList +// ) +// is MvModuleSpecBlock -> processor.matchAll( +// contextScopeInfo, +// scope.allUseItems(), +// scope.schemaList, +// scope.specFunctionList +// ) +// else -> false +// } - Namespace.MODULE -> when (scope) { - is MvItemsOwner -> - processor.matchAll(contextScopeInfo, scope.moduleUseItems()) - else -> false - } +// Namespace.MODULE -> when (scope) { +// is MvItemsOwner -> +// processor.matchAll(contextScopeInfo, scope.moduleUseItems()) +// else -> false +// } + else -> false } if (stop) return true } diff --git a/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt b/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt index a2fa79305..35a5a691d 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt @@ -34,8 +34,8 @@ fun interface MatchingProcessor { .flatten() .any { match(contextScopeInfo, it) } - fun matchAll(vararg collections: Iterable): Boolean = - sequenceOf(*collections) - .flatten() - .any { match(it) } +// fun matchAll(vararg collections: Iterable): Boolean = +// sequenceOf(*collections) +// .flatten() +// .any { match(it) } } diff --git a/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt index 6b79a1eba..bc42d594c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt @@ -87,20 +87,20 @@ fun processModuleItems( contextScopeInfo.isMslScope && processModuleSpecItems(module, namespaces, contextScopeInfo, processor) } -fun resolveModuleItem( - module: MvModule, - name: String, - namespaces: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo, -): List { - val resolved = mutableListOf() - processModuleItems(module, namespaces, visibilities, contextScopeInfo) { - if (it.name == name) { - resolved.add(it.element) - return@processModuleItems true - } - return@processModuleItems false - } - return resolved -} +//fun resolveModuleItem( +// module: MvModule, +// name: String, +// namespaces: Set, +// visibilities: Set, +// contextScopeInfo: ContextScopeInfo, +//): List { +// val resolved = mutableListOf() +// processModuleItems(module, namespaces, visibilities, contextScopeInfo) { +// if (it.name == name) { +// resolved.add(it.element) +// return@processModuleItems true +// } +// return@processModuleItems false +// } +// return resolved +//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt index 1f8f2d6b5..e419a83d8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt @@ -1,22 +1,10 @@ package org.move.lang.core.resolve -import com.intellij.psi.search.GlobalSearchScope -import org.move.cli.containingMovePackage -import org.move.cli.settings.moveSettings -import org.move.lang.MoveFile import org.move.lang.core.psi.* -import org.move.lang.core.psi.NamedItemScope.MAIN -import org.move.lang.core.psi.NamedItemScope.VERIFY import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.LetStmtScope.EXPR_STMT import org.move.lang.core.resolve.LetStmtScope.NONE import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.types.address -import org.move.lang.index.MvNamedElementIndex -import org.move.lang.moveProject -import org.move.lang.toNioPathOrNull import org.move.stdext.wrapWithList data class ContextScopeInfo( @@ -41,8 +29,8 @@ data class ContextScopeInfo( companion object { /// really does not affect anything, created just to allow creating CompletionContext everywhere - fun default(): ContextScopeInfo = ContextScopeInfo(setOf(MAIN), NONE) - fun msl(): ContextScopeInfo = ContextScopeInfo(setOf(VERIFY), EXPR_STMT) +// fun default(): ContextScopeInfo = ContextScopeInfo(setOf(MAIN), NONE) +// fun msl(): ContextScopeInfo = ContextScopeInfo(setOf(VERIFY), EXPR_STMT) fun from(element: MvElement): ContextScopeInfo { return ContextScopeInfo( @@ -91,165 +79,165 @@ fun resolveLocalItem( } // go from local MODULE reference to corresponding FqModuleRef (from import) -fun resolveIntoFQModuleRefInUseSpeck(moduleRef: MvModuleRef): MvFQModuleRef? { - check(moduleRef !is MvFQModuleRef) { "Should be handled on the upper level" } - - // module refers to ModuleImport - var resolved = resolveLocalItem(moduleRef, setOf(Namespace.MODULE)).firstOrNull() - if (resolved is MvUseAlias) { - resolved = resolved.moduleUseSpeck ?: resolved.useItem - } - if (resolved is MvUseItem && resolved.isSelf) { - return resolved.itemUseSpeck.fqModuleRef - } -// if (resolved !is MvModuleUseSpeck) return null - return (resolved as? MvModuleUseSpeck)?.fqModuleRef -// return resolved.fqModuleRef -} - -fun processQualItem( - item: MvNamedElement, - namespaces: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - val matched = when { - item is MvModule && Namespace.MODULE in namespaces - || item is MvStruct && Namespace.TYPE in namespaces - || item is MvSchema && Namespace.SCHEMA in namespaces -> - processor.match(contextScopeInfo, item) - - item is MvFunction && Namespace.FUNCTION in namespaces -> { - if (item.hasTestAttr) return false - for (vis in visibilities) { - when { - vis is Visibility.Public - && item.visibility == FunctionVisibility.PUBLIC -> processor.match( - contextScopeInfo, - item - ) - - vis is Visibility.PublicScript - && item.visibility == FunctionVisibility.PUBLIC_SCRIPT -> - processor.match(contextScopeInfo, item) - - vis is Visibility.PublicFriend && item.visibility == FunctionVisibility.PUBLIC_FRIEND -> { - val itemModule = item.module ?: return false - val currentModule = vis.currentModule.element ?: return false - if (currentModule.fqModule() in itemModule.declaredFriendModules) { - processor.match(contextScopeInfo, item) - } - } - - vis is Visibility.PublicPackage && item.visibility == FunctionVisibility.PUBLIC_PACKAGE -> { - if (!item.project.moveSettings.enablePublicPackage) { - return false - } - val itemPackage = item.containingMovePackage ?: return false - if (vis.originPackage == itemPackage) { - processor.match(contextScopeInfo, item) - } - } - - vis is Visibility.Internal -> processor.match(contextScopeInfo, item) - } - } - false - } - else -> false - } - return matched -} - -fun processModulesInFile(file: MoveFile, moduleProcessor: MatchingProcessor): Boolean { - for (module in file.modules()) { - if (moduleProcessor.match(module)) return true - } - return false -} - -fun processFQModuleRef( - fqModuleRef: MvFQModuleRef, - processor: MatchingProcessor, -) { - val moveProj = fqModuleRef.moveProject ?: return - val refAddressText = fqModuleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) - - val contextScopeInfo = ContextScopeInfo( - letStmtScope = fqModuleRef.letStmtScope, - refItemScopes = fqModuleRef.refItemScopes, - ) - val moduleProcessor = MatchingProcessor { - if (!contextScopeInfo.matches(it.element)) { - return@MatchingProcessor false - } - val entry = ScopeItem(it.name, it.element as MvModule) - val modAddressText = entry.element.address(moveProj)?.canonicalValue(moveProj) - if (modAddressText != refAddressText) - return@MatchingProcessor false - processor.match(entry) - } - - // first search modules in the current file - val currentFile = fqModuleRef.containingMoveFile ?: return - var stopped = processModulesInFile(currentFile, moduleProcessor) -// var stopped = -// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, moduleProcessor) - if (stopped) return - - moveProj.processMoveFiles { moveFile -> - // skip current file as it's processed already - if (moveFile.toNioPathOrNull() == currentFile.toNioPathOrNull()) - return@processMoveFiles true - stopped = processModulesInFile(moveFile, moduleProcessor) - // if not resolved, returns true to indicate that next file should be tried - !stopped - } -} - -fun processFQModuleRef( - moduleRef: MvFQModuleRef, - target: String, - processor: MatchingProcessor, -) { - val project = moduleRef.project - val moveProj = moduleRef.moveProject ?: return - val refAddress = moduleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) - - val contextScopeInfo = ContextScopeInfo( - letStmtScope = moduleRef.letStmtScope, - refItemScopes = moduleRef.refItemScopes, - ) - val matchModule = MatchingProcessor { - if (!contextScopeInfo.matches(it.element)) return@MatchingProcessor false - val entry = ScopeItem(it.name, it.element as MvModule) - // TODO: check belongs to the current project - val modAddress = entry.element.address(moveProj)?.canonicalValue(moveProj) - - if (modAddress != refAddress) return@MatchingProcessor false - processor.match(entry) - } - - // search modules in the current file first - val currentFile = moduleRef.containingMoveFile ?: return - val stopped = processModulesInFile(currentFile, matchModule) -// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, matchModule) - if (stopped) return - - val currentFileScope = GlobalSearchScope.fileScope(currentFile) - val searchScope = - moveProj.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) - - MvNamedElementIndex - .processElementsByName(project, target, searchScope) { - val matched = - processQualItem(it, setOf(Namespace.MODULE), Visibility.local(), contextScopeInfo, matchModule) - if (matched) return@processElementsByName false - - true - } -} +//fun resolveIntoFQModuleRefInUseSpeck(moduleRef: MvModuleRef): MvFQModuleRef? { +// check(moduleRef !is MvFQModuleRef) { "Should be handled on the upper level" } +// +// // module refers to ModuleImport +// var resolved = resolveLocalItem(moduleRef, setOf(Namespace.MODULE)).firstOrNull() +// if (resolved is MvUseAlias) { +// resolved = resolved.moduleUseSpeck ?: resolved.useItem +// } +// if (resolved is MvUseItem && resolved.isSelf) { +// return resolved.itemUseSpeck.fqModuleRef +// } +//// if (resolved !is MvModuleUseSpeck) return null +// return (resolved as? MvModuleUseSpeck)?.fqModuleRef +//// return resolved.fqModuleRef +//} + +//fun processQualItem( +// item: MvNamedElement, +// namespaces: Set, +// visibilities: Set, +// contextScopeInfo: ContextScopeInfo, +// processor: MatchingProcessor, +//): Boolean { +// val matched = when { +// item is MvModule && Namespace.MODULE in namespaces +// || item is MvStruct && Namespace.TYPE in namespaces +// || item is MvSchema && Namespace.SCHEMA in namespaces -> +// processor.match(contextScopeInfo, item) +// +// item is MvFunction && Namespace.FUNCTION in namespaces -> { +// if (item.hasTestAttr) return false +// for (vis in visibilities) { +// when { +// vis is Visibility.Public +// && item.visibility == FunctionVisibility.PUBLIC -> processor.match( +// contextScopeInfo, +// item +// ) +// +// vis is Visibility.PublicScript +// && item.visibility == FunctionVisibility.PUBLIC_SCRIPT -> +// processor.match(contextScopeInfo, item) +// +// vis is Visibility.PublicFriend && item.visibility == FunctionVisibility.PUBLIC_FRIEND -> { +// val itemModule = item.module ?: return false +// val currentModule = vis.currentModule.element ?: return false +// if (currentModule.fqModule() in itemModule.declaredFriendModules) { +// processor.match(contextScopeInfo, item) +// } +// } +// +// vis is Visibility.PublicPackage && item.visibility == FunctionVisibility.PUBLIC_PACKAGE -> { +// if (!item.project.moveSettings.enablePublicPackage) { +// return false +// } +// val itemPackage = item.containingMovePackage ?: return false +// if (vis.originPackage == itemPackage) { +// processor.match(contextScopeInfo, item) +// } +// } +// +// vis is Visibility.Internal -> processor.match(contextScopeInfo, item) +// } +// } +// false +// } +// else -> false +// } +// return matched +//} + +//fun processModulesInFile(file: MoveFile, moduleProcessor: MatchingProcessor): Boolean { +// for (module in file.modules()) { +// if (moduleProcessor.match(module)) return true +// } +// return false +//} + +//fun processFQModuleRef( +// fqModuleRef: MvFQModuleRef, +// processor: MatchingProcessor, +//) { +// val moveProj = fqModuleRef.moveProject ?: return +// val refAddressText = fqModuleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) +// +// val contextScopeInfo = ContextScopeInfo( +// letStmtScope = fqModuleRef.letStmtScope, +// refItemScopes = fqModuleRef.refItemScopes, +// ) +// val moduleProcessor = MatchingProcessor { +// if (!contextScopeInfo.matches(it.element)) { +// return@MatchingProcessor false +// } +// val entry = ScopeItem(it.name, it.element as MvModule) +// val modAddressText = entry.element.address(moveProj)?.canonicalValue(moveProj) +// if (modAddressText != refAddressText) +// return@MatchingProcessor false +// processor.match(entry) +// } +// +// // first search modules in the current file +// val currentFile = fqModuleRef.containingMoveFile ?: return +// var stopped = processModulesInFile(currentFile, moduleProcessor) +//// var stopped = +//// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, moduleProcessor) +// if (stopped) return +// +// moveProj.processMoveFiles { moveFile -> +// // skip current file as it's processed already +// if (moveFile.toNioPathOrNull() == currentFile.toNioPathOrNull()) +// return@processMoveFiles true +// stopped = processModulesInFile(moveFile, moduleProcessor) +// // if not resolved, returns true to indicate that next file should be tried +// !stopped +// } +//} + +//fun processFQModuleRef( +// moduleRef: MvFQModuleRef, +// target: String, +// processor: MatchingProcessor, +//) { +// val project = moduleRef.project +// val moveProj = moduleRef.moveProject ?: return +// val refAddress = moduleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) +// +// val contextScopeInfo = ContextScopeInfo( +// letStmtScope = moduleRef.letStmtScope, +// refItemScopes = moduleRef.refItemScopes, +// ) +// val matchModule = MatchingProcessor { +// if (!contextScopeInfo.matches(it.element)) return@MatchingProcessor false +// val entry = ScopeItem(it.name, it.element as MvModule) +// // TODO: check belongs to the current project +// val modAddress = entry.element.address(moveProj)?.canonicalValue(moveProj) +// +// if (modAddress != refAddress) return@MatchingProcessor false +// processor.match(entry) +// } +// +// // search modules in the current file first +// val currentFile = moduleRef.containingMoveFile ?: return +// val stopped = processModulesInFile(currentFile, matchModule) +//// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, matchModule) +// if (stopped) return +// +// val currentFileScope = GlobalSearchScope.fileScope(currentFile) +// val searchScope = +// moveProj.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) +// +// MvNamedElementIndex +// .processElementsByName(project, target, searchScope) { +// val matched = +// processQualItem(it, setOf(Namespace.MODULE), Visibility.local(), contextScopeInfo, matchModule) +// if (matched) return@processElementsByName false +// +// true +// } +//} fun walkUpThroughScopes( start: MvElement, diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt index d77894cd5..9b5ed81a4 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt @@ -1,30 +1,24 @@ package org.move.lang.core.resolve.ref -import org.move.lang.core.psi.MvFQModuleRef -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.resolve.processFQModuleRef -import org.move.stdext.wrapWithList +//interface MvFQModuleReference : MvPolyVariantReference -interface MvFQModuleReference : MvPolyVariantReference - -class MvFQModuleReferenceImpl( - element: MvFQModuleRef, -) : MvPolyVariantReferenceCached(element), MvFQModuleReference { - - override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE - - override fun multiResolveInner(): List { - val referenceName = element.referenceName ?: return emptyList() - var resolved: MvModule? = null - processFQModuleRef(element, referenceName) { - if (it.name == referenceName) { - resolved = it.element - true - } else { - false - } - } - return resolved.wrapWithList() - } -} +//class MvFQModuleReferenceImpl( +// element: MvFQModuleRef, +//) : MvPolyVariantReferenceCached(element), MvFQModuleReference { +// +// override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE +// +// override fun multiResolveInner(): List { +// val referenceName = element.referenceName ?: return emptyList() +// var resolved: MvModule? = null +// processFQModuleRef(element, referenceName) { +// if (it.name == referenceName) { +// resolved = it.element +// true +// } else { +// false +// } +// } +// return resolved.wrapWithList() +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt index 81eacd948..1d757ecfb 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt @@ -1,31 +1,25 @@ package org.move.lang.core.resolve.ref -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.isSelfModuleRef -import org.move.lang.core.psi.ext.itemUseSpeck -import org.move.lang.core.resolve.resolveLocalItem -import org.move.stdext.wrapWithList - -class MvModuleReferenceImpl( - element: MvModuleRef, -): MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner(): List { - if (element.isSelfModuleRef) return element.containingModule.wrapWithList() - - check(element !is MvFQModuleRef) { - "That element has different reference item" - } - - val resolved = resolveLocalItem(element, setOf(Namespace.MODULE)).firstOrNull() - if (resolved is MvUseAlias) { - return resolved.wrapWithList() - } - val moduleRef = when { - resolved is MvUseItem && resolved.text == "Self" -> resolved.itemUseSpeck.fqModuleRef - resolved is MvModuleUseSpeck -> resolved.fqModuleRef - else -> return emptyList() - } - return moduleRef?.reference?.resolve().wrapWithList() - } -} +//class MvModuleReferenceImpl( +// element: MvModuleRef, +//): MvPolyVariantReferenceCached(element) { +// +// override fun multiResolveInner(): List { +// if (element.isSelfModuleRef) return element.containingModule.wrapWithList() +// +// check(element !is MvFQModuleRef) { +// "That element has different reference item" +// } +// +// val resolved = resolveLocalItem(element, setOf(Namespace.MODULE)).firstOrNull() +// if (resolved is MvUseAlias) { +// return resolved.wrapWithList() +// } +// val moduleRef = when { +// resolved is MvUseItem && resolved.text == "Self" -> resolved.itemUseSpeck.fqModuleRef +// resolved is MvModuleUseSpeck -> resolved.fqModuleRef +// else -> return emptyList() +// } +// return moduleRef?.reference?.resolve().wrapWithList() +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt index d2926f47c..d2b4b39d5 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt @@ -1,75 +1,71 @@ package org.move.lang.core.resolve.ref -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.* - -class MvPathReferenceImpl( - element: MvPath, -): MvPolyVariantReferenceCached(element), MvPathReference { - - override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE - - override fun multiResolveInner(): List { - val ns = element.allowedNamespaces() - val vs = Visibility.visibilityScopesForElement(element) - val contextScopeInfo = - ContextScopeInfo( - refItemScopes = element.refItemScopes, - letStmtScope = element.letStmtScope, - ) - - val refName = element.referenceName ?: return emptyList() - val moduleRef = element.moduleRef - // first, see whether it's a fully qualified path (ADDRESS::MODULE::NAME) and try to resolve those - if (moduleRef is MvFQModuleRef) { - // TODO: can be replaced with index call - val module = moduleRef.reference?.resolve() as? MvModule ?: return emptyList() - return resolveModuleItem(module, refName, ns, vs, contextScopeInfo) - } - // second, - // if it's MODULE::NAME -> resolve MODULE into corresponding FQModuleRef using imports - if (moduleRef != null) { - if (moduleRef.isSelfModuleRef) { - val containingModule = moduleRef.containingModule ?: return emptyList() - return resolveModuleItem( - containingModule, - refName, - ns, - setOf(Visibility.Internal), - contextScopeInfo - ) - } - val useSpeckFQModuleRef = resolveIntoFQModuleRefInUseSpeck(moduleRef) ?: return emptyList() - val useSpeckModule = - useSpeckFQModuleRef.reference?.resolve() as? MvModule ?: return emptyList() - return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) - } else { - // if it's NAME - // special case second argument of update_field function in specs - if (element.isUpdateFieldArg2) return emptyList() - - // try local names - val item = resolveLocalItem(element, ns).firstOrNull() ?: return emptyList() - // local name -> return - return when (item) { - // item import - is MvUseItem -> { - // find corresponding FQModuleRef from imports and resolve -// // TODO: index call - val useSpeckModule = - item.itemUseSpeck.fqModuleRef.reference?.resolve() as? MvModule - ?: return emptyList() - return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) - } - // module import - is MvModuleUseSpeck -> { - val module = item.fqModuleRef?.reference?.resolve() as? MvModule - return listOfNotNull(module) - } - // local item - else -> listOf(item) - } - } - } -} +//class MvPathReferenceImpl( +// element: MvPath, +//): MvPolyVariantReferenceCached(element), MvPathReference { +// +// override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE +// +// override fun multiResolveInner(): List { +// val ns = element.allowedNamespaces() +// val vs = Visibility.visibilityScopesForElement(element) +// val contextScopeInfo = +// ContextScopeInfo( +// refItemScopes = element.refItemScopes, +// letStmtScope = element.letStmtScope, +// ) +// +// val refName = element.referenceName ?: return emptyList() +// val moduleRef = element.moduleRef +// // first, see whether it's a fully qualified path (ADDRESS::MODULE::NAME) and try to resolve those +// if (moduleRef is MvFQModuleRef) { +// // TODO: can be replaced with index call +// val module = moduleRef.reference?.resolve() as? MvModule ?: return emptyList() +// return resolveModuleItem(module, refName, ns, vs, contextScopeInfo) +// } +// // second, +// // if it's MODULE::NAME -> resolve MODULE into corresponding FQModuleRef using imports +// if (moduleRef != null) { +// if (moduleRef.isSelfModuleRef) { +// val containingModule = moduleRef.containingModule ?: return emptyList() +// return resolveModuleItem( +// containingModule, +// refName, +// ns, +// setOf(Visibility.Internal), +// contextScopeInfo +// ) +// } +// val useSpeckFQModuleRef = resolveIntoFQModuleRefInUseSpeck(moduleRef) ?: return emptyList() +// val useSpeckModule = +// useSpeckFQModuleRef.reference?.resolve() as? MvModule ?: return emptyList() +// return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) +// } else { +// // if it's NAME +// // special case second argument of update_field function in specs +// if (element.isUpdateFieldArg2) return emptyList() +// +// // try local names +// val item = resolveLocalItem(element, ns).firstOrNull() ?: return emptyList() +// // local name -> return +// return when (item) { +// // item import +// is MvUseItem -> { +// // find corresponding FQModuleRef from imports and resolve +//// // TODO: index call +// val useSpeckModule = +// item.itemUseSpeck.fqModuleRef.reference?.resolve() as? MvModule +// ?: return emptyList() +// return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) +// } +// // module import +// is MvModuleUseSpeck -> { +// val module = item.fqModuleRef?.reference?.resolve() as? MvModule +// return listOfNotNull(module) +// } +// // local item +// else -> listOf(item) +// } +// } +// } +//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt index 959ef6bd7..4e2d0f9d9 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt @@ -61,9 +61,9 @@ interface MvNameAccessChainReferenceElement : MvReferenceElement { override fun getReference(): MvPath2Reference? } -interface MvFQModuleReferenceElement : MvReferenceElement { - override fun getReference(): MvFQModuleReference? -} +//interface MvFQModuleReferenceElement : MvReferenceElement { +// override fun getReference(): MvFQModuleReference? +//} interface MvStructPatFieldReferenceElement : MvMandatoryReferenceElement diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index e75a4edd9..3db33f0d6 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -214,7 +214,7 @@ fun processItemsInScope( val module = scope.parent as MvModule processor.processAll( // contextScopeInfo, - scope.allUseItems(), +// scope.allUseItems(), module.structs() ) } @@ -238,12 +238,12 @@ fun processItemsInScope( Namespace.SCHEMA -> when (scope) { is MvModuleBlock -> processor.processAll( // contextScopeInfo, - scope.allUseItems(), +// scope.allUseItems(), scope.schemaList ) is MvModuleSpecBlock -> processor.processAll( // contextScopeInfo, - scope.allUseItems(), +// scope.allUseItems(), scope.schemaList, scope.specFunctionList ) diff --git a/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt index b13fc4ab1..0cc3dbfd7 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt @@ -6,7 +6,6 @@ import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.ext.builtinFunctions -import org.move.lang.core.resolve.ContextScopeInfo import org.move.utils.tests.MvTestBase import org.move.utils.tests.base.findElementInEditor @@ -44,7 +43,8 @@ class BuiltInFunctionLookupTest: MvTestBase() { val moduleElement = myFixture.findElementInEditor() val lookup = moduleElement.builtinFunctions().single { it.name == name }.let { - it.createLookupElement(CompletionContext(it, ContextScopeInfo.default())) + it.createLookupElement(CompletionContext(it, false)) +// it.createLookupElement(CompletionContext(it, ContextScopeInfo.default())) } checkLookupPresentation( lookup, diff --git a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt index c06a7d84c..b70d1f5c0 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt @@ -198,7 +198,8 @@ class LookupElementTest: MvTestBase() { val element = myFixture.findElementInEditor() as? MvNamedElement ?: error("Marker `^` should point to the MvNamedElement") - val completionCtx = CompletionContext(element, ContextScopeInfo.default()) + val completionCtx = CompletionContext(element, false) +// val completionCtx = CompletionContext(element, ContextScopeInfo.default()) val lookup = element.createLookupElement(completionCtx) checkLookupPresentation( lookup, diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 335dddc4d..916ab9512 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -412,7 +412,8 @@ module 0x1::string_tests { } """) - fun `test resolve module from import with unknown named address`() = checkByCode(""" + @NamedAddress("aptos_framework", "0x1") + fun `test resolve module from import with named address`() = checkByCode(""" module aptos_framework::m1 {} //X module 0x1::m { @@ -420,4 +421,12 @@ module 0x1::string_tests { //^ } """) + + fun `test cannot resolve module with unknown named address`() = checkByCode(""" + module aptos_framework::m1 {} + module 0x1::m { + use aptos_framework::m1; + //^ unresolved + } + """) } From 858fd9a4ac5b86cf2df41f341ecc067b7b8d11f2 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 18:20:26 +0300 Subject: [PATCH 24/43] correctly handle item scopes --- .../ide/inspections/imports/BasePathType.kt | 3 +++ .../utils/imports/ImportCandidateCollector.kt | 2 +- .../org/move/lang/core/psi/NamedItemScope.kt | 7 ++++++ .../move/lang/core/resolve2/ItemResolution.kt | 2 +- .../core/resolve2/LexicalDeclarations2.kt | 5 ++++- .../move/lang/core/resolve2/Visibility2.kt | 22 ++++++++++++++----- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt index ad39e4f4c..aa4d50d87 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt @@ -43,6 +43,9 @@ val MvPath.pathUsageScope: NamedItemScope if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { return NamedItemScope.TEST } + if (parentElement is MvDocAndAttributeOwner && parentElement.hasVerifyOnlyAttr) { + return NamedItemScope.VERIFY + } if (parentElement is MvFunction && parentElement.hasTestAttr) { return NamedItemScope.TEST } diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt index cd70da6cc..a9cba16dc 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt @@ -42,7 +42,7 @@ object ImportCandidateCollector { val elementNs = element.namespace if (elementNs !in namespaces) return@processElementsByName true val visibilityFilter = - (element as? MvItemElement)?.visInfo?.createFilter() ?: VisibilityFilter { _, _ -> Visible } + (element as? MvItemElement)?.visInfo()?.createFilter() ?: VisibilityFilter { _, _ -> Visible } val visibilityStatus = visibilityFilter.filter(pathElement, namespaces) if (visibilityStatus != Visible) return@processElementsByName true diff --git a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt index e7b3be545..60b8bef2f 100644 --- a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt +++ b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt @@ -13,6 +13,13 @@ enum class NamedItemScope { val isTest get() = this == TEST + fun shrinkScope(adjustmentScope: NamedItemScope): NamedItemScope { + if (this == MAIN) { + return adjustmentScope + } + return this + } + companion object { fun all(): Set = setOf(MAIN, TEST, VERIFY) } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 79f8d3a3e..3000e8d35 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -48,7 +48,7 @@ fun processItemDeclarations( val namespace = item.namespace if (namespace !in ns) continue - val visibilityFilter = item.visInfo.createFilter() + val visibilityFilter = item.visInfo().createFilter() if (processor.process(name, item, EnumSet.of(namespace), visibilityFilter)) return true } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 3db33f0d6..a2a083044 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -1,6 +1,7 @@ package org.move.lang.core.resolve2 import com.intellij.psi.util.PsiTreeUtil +import org.move.ide.inspections.imports.pathUsageScope import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* @@ -293,8 +294,10 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val element = alias ?: namedElement val namespace = namedElement.namespace + val importUsageScope = path.pathUsageScope val visibilityFilter = - (namedElement as? MvItemElement)?.visInfo?.createFilter() ?: VisibilityFilter { _, _ -> Visible } + (namedElement as? MvItemElement)?.visInfo(adjustmentScope = importUsageScope)?.createFilter() + ?: VisibilityFilter { _, _ -> Visible } if (namespace in ns && processor.process(name, element, ns, visibilityFilter)) { stop = true diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 6413dca15..852918a2c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -4,27 +4,32 @@ import org.move.cli.containingMovePackage import org.move.cli.settings.moveSettings import org.move.ide.inspections.imports.pathUsageScope import org.move.lang.core.psi.* +import org.move.lang.core.psi.NamedItemScope.MAIN import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ModInfo import org.move.lang.core.resolve.VisibilityFilter import org.move.lang.core.resolve.VisibilityStatus.Invisible import org.move.lang.core.resolve.VisibilityStatus.Visible -import org.move.lang.core.resolve.ref.Namespace.* +import org.move.lang.core.resolve.ref.Namespace.NAME +import org.move.lang.core.resolve.ref.Namespace.TYPE import org.move.lang.core.resolve.ref.Visibility2 import org.move.lang.core.resolve.ref.Visibility2.* data class ItemVisibilityInfo( val item: MvItemElement, - val isTestOnly: Boolean, + val usageScope: NamedItemScope, val vis: Visibility2, ) -val MvItemElement.visInfo: ItemVisibilityInfo get() = - ItemVisibilityInfo(this, isTestOnly = this.hasTestOnlyAttr, vis = this.visibility2) +fun MvItemElement.visInfo(adjustmentScope: NamedItemScope = MAIN): ItemVisibilityInfo { + // todo: can be lazy + val itemUsageScope = this.itemScope.shrinkScope(adjustmentScope) + return ItemVisibilityInfo(this, usageScope = itemUsageScope, vis = this.visibility2) +} /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { - val (item, isTestOnly, visibility) = this + val (item, itemUsageScope, visibility) = this return VisibilityFilter { path, namespaces -> // inside msl everything is visible @@ -38,6 +43,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { if (attrItem != null) return@VisibilityFilter Visible val pathUsageScope = path.pathUsageScope + val useSpeck = path.useSpeck if (useSpeck != null) { // inside import, all visibilities except for private work @@ -54,7 +60,11 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { if (item is MvFunction && item.hasTestAttr) return@VisibilityFilter Invisible // #[test_only] items in non-test-only scope - if (isTestOnly && !pathUsageScope.isTest) return@VisibilityFilter Invisible + if (itemUsageScope != MAIN) { + // cannot be used everywhere, need to check for scope compatibility + if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible + } +// if (isTestOnly && !pathUsageScope.isTest) return@VisibilityFilter Invisible // Self::method val itemModule = item.containingModule From 916731b02e64c990bc9afb3e8bd24196553ab847 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 19:28:00 +0300 Subject: [PATCH 25/43] attempt to remove ContextScopeInfo filter --- .../utils/imports/ImportCandidateCollector.kt | 3 +- .../org/move/lang/core/psi/ext/MvElement.kt | 2 +- .../org/move/lang/core/resolve/Processors.kt | 2 + .../core/resolve2/LexicalDeclarations2.kt | 72 ++----------------- .../lang/core/resolve2/NameResolution2.kt | 27 +++---- .../move/lang/core/resolve2/Visibility2.kt | 23 +++--- .../core/resolve2/ref/Path2ReferenceImpl.kt | 1 + .../move/lang/resolve/ResolveFunctionTest.kt | 31 +++++++- 8 files changed, 64 insertions(+), 97 deletions(-) diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt index a9cba16dc..7696cc8b4 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt @@ -41,8 +41,7 @@ object ImportCandidateCollector { .processElementsByName(project, targetName, searchScope) { element -> val elementNs = element.namespace if (elementNs !in namespaces) return@processElementsByName true - val visibilityFilter = - (element as? MvItemElement)?.visInfo()?.createFilter() ?: VisibilityFilter { _, _ -> Visible } + val visibilityFilter = element.visInfo().createFilter() val visibilityStatus = visibilityFilter.filter(pathElement, namespaces) if (visibilityStatus != Visible) return@processElementsByName true 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 9a7241946..0210741e4 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 @@ -31,7 +31,7 @@ val MvNamedElement.isMslOnlyItem: Boolean var element: PsiElement? = this while (element != null) { // use items always non-msl, otherwise import resolution doesn't work correctly - if (element is MvUseItem) return false +// if (element is MvUseItem) return false // module items if (element is MvModule diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 1a65b9ec3..fba0ee2e8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -8,8 +8,10 @@ import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvPath import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.createFilter import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.ref.RsPathResolveResult +import org.move.lang.core.resolve2.visInfo import org.move.stdext.intersects /** diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index a2a083044..60c865cf8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -3,10 +3,10 @@ package org.move.lang.core.resolve2 import com.intellij.psi.util.PsiTreeUtil import org.move.ide.inspections.imports.pathUsageScope import org.move.lang.core.psi.* +import org.move.lang.core.psi.NamedItemScope.MAIN import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.* -import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.util.forEachLeafSpeck @@ -20,32 +20,11 @@ fun processItemsInScope( ): Boolean { for (namespace in namespaces) { val stop = when (namespace) { - Namespace.CONST -> { - false -// val found = when (scope) { -// is MvModuleBlock -> { -// val module = scope.parent as MvModule -// processor.processAll( -//// contextScopeInfo, -// module.consts(), -// ) -// } -// else -> false -// } -//// if (!found) { -//// if (scope is MvItemsOwner) { -//// if (processor.processAll(scope.allUseItems())) return true -//// } -//// } -// found - } - Namespace.NAME -> { val found = when (scope) { is MvModuleBlock -> { val module = scope.parent as MvModule processor.processAll( -// contextScopeInfo, module.structs(), module.consts(), ) @@ -130,15 +109,10 @@ fun processItemsInScope( } !isVisited } -// val processorWithShadowing = MatchingProcessor { entry -> -// ((entry.name !in visited) -// && processor.process(entry).also { visited += entry.name }) -// } var found = shadowingProcessor.processAll(namedElements) if (!found && scope is MvSpecCodeBlock) { // if inside SpecCodeBlock, process also with builtin spec consts and global variables found = shadowingProcessor.processAll( -// contextScopeInfo, scope.builtinSpecConsts(), scope.globalVariables() ) @@ -147,11 +121,6 @@ fun processItemsInScope( } else -> false } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (scope.processUseSpeckElements(namespaces, processor)) return true -// } -// } found } Namespace.FUNCTION -> { @@ -172,7 +141,6 @@ fun processItemsInScope( val specFunctions = scope.specFunctionList val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } processor.processAll( -// contextScopeInfo, specFunctions, specInlineFunctions ) @@ -192,9 +160,6 @@ fun processItemsInScope( } else -> false } -// if (!found) { -// -// } found } @@ -213,11 +178,7 @@ fun processItemsInScope( } is MvModuleBlock -> { val module = scope.parent as MvModule - processor.processAll( -// contextScopeInfo, -// scope.allUseItems(), - module.structs() - ) + processor.processAll(module.structs()) } is MvApplySchemaStmt -> { val toPatterns = scope.applyTo?.functionPatternList.orEmpty() @@ -228,35 +189,15 @@ fun processItemsInScope( else -> false } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (scope.processUseSpeckElements(namespaces, processor)) return true -// } -// } found } Namespace.SCHEMA -> when (scope) { - is MvModuleBlock -> processor.processAll( -// contextScopeInfo, -// scope.allUseItems(), - scope.schemaList - ) - is MvModuleSpecBlock -> processor.processAll( -// contextScopeInfo, -// scope.allUseItems(), - scope.schemaList, - scope.specFunctionList - ) - else -> false - } - - Namespace.MODULE -> when (scope) { - is MvItemsOwner -> - processor.processAll(emptyList()) -// processor.processAll(scope.moduleUseItems()) + is MvModuleBlock -> processor.processAll(scope.schemaList) + is MvModuleSpecBlock -> processor.processAll(scope.schemaList, scope.specFunctionList) else -> false } + else -> false } if (stop) return true } @@ -296,8 +237,7 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val namespace = namedElement.namespace val importUsageScope = path.pathUsageScope val visibilityFilter = - (namedElement as? MvItemElement)?.visInfo(adjustmentScope = importUsageScope)?.createFilter() - ?: VisibilityFilter { _, _ -> Visible } + namedElement.visInfo(adjustmentScope = importUsageScope).createFilter() if (namespace in ns && processor.process(name, element, ns, visibilityFilter)) { stop = true diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index d12461c96..519a696b4 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -5,10 +5,12 @@ import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve.ref.Namespace.MODULE import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.types.Address import org.move.lang.core.types.address import org.move.lang.index.MvNamedElementIndex +import java.util.EnumSet fun processNestedScopesUpwards( scopeStart: MvElement, @@ -38,29 +40,22 @@ fun processModulePathResolveVariants( // if no project, cannot use the index if (moveProject == null) return false - val equalAddressProcessor = processor.wrapWithFilter { e -> + val project = element.project + val searchScope = moveProject.searchScope() + + val addressProcessor = processor.wrapWithFilter { e -> val candidate = e.element as? MvModule ?: return@wrapWithFilter false val candidateAddress = candidate.address(moveProject) address == candidateAddress } - // search modules in the current file first -// val currentFile = element.containingMoveFile ?: return false -// for (module in currentFile.modules()) { -// if (equalAddressProcessor.process(module)) return true -// } - - val project = element.project -// val currentFileScope = GlobalSearchScope.fileScope(currentFile) -// val searchScope = -// moveProject.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) - val searchScope = moveProject.searchScope() - var stop = false - for (name in processor.names.orEmpty()) { + for (targetModuleName in processor.names.orEmpty()) { MvNamedElementIndex - .processElementsByName(project, name, searchScope) { - stop = equalAddressProcessor.process(it) + .processElementsByName(project, targetModuleName, searchScope) { + val module = it + val visFilter = module.visInfo().createFilter() + stop = addressProcessor.process(targetModuleName, module, setOf(MODULE), visFilter) // true to continue processing, if .process does not find anything, it returns false !stop } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 852918a2c..cc30fe9ab 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -16,15 +16,16 @@ import org.move.lang.core.resolve.ref.Visibility2 import org.move.lang.core.resolve.ref.Visibility2.* data class ItemVisibilityInfo( - val item: MvItemElement, + val item: MvNamedElement, val usageScope: NamedItemScope, val vis: Visibility2, ) -fun MvItemElement.visInfo(adjustmentScope: NamedItemScope = MAIN): ItemVisibilityInfo { +fun MvNamedElement.visInfo(adjustmentScope: NamedItemScope = MAIN): ItemVisibilityInfo { // todo: can be lazy val itemUsageScope = this.itemScope.shrinkScope(adjustmentScope) - return ItemVisibilityInfo(this, usageScope = itemUsageScope, vis = this.visibility2) + val visibility = (this as? MvVisibilityOwner)?.visibility2 ?: Public + return ItemVisibilityInfo(this, usageScope = itemUsageScope, vis = visibility) } /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ @@ -59,14 +60,18 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // #[test] functions cannot be used from non-imports if (item is MvFunction && item.hasTestAttr) return@VisibilityFilter Invisible + // todo: uncomment when ContextScopeInfo filter is removed // #[test_only] items in non-test-only scope - if (itemUsageScope != MAIN) { - // cannot be used everywhere, need to check for scope compatibility - if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible - } -// if (isTestOnly && !pathUsageScope.isTest) return@VisibilityFilter Invisible +// if (itemUsageScope != MAIN) { +// // cannot be used everywhere, need to check for scope compatibility +// if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible +// } + + // todo: uncomment when ContextScopeInfo filter is removed + // we're in non-msl scope at this point, msl only items aren't available +// if (item !is MvModule && item is MslOnlyElement) return@VisibilityFilter Invisible - // Self::method + // local methods, Self::method - everything is visible val itemModule = item.containingModule val pathModule = path.containingModule if (itemModule == pathModule) return@VisibilityFilter Visible diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index b987fc534..1547b70f7 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -63,6 +63,7 @@ fun processPathResolveVariants( processor: RsResolveProcessor ): Boolean { val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) +// val contextProcessor = processor return when (pathKind) { is NamedAddress, is ValueAddress -> false is PathKind.UnqualifiedPath -> { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index cfa1b3427..8a785f560 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -496,9 +496,9 @@ class ResolveFunctionTest: ResolveTestCase() { } module 0x1::M2 { use 0x1::M1; - //^ unresolved fun call() { M1::call(); + //^ unresolved } } """ @@ -861,7 +861,7 @@ module 0x1::mod { """ ) - fun `test verify_only not accessible in the regular code`() = checkByCode( + fun `test verify_only not accessible in the regular code for local functions`() = checkByCode( """ module 0x1::m { #[verify_only] @@ -870,10 +870,35 @@ module 0x1::mod { let _ = call(); //^ unresolved } - } + } """ ) + fun `test test_only not accessible in the regular code for local functions`() = checkByCode( + """ + module 0x1::m { + #[test_only] + fun call(): u8 { 1 } + fun main() { + let _ = call(); + //^ unresolved + } + } + """ + ) + +// fun `test entry function not accessible from non-entry code`() = checkByCode( +// """ +// module 0x1::m { +// public(script) fun call() { 1 } +// fun main() { +// let _ = call(); +// //^ unresolved +// } +// } +// """ +// ) + fun `test resolve local test-only import into test-only item`() = checkByCode( """ module 0x1::m { From 7812f689280fe8df70ddf608e8fba308dddeba0e Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 18 Jul 2024 23:45:32 +0300 Subject: [PATCH 26/43] fix use speck two element named address path kind --- .../cli/settings/MvProjectSettingsService.kt | 6 ++++++ .../org/move/ide/inspections/imports/UseItem.kt | 16 +++------------- .../org/move/lang/core/resolve2/PathKind.kt | 12 ++++++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt b/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt index 5f3e18bf2..5a6da2c89 100644 --- a/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt +++ b/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt @@ -127,6 +127,12 @@ fun Path?.isValidExecutable(): Boolean { fun isDebugModeEnabled(): Boolean = Registry.`is`("org.move.debug.enabled") +fun debugError(message: String) { + if (isDebugModeEnabled()) { + error(message) + } +} + fun debugErrorOrFallback(message: String, fallback: T): T { if (isDebugModeEnabled()) { error(message) diff --git a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt index 50a3c474e..cada14411 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt @@ -1,5 +1,7 @@ package org.move.ide.inspections.imports +import org.move.cli.settings.debugError +import org.move.cli.settings.debugErrorOrFallback import org.move.ide.inspections.imports.UseItemType.* import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt @@ -34,11 +36,8 @@ val MvUseStmt.useItems: List when (pathKind) { is PathKind.QualifiedPath.Module -> items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) -// is ModulePath -> { -// items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) -// } is PathKind.QualifiedPath.ModuleItem -> { - // cannot be + debugError("not reachable, must be a bug") return@forEachLeafSpeck false } is PathKind.QualifiedPath -> { @@ -50,15 +49,6 @@ val MvUseStmt.useItems: List items.add(UseItem(useSpeck, nameOrAlias, ITEM, stmtItemScope)) } } -// is QualifiedPath -> { -// if (kind.path.referenceName == "Self") { -// val moduleName = -// useAlias?.name ?: kind.qualifier.referenceName ?: return@forEachLeafSpeck false -// items.add(UseItem(useSpeck, moduleName, SELF_MODULE, stmtItemScope)) -// } else { -// items.add(UseItem(useSpeck, nameOrAlias, ITEM, stmtItemScope)) -// } -// } else -> return@forEachLeafSpeck false } false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt index 2843b95fa..942274f87 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt @@ -6,6 +6,7 @@ import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.allowedNamespaces import org.move.lang.core.psi.ext.ancestorStrict +import org.move.lang.core.psi.ext.isUseSpeck import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.types.Address import org.move.lang.moveProject @@ -101,12 +102,15 @@ fun MvPath.pathKind(overwriteNs: Set? = null): PathKind { // known named address, can be module path return PathKind.QualifiedPath.Module(this, qualifierPath, ns, namedAddress) } - } - else -> { - // module::name - return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) + if (this.isUseSpeck) { + // use std::main where std is the unknown named address + val address = Address.Named(qualifierItemName, null, moveProject) + return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) + } } } + // module::name + return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) } // three-element path From 3fd65fed175258de18216fd83cf45f04a6755b73 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 01:00:03 +0300 Subject: [PATCH 27/43] remove address by value inspection --- .../AddressByValueImportInspection.kt | 42 ----- src/main/resources/META-INF/plugin.xml | 10 +- .../AddressByValueImportInspectionTest.kt | 160 ------------------ 3 files changed, 3 insertions(+), 209 deletions(-) delete mode 100644 src/main/kotlin/org/move/ide/inspections/AddressByValueImportInspection.kt delete mode 100644 src/test/kotlin/org/move/ide/inspections/AddressByValueImportInspectionTest.kt diff --git a/src/main/kotlin/org/move/ide/inspections/AddressByValueImportInspection.kt b/src/main/kotlin/org/move/ide/inspections/AddressByValueImportInspection.kt deleted file mode 100644 index 33bf76429..000000000 --- a/src/main/kotlin/org/move/ide/inspections/AddressByValueImportInspection.kt +++ /dev/null @@ -1,42 +0,0 @@ -package org.move.ide.inspections - -import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.codeInspection.ProblemsHolder -import org.move.cli.Consts -import org.move.ide.inspections.fixes.ChangeAddressNameFix -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvModuleUseSpeck -import org.move.lang.core.psi.MvVisitor -import org.move.lang.core.types.Address -import org.move.lang.core.types.address -import org.move.lang.moveProject - -class AddressByValueImportInspection : MvLocalInspectionTool() { - override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): MvVisitor = - object : MvVisitor() { - override fun visitModuleUseSpeck(o: MvModuleUseSpeck) { - val moduleRef = o.fqModuleRef ?: return - // no error if unresolved by value (default) - val module = moduleRef.reference?.resolve() as? MvModule ?: return - - val moveProj = moduleRef.moveProject ?: return - - val refAddress = moduleRef.addressRef.address(moveProj) ?: return - if (refAddress !is Address.Named) return - if (refAddress.addressLit(moveProj)?.canonical() == Consts.ADDR_PLACEHOLDER) return - - val modAddress = module.address(moveProj) ?: return - if (modAddress !is Address.Named) return - if (modAddress.addressLit(moveProj)?.canonical() == Consts.ADDR_PLACEHOLDER) return - - if (!Address.eq(refAddress, modAddress)) { - holder.registerProblem( - moduleRef, - "Module is declared with a different address `${modAddress.name}`", - ProblemHighlightType.WEAK_WARNING, - ChangeAddressNameFix(moduleRef, modAddress.name), - ) - } - } - } -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 71a26638d..30e987fcb 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -46,9 +46,9 @@ - + @@ -276,10 +276,6 @@ displayName="Unused test signer" enabledByDefault="true" level="WARNING" implementationClass="org.move.ide.inspections.UnusedTestSignerInspection" /> - aptos_std::debug/*caret*/; - fun main() { - debug::print(); - } - } - """ - ) - move( - "debug.move", """ - module std::debug { - public native fun print(); - } - """ - ) - } - }, """ - module aptos_std::main { - use std::debug; - fun main() { - debug::print(); - } - } - """, checkWeakWarn = true - ) -} From c207e5968c327d35aa2f8a1f7ef7a789b8cbd8e4 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 01:29:20 +0300 Subject: [PATCH 28/43] remove old code --- src/main/grammars/MoveParser.bnf | 76 +-------- src/main/kotlin/org/move/cli/MoveProject.kt | 2 +- .../move/cli}/tests/NamedAddressService.kt | 7 +- .../inspections/fixes/ChangeAddressNameFix.kt | 37 ----- .../move/ide/refactoring/MvImportOptimizer.kt | 157 +++++++++--------- .../move/ide/search/MvUsageTypeProvider.kt | 6 +- .../move/ide/utils/imports/UseStmtWrapper.kt | 2 - .../providers/ModulesCompletionProvider.kt | 24 --- .../org/move/lang/core/psi/MvPsiFactory.kt | 31 ---- .../org/move/lang/core/psi/ext/MvElement.kt | 4 +- .../move/lang/core/psi/ext/MvItemUseSpeck.kt | 6 - .../move/lang/core/psi/ext/MvItemsOwner.kt | 62 ++----- .../lang/core/psi/ext/MvModuleUseSpeck.kt | 22 --- .../org/move/lang/core/psi/ext/MvPath.kt | 2 - .../org/move/lang/core/psi/ext/MvUseAlias.kt | 10 +- .../org/move/lang/core/psi/ext/MvUseItem.kt | 30 ---- .../move/lang/core/psi/ext/MvUseItemGroup.kt | 5 - .../org/move/lang/core/psi/ext/MvUseStmt.kt | 152 +++++++++-------- .../org/move/ide/search/FindUsagesTest.kt | 8 + .../kotlin/org/move/utils/tests/MvTestBase.kt | 2 + 20 files changed, 191 insertions(+), 454 deletions(-) rename src/{test/kotlin/org/move/utils => main/kotlin/org/move/cli}/tests/NamedAddressService.kt (89%) delete mode 100644 src/main/kotlin/org/move/ide/inspections/fixes/ChangeAddressNameFix.kt delete mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvItemUseSpeck.kt delete mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvModuleUseSpeck.kt diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 5942e39e4..967f590bf 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -519,11 +519,6 @@ FriendDecl ::= Attr* friend PathImpl ';' implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] } -UseStmt2 ::= Attr* use (ItemUseSpeck | ModuleUseSpeck) ';' { - pin = "use" - implements = [ "org.move.lang.core.psi.ext.MvDocAndAttributeOwner" ] -} - UseStmt ::= Attr* use UseSpeck ';' { pin = "use" extends = Stmt @@ -544,43 +539,6 @@ private UseSpeck_with_recover ::= !'}' UseSpeck (','|&'}') { } private UseSpeck_recover ::= !('}' | '{' | IDENTIFIER | '::' ) -ModuleUseSpeck ::= (AddressRef !'::') | FQModuleRef UseAlias? -{ - name = "qual path to module" - implements = [ - "org.move.lang.core.psi.MvNamedElement" -// "org.move.lang.core.psi.MvUseSpeck" - ] - mixin = "org.move.lang.core.psi.ext.MvModuleUseSpeckMixin" -} -ItemUseSpeck ::= FQModuleRef '::' (UseItem | UseItemGroup) -{ - pin = 2 - name = "qual path to imported item" -// implements = [ -// "org.move.lang.core.psi.MvUseSpeck" -// ] -} - -UseItemGroup ::= '{' <>? '}' -{ - pin = 1 -} -private MultiItemUse_member_with_recovery ::= !('}' | ';' | <>) UseItem -{ - pin = 1 -} - -UseItem ::= IDENTIFIER UseAlias? -{ - pin = 1 - name = "item name" -// implements = [ -// "org.move.lang.core.psi.MvNamedElement" -// "org.move.lang.core.resolve.ref.MvMandatoryReferenceElement" -// ] -// mixin = "org.move.lang.core.psi.ext.MvUseItemMixin" -} UseAlias ::= as IDENTIFIER { pin = 1 @@ -1111,34 +1069,18 @@ PathAddress ::= DIEM_ADDRESS | BECH32_ADDRESS | POLKADOT_ADDRESS -private LocalPathIdent ::= PATH_MODE_IDENTIFIER -private ModulePathIdent ::= ModuleRef ('::' !(PATH_MODE_IDENTIFIER '::')) PATH_MODE_IDENTIFIER -{ - pin = 2 -} -private FQModulePathIdent ::= FQModuleRef '::' PATH_MODE_IDENTIFIER -{ - pin = 1 -} +//private LocalPathIdent ::= PATH_MODE_IDENTIFIER +//private ModulePathIdent ::= ModuleRef ('::' !(PATH_MODE_IDENTIFIER '::')) PATH_MODE_IDENTIFIER +//{ +// pin = 2 +//} +//private FQModulePathIdent ::= FQModuleRef '::' PATH_MODE_IDENTIFIER +//{ +// pin = 1 +//} private PATH_MODE_IDENTIFIER ::= (<> IDENTIFIER) | (<> ('*' | IDENTIFIER)) -ModuleRef ::= PATH_MODE_IDENTIFIER | FQModuleRef -{ -// implements = ["org.move.lang.core.resolve.ref.MvReferenceElement"] -// mixin = "org.move.lang.core.psi.ext.MvModuleRefMixin" -} - -FQModuleRef ::= AddressRef '::' PATH_MODE_IDENTIFIER -{ - pin = 2 - extends = ModuleRef -// implements = [ -// "org.move.lang.core.resolve.ref.MvFQModuleReferenceElement" -// ] -// mixin = "org.move.lang.core.psi.ext.MvFQModuleRefMixin" -} - AddressRef ::= NamedAddress | DIEM_ADDRESS | INTEGER_LITERAL diff --git a/src/main/kotlin/org/move/cli/MoveProject.kt b/src/main/kotlin/org/move/cli/MoveProject.kt index 2cb0098c4..61fafdc11 100644 --- a/src/main/kotlin/org/move/cli/MoveProject.kt +++ b/src/main/kotlin/org/move/cli/MoveProject.kt @@ -14,6 +14,7 @@ import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker import org.move.cli.manifest.AptosConfigYaml import org.move.cli.manifest.MoveToml +import org.move.cli.tests.NamedAddressService import org.move.lang.MoveFile import org.move.lang.core.psi.MvModule import org.move.lang.core.types.Address @@ -27,7 +28,6 @@ import org.move.openapiext.contentRoots import org.move.stdext.chain import org.move.stdext.iterateMoveVirtualFiles import org.move.stdext.wrapWithList -import org.move.utils.tests.NamedAddressService import org.toml.lang.TomlLanguage import org.toml.lang.psi.TomlFile import java.nio.file.Path diff --git a/src/test/kotlin/org/move/utils/tests/NamedAddressService.kt b/src/main/kotlin/org/move/cli/tests/NamedAddressService.kt similarity index 89% rename from src/test/kotlin/org/move/utils/tests/NamedAddressService.kt rename to src/main/kotlin/org/move/cli/tests/NamedAddressService.kt index 2bb7a9f18..8725dcf25 100644 --- a/src/test/kotlin/org/move/utils/tests/NamedAddressService.kt +++ b/src/main/kotlin/org/move/cli/tests/NamedAddressService.kt @@ -1,17 +1,18 @@ -package org.move.utils.tests +package org.move.cli.tests import org.move.cli.MoveProject import org.move.lang.core.types.Address import org.move.lang.core.types.Address.Named interface NamedAddressService { - fun getNamedAddress(moveProject: MoveProject, name: String): Named? + fun getNamedAddress(moveProject: MoveProject, name: String): Address.Named? } class NamedAddressServiceImpl: NamedAddressService { - override fun getNamedAddress(moveProject: MoveProject, name: String): Named? = null + override fun getNamedAddress(moveProject: MoveProject, name: String): Address.Named? = null } + class NamedAddressServiceTestImpl: NamedAddressService { val namedAddresses: MutableMap = mutableMapOf() diff --git a/src/main/kotlin/org/move/ide/inspections/fixes/ChangeAddressNameFix.kt b/src/main/kotlin/org/move/ide/inspections/fixes/ChangeAddressNameFix.kt deleted file mode 100644 index 3a9f70732..000000000 --- a/src/main/kotlin/org/move/ide/inspections/fixes/ChangeAddressNameFix.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.move.ide.inspections.fixes - -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFile -import org.move.ide.inspections.DiagnosticFix -import org.move.lang.core.psi.MvFQModuleRef -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.psiFactory -import org.move.lang.core.types.address -import org.move.lang.moveProject - -class ChangeAddressNameFix( - moduleRef: MvFQModuleRef, - val newAddressRefName: String -) : DiagnosticFix(moduleRef) { - - override fun getText(): String = "Change address to `$newAddressRefName`" - override fun getFamilyName(): String = "Change address ref" - - override fun stillApplicable(project: Project, file: PsiFile, element: MvFQModuleRef): Boolean { - return element.addressRef.namedAddress?.referenceName != newAddressRefName - } - - override fun invoke(project: Project, file: PsiFile, element: MvFQModuleRef) { - val ref = element - - // resolve by value - val mod = ref.reference?.resolve() as? MvModule ?: return - val proj = mod.moveProject ?: return - - val modAddressRef = mod.addressRef ?: return - if (ref.addressRef.address(proj) != mod.address(proj)) { - val newAddressRef = project.psiFactory.addressRef(modAddressRef.text) - ref.addressRef.replace(newAddressRef) - } - } -} diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index d20941e98..a6ad6d978 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -28,7 +28,6 @@ class MvImportOptimizer : ImportOptimizer { val holder = ProblemsHolder(InspectionManager.getInstance(file.project), file, false) val importVisitor = ImportAnalyzer2(holder) -// val importVisitor = ImportAnalyzer(holder) object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { if (element is MvItemsOwner) { @@ -78,91 +77,89 @@ class MvImportOptimizer : ImportOptimizer { } } - private fun mergeItemGroups(useStmtOwner: MvItemsOwner) { - val psiFactory = useStmtOwner.project.psiFactory - val leftBrace = useStmtOwner.findFirstChildByType(L_BRACE) ?: return - - val useStmts = useStmtOwner.useStmtList - useStmts - .groupBy { Pair(it.fqModuleText, it.hasTestOnlyAttr) } - .forEach { (key, stmts) -> - val (fqModuleText, isTestOnly) = key - if (fqModuleText == null) return@forEach - - // special case: if single stmt and import like `use 0x1::Main::Self;`, change to `0x1::Main` -// if (stmts.size == 1) { -// val stmt = stmts.single() -// val useItem = stmt.childUseItems.singleOrNull()?.takeIf { it.text == "Self" } -// if (useItem != null) { -// val newStmt = psiFactory.useStmt(fqModuleText, isTestOnly) -// stmt.replace(newStmt) -// } -// return@forEach +// private fun mergeItemGroups(useStmtOwner: MvItemsOwner) { +// val psiFactory = useStmtOwner.project.psiFactory +// val leftBrace = useStmtOwner.findFirstChildByType(L_BRACE) ?: return +// +// val useStmts = useStmtOwner.useStmtList +// useStmts +// .groupBy { Pair(it.fqModuleText, it.hasTestOnlyAttr) } +// .forEach { (key, stmts) -> +// val (fqModuleText, isTestOnly) = key +// if (fqModuleText == null) return@forEach +// +// // special case: if single stmt and import like `use 0x1::Main::Self;`, change to `0x1::Main` +//// if (stmts.size == 1) { +//// val stmt = stmts.single() +//// val useItem = stmt.childUseItems.singleOrNull()?.takeIf { it.text == "Self" } +//// if (useItem != null) { +//// val newStmt = psiFactory.useStmt(fqModuleText, isTestOnly) +//// stmt.replace(newStmt) +//// } +//// return@forEach +//// } +// +// val useItemNames = mutableListOf() +// if (stmts.any { it.moduleUseSpeck != null }) { +// useItemNames.add("Self") // } - - val useItemNames = mutableListOf() - if (stmts.any { it.moduleUseSpeck != null }) { - useItemNames.add("Self") - } - useItemNames.addAll(stmts.flatMap { it.childUseItems }.map { it.text }) - val newStmt = - psiFactory.useStmt( - "$fqModuleText::{${useItemNames.joinToString(", ")}}", - isTestOnly - ) - useStmtOwner.addAfter(newStmt, leftBrace) - stmts.forEach { it.delete() } - } - } - - companion object { - private fun MvUseGroup.sortUseSpecks() { - val sortedList = useSpeckList - .sortedWith(COMPARATOR_FOR_ITEMS_IN_USE_GROUP) - .map { it.copy() } - useSpeckList.zip(sortedList).forEach { it.first.replace(it.second) } +// useItemNames.addAll(stmts.flatMap { it.childUseItems }.map { it.text }) +// val newStmt = +// psiFactory.useStmt( +// "$fqModuleText::{${useItemNames.joinToString(", ")}}", +// isTestOnly +// ) +// useStmtOwner.addAfter(newStmt, leftBrace) +// stmts.forEach { it.delete() } +// } +// } + + /** Returns true if successfully removed, e.g. `use aaa::{bbb};` -> `use aaa::bbb;` */ + private fun removeCurlyBracesIfPossible(rootUseSpeck: MvUseSpeck, psiFactory: MvPsiFactory) { + val itemUseSpeck = rootUseSpeck.useGroup?.asTrivial ?: return + + val newUseSpeck = psiFactory.useSpeck("0x1::dummy::call") + val newUseSpeckPath = newUseSpeck.path + newUseSpeckPath.path?.replace(rootUseSpeck.path) + itemUseSpeck.path.identifier?.let { newUseSpeckPath.identifier?.replace(it) } + + val useAlias = itemUseSpeck.useAlias + if (useAlias != null) { + newUseSpeck.add(useAlias) } - /** Returns true if successfully removed, e.g. `use aaa::{bbb};` -> `use aaa::bbb;` */ - private fun removeCurlyBracesIfPossible(rootUseSpeck: MvUseSpeck, psiFactory: MvPsiFactory) { - val itemUseSpeck = rootUseSpeck.useGroup?.asTrivial ?: return - - val newUseSpeck = psiFactory.useSpeck("0x1::dummy::call") - val newUseSpeckPath = newUseSpeck.path - newUseSpeckPath.path?.replace(rootUseSpeck.path) - itemUseSpeck.path.identifier?.let { newUseSpeckPath.identifier?.replace(it) } - - val useAlias = itemUseSpeck.useAlias - if (useAlias != null) { - newUseSpeck.add(useAlias) - } - - rootUseSpeck.replace(newUseSpeck) - } + rootUseSpeck.replace(newUseSpeck) + } - private fun reorderUseStmtsIntoGroups(useScope: MvItemsOwner) { - val useStmts = useScope.useStmtList - val first = useScope.childrenOfType() - .firstOrNull { it !is MvAttr && it !is PsiComment } ?: return - val psiFactory = useScope.project.psiFactory - val sortedUses = useStmts - .asSequence() - .map { UseStmtWrapper(it) } - .sorted() - for ((useWrapper, nextUseWrapper) in sortedUses.withNext()) { - val addedUseItem = useScope.addBefore(useWrapper.useStmt, first) - useScope.addAfter(psiFactory.createNewline(), addedUseItem) - val addNewLine = - useWrapper.packageGroupLevel != nextUseWrapper?.packageGroupLevel + private fun reorderUseStmtsIntoGroups(useScope: MvItemsOwner) { + val useStmts = useScope.useStmtList + val first = useScope.childrenOfType() + .firstOrNull { it !is MvAttr && it !is PsiComment } ?: return + val psiFactory = useScope.project.psiFactory + val sortedUses = useStmts + .asSequence() + .map { UseStmtWrapper(it) } + .sorted() + for ((useWrapper, nextUseWrapper) in sortedUses.withNext()) { + val addedUseItem = useScope.addBefore(useWrapper.useStmt, first) + useScope.addAfter(psiFactory.createNewline(), addedUseItem) + val addNewLine = + useWrapper.packageGroupLevel != nextUseWrapper?.packageGroupLevel // && (nextUseWrapper != null || useScope is MvModuleBlock) - if (addNewLine) { - useScope.addAfter(psiFactory.createNewline(), addedUseItem) - } - } - useStmts.forEach { - (it.nextSibling as? PsiWhiteSpace)?.delete() - it.delete() + if (addNewLine) { + useScope.addAfter(psiFactory.createNewline(), addedUseItem) } } + useStmts.forEach { + (it.nextSibling as? PsiWhiteSpace)?.delete() + it.delete() + } + } + + private fun MvUseGroup.sortUseSpecks() { + val sortedList = useSpeckList + .sortedWith(COMPARATOR_FOR_ITEMS_IN_USE_GROUP) + .map { it.copy() } + useSpeckList.zip(sortedList).forEach { it.first.replace(it.second) } } } diff --git a/src/main/kotlin/org/move/ide/search/MvUsageTypeProvider.kt b/src/main/kotlin/org/move/ide/search/MvUsageTypeProvider.kt index ef705a82d..21c6aaf96 100644 --- a/src/main/kotlin/org/move/ide/search/MvUsageTypeProvider.kt +++ b/src/main/kotlin/org/move/ide/search/MvUsageTypeProvider.kt @@ -11,9 +11,8 @@ import com.intellij.usages.impl.rules.UsageType import com.intellij.usages.impl.rules.UsageTypeProviderEx import org.move.lang.core.psi.MvAddressRef import org.move.lang.core.psi.MvExpr -import org.move.lang.core.psi.MvFQModuleRef -object MvUsageTypeProvider : UsageTypeProviderEx { +object MvUsageTypeProvider: UsageTypeProviderEx { // Instantiate each UsageType only once, so that the equality check in UsageTypeGroup.equals() works correctly // private val TYPE_REFERENCE = UsageType { "type reference" } @@ -46,9 +45,8 @@ object MvUsageTypeProvider : UsageTypeProviderEx { } override fun getUsageType(element: PsiElement, targets: Array): UsageType? { -// val refinedElement = element?.findExpansionElements()?.firstOrNull()?.parent ?: element val parent = element.parent ?: return null - if (element is MvFQModuleRef) return MODULE +// if (element is MvFQModuleRef) return MODULE return when (parent) { is MvExpr -> EXPR is MvAddressRef -> ADDRESS_REF diff --git a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt index ada827a6c..2a2d0db44 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt @@ -6,8 +6,6 @@ package org.move.ide.utils.imports import org.move.cli.MoveProject -import org.move.lang.core.psi.MvAddressRef -import org.move.lang.core.psi.MvUseItem import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.* diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt index 015f550e6..24599d4dc 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ModulesCompletionProvider.kt @@ -1,29 +1,5 @@ package org.move.lang.core.completion.providers -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.patterns.ElementPattern -import com.intellij.psi.PsiElement -import com.intellij.util.ProcessingContext -import org.move.ide.inspections.imports.ImportContext -import org.move.ide.utils.imports.ImportCandidateCollector.getCompletionCandidates -import org.move.lang.core.MvPsiPatterns -import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.IMPORTED_MODULE_PRIORITY -import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY -import org.move.lang.core.completion.createLookupElement -import org.move.lang.core.psi.MvPath -import org.move.lang.core.psi.containingModule -import org.move.lang.core.psi.containingModuleSpec -import org.move.lang.core.psi.ext.equalsTo -import org.move.lang.core.psi.ext.moduleRef -import org.move.lang.core.psi.refItemScopes -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.letStmtScope -import org.move.lang.core.resolve.processItems -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility - //object ModulesCompletionProvider2: MvCompletionProvider() { // override val elementPattern: ElementPattern // get() = diff --git a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt index e8f5e8e72..6e7b02832 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt @@ -99,37 +99,6 @@ class MvPsiFactory(val project: Project) { ?: error("Failed to create an item import from text: `$speckText`") } - fun itemUseSpeck(fqModuleText: String, useItem: String): MvItemUseSpeck { - return createFromText("module 0x1::_DummyModule { use $fqModuleText::$useItem; }") - ?: error("Cannot create item use speck") -// return if (names.size == 1) { -// createFromText("module 0x1::_DummyModule { use $fqModuleText::$useItem; }") -// ?: error("") -// } else { -// val namesText = names.joinToString(", ", "{", "}") -// createFromText("module 0x1::_DummyModule { use $fqModuleText::$namesText; }") -// ?: error("") -// } - } - - fun itemUseSpeck(fqModuleText: String, names: List): MvItemUseSpeck { - assert(names.isNotEmpty()) - return if (names.size == 1) { - createFromText("module 0x1::_DummyModule { use $fqModuleText::${names.first()}; }") - ?: error("") - } else { - val namesText = names.joinToString(", ", "{", "}") - createFromText("module 0x1::_DummyModule { use $fqModuleText::$namesText; }") - ?: error("") - } - } - - fun useGroup(items: List): MvUseItemGroup { - val allItemsText = items.joinToString(", ") - return createFromText("module 0x1::_DummyModule { use 0x1::Module::{$allItemsText}; }") - ?: error("Failed to create an item import from text: `$allItemsText`") - } - fun useSpeckWithEmptyUseGroup(): MvUseSpeck { return createFromText("module 0x1::_DummyModule { use 0x1::dummy::{}; }") ?: error("Failed to create a use speck") 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 0210741e4..adfaebc40 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 @@ -49,8 +49,6 @@ val MvNamedElement.isMslOnlyItem: Boolean val MvMethodOrPath.isMslScope get() = this.isMslInner() -val MvModuleRef.isMslScope: Boolean get() = this.isMslInner() - fun PsiElement.isMsl(): Boolean = isMslInner() //fun PsiElement.isMslLegacy(): Boolean { // return CachedValuesManager.getProjectPsiDependentCache(this) { @@ -79,7 +77,7 @@ private fun PsiElement.isMslInner(): Boolean { var element: PsiElement? = it while (element != null) { // use items always non-msl, otherwise import resolution doesn't work correctly - if (element is MvUseItem) return@getProjectPsiDependentCache false + if (element is MvUseSpeck) return@getProjectPsiDependentCache false // module items if (element is MvModule diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemUseSpeck.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemUseSpeck.kt deleted file mode 100644 index 87d4a0413..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemUseSpeck.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.move.lang.core.psi.ext - -import org.move.lang.core.psi.MvItemUseSpeck - -fun MvItemUseSpeck.names(): List = - this.useItemGroup?.names ?: listOfNotNull(this.useItem?.name) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index 7b65e0a41..afc6f7aa1 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -1,6 +1,5 @@ package org.move.lang.core.psi.ext -import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache import org.move.lang.core.psi.* import org.move.stdext.buildList @@ -24,54 +23,15 @@ val MvModule.innerSpecItems: List val module = this return buildList { addAll(module.allModuleSpecs() - .map { - it.moduleItemSpecs() - .flatMap { spec -> spec.itemSpecBlock?.globalVariables().orEmpty() } - } - .flatten()) + .map { + it.moduleItemSpecs() + .flatMap { spec -> spec.itemSpecBlock?.globalVariables().orEmpty() } + } + .flatten()) addAll(module.specInlineFunctions()) } } -//fun MvItemsOwner.moduleUseItems(): List = -// listOf( -//// moduleUseSpecksNoAliases(), -//// moduleUseSpecksAliases(), -//// selfModuleUseItemNoAliases(), -//// selfModuleUseItemAliases(), -// ) -// ).flatten() - -fun MvItemsOwner.moduleUseSpecksNoAliases(): List = - moduleUseSpecks() - .filter { it.useAlias == null } - -//fun MvItemsOwner.moduleUseSpecksAliases(): List = -// moduleUseSpecks().mapNotNull { it.useAlias } - - -private fun MvItemsOwner.moduleUseSpecks(): List { - return getProjectPsiDependentCache(this) { - useStmtList.mapNotNull { it.moduleUseSpeck } - } -} - -//fun MvItemsOwner.psiUseItems(): List { -// return getProjectPsiDependentCache(this) { importsOwner -> -// importsOwner -// .useStmtList -// .mapNotNull { it.itemUseSpeck } -// .flatMap { -// val item = it.useItem -// if (item != null) { -// listOf(item) -// } else -// it.useItemGroup?.useItemList.orEmpty() -// } -// -// } -//} - fun MvItemsOwner.allUseItems(): List = emptyList() // listOf( // useItemsNoAliases(), @@ -110,12 +70,12 @@ fun MvItemsOwner.shortestPathText(item: MvNamedElement): String? { // } val module = item.containingModule ?: return null val moduleName = module.name ?: return null - for (moduleImport in this.moduleUseSpecksNoAliases()) { - val importedModule = moduleImport.fqModuleRef?.reference?.resolve() ?: continue - if (importedModule == module) { - return "$moduleName::$itemName" - } - } +// for (moduleImport in this.moduleUseSpecksNoAliases()) { +// val importedModule = moduleImport.fqModuleRef?.reference?.resolve() ?: continue +// if (importedModule == module) { +// return "$moduleName::$itemName" +// } +// } val addressName = module.addressRef()?.text ?: return null return "$addressName::$moduleName::$itemName" } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleUseSpeck.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleUseSpeck.kt deleted file mode 100644 index 1eb0f84dc..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleUseSpeck.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.move.lang.core.psi.ext - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiElement -import org.move.ide.MoveIcons -import org.move.lang.core.psi.MvModuleUseSpeck -import org.move.lang.core.psi.impl.MvNamedElementImpl -import javax.swing.Icon - -abstract class MvModuleUseSpeckMixin(node: ASTNode) : MvNamedElementImpl(node), - MvModuleUseSpeck { - override val nameElement: PsiElement? - get() = - useAlias?.identifier ?: fqModuleRef?.identifier - - override fun getIcon(flags: Int): Icon = MoveIcons.MODULE - -// override fun getReference(): MvReference { -// return MvModuleReferenceImpl(moduleRef) -// } - -} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 51a040182..89a7d87da 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -162,8 +162,6 @@ fun MvPath.importCandidateNamespaces(): Set { } } -val MvPath.moduleRef: MvModuleRef? get() = error("unimplemented") - val MvPath.hasColonColon: Boolean get() = colonColon != null val MvPath.useSpeck: MvUseSpeck? get() = this.rootPath().parent as? MvUseSpeck diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt index 7f68f4003..fe734dd2c 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseAlias.kt @@ -1,17 +1,11 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode -import org.move.lang.core.psi.MvModuleUseSpeck import org.move.lang.core.psi.MvUseAlias -import org.move.lang.core.psi.MvUseItem import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.impl.MvNameIdentifierOwnerImpl -val MvUseAlias.useItem: MvUseItem? get() = this.parent as? MvUseItem - val MvUseAlias.parentUseSpeck: MvUseSpeck get() = this.parent as MvUseSpeck -val MvUseAlias.moduleUseSpeck: MvModuleUseSpeck? get() = this.parent as? MvModuleUseSpeck - -abstract class MvUseAliasMixin(node: ASTNode) : MvNameIdentifierOwnerImpl(node), - MvUseAlias +abstract class MvUseAliasMixin(node: ASTNode): MvNameIdentifierOwnerImpl(node), + MvUseAlias diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt index 6555aa387..ee66366af 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt @@ -2,36 +2,6 @@ package org.move.lang.core.psi.ext import org.move.lang.core.psi.* -val MvUseItem.itemUseSpeck: MvItemUseSpeck - get() = ancestorStrict() ?: error("MvUseItem outside MvItemUseSpeck") - -val MvUseItem.annotationItem: MvElement - get() { - val parent = this.parent - if (parent is MvUseItemGroup && parent.useItemList.size != 1) return this - return useStmt - } - -val MvUseItem.useStmt: MvUseStmt - get() = - ancestorStrict() ?: error("always has MvUseStmt as ancestor") - -val MvUseItem.nameOrAlias: String? - get() { - val alias = this.useAlias - if (alias != null) { - return alias.identifier?.text - } - return this.identifier.text - } - -//val MvUseItem.moduleName: String -// get() { -// val useStmt = this.ancestorStrict() -// return useStmt?.itemUseSpeck?.fqModuleRef?.referenceName.orEmpty() -// } - -val MvUseItem.isSelf: Boolean get() = this.identifier.textMatches("Self") val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false //class MvUseItemReferenceElement( diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt index fb965f772..17f7a5325 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt @@ -2,14 +2,9 @@ package org.move.lang.core.psi.ext import com.intellij.psi.PsiComment import com.intellij.psi.SyntaxTraverser -import org.move.lang.core.psi.MvItemUseSpeck import org.move.lang.core.psi.MvUseGroup -import org.move.lang.core.psi.MvUseItem -import org.move.lang.core.psi.MvUseItemGroup import org.move.lang.core.psi.MvUseSpeck -val MvUseItemGroup.names get() = this.useItemList.mapNotNull { it.identifier.text } - val MvUseGroup.names get() = this.useSpeckList.mapNotNull { it.path.identifier?.text } //val MvUseItemGroup.parentUseSpeck: MvItemUseSpeck get() = parent as MvItemUseSpeck diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt index 8f109ec4a..235c10552 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt @@ -1,29 +1,25 @@ package org.move.lang.core.psi.ext -import org.move.ide.inspections.imports.declaredItemScope -import org.move.lang.core.psi.* -import org.move.stdext.wrapWithList +//val MvUseStmt.moduleUseSpeck: MvModuleUseSpeck? get() = null +//val MvUseStmt.itemUseSpeck: MvItemUseSpeck? get() = null -val MvUseStmt.moduleUseSpeck: MvModuleUseSpeck? get() = null -val MvUseStmt.itemUseSpeck: MvItemUseSpeck? get() = null - -val MvUseStmt.addressRef: MvAddressRef? - get() { - val moduleUseSpeck = this.moduleUseSpeck - if (moduleUseSpeck != null) { - val fqModuleRef = moduleUseSpeck.fqModuleRef - if (fqModuleRef != null) { - return fqModuleRef.addressRef - } else { - return moduleUseSpeck.addressRef - } - } - val itemUseSpeck = this.itemUseSpeck - if (itemUseSpeck != null) { - return itemUseSpeck.fqModuleRef.addressRef - } - return null - } +//val MvUseStmt.addressRef: MvAddressRef? +// get() { +// val moduleUseSpeck = this.moduleUseSpeck +// if (moduleUseSpeck != null) { +// val fqModuleRef = moduleUseSpeck.fqModuleRef +// if (fqModuleRef != null) { +// return fqModuleRef.addressRef +// } else { +// return moduleUseSpeck.addressRef +// } +// } +// val itemUseSpeck = this.itemUseSpeck +// if (itemUseSpeck != null) { +// return itemUseSpeck.fqModuleRef.addressRef +// } +// return null +// } //val MvUseStmt.useGroupLevel: Int // get() { @@ -31,68 +27,68 @@ val MvUseStmt.addressRef: MvAddressRef? // return this.addressRef?.useGroupLevel ?: -1 // } -val MvUseStmt.fqModuleText: String? - get() { - val fqModuleRef = this.fqModuleRef ?: return null - return fqModuleRef.text - } - -val MvUseStmt.fqModuleRef: MvFQModuleRef? - get() { - val moduleUseSpeck = this.moduleUseSpeck - if (moduleUseSpeck != null) { - return moduleUseSpeck.fqModuleRef - } - val itemUseSpeck = this.itemUseSpeck - if (itemUseSpeck != null) { - return itemUseSpeck.fqModuleRef - } - return null - } +//val MvUseStmt.fqModuleText: String? +// get() { +// val fqModuleRef = this.fqModuleRef ?: return null +// return fqModuleRef.text +// } -val MvUseStmt.childUseItems: List - get() { - return this.itemUseSpeck?.useItems.orEmpty() +//val MvUseStmt.fqModuleRef: MvFQModuleRef? +// get() { +// val moduleUseSpeck = this.moduleUseSpeck +// if (moduleUseSpeck != null) { +// return moduleUseSpeck.fqModuleRef +// } +// val itemUseSpeck = this.itemUseSpeck // if (itemUseSpeck != null) { -// return itemUseSpeck.useItems -//// val group = itemUseSpeck.useItemGroup -//// if (group != null) { -//// return group.useItemList -//// } -//// return itemUseSpeck.useItem.wrapWithList() +// return itemUseSpeck.fqModuleRef // } -// return emptyList() - } - -val MvItemUseSpeck.useItems: List - get() { - val group = this.useItemGroup - if (group != null) { - return group.useItemList - } - return this.useItem.wrapWithList() - } +// return null +// } +//val MvUseStmt.childUseItems: List +// get() { +// return this.itemUseSpeck?.useItems.orEmpty() +//// if (itemUseSpeck != null) { +//// return itemUseSpeck.useItems +////// val group = itemUseSpeck.useItemGroup +////// if (group != null) { +////// return group.useItemList +////// } +////// return itemUseSpeck.useItem.wrapWithList() +//// } +//// return emptyList() +// } -sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemScope) { - data class Module( - override val nameOrAlias: String, - override val scope: NamedItemScope, - val moduleUseSpeck: MvModuleUseSpeck, - ): UseSpeck(nameOrAlias, scope) +//val MvItemUseSpeck.useItems: List +// get() { +// val group = this.useItemGroup +// if (group != null) { +// return group.useItemList +// } +// return this.useItem.wrapWithList() +// } - data class SelfModule( - override val nameOrAlias: String, - override val scope: NamedItemScope, - val useItem: MvUseItem, - ): UseSpeck(nameOrAlias, scope) - data class Item( - override val nameOrAlias: String, - override val scope: NamedItemScope, - val useItem: MvUseItem, - ): UseSpeck(nameOrAlias, scope) -} +//sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemScope) { +// data class Module( +// override val nameOrAlias: String, +// override val scope: NamedItemScope, +// val moduleUseSpeck: MvModuleUseSpeck, +// ): UseSpeck(nameOrAlias, scope) +// +// data class SelfModule( +// override val nameOrAlias: String, +// override val scope: NamedItemScope, +// val useItem: MvUseItem, +// ): UseSpeck(nameOrAlias, scope) +// +// data class Item( +// override val nameOrAlias: String, +// override val scope: NamedItemScope, +// val useItem: MvUseItem, +// ): UseSpeck(nameOrAlias, scope) +//} //val MvUseStmt.useSpecks: List diff --git a/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt b/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt index 29e86ee93..2ed395fd7 100644 --- a/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt +++ b/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt @@ -41,6 +41,14 @@ class FindUsagesTest : MvTestBase() { } """) + fun `test module`() = doTestByText(""" + module 0x1::m {} + //^ + module 0x1::main { + use 0x1::m; // - module + } + """) + private fun doTestByText(@Language("Move") code: String) { InlineFile(code) diff --git a/src/test/kotlin/org/move/utils/tests/MvTestBase.kt b/src/test/kotlin/org/move/utils/tests/MvTestBase.kt index 979ebd9ba..a5ef879e1 100644 --- a/src/test/kotlin/org/move/utils/tests/MvTestBase.kt +++ b/src/test/kotlin/org/move/utils/tests/MvTestBase.kt @@ -13,6 +13,8 @@ import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.enableInspectionTool import org.intellij.lang.annotations.Language import org.move.cli.settings.moveSettings +import org.move.cli.tests.NamedAddressService +import org.move.cli.tests.NamedAddressServiceTestImpl import org.move.ide.inspections.fixes.CompilerV2Feat import org.move.ide.inspections.fixes.CompilerV2Feat.* import org.move.utils.tests.base.MvTestCase From bebd117469aea74a0017ef551545fac2484996f1 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 04:02:37 +0300 Subject: [PATCH 29/43] fix some tests --- .../providers/MvCompletionProvider.kt | 8 +- .../providers/MvPathCompletionProvider2.kt | 38 ++++-- .../move/lang/core/resolve/ref/Namespace.kt | 1 + .../core/resolve2/LexicalDeclarations2.kt | 5 +- .../lang/core/resolve2/NameResolution2.kt | 26 +++- .../move/lang/core/resolve2/Visibility2.kt | 14 +- .../core/resolve2/ref/Path2ReferenceImpl.kt | 4 +- .../org/move/lang/core/stubs/StubIndexing.kt | 3 + .../move/lang/core/stubs/impl/MvFileStub.kt | 2 +- .../org/move/lang/core/types/Address.kt | 4 +- .../org/move/lang/index/MvModuleIndex.kt | 53 +++++++ .../move/lang/index/MvNamedElementIndex.kt | 7 +- src/main/resources/META-INF/plugin.xml | 1 + .../completion/names/ModulesCompletionTest.kt | 129 ++++++++++++++---- .../completion/names/StructsCompletionTest.kt | 1 + .../resolve/ResolveItemsTreeProjectTest.kt | 5 +- .../completion/MoveCompletionTestFixture.kt | 4 + .../org/move/lang/parser/complete/friend.txt | 16 ++- .../org/move/lang/parser/specs/spec_file.txt | 7 +- 19 files changed, 247 insertions(+), 81 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/index/MvModuleIndex.kt diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt index 0f3e177e9..a4d94bf6d 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvCompletionProvider.kt @@ -2,28 +2,24 @@ package org.move.lang.core.completion.providers import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionProvider -import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.patterns.ElementPattern import com.intellij.psi.PsiElement -import org.move.ide.inspections.imports.ImportContext import org.move.ide.utils.imports.ImportCandidate -import org.move.ide.utils.imports.ImportCandidateCollector import org.move.ide.utils.imports.import import org.move.lang.core.completion.DefaultInsertHandler import org.move.lang.core.completion.getElementOfType import org.move.lang.core.psi.MvElement -import org.move.lang.index.MvNamedElementIndex -abstract class MvCompletionProvider : CompletionProvider() { +abstract class MvCompletionProvider: CompletionProvider() { abstract val elementPattern: ElementPattern } class ImportInsertHandler( val parameters: CompletionParameters, private val candidate: ImportCandidate -) : DefaultInsertHandler() { +): DefaultInsertHandler() { override fun handleInsert(element: MvElement, context: InsertionContext, item: LookupElement) { super.handleInsert(element, context, item) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index c20617bc1..ecff64c16 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -20,6 +20,7 @@ import org.move.lang.core.resolve.LetStmtScope.EXPR_STMT import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.* +import org.move.lang.core.resolve2.PathKind import org.move.lang.core.resolve2.pathKind import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.resolve2.ref.processPathResolveVariants @@ -73,13 +74,24 @@ object MvPathCompletionProvider2: MvCompletionProvider() { } val ns = buildSet { - add(MODULE) - when (parentElement) { - is MvPathType -> add(TYPE) - is MvSchemaLit -> add(SCHEMA) - else -> { - add(NAME) - add(FUNCTION) + val pathKind = pathElement.pathKind() + if (resolutionCtx.isUseSpeck) { + when (pathKind) { + is PathKind.QualifiedPath.Module -> add(MODULE) + is PathKind.QualifiedPath -> addAll(Namespace.items()) + else -> {} + } + } else { + if (pathKind is PathKind.UnqualifiedPath) { + add(MODULE) + } + when (parentElement) { + is MvPathType -> add(TYPE) + is MvSchemaLit -> add(SCHEMA) + else -> { + add(NAME) + add(FUNCTION) + } } } } @@ -138,20 +150,16 @@ object MvPathCompletionProvider2: MvCompletionProvider() { } val pathKind = pathElement.pathKind(overwriteNs = ns) -// val pathKind = classifyPath(pathElement, overwriteNs = ns) processPathResolveVariants(resolutionCtx, pathKind, completionCollector) // disable auto-import in module specs for now if (pathElement.containingModuleSpec != null) return + // no out-of-scope completions for use specks + if (pathElement.isUseSpeck) return + val originalPathElement = parameters.originalPosition?.parent as? MvPath ?: return - val importContext = - ImportContext.from( - originalPathElement, - ns, -// setOf(Visibility.Public), -// completionContext.contextScopeInfo - ) + val importContext = ImportContext.from(originalPathElement, ns) val candidates = ImportCandidateCollector.getCompletionCandidates( parameters, diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index 290aa983f..7279ad877 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -68,6 +68,7 @@ enum class Namespace { fun all(): Set { return EnumSet.of(NAME, FUNCTION, TYPE, SCHEMA, MODULE, CONST) } + fun items(): Set = EnumSet.of(NAME, FUNCTION, TYPE, SCHEMA, CONST) fun none(): Set = setOf() } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index 60c865cf8..d1e230f4b 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -3,7 +3,6 @@ package org.move.lang.core.resolve2 import com.intellij.psi.util.PsiTreeUtil import org.move.ide.inspections.imports.pathUsageScope import org.move.lang.core.psi.* -import org.move.lang.core.psi.NamedItemScope.MAIN import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.* @@ -235,9 +234,9 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val element = alias ?: namedElement val namespace = namedElement.namespace - val importUsageScope = path.pathUsageScope + val useSpeckUsageScope = path.pathUsageScope val visibilityFilter = - namedElement.visInfo(adjustmentScope = importUsageScope).createFilter() + namedElement.visInfo(adjustScope = useSpeckUsageScope).createFilter() if (namespace in ns && processor.process(name, element, ns, visibilityFilter)) { stop = true diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 519a696b4..a96c8bacc 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -9,8 +9,7 @@ import org.move.lang.core.resolve.ref.Namespace.MODULE import org.move.lang.core.resolve2.ref.PathResolutionContext import org.move.lang.core.types.Address import org.move.lang.core.types.address -import org.move.lang.index.MvNamedElementIndex -import java.util.EnumSet +import org.move.lang.index.MvModuleIndex fun processNestedScopesUpwards( scopeStart: MvElement, @@ -43,19 +42,32 @@ fun processModulePathResolveVariants( val project = element.project val searchScope = moveProject.searchScope() - val addressProcessor = processor.wrapWithFilter { e -> + val addrProcessor = processor.wrapWithFilter { e -> val candidate = e.element as? MvModule ?: return@wrapWithFilter false val candidateAddress = candidate.address(moveProject) address == candidateAddress } + val targetNames = addrProcessor.names + if (targetNames == null) { + // completion + val moduleNames = MvModuleIndex.getAllModuleNames(project) + moduleNames.forEach { moduleName -> + val modules = MvModuleIndex.getModulesByName(project, moduleName, searchScope) + for (module in modules) { + if (addrProcessor.process(moduleName, module)) return true + } + } + return false + } + var stop = false - for (targetModuleName in processor.names.orEmpty()) { - MvNamedElementIndex - .processElementsByName(project, targetModuleName, searchScope) { + for (targetModuleName in targetNames) { + MvModuleIndex + .processModulesByName(project, targetModuleName, searchScope) { val module = it val visFilter = module.visInfo().createFilter() - stop = addressProcessor.process(targetModuleName, module, setOf(MODULE), visFilter) + stop = addrProcessor.process(targetModuleName, module, setOf(MODULE), visFilter) // true to continue processing, if .process does not find anything, it returns false !stop } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index cc30fe9ab..6a58cbd1e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -21,9 +21,9 @@ data class ItemVisibilityInfo( val vis: Visibility2, ) -fun MvNamedElement.visInfo(adjustmentScope: NamedItemScope = MAIN): ItemVisibilityInfo { +fun MvNamedElement.visInfo(adjustScope: NamedItemScope = MAIN): ItemVisibilityInfo { // todo: can be lazy - val itemUsageScope = this.itemScope.shrinkScope(adjustmentScope) + val itemUsageScope = this.itemScope.shrinkScope(adjustScope) val visibility = (this as? MvVisibilityOwner)?.visibility2 ?: Public return ItemVisibilityInfo(this, usageScope = itemUsageScope, vis = visibility) } @@ -62,14 +62,14 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // todo: uncomment when ContextScopeInfo filter is removed // #[test_only] items in non-test-only scope -// if (itemUsageScope != MAIN) { -// // cannot be used everywhere, need to check for scope compatibility -// if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible -// } + if (itemUsageScope != MAIN) { + // cannot be used everywhere, need to check for scope compatibility + if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible + } // todo: uncomment when ContextScopeInfo filter is removed // we're in non-msl scope at this point, msl only items aren't available -// if (item !is MvModule && item is MslOnlyElement) return@VisibilityFilter Invisible + if (item is MslOnlyElement) return@VisibilityFilter Invisible // local methods, Self::method - everything is visible val itemModule = item.containingModule diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 1547b70f7..436a3889f 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -163,9 +163,7 @@ class PathResolutionContext( } val containingModule: MvModule? get() = lazyContainingModule.value - private var lazyUseSpeck: Lazy = lazy(NONE) { - path.useSpeck - } + private var lazyUseSpeck: Lazy = lazy(NONE) { path.useSpeck } val useSpeck: MvUseSpeck? get() = lazyUseSpeck.value val isUseSpeck: Boolean get() = useSpeck != null diff --git a/src/main/kotlin/org/move/lang/core/stubs/StubIndexing.kt b/src/main/kotlin/org/move/lang/core/stubs/StubIndexing.kt index 32d899f9f..cc1d05afc 100644 --- a/src/main/kotlin/org/move/lang/core/stubs/StubIndexing.kt +++ b/src/main/kotlin/org/move/lang/core/stubs/StubIndexing.kt @@ -6,6 +6,9 @@ import org.move.lang.index.* import org.move.lang.moveProject fun IndexSink.indexModuleStub(stub: MvModuleStub) { + stub.name?.let { + occurrence(MvModuleIndex.KEY, it) + } indexNamedStub(stub) } diff --git a/src/main/kotlin/org/move/lang/core/stubs/impl/MvFileStub.kt b/src/main/kotlin/org/move/lang/core/stubs/impl/MvFileStub.kt index dc61c4bb6..9cf7ac2c4 100644 --- a/src/main/kotlin/org/move/lang/core/stubs/impl/MvFileStub.kt +++ b/src/main/kotlin/org/move/lang/core/stubs/impl/MvFileStub.kt @@ -17,7 +17,7 @@ class MvFileStub(file: MoveFile?) : PsiFileStubImpl(file) { override fun getType() = Type object Type : IStubFileElementType(MoveLanguage) { - private const val STUB_VERSION = 24 + private const val STUB_VERSION = 25 // Bump this number if Stub structure changes override fun getStubVersion(): Int = MoveParserDefinition.PARSER_VERSION + STUB_VERSION diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index 6ec43ea44..14b235624 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -103,7 +103,9 @@ sealed class Address { val leftValue = left.value?.let { normalizeValue(it) } val rightValue = right.value?.let { normalizeValue(it) } if (leftValue == null && rightValue == null) { - return left.name == right.name + // null items cannot be equal + return false +// return left.name == right.name } return leftValue == rightValue } diff --git a/src/main/kotlin/org/move/lang/index/MvModuleIndex.kt b/src/main/kotlin/org/move/lang/index/MvModuleIndex.kt new file mode 100644 index 000000000..6d77c673f --- /dev/null +++ b/src/main/kotlin/org/move/lang/index/MvModuleIndex.kt @@ -0,0 +1,53 @@ +package org.move.lang.index + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.stubs.StringStubIndexExtension +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.stubs.StubIndexKey +import org.move.lang.core.psi.MvModule +import org.move.lang.core.stubs.impl.MvFileStub +import org.move.openapiext.checkCommitIsNotInProgress + +class MvModuleIndex: StringStubIndexExtension() { + override fun getVersion(): Int = MvFileStub.Type.stubVersion + override fun getKey(): StubIndexKey = KEY + + companion object { + val KEY: StubIndexKey = + StubIndexKey.createIndexKey("org.move.index.ModuleIndex") + + fun getAllModuleNames(project: Project): Collection { + checkCommitIsNotInProgress(project) + return StubIndex.getInstance().getAllKeys(KEY, project) + } + + fun processModulesByName( + project: Project, + target: String, + scope: GlobalSearchScope = GlobalSearchScope.allScope(project), + processor: (MvModule) -> Boolean, + ) { + checkCommitIsNotInProgress(project) + StubIndex.getInstance() + .processElements(KEY, target, project, scope, MvModule::class.java, processor) + } + + fun getModulesByName( + project: Project, + name: String, + scope: GlobalSearchScope, + ): Collection { + checkCommitIsNotInProgress(project) + return StubIndex.getElements(KEY, name, project, scope, MvModule::class.java) + } + + fun getModuleByName( + project: Project, + name: String, + scope: GlobalSearchScope, + ): MvModule? { + return getModulesByName(project, name, scope).singleOrNull() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt b/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt index 54e7500a4..fad808c44 100644 --- a/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt +++ b/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt @@ -5,11 +5,16 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndexKey +import com.intellij.util.Processor import org.move.lang.core.psi.MvNamedElement +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.RsResolveProcessorBase +import org.move.lang.core.resolve.ScopeEntry +import org.move.lang.core.resolve.lazy import org.move.lang.core.stubs.impl.MvFileStub import org.move.openapiext.checkCommitIsNotInProgress -class MvNamedElementIndex : StringStubIndexExtension() { +class MvNamedElementIndex: StringStubIndexExtension() { override fun getVersion(): Int = MvFileStub.Type.stubVersion override fun getKey(): StubIndexKey = KEY diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 30e987fcb..1b697a2bb 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -73,6 +73,7 @@ + Date: Tue, 23 Jul 2024 20:38:50 +0300 Subject: [PATCH 30/43] fix curly braces test --- .../intentions/RemoveCurlyBracesIntention.kt | 55 +++++++++++++------ .../completion/names/ModulesCompletionTest.kt | 10 ++++ .../completion/names/StructsCompletionTest.kt | 1 - 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt index 15002c32d..efeaf1ccf 100644 --- a/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt +++ b/src/main/kotlin/org/move/ide/intentions/RemoveCurlyBracesIntention.kt @@ -3,7 +3,7 @@ package org.move.ide.intentions import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement -import org.move.lang.core.psi.MvUseGroup +import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.ancestorStrict import org.move.lang.core.psi.ext.endOffset @@ -14,40 +14,61 @@ class RemoveCurlyBracesIntention: MvElementBaseIntentionAction() ?: return null - val useGroup = useStmt.useSpeck?.useGroup ?: return null + val useSpeck = useStmt.useSpeck ?: return null + val useGroup = useSpeck.useGroup ?: return null if (useGroup.useSpeckList.size > 1) return null - return Context(useGroup) + return Context(useSpeck) } override fun invoke(project: Project, editor: Editor, ctx: Context) { - val itemUseGroup = ctx.useGroup + val useSpeck = ctx.useSpeck // Save the cursor position, adjusting for curly brace removal val caret = editor.caretModel.offset val newOffset = when { - caret < itemUseGroup.startOffset -> caret - caret < itemUseGroup.endOffset -> caret - 1 + caret < useSpeck.startOffset -> caret + caret < useSpeck.endOffset -> caret - 1 else -> caret - 2 } - itemUseGroup.removeCurlyBraces() + useSpeck.removeCurlyBraces() editor.caretModel.moveToOffset(newOffset) } } -private fun MvUseGroup.removeCurlyBraces() { +private fun MvUseSpeck.removeCurlyBraces() { val psiFactory = this.project.psiFactory - val itemUse = this.useSpeckList.singleOrNull() ?: return - val refName = itemUse.path.referenceName ?: return - val aliasName = itemUse.useAlias?.name + val useGroup = this.useGroup ?: return + val itemUseSpeck = useGroup.useSpeckList.singleOrNull() ?: return - var newText = refName - if (aliasName != null) { - newText += " as $aliasName" + val newPath = psiFactory.path("0x1::dummy::call") + + val itemIdentifier = itemUseSpeck.path.identifier ?: return + // copy identifier + newPath.identifier?.replace(itemIdentifier.copy()) + // copy module path + newPath.path?.replace(this.path.copy()) + + val dummyUseSpeck = psiFactory.useSpeck("0x1::dummy::call as mycall") + dummyUseSpeck.path.replace(newPath) + + val useAlias = itemUseSpeck.useAlias + if (useAlias != null) { + dummyUseSpeck.useAlias?.replace(useAlias) + } else { + dummyUseSpeck.useAlias?.delete() } - val newItemUse = psiFactory.useSpeckForGroup(newText) - this.replace(newItemUse) + + +// val aliasName = itemUseSpeck.useAlias?.name +// +// var newText = refName +// if (aliasName != null) { +// newText += " as $aliasName" +// } +// val newItemUse = psiFactory.useSpeckForGroup(newText) + this.replace(dummyUseSpeck) } diff --git a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt index 3eaa23e21..ec9df2681 100644 --- a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt @@ -253,4 +253,14 @@ class ModulesCompletionTest: CompletionTestCase() { } """ ) + + // todo: error from ::Self module completion, which is handled with the module name instead + fun `test no modules completion for item position`() = checkNoCompletion(""" + module 0x1::Transaction { + } + module 0x1::M { + fun main(a: 0x1::Transaction::Tra/*caret*/) { + } + } + """) } diff --git a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt index e16f53e7b..f9923dd76 100644 --- a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt @@ -198,7 +198,6 @@ class StructsCompletionTest: CompletionTestCase() { } """) - // todo: false positive from ::Self module completion, which is handled instead with the module name fun `test module struct completion in type position`() = doSingleCompletion(""" module 0x1::Transaction { struct Type { From 3e72aacf78ff7bc42f4f7d4191eee497a9872211 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 20:46:13 +0300 Subject: [PATCH 31/43] fix highlighting test --- .../org/move/ide/annotator/HighlightingAnnotator.kt | 2 +- .../org/move/ide/annotator/HighlightingAnnotatorTest.kt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt index fc9d91517..decacf0d5 100644 --- a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt @@ -145,7 +145,7 @@ class HighlightingAnnotator: MvAnnotatorBase() { is MvStructLitExpr -> MvColor.STRUCT is MvStructPat -> MvColor.STRUCT is MvRefExpr -> { - val item = path.reference?.resolve() ?: return null + val item = path.reference?.resolveFollowingAliases() ?: return null when { item is MvConst -> MvColor.CONSTANT else -> { diff --git a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt index b8276196e..6f96e24e0 100644 --- a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt @@ -327,10 +327,10 @@ class HighlightingAnnotatorTest: AnnotatorTestCase(HighlightingAnnotator::class) """ module 0x1::m { struct S { field: u8 } - fun receiver(self: S, self: u8): u8 { + fun receiver(self: S): u8 { self.field } - fun main(s: S) { + fun main(s: S, self: u8) { s.receiver(); } } @@ -341,10 +341,10 @@ class HighlightingAnnotatorTest: AnnotatorTestCase(HighlightingAnnotator::class) """ module 0x1::m { struct S { field: u8 } - fun receiver(self: S, self: u8): u8 { + fun receiver(self: S): u8 { self.field } - fun main(s: S) { + fun main(s: S, self: u8) { s.receiver(); } } From 6db78ed660dc147a47787b53ea48fe76d1345b83 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 20:52:56 +0300 Subject: [PATCH 32/43] drop redundant qualified path inspection --- .../RedundantQualifiedPathInspection.kt | 55 ---- .../move/lang/core/psi/ext/MvItemsOwner.kt | 48 +--- src/main/resources/META-INF/plugin.xml | 4 - .../RedundantQualifiedPathInspectionTest.kt | 240 ------------------ 4 files changed, 1 insertion(+), 346 deletions(-) delete mode 100644 src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt delete mode 100644 src/test/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspectionTest.kt diff --git a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt b/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt deleted file mode 100644 index e4a1a331a..000000000 --- a/src/main/kotlin/org/move/ide/inspections/RedundantQualifiedPathInspection.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.move.ide.inspections - -import com.intellij.codeInspection.LocalQuickFix -import com.intellij.codeInspection.ProblemDescriptor -import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.codeInspection.ProblemsHolder -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.TextRange -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.shortestPathText - -class RedundantQualifiedPathInspection : MvLocalInspectionTool() { - - override val isSyntaxOnly: Boolean get() = true - - override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): MvVisitor = - object : MvVisitor() { - override fun visitPath(path: MvPath) { - val pathText = path.text - .replace(path.typeArgumentList?.text.orEmpty(), "") - .replace(Regex("\\s"), "") - val item = path.reference?.resolveFollowingAliases() ?: return - - val importsOwner = path.containingScript?.scriptBlock - ?: path.containingModule?.moduleBlock - ?: return - val shortestPathText = importsOwner.shortestPathText(item) ?: return - // if aliases are involved, could lead to bugs - if (!pathText.endsWith(shortestPathText)) return - - val diff = pathText.length - shortestPathText.length - if (diff > 0) { - if (pathText.substring(0, diff) == "Self::") return - val range = TextRange.from(0, diff) - holder.registerProblem( - path, - "Redundant qualifier", - ProblemHighlightType.LIKE_UNUSED_SYMBOL, - range, - object : LocalQuickFix { - override fun getFamilyName(): String = "Remove redundant qualifier" - - override fun applyFix( - project: Project, - descriptor: ProblemDescriptor - ) { - val newPath = project.psiFactory.path(shortestPathText) - descriptor.psiElement.replace(newPath) - } - - }) - } - } - } -} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt index afc6f7aa1..270d2201b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemsOwner.kt @@ -32,50 +32,4 @@ val MvModule.innerSpecItems: List } } -fun MvItemsOwner.allUseItems(): List = emptyList() -// listOf( -// useItemsNoAliases(), -// useItemsAliases(), -// ).flatten() - -//fun MvItemsOwner.useItemsNoAliases(): List = -// psiUseItems() -// .filter { !it.isSelf } -// .filter { it.useAlias == null } - -//fun MvItemsOwner.useItemsAliases(): List = -// psiUseItems() -// .filter { !it.isSelf } -// .mapNotNull { it.useAlias } - -//fun MvItemsOwner.selfModuleUseItemNoAliases(): List = -// psiUseItems() -// .filter { it.isSelf && it.useAlias == null } - -//fun MvItemsOwner.selfModuleUseItemAliases(): List = -// psiUseItems() -// .filter { it.isSelf } -// .mapNotNull { it.useAlias } - -fun MvItemsOwner.shortestPathText(item: MvNamedElement): String? { - val itemName = item.name ?: return null - // local - if (this == item.containingItemsOwner) return itemName - -// for (useItem in this.useItemsNoAliases()) { -// val importedItem = useItem.reference.resolve() ?: continue -// if (importedItem == item) { -// return itemName -// } -// } - val module = item.containingModule ?: return null - val moduleName = module.name ?: return null -// for (moduleImport in this.moduleUseSpecksNoAliases()) { -// val importedModule = moduleImport.fqModuleRef?.reference?.resolve() ?: continue -// if (importedModule == module) { -// return "$moduleName::$itemName" -// } -// } - val addressName = module.addressRef()?.text ?: return null - return "$addressName::$moduleName::$itemName" -} +fun MvItemsOwner.allUseItems(): List = emptyList() \ 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 1b697a2bb..ad23413ae 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -241,10 +241,6 @@ displayName="Local variable naming convention" enabledByDefault="true" level="WARNING" implementationClass="org.move.ide.inspections.MvLocalBindingNamingInspection" /> - 0x1/*caret*/::M::call(); - } - } - """, """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - fun m() { - /*caret*/M::call(); - } - } - """ - ) - - fun `test error if fully qualified path and method imported`() = checkFixByText( - "Remove redundant qualifier", """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M::call; - fun m() { - 0x1::M/*caret*/::call(); - } - } - """, """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M::call; - fun m() { - /*caret*/call(); - } - } - """ - ) - - fun `test error if qualified path and method imported`() = checkFixByText( - "Remove redundant qualifier", """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - use 0x1::M::call; - fun m() { - M/*caret*/::call(); - } - } - """, """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - use 0x1::M::call; - fun m() { - /*caret*/call(); - } - } - """ - ) - - fun `test no error if qualified path and method imported with alias`() = checkWarnings(""" - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - use 0x1::M::call as mycall_mycall_mycall; - fun m() { - mycall_mycall_mycall(); - } - } - """ - ) - - fun `test error method imported is higher priority`() = checkFixByText( - "Remove redundant qualifier", """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - use 0x1::M::call; - fun m() { - 0x1::M/*caret*/::call(); - } - } - """, """ - module 0x1::M { - public fun call() {} - } - module 0x1::M2 { - use 0x1::M; - use 0x1::M::call; - fun m() { - /*caret*/call(); - } - } - """ - ) - - fun `test no redundant qual with Self path`() = checkWarnings(""" - module 0x1::M { - struct S {} - fun call() {} - fun m(a: Self::S) acquires Self::S { - Self::call(); - } - } - """) - - fun `test no redundant qualifier for struct with generic`() = checkWarnings(""" - module 0x1::Coin { - struct MintCapability has store {} - } - module 0x1::M { - use 0x1::Coin::MintCapability; - - struct BTC {} - struct Caps has key { - cap2: MintCapability, - } - } - """) - - fun `test no redundant qualifier for line break`() = checkWarnings(""" - module 0x1::coin { - public fun get_collateral_counts_test(): (u64, u64) { (1, 1) } - } - module 0x1::M { - use 0x1::coin; - fun call() { - coin:: - get_collateral_counts_test(); - } - } - """) - -// fun `test remove redundant qualifier with specified generic`() = checkFixByText( -// "Remove redundant qualifier", """ -// module 0x1::M { -// public fun call() {} -// } -// module 0x1::M2 { -// use 0x1::M; -// use 0x1::M::call; -// fun m() { -// 0x1::M/*caret*/::call(); -// } -// } -// """, """ -// module 0x1::M { -// public fun call() {} -// } -// module 0x1::M2 { -// use 0x1::M; -// use 0x1::M::call; -// fun m() { -// /*caret*/call(); -// } -// } -// """ -// ) - -// fun `test no redundant qualifier if import is in a different scope`() = checkByText(""" -//module 0x1::string { -// public fun call() {} -//} -//module 0x1::main { -// #[test_only] -// use 0x1::string; -// -// fun main() { -// 0x1::string::call(); -// } -//} -// """) - -} From ca707b15bc8e575c74d9d2038dbf4f4469d04a42 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 21:44:46 +0300 Subject: [PATCH 33/43] fix addresses completion --- .../completion/CommonCompletionContributor.kt | 20 ++--- ...amedAddressInUseStmtCompletionProvider.kt} | 38 +++++++-- .../org/move/lang/core/resolve2/PathKind.kt | 85 ++++++++++++------- .../move/lang/resolve/ResolveModulesTest.kt | 7 ++ 4 files changed, 98 insertions(+), 52 deletions(-) rename src/main/kotlin/org/move/lang/core/completion/providers/{AddressesCompletionProvider.kt => NamedAddressInUseStmtCompletionProvider.kt} (66%) diff --git a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt index 0b818ecf2..fdf13423c 100644 --- a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt +++ b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt @@ -14,8 +14,12 @@ class CommonCompletionContributor : CompletionContributor() { // extend(CompletionType.BASIC, FunctionsCompletionProvider) // extend(CompletionType.BASIC, SchemasCompletionProvider) extend(CompletionType.BASIC, SpecItemCompletionProvider) - extend(CompletionType.BASIC, AddressesCompletionProvider) + + // addresses + extend(CompletionType.BASIC, NamedAddressInUseStmtCompletionProvider) + extend(CompletionType.BASIC, NamedAddressAtValueExprCompletionProvider) extend(CompletionType.BASIC, AddressInModuleDeclCompletionProvider) + // extend(CompletionType.BASIC, TypesCompletionProvider) // extend(CompletionType.BASIC, ImportsCompletionProvider) // extend(CompletionType.BASIC, ModulesCompletionProvider) @@ -24,16 +28,10 @@ class CommonCompletionContributor : CompletionContributor() { extend(CompletionType.BASIC, StructPatCompletionProvider) extend(CompletionType.BASIC, SchemaFieldsCompletionProvider) extend(CompletionType.BASIC, MvPathCompletionProvider2) - extend( - CompletionType.BASIC, - MvPsiPatterns.ability(), - AbilitiesCompletionProvider - ) - extend( - CompletionType.BASIC, - MvPsiPatterns.refExpr(), - BoolsCompletionProvider - ) + + extend(CompletionType.BASIC, MvPsiPatterns.ability(), AbilitiesCompletionProvider) + extend(CompletionType.BASIC, MvPsiPatterns.refExpr(), BoolsCompletionProvider) + extend(CompletionType.BASIC, MacrosCompletionProvider) extend(CompletionType.BASIC, VectorLiteralCompletionProvider) extend(CompletionType.BASIC, MethodOrFieldCompletionProvider) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/AddressesCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt similarity index 66% rename from src/main/kotlin/org/move/lang/core/completion/providers/AddressesCompletionProvider.kt rename to src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt index ed5e72166..b9f4053e6 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/AddressesCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt @@ -11,14 +11,16 @@ import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.cli.AddressVal import org.move.ide.MoveIcons +import org.move.lang.core.MvPsiPatterns import org.move.lang.core.completion.alreadyHasColonColon import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvNamedAddress +import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psiElement import org.move.lang.core.withParent import org.move.lang.moveProject -object AddressInModuleDeclCompletionProvider : MvCompletionProvider() { +object AddressInModuleDeclCompletionProvider: MvCompletionProvider() { override val elementPattern: ElementPattern get() = PlatformPatterns .psiElement() @@ -30,8 +32,7 @@ object AddressInModuleDeclCompletionProvider : MvCompletionProvider() { context: ProcessingContext, result: CompletionResultSet ) { - val element = parameters.position - val moveProject = element.moveProject ?: return + val moveProject = parameters.position.moveProject ?: return val addresses = moveProject.addressValues() for ((name, value) in addresses.entries.sortedBy { it.key }) { val lookup = LookupElementBuilder @@ -49,7 +50,7 @@ object AddressInModuleDeclCompletionProvider : MvCompletionProvider() { } } -object AddressesCompletionProvider : MvCompletionProvider() { +object NamedAddressAtValueExprCompletionProvider: MvCompletionProvider() { override val elementPattern: ElementPattern get() = PlatformPatterns .psiElement().withParent() @@ -63,10 +64,31 @@ object AddressesCompletionProvider : MvCompletionProvider() { context: ProcessingContext, result: CompletionResultSet ) { - val element = parameters.position - val moveProject = element.moveProject ?: return - val addresses = moveProject.addressValues() - for ((name, addressVal) in addresses.entries.sortedBy { it.key }) { + val moveProject = parameters.position.moveProject ?: return + val declaredNamedAddresses = moveProject.addresses().values + for ((name, addressVal) in declaredNamedAddresses.entries.sortedBy { it.key }) { + val lookup = addressVal.createCompletionLookupElement(name) + result.addElement(lookup) + } + } +} + +object NamedAddressInUseStmtCompletionProvider: MvCompletionProvider() { + override val elementPattern: ElementPattern + get() = MvPsiPatterns.path() + .and( + PlatformPatterns.psiElement() + .withSuperParent(3, psiElement()) + ) + + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + val moveProject = parameters.position.moveProject ?: return + val declaredNamedAddresses = moveProject.addresses().values + for ((name, addressVal) in declaredNamedAddresses.entries.sortedBy { it.key }) { val lookup = addressVal.createCompletionLookupElement(name) result.addElement(lookup) } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt index 942274f87..a139f6196 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt @@ -1,5 +1,6 @@ package org.move.lang.core.resolve2 +import org.move.cli.MoveProject import org.move.lang.core.psi.MvPath import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseSpeck @@ -7,6 +8,7 @@ import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.allowedNamespaces import org.move.lang.core.psi.ext.ancestorStrict import org.move.lang.core.psi.ext.isUseSpeck +import org.move.lang.core.psi.ext.useSpeck import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.types.Address import org.move.lang.moveProject @@ -44,55 +46,72 @@ sealed class PathKind { fun MvPath.pathKind(overwriteNs: Set? = null): PathKind { val ns = overwriteNs ?: this.allowedNamespaces() - val qualifierPath = this.path + // [0x1::foo]::bar + // ^ qualifier + val qualifier = this.path val moveProject = this.moveProject val useGroup = this.ancestorStrict() if (useGroup != null) { // use 0x1::m::{item} // ^ - val qualifier = (useGroup.parent as MvUseSpeck).path - return PathKind.QualifiedPath.UseGroupItem(this, qualifier, ns) + val useSpeckQualifier = (useGroup.parent as MvUseSpeck).path + return PathKind.QualifiedPath.UseGroupItem(this, useSpeckQualifier, ns) } - if (qualifierPath == null) { - val parentPath = this.parent as? MvPath - if (parentPath != null) { - // can be an address - val pathAddress = this.pathAddress - val referenceName = this.referenceName - when { - pathAddress != null -> return PathKind.ValueAddress(Address.Value(pathAddress.text)) - moveProject != null && referenceName != null -> { - // try for named address - val namedAddress = moveProject.getNamedAddressTestAware(referenceName) - if (namedAddress != null) { - return PathKind.NamedAddress(namedAddress) - } - // check whether it's a first item in use speck - val speckParent = parentPath.parent as? MvUseSpeck - if (speckParent != null && speckParent.parent is MvUseStmt) { - // always a named address, even if unknown - return PathKind.NamedAddress(Address.Named(referenceName, null, moveProject)) - } - } + if (qualifier == null) { + // one-element path + + // if pathAddress exists, it means it has to be a value address + val pathAddress = this.pathAddress + if (pathAddress != null) { + return PathKind.ValueAddress(Address.Value(pathAddress.text)) + } + val referenceName = this.referenceName ?: error("if pathAddress is null, reference has to be non-null") + + // check whether it's a first element in use stmt, i.e. use [std]::module; + // ^ + val useSpeck = this.useSpeck + if (useSpeck != null && useSpeck.parent is MvUseStmt) { + // if so, local path expr is a named address + val namedAddress = moveProject?.getNamedAddressTestAware(referenceName) + if (namedAddress != null) { + return PathKind.NamedAddress(namedAddress) + } + // and it can be with null value if absent, still a named address + return PathKind.NamedAddress(Address.Named(referenceName, null, moveProject)) + } + + // check whether it's inside use group, then it cannot be named address +// if (this.useSpeck?.useGroup != null) { +// return PathKind.UnqualifiedPath(ns) +// } + + // outside use stmt context + if (moveProject != null) { + // try whether it's a named address + val namedAddress = moveProject.getNamedAddressTestAware(referenceName) + if (namedAddress != null) { + return PathKind.NamedAddress(namedAddress) } } + + // if it's not, then it just an unqualified path return PathKind.UnqualifiedPath(ns) } - val qualifierOfQualifier = qualifierPath.path + val qualifierOfQualifier = qualifier.path // two-element paths if (qualifierOfQualifier == null) { - val qualifierPathAddress = qualifierPath.pathAddress - val qualifierItemName = qualifierPath.referenceName + val qualifierPathAddress = qualifier.pathAddress + val qualifierItemName = qualifier.referenceName when { // 0x1::bar // ^ qualifierPathAddress != null -> { val address = Address.Value(qualifierPathAddress.text) - return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) + return PathKind.QualifiedPath.Module(this, qualifier, ns, address) } // aptos_framework::bar // ^ @@ -100,19 +119,19 @@ fun MvPath.pathKind(overwriteNs: Set? = null): PathKind { val namedAddress = moveProject.getNamedAddressTestAware(qualifierItemName) if (namedAddress != null) { // known named address, can be module path - return PathKind.QualifiedPath.Module(this, qualifierPath, ns, namedAddress) + return PathKind.QualifiedPath.Module(this, qualifier, ns, namedAddress) } if (this.isUseSpeck) { // use std::main where std is the unknown named address val address = Address.Named(qualifierItemName, null, moveProject) - return PathKind.QualifiedPath.Module(this, qualifierPath, ns, address) + return PathKind.QualifiedPath.Module(this, qualifier, ns, address) } } } // module::name - return PathKind.QualifiedPath.ModuleItem(this, qualifierPath, ns) + return PathKind.QualifiedPath.ModuleItem(this, qualifier, ns) } // three-element path - return PathKind.QualifiedPath.FQModuleItem(this, qualifierPath, ns) -} \ No newline at end of file + return PathKind.QualifiedPath.FQModuleItem(this, qualifier, ns) +} diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 916ab9512..99a7db4e4 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -429,4 +429,11 @@ module 0x1::string_tests { //^ unresolved } """) + + fun `test cannot resolve named address in incomplete path use stmt`() = checkByCode(""" + module 0x1::m { + use aptos_framework + //^ unresolved + } + """) } From ab4475a02882ddc61db7a81afcf1024588c2ab8d Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 21:57:05 +0300 Subject: [PATCH 34/43] add more tests for modules completion --- .../project/ModulesCompletionProjectTest.kt | 73 +++++++++++++++++-- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/src/test/kotlin/org/move/lang/completion/names/project/ModulesCompletionProjectTest.kt b/src/test/kotlin/org/move/lang/completion/names/project/ModulesCompletionProjectTest.kt index c3605e428..3d3f39438 100644 --- a/src/test/kotlin/org/move/lang/completion/names/project/ModulesCompletionProjectTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/project/ModulesCompletionProjectTest.kt @@ -2,7 +2,7 @@ package org.move.lang.completion.names.project import org.move.utils.tests.completion.CompletionProjectTestCase -class ModulesCompletionProjectTest : CompletionProjectTestCase() { +class ModulesCompletionProjectTest: CompletionProjectTestCase() { fun `test complete modules from all the files in imports`() = checkContainsCompletionsExact(listOf("M1", "M2")) { @@ -121,7 +121,7 @@ class ModulesCompletionProjectTest : CompletionProjectTestCase() { } } - fun `test named address is identified only with name`() = checkNoCompletion { + fun `test no named address completion in module position`() = checkNoCompletion { moveToml( """ [package] @@ -129,22 +129,79 @@ class ModulesCompletionProjectTest : CompletionProjectTestCase() { [addresses] Std = "0x1" - Pontem = "0x1" + Pontem = "0x2" """ ) sources { move( "mod.move", """ module Std::StdMod {} - module Pontem::PontemMod {} + module Pontem::MyMod {} module 0x1::MyMod { - use 0x1::Pont/*caret*/ + use 0x2::Pont/*caret*/ } """ ) } } + fun `test no named address completion in item position`() = checkNoCompletion { + moveToml( + """ + [package] + name = "package" + + [addresses] + Std = "0x1" + Pontem = "0x2" + """ + ) + sources { + move( + "mod.move", """ + module Std::StdMod {} + module Pontem::MyMod {} + module 0x1::MyMod { + use 0x2::MyMod::Pont/*caret*/ + } + """ + ) + } + } + + fun `test completion for value address is available if identified with name`() = doSingleCompletion( + { + moveToml( + """ + [package] + name = "package" + + [addresses] + Std = "0x1" + Pontem = "0x2" + """ + ) + sources { + move( + "mod.move", """ + module Std::StdMod {} + module Pontem::PontemMod {} + module 0x1::MyMod { + use 0x2::Pont/*caret*/ + } + """ + ) + } + }, + """ + module Std::StdMod {} + module Pontem::PontemMod {} + module 0x1::MyMod { + use 0x2::PontemMod/*caret*/ + } + """ + ) + fun `test modules from tests directory should not be in completion of sources`() = checkNoCompletion { namedMoveToml("MyPackage") sources { @@ -205,11 +262,13 @@ class ModulesCompletionProjectTest : CompletionProjectTestCase() { """ ) sources { - main(""" + main( + """ module 0x1::M { use aptos_std::de/*caret*/; } - """) + """ + ) move( "debug.move", """ module std::debug { From d7578197c1dfe9b7a6d1aba19da841538149ef87 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 23 Jul 2024 22:15:41 +0300 Subject: [PATCH 35/43] remove find usages test --- .../kotlin/org/move/ide/search/FindUsagesTest.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt b/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt index 2ed395fd7..51ad53198 100644 --- a/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt +++ b/src/test/kotlin/org/move/ide/search/FindUsagesTest.kt @@ -40,14 +40,14 @@ class FindUsagesTest : MvTestBase() { } } """) - - fun `test module`() = doTestByText(""" - module 0x1::m {} - //^ - module 0x1::main { - use 0x1::m; // - module - } - """) +// +// fun `test module`() = doTestByText(""" +// module 0x1::m {} +// //^ +// module 0x1::main { +// use 0x1::m; // - module +// } +// """) private fun doTestByText(@Language("Move") code: String) { InlineFile(code) From ca5cbb4597fcf5af6dbe81cc85559a6646e91963 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 30 Jul 2024 23:14:20 +0300 Subject: [PATCH 36/43] remove ContextScopeInfo.matches usages --- .../move/ide/refactoring/MvImportOptimizer.kt | 37 ------------------- .../lang/core/completion/LookupElements.kt | 2 +- .../providers/MvPathCompletionProvider2.kt | 3 +- .../org/move/lang/core/psi/MvPsiFactory.kt | 5 +-- .../move/lang/core/psi/ext/MvItemSpecBlock.kt | 12 +++--- .../org/move/lang/core/psi/ext/MvModule.kt | 3 ++ .../move/lang/core/resolve/NameResolution.kt | 6 +-- .../org/move/lang/core/resolve/Processors.kt | 12 +++++- .../core/resolve2/LexicalDeclarations2.kt | 32 +++++++++------- .../move/lang/core/resolve2/Visibility2.kt | 9 +++-- .../core/resolve2/ref/Path2ReferenceImpl.kt | 4 +- .../org/move/lang/core/types/Address.kt | 4 +- .../completion/names/StructsCompletionTest.kt | 1 + .../lang/resolve/ResolveStructFieldsTest.kt | 4 +- .../annotation/MvAnnotationTestFixture.kt | 6 +-- 15 files changed, 61 insertions(+), 79 deletions(-) diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index a6ad6d978..95715fe2d 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -77,43 +77,6 @@ class MvImportOptimizer : ImportOptimizer { } } -// private fun mergeItemGroups(useStmtOwner: MvItemsOwner) { -// val psiFactory = useStmtOwner.project.psiFactory -// val leftBrace = useStmtOwner.findFirstChildByType(L_BRACE) ?: return -// -// val useStmts = useStmtOwner.useStmtList -// useStmts -// .groupBy { Pair(it.fqModuleText, it.hasTestOnlyAttr) } -// .forEach { (key, stmts) -> -// val (fqModuleText, isTestOnly) = key -// if (fqModuleText == null) return@forEach -// -// // special case: if single stmt and import like `use 0x1::Main::Self;`, change to `0x1::Main` -//// if (stmts.size == 1) { -//// val stmt = stmts.single() -//// val useItem = stmt.childUseItems.singleOrNull()?.takeIf { it.text == "Self" } -//// if (useItem != null) { -//// val newStmt = psiFactory.useStmt(fqModuleText, isTestOnly) -//// stmt.replace(newStmt) -//// } -//// return@forEach -//// } -// -// val useItemNames = mutableListOf() -// if (stmts.any { it.moduleUseSpeck != null }) { -// useItemNames.add("Self") -// } -// useItemNames.addAll(stmts.flatMap { it.childUseItems }.map { it.text }) -// val newStmt = -// psiFactory.useStmt( -// "$fqModuleText::{${useItemNames.joinToString(", ")}}", -// isTestOnly -// ) -// useStmtOwner.addAfter(newStmt, leftBrace) -// stmts.forEach { it.delete() } -// } -// } - /** Returns true if successfully removed, e.g. `use aaa::{bbb};` -> `use aaa::bbb;` */ private fun removeCurlyBracesIfPossible(rootUseSpeck: MvUseSpeck, psiFactory: MvPsiFactory) { val itemUseSpeck = rootUseSpeck.useGroup?.asTrivial ?: return diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index 7ebde3e82..3a9075fca 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -233,7 +233,7 @@ open class DefaultInsertHandler(val completionCtx: CompletionContext? = null): I when (element) { is MvFunctionLike -> { // no suffix for imports - if (completionCtx?.resolutionCtx?.isUseSpeck ?: false) return + if (completionCtx?.resolutionCtx?.isUseSpeck == true) return val isMethodCall = context.getElementOfType() != null val requiresExplicitTypes = diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index ecff64c16..5e44a3480 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -121,12 +121,13 @@ object MvPathCompletionProvider2: MvCompletionProvider() { result: CompletionResultSet, completionFilters: List = emptyList() ) { -// val qualifier = pathElement.qualifier val structAsType = TYPE in ns val resolutionCtx = completionContext.resolutionCtx ?: error("always non-null in path completion") var completionCollector = createProcessor { e -> val element = e.element as? MvNamedElement ?: return@createProcessor + // check for visibility + if (!e.isVisibleFrom(pathElement)) return@createProcessor val lookup = element.createLookupElement( completionContext, diff --git a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt index 6e7b02832..acf5b8d59 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvPsiFactory.kt @@ -76,9 +76,8 @@ class MvPsiFactory(val project: Project) { createFromText("module 0x1::_DummyModule { $text }") ?: error("Failed to create const") - @Suppress("InvalidModuleDeclaration") - fun builtinConst(text: String): MvConst = - createFromText("module spec_builtins { $text }") ?: error("Failed to create const") + fun specBuiltinConst(text: String): MvConst = + createFromText("module 0x0::spec_builtins { $text }") ?: error("Failed to create const") inline fun expr(text: String): T = createFromText("module 0x1::_DummyModule { fun call() { let _ = $text; } }") diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemSpecBlock.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemSpecBlock.kt index 964d65e06..6bd6eee04 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvItemSpecBlock.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvItemSpecBlock.kt @@ -8,15 +8,15 @@ fun MvSpecCodeBlock.builtinSpecConsts(): List { return CachedValuesManager.getProjectPsiDependentCache(this) { val psiFactory = it.project.psiFactory listOf( - psiFactory.builtinConst( + psiFactory.specBuiltinConst( "const MAX_U256: u256 = " + "115792089237316195423570985008687907853269984665640564039457584007913129639935;" ), - psiFactory.builtinConst("const MAX_U128: u128 = 340282366920938463463374607431768211455;"), - psiFactory.builtinConst("const MAX_U64: u64 = 18446744073709551615;"), - psiFactory.builtinConst("const MAX_U32: u32 = 4294967295;"), - psiFactory.builtinConst("const MAX_U16: u16 = 65535;"), - psiFactory.builtinConst("const MAX_U8: u8 = 255;"), + psiFactory.specBuiltinConst("const MAX_U128: u128 = 340282366920938463463374607431768211455;"), + psiFactory.specBuiltinConst("const MAX_U64: u64 = 18446744073709551615;"), + psiFactory.specBuiltinConst("const MAX_U32: u32 = 4294967295;"), + psiFactory.specBuiltinConst("const MAX_U16: u16 = 65535;"), + psiFactory.specBuiltinConst("const MAX_U8: u8 = 255;"), ) } } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index 68803a3f8..d0ca218cd 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -74,6 +74,9 @@ fun MvModule.testFunctions(): List = it.allFunctions().filter { f -> f.hasTestAttr } } +val MvModule.isBuiltins: Boolean get() = this.name == "builtins" && (this.address(null)?.is0x0 ?: false) +val MvModule.isSpecBuiltins: Boolean get() = this.name == "spec_builtins" && (this.address(null)?.is0x0 ?: false) + fun MvModule.builtinFunctions(): List { return getProjectPsiDependentCache(this) { val text = """ diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt index e419a83d8..f829c22cc 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt @@ -23,9 +23,9 @@ data class ContextScopeInfo( return true } - fun wrapWithContextFilter(processor: RsResolveProcessorBase): RsResolveProcessorBase { - return processor.wrapWithFilter { e: T -> this.matches(e.element) } - } +// fun wrapWithContextFilter(processor: RsResolveProcessorBase): RsResolveProcessorBase { +// return processor.wrapWithFilter { e: T -> this.matches(e.element) } +// } companion object { /// really does not affect anything, created just to allow creating CompletionContext everywhere diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index fba0ee2e8..661c59992 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -7,6 +7,7 @@ import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.ext.MvItemElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.createFilter import org.move.lang.core.resolve2.ref.PathResolutionContext @@ -350,7 +351,6 @@ private fun collectPathScopeEntry( val visibilityStatus = e.getVisibilityStatusFrom(ctx.path) val isVisible = visibilityStatus == VisibilityStatus.Visible result += RsPathResolveResult(element, isVisible) -// } } fun pickFirstResolveVariant(referenceName: String?, f: (RsResolveProcessor) -> Unit): MvElement? = @@ -541,6 +541,16 @@ fun RsResolveProcessor.process( visibilityFilter: VisibilityFilter ): Boolean = process(ScopeEntryWithVisibility(name, e, namespaces, visibilityFilter)) +fun RsResolveProcessor.processAllItems( + namespaces: Set, + vararg collections: Iterable, +): Boolean { + return sequenceOf(*collections).flatten().any { e -> + val name = e.name ?: return false + val visibilityFilter = e.visInfo().createFilter() + process(ScopeEntryWithVisibility(name, e, namespaces, visibilityFilter)) + } +} fun RsResolveProcessor.process( name: String, diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index d1e230f4b..e13ceac7d 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -13,23 +13,24 @@ import org.move.lang.core.resolve2.util.forEachLeafSpeck fun processItemsInScope( scope: MvElement, cameFrom: MvElement, - namespaces: Set, + ns: Set, ctx: PathResolutionContext, processor: RsResolveProcessor, ): Boolean { - for (namespace in namespaces) { + for (namespace in ns) { val stop = when (namespace) { Namespace.NAME -> { val found = when (scope) { is MvModuleBlock -> { val module = scope.parent as MvModule - processor.processAll( + processor.processAllItems( + ns, module.structs(), module.consts(), ) } - is MvModuleSpecBlock -> processor.processAll(scope.schemaList) - is MvScript -> processor.processAll(scope.consts()) + is MvModuleSpecBlock -> processor.processAllItems(ns, scope.schemaList) + is MvScript -> processor.processAllItems(ns, scope.consts()) is MvFunctionLike -> processor.processAll(scope.allParamsAsBindings) is MvLambdaExpr -> processor.processAll(scope.bindingPatList) is MvForExpr -> { @@ -111,7 +112,8 @@ fun processItemsInScope( var found = shadowingProcessor.processAll(namedElements) if (!found && scope is MvSpecCodeBlock) { // if inside SpecCodeBlock, process also with builtin spec consts and global variables - found = shadowingProcessor.processAll( + found = shadowingProcessor.processAllItems( + ns, scope.builtinSpecConsts(), scope.globalVariables() ) @@ -129,9 +131,10 @@ fun processItemsInScope( val specFunctions = listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() val specInlineFunctions = module.moduleItemSpecs().flatMap { it.specInlineFunctions() } - processor.processAll( - module.allNonTestFunctions(), + processor.processAllItems( + ns, module.builtinFunctions(), + module.allNonTestFunctions(), specFunctions, specInlineFunctions ) @@ -139,7 +142,8 @@ fun processItemsInScope( is MvModuleSpecBlock -> { val specFunctions = scope.specFunctionList val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } - processor.processAll( + processor.processAllItems( + ns, specFunctions, specInlineFunctions ) @@ -155,7 +159,7 @@ fun processItemsInScope( } is MvSpecCodeBlock -> { val inlineFunctions = scope.specInlineFunctions().asReversed() - return processor.processAll(inlineFunctions) + processor.processAllItems(ns, inlineFunctions) } else -> false } @@ -177,7 +181,7 @@ fun processItemsInScope( } is MvModuleBlock -> { val module = scope.parent as MvModule - processor.processAll(module.structs()) + processor.processAllItems(ns, module.structs()) } is MvApplySchemaStmt -> { val toPatterns = scope.applyTo?.functionPatternList.orEmpty() @@ -192,8 +196,8 @@ fun processItemsInScope( } Namespace.SCHEMA -> when (scope) { - is MvModuleBlock -> processor.processAll(scope.schemaList) - is MvModuleSpecBlock -> processor.processAll(scope.schemaList, scope.specFunctionList) + is MvModuleBlock -> processor.processAllItems(ns, scope.schemaList) + is MvModuleSpecBlock -> processor.processAllItems(ns, scope.schemaList, scope.specFunctionList) else -> false } else -> false @@ -202,7 +206,7 @@ fun processItemsInScope( } if (scope is MvItemsOwner) { - if (scope.processUseSpeckElements(namespaces, processor)) return true + if (scope.processUseSpeckElements(ns, processor)) return true } return false diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 6a58cbd1e..7e78eef69 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -60,20 +60,21 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // #[test] functions cannot be used from non-imports if (item is MvFunction && item.hasTestAttr) return@VisibilityFilter Invisible - // todo: uncomment when ContextScopeInfo filter is removed + val itemModule = item.containingModule + // 0x0::builtins module items are always visible + if (itemModule != null && itemModule.isBuiltins) return@VisibilityFilter Visible + // #[test_only] items in non-test-only scope if (itemUsageScope != MAIN) { // cannot be used everywhere, need to check for scope compatibility if (itemUsageScope != pathUsageScope) return@VisibilityFilter Invisible } - // todo: uncomment when ContextScopeInfo filter is removed // we're in non-msl scope at this point, msl only items aren't available if (item is MslOnlyElement) return@VisibilityFilter Invisible - // local methods, Self::method - everything is visible - val itemModule = item.containingModule val pathModule = path.containingModule + // local methods, Self::method - everything is visible if (itemModule == pathModule) return@VisibilityFilter Visible when (visibility) { diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 436a3889f..aabbea711 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -62,8 +62,8 @@ fun processPathResolveVariants( pathKind: PathKind, processor: RsResolveProcessor ): Boolean { - val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) -// val contextProcessor = processor +// val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) + val contextProcessor = processor return when (pathKind) { is NamedAddress, is ValueAddress -> false is PathKind.UnqualifiedPath -> { diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index 14b235624..6b6a6765a 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -40,8 +40,10 @@ class AddressLit(val original: String) { sealed class Address { - abstract fun canonicalValue(moveProject: MoveProject): String? abstract fun text(): String + abstract fun canonicalValue(moveProject: MoveProject): String? + + val is0x0 get() = this is Value && this.addressLit().original == "0x0" class Value(private val value: String) : Address() { fun addressLit(): AddressLit = AddressLit(value) diff --git a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt index f9923dd76..51f568f83 100644 --- a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt @@ -198,6 +198,7 @@ class StructsCompletionTest: CompletionTestCase() { } """) + // todo: error from ::Self module completion, which is handled with the module name instead fun `test module struct completion in type position`() = doSingleCompletion(""" module 0x1::Transaction { struct Type { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveStructFieldsTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveStructFieldsTest.kt index 52a3b49aa..ac5907ea6 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveStructFieldsTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveStructFieldsTest.kt @@ -87,10 +87,10 @@ class ResolveStructFieldsTest : ResolveTestCase() { """ module 0x1::M { struct CapState has key { delegates: vector
} - //X + //X fun m() acquires CapState { borrow_global_mut>(@0x1).delegates; - //^ + //^ } } """ diff --git a/src/test/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt b/src/test/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt index baee22110..b2cf780e5 100644 --- a/src/test/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt +++ b/src/test/kotlin/org/move/utils/tests/annotation/MvAnnotationTestFixture.kt @@ -10,12 +10,10 @@ import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile -import com.intellij.testFramework.IndexingTestUtil import com.intellij.testFramework.InspectionTestUtil import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.fixtures.CodeInsightTestFixture import com.intellij.testFramework.fixtures.impl.BaseFixture -import com.intellij.vcs.log.data.index.isIndexingEnabled import junit.framework.TestCase import org.intellij.lang.annotations.Language import org.move.ide.annotator.MvAnnotatorBase @@ -26,7 +24,7 @@ class MvAnnotationTestFixture( val codeInsightFixture: CodeInsightTestFixture, private var annotatorClasses: List> = emptyList(), private var inspectionClasses: List> = emptyList(), -) : BaseFixture() { +): BaseFixture() { val project: Project get() = codeInsightFixture.project lateinit var enabledInspections: List @@ -67,7 +65,7 @@ class MvAnnotationTestFixture( private fun configureByText(text: String): PsiFile { val psiFile = codeInsightFixture.configureByText("main.move", replaceCaretMarker(text.trimIndent())) // build indexes - IndexingTestUtil.waitUntilIndexesAreReady(codeInsightFixture.project) +// IndexingTestUtil.waitUntilIndexesAreReady(codeInsightFixture.project) return psiFile } From 7d4de7e97f87fe49dc67d33acd0465be198d6d52 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Tue, 30 Jul 2024 23:31:56 +0300 Subject: [PATCH 37/43] remove old code --- .../MethodOrFieldCompletionProvider.kt | 8 +- .../providers/MvPathCompletionProvider2.kt | 14 +-- .../SchemaFieldsCompletionProvider.kt | 5 +- .../providers/StructPatCompletionProvider.kt | 1 - .../lang/core/psi/ext/MvSchemaLitField.kt | 12 +- .../org/move/lang/core/psi/ext/MvUseGroup.kt | 15 ++- .../org/move/lang/core/psi/ext/MvUseItem.kt | 67 ---------- .../move/lang/core/psi/ext/MvUseItemGroup.kt | 18 --- .../org/move/lang/core/psi/ext/MvUseSpeck.kt | 4 +- .../org/move/lang/core/psi/ext/MvUseStmt.kt | 119 ------------------ .../move/lang/core/resolve/NameResolution.kt | 17 --- .../org/move/lang/core/resolve/Processors.kt | 1 + .../core/resolve2/ref/Path2ReferenceImpl.kt | 15 +-- 13 files changed, 41 insertions(+), 255 deletions(-) delete mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt delete mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt delete mode 100644 src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index bdd5f83c3..3cbf2f229 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -44,10 +44,10 @@ object MethodOrFieldCompletionProvider: MvCompletionProvider() { fun addMethodOrFieldVariants(element: MvMethodOrField, result: CompletionResultSet) { val msl = element.isMsl() val receiverTy = element.inferReceiverTy(msl).knownOrNull() ?: return - val scopeInfo = ContextScopeInfo( - letStmtScope = element.letStmtScope, - refItemScopes = element.refItemScopes, - ) +// val scopeInfo = ContextScopeInfo( +// letStmtScope = element.letStmtScope, +// refItemScopes = element.refItemScopes, +// ) val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(element, msl) val ctx = CompletionContext(element, msl, expectedTy) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 5e44a3480..2555a9eba 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -46,13 +46,13 @@ object MvPathCompletionProvider2: MvCompletionProvider() { if (parameters.position !== pathElement.referenceNameElement) return val parentElement = pathElement.rootPath().parent - val contextScopeInfo = - if (parentElement is MvSchemaLit) - ContextScopeInfo( - refItemScopes = pathElement.itemScopes, - letStmtScope = EXPR_STMT - ) else ContextScopeInfo.from(pathElement) - val resolutionCtx = PathResolutionContext(pathElement, contextScopeInfo) +// val contextScopeInfo = +// if (parentElement is MvSchemaLit) +// ContextScopeInfo( +// refItemScopes = pathElement.itemScopes, +// letStmtScope = EXPR_STMT +// ) else ContextScopeInfo.from(pathElement) + val resolutionCtx = PathResolutionContext(pathElement) val msl = pathElement.isMslScope val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt index 9107446ca..0c127d2e3 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt @@ -15,9 +15,8 @@ import org.move.lang.core.withParent object SchemaFieldsCompletionProvider: MvCompletionProvider() { override val elementPattern: ElementPattern - get() = PlatformPatterns - .psiElement() - .withParent() + get() = + PlatformPatterns.psiElement().withParent() override fun addCompletions( parameters: CompletionParameters, diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt index bd9715e66..735deea35 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt @@ -43,7 +43,6 @@ object StructPatCompletionProvider: MvCompletionProvider() { refItemScopes = bindingPat.namedItemScopes, ) val completionCtx = CompletionContext(bindingPat, bindingPat.isMsl()) -// val completionCtx = CompletionContext(bindingPat, contextScopeInfo) processModuleItems(module, namespaces, setOf(Visibility.Internal), contextScopeInfo) { val lookup = it.element.createLookupElement(completionCtx) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt index c543922a0..7883b13fe 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt @@ -3,6 +3,7 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode import org.move.lang.MvElementTypes import org.move.lang.core.psi.* +import org.move.lang.core.resolve.collectPathResolveVariants import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached import org.move.lang.core.resolve.ref.Namespace @@ -21,7 +22,7 @@ fun MvSchemaLitField.resolveToBinding(): MvBindingPat? = resolveToElement() class MvSchemaFieldReferenceImpl( element: MvSchemaLitField ) : MvPolyVariantReferenceCached(element) { - override fun multiResolveInner(): List = resolveIntoSchemaField(element) + override fun multiResolveInner(): List = collectSchemaFieldResolveVariants(element) } class MvSchemaFieldShorthandReferenceImpl( @@ -29,7 +30,7 @@ class MvSchemaFieldShorthandReferenceImpl( ) : MvPolyVariantReferenceCached(element) { override fun multiResolveInner(): List { return listOf( - resolveIntoSchemaField(element), + collectSchemaFieldResolveVariants(element), resolveLocalItem(element, setOf(Namespace.NAME)) ).flatten() } @@ -46,11 +47,10 @@ abstract class MvSchemaLitFieldMixin(node: ASTNode) : MvElementImpl(node), } } -private fun resolveIntoSchemaField(element: MvSchemaLitField): List { +private fun collectSchemaFieldResolveVariants(element: MvSchemaLitField): List { val schemaLit = element.schemaLit ?: return emptyList() - val schema = schemaLit.path.maybeSchema + val schema = schemaLit.path.maybeSchema ?: return emptyList() val referenceName = element.referenceName return schema - ?.fieldBindings.orEmpty() - .filter { it.name == referenceName } + .fieldBindings.filter { it.name == referenceName } } \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt index af26397b8..7a2a88a79 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseGroup.kt @@ -1,6 +1,19 @@ package org.move.lang.core.psi.ext +import com.intellij.psi.PsiComment +import com.intellij.psi.SyntaxTraverser import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseSpeck -val MvUseGroup.parentUseSpeck: MvUseSpeck get() = parent as MvUseSpeck \ No newline at end of file +val MvUseGroup.parentUseSpeck: MvUseSpeck get() = parent as MvUseSpeck + +val MvUseGroup.names get() = this.useSpeckList.mapNotNull { it.path.identifier?.text } + +val MvUseGroup.asTrivial: MvUseSpeck? + get() { + val speck = useSpeckList.singleOrNull() ?: return null + // Do not change use-groups with comments + if (SyntaxTraverser.psiTraverser(this).traverse().any { it is PsiComment }) return null + return speck + } + diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt deleted file mode 100644 index ee66366af..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItem.kt +++ /dev/null @@ -1,67 +0,0 @@ -package org.move.lang.core.psi.ext - -import org.move.lang.core.psi.* - -val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false - -//class MvUseItemReferenceElement( -// element: MvUseItem -//): MvPolyVariantReferenceCached(element) { -// -// override fun multiResolveInner(): List { -// val fqModuleRef = element.itemUseSpeck.fqModuleRef -// val module = -// fqModuleRef.reference?.resolve() as? MvModule ?: return emptyList() -// if ((element.useAlias == null && element.text == "Self") -// || (element.useAlias != null && element.text.startsWith("Self as")) -// ) { -// return listOf(module) -// } -// -// val ns = setOf( -// Namespace.TYPE, -// Namespace.NAME, -// Namespace.FUNCTION, -// Namespace.SCHEMA, -// Namespace.CONST -// ) -// val vs = Visibility.visibilityScopesForElement(fqModuleRef) -// -// // import has MAIN+VERIFY, and TEST if it or any of the parents has test -// val useItemScopes = mutableSetOf(NamedItemScope.MAIN, NamedItemScope.VERIFY) -// -// // gather scopes for all parents up to MvUseStmt -// var scopedElement: MvElement? = element -// while (scopedElement != null) { -// useItemScopes.addAll(scopedElement.itemScopes) -// scopedElement = scopedElement.parent as? MvElement -// } -// -// val contextScopeInfo = -// ContextScopeInfo( -// letStmtScope = LetStmtScope.EXPR_STMT, -// refItemScopes = useItemScopes, -// ) -// return resolveModuleItem( -// module, -// element.referenceName, -// ns, -// vs, -// contextScopeInfo -// ) -// } -// -//} - -//abstract class MvUseItemMixin(node: ASTNode): MvNamedElementImpl(node), -// MvUseItem { -// override fun getName(): String? { -// val name = super.getName() -// if (name != "Self") return name -// return ancestorStrict()?.fqModuleRef?.referenceName ?: name -// } -// -// override val referenceNameElement: PsiElement get() = identifier -// -// override fun getReference() = MvUseItemReferenceElement(this) -//} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt deleted file mode 100644 index 17f7a5325..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseItemGroup.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.move.lang.core.psi.ext - -import com.intellij.psi.PsiComment -import com.intellij.psi.SyntaxTraverser -import org.move.lang.core.psi.MvUseGroup -import org.move.lang.core.psi.MvUseSpeck - -val MvUseGroup.names get() = this.useSpeckList.mapNotNull { it.path.identifier?.text } - -//val MvUseItemGroup.parentUseSpeck: MvItemUseSpeck get() = parent as MvItemUseSpeck - -val MvUseGroup.asTrivial: MvUseSpeck? - get() { - val speck = useSpeckList.singleOrNull() ?: return null - // Do not change use-groups with comments - if (SyntaxTraverser.psiTraverser(this).traverse().any { it is PsiComment }) return null - return speck - } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt index 554821f59..159fdf5c2 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt @@ -8,4 +8,6 @@ val MvUseSpeck.qualifier: MvPath? get() { val parentUseSpeck = (context as? MvUseGroup)?.parentUseSpeck ?: return null return parentUseSpeck.pathOrQualifier } -val MvUseSpeck.pathOrQualifier: MvPath? get() = path ?: qualifier \ No newline at end of file +val MvUseSpeck.pathOrQualifier: MvPath? get() = path ?: qualifier + +val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt deleted file mode 100644 index 235c10552..000000000 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseStmt.kt +++ /dev/null @@ -1,119 +0,0 @@ -package org.move.lang.core.psi.ext - -//val MvUseStmt.moduleUseSpeck: MvModuleUseSpeck? get() = null -//val MvUseStmt.itemUseSpeck: MvItemUseSpeck? get() = null - -//val MvUseStmt.addressRef: MvAddressRef? -// get() { -// val moduleUseSpeck = this.moduleUseSpeck -// if (moduleUseSpeck != null) { -// val fqModuleRef = moduleUseSpeck.fqModuleRef -// if (fqModuleRef != null) { -// return fqModuleRef.addressRef -// } else { -// return moduleUseSpeck.addressRef -// } -// } -// val itemUseSpeck = this.itemUseSpeck -// if (itemUseSpeck != null) { -// return itemUseSpeck.fqModuleRef.addressRef -// } -// return null -// } - -//val MvUseStmt.useGroupLevel: Int -// get() { -// if (this.hasTestOnlyAttr) return 5 -// return this.addressRef?.useGroupLevel ?: -1 -// } - -//val MvUseStmt.fqModuleText: String? -// get() { -// val fqModuleRef = this.fqModuleRef ?: return null -// return fqModuleRef.text -// } - -//val MvUseStmt.fqModuleRef: MvFQModuleRef? -// get() { -// val moduleUseSpeck = this.moduleUseSpeck -// if (moduleUseSpeck != null) { -// return moduleUseSpeck.fqModuleRef -// } -// val itemUseSpeck = this.itemUseSpeck -// if (itemUseSpeck != null) { -// return itemUseSpeck.fqModuleRef -// } -// return null -// } - -//val MvUseStmt.childUseItems: List -// get() { -// return this.itemUseSpeck?.useItems.orEmpty() -//// if (itemUseSpeck != null) { -//// return itemUseSpeck.useItems -////// val group = itemUseSpeck.useItemGroup -////// if (group != null) { -////// return group.useItemList -////// } -////// return itemUseSpeck.useItem.wrapWithList() -//// } -//// return emptyList() -// } - -//val MvItemUseSpeck.useItems: List -// get() { -// val group = this.useItemGroup -// if (group != null) { -// return group.useItemList -// } -// return this.useItem.wrapWithList() -// } - - -//sealed class UseSpeck(open val nameOrAlias: String, open val scope: NamedItemScope) { -// data class Module( -// override val nameOrAlias: String, -// override val scope: NamedItemScope, -// val moduleUseSpeck: MvModuleUseSpeck, -// ): UseSpeck(nameOrAlias, scope) -// -// data class SelfModule( -// override val nameOrAlias: String, -// override val scope: NamedItemScope, -// val useItem: MvUseItem, -// ): UseSpeck(nameOrAlias, scope) -// -// data class Item( -// override val nameOrAlias: String, -// override val scope: NamedItemScope, -// val useItem: MvUseItem, -// ): UseSpeck(nameOrAlias, scope) -//} - - -//val MvUseStmt.useSpecks: List -// get() { -// val stmtItemScope = this.declaredItemScope -// val moduleUseSpeck = this.moduleUseSpeck -// if (moduleUseSpeck != null) { -// val nameOrAlias = moduleUseSpeck.nameElement?.text ?: return emptyList() -// return listOf(UseSpeck.Module(nameOrAlias, stmtItemScope, moduleUseSpeck)) -// } -// return this.itemUseSpeck?.useItems.orEmpty() -// .mapNotNull { -// if (it.isSelf) { -// val useAlias = it.useAlias -// val nameOrAlias = -// if (useAlias != null) { -// val aliasName = useAlias.name ?: return@mapNotNull null -// aliasName -// } else { -// it.moduleName -// } -// UseSpeck.SelfModule(nameOrAlias, stmtItemScope, it) -// } else { -// val nameOrAlias = it.nameOrAlias ?: return@mapNotNull null -// UseSpeck.Item(nameOrAlias, stmtItemScope, it) -// } -// } -// } diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt index f829c22cc..3238bb078 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt @@ -22,23 +22,6 @@ data class ContextScopeInfo( ) return false return true } - -// fun wrapWithContextFilter(processor: RsResolveProcessorBase): RsResolveProcessorBase { -// return processor.wrapWithFilter { e: T -> this.matches(e.element) } -// } - - companion object { - /// really does not affect anything, created just to allow creating CompletionContext everywhere -// fun default(): ContextScopeInfo = ContextScopeInfo(setOf(MAIN), NONE) -// fun msl(): ContextScopeInfo = ContextScopeInfo(setOf(VERIFY), EXPR_STMT) - - fun from(element: MvElement): ContextScopeInfo { - return ContextScopeInfo( - refItemScopes = element.itemScopes, - letStmtScope = element.letStmtScope, - ) - } - } } fun processItems( diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 661c59992..3844fa954 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -1,6 +1,7 @@ package org.move.lang.core.resolve import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.psi.ResolveResult import com.intellij.util.SmartList import org.move.lang.core.completion.CompletionContext import org.move.lang.core.psi.MvElement diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index aabbea711..15ca5d64c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -46,13 +46,8 @@ class Path2ReferenceImpl(element: MvPath): override fun invoke(path: MvElement): List> { // should not really happen if (path !is MvPath) return emptyList() - - val ctx = PathResolutionContext( - path = path, - contextScopeInfo = ContextScopeInfo.from(path) - ) - return resolvePath(ctx, path) -// return resolvePath(ctx, path, classifyPath(path)) + val resolutionCtx = PathResolutionContext(path) + return resolvePath(resolutionCtx, path) } } } @@ -149,10 +144,8 @@ fun processQualifiedPathResolveVariants( return false } -class PathResolutionContext( - val path: MvPath, - val contextScopeInfo: ContextScopeInfo, -) { +class PathResolutionContext(val path: MvPath) { + private var lazyContainingMoveProject: Lazy = lazy(NONE) { path.moveProject } From 9955dfadcd77a5a3a61e68a66fb81233cfc61a09 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 31 Jul 2024 00:05:59 +0300 Subject: [PATCH 38/43] schema field resolution refactor, more tests --- .../SchemaFieldsCompletionProvider.kt | 41 +++++++++++---- .../org/move/lang/core/psi/ext/MvSchemaLit.kt | 2 - .../lang/core/psi/ext/MvSchemaLitField.kt | 46 +++++++++++------ .../completion/names/SpecsCompletionTest.kt | 50 ++++++++++++++++++- 4 files changed, 108 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt index 0c127d2e3..1bcc08ea9 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt @@ -8,9 +8,12 @@ import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement +import org.move.lang.core.completion.getOriginalOrSelf +import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvSchemaLitField +import org.move.lang.core.psi.completionPriority import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ContextScopeInfo +import org.move.lang.core.resolve.createProcessor import org.move.lang.core.withParent object SchemaFieldsCompletionProvider: MvCompletionProvider() { @@ -24,17 +27,33 @@ object SchemaFieldsCompletionProvider: MvCompletionProvider() { result: CompletionResultSet ) { val pos = parameters.position - val element = pos.parent as? MvSchemaLitField ?: return - val schemaLit = element.schemaLit ?: return - val schema = schemaLit.schema ?: return - val providedFieldNames = schemaLit.fieldNames + val literalField = pos.parent as? MvSchemaLitField ?: return - val completionCtx = CompletionContext(element, element.isMsl()) -// val completionCtx = CompletionContext(element, ContextScopeInfo.msl()) - for (fieldBinding in schema.fieldBindings.filter { it.name !in providedFieldNames }) { - result.addElement( - fieldBinding.createLookupElement(completionCtx) - ) + val schemaLit = literalField.schemaLit?.getOriginalOrSelf() ?: return + val existingFieldNames = schemaLit.fields + .filter { !it.textRange.contains(pos.textOffset) } + .map { it.referenceName } + + val completionCtx = CompletionContext(literalField, literalField.isMsl()) + val completionCollector = createProcessor { e -> + val element = e.element as? MvNamedElement ?: return@createProcessor + // check for visibility +// if (!e.isVisibleFrom(pathElement)) return@createProcessor + if (e.name in existingFieldNames) return@createProcessor + val lookup = + element.createLookupElement( + completionCtx, + priority = element.completionPriority + ) + result.addElement(lookup) } + processSchemaLitFieldResolveVariants(literalField, completionCollector) + +// val completionCtx = CompletionContext(element, ContextScopeInfo.msl()) +// for (fieldBinding in schema.fieldBindings.filter { it.name !in providedFieldNames }) { +// result.addElement( +// fieldBinding.createLookupElement(completionCtx) +// ) +// } } } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt index dccc85505..2c4637c19 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLit.kt @@ -7,5 +7,3 @@ import org.move.lang.core.psi.MvSchemaLitField val MvSchemaLit.schema: MvSchema? get() = this.path.reference?.resolveFollowingAliases() as? MvSchema val MvSchemaLit.fields: List get() = schemaFieldsBlock?.schemaLitFieldList.orEmpty() - -val MvSchemaLit.fieldNames: List get() = fields.map { it.referenceName } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt index 7883b13fe..a1e6d4efc 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt @@ -3,17 +3,16 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode import org.move.lang.MvElementTypes import org.move.lang.core.psi.* -import org.move.lang.core.resolve.collectPathResolveVariants +import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.resolveLocalItem val MvSchemaLitField.isShorthand get() = !hasChild(MvElementTypes.COLON) val MvSchemaLitField.schemaLit: MvSchemaLit? get() = ancestorStrict(stopAt = MvSpecCodeBlock::class.java) -inline fun MvSchemaLitField.resolveToElement(): T? = +inline fun MvSchemaLitField.resolveToElement(): T? = reference.multiResolve().filterIsInstance().singleOrNull() fun MvSchemaLitField.resolveToDeclaration(): MvSchemaFieldStmt? = resolveToElement() @@ -21,23 +20,23 @@ fun MvSchemaLitField.resolveToBinding(): MvBindingPat? = resolveToElement() class MvSchemaFieldReferenceImpl( element: MvSchemaLitField -) : MvPolyVariantReferenceCached(element) { - override fun multiResolveInner(): List = collectSchemaFieldResolveVariants(element) +): MvPolyVariantReferenceCached(element) { + override fun multiResolveInner(): List = collectSchemaLitFieldResolveVariants(element) } class MvSchemaFieldShorthandReferenceImpl( element: MvSchemaLitField -) : MvPolyVariantReferenceCached(element) { +): MvPolyVariantReferenceCached(element) { override fun multiResolveInner(): List { return listOf( - collectSchemaFieldResolveVariants(element), + collectSchemaLitFieldResolveVariants(element), resolveLocalItem(element, setOf(Namespace.NAME)) ).flatten() } } -abstract class MvSchemaLitFieldMixin(node: ASTNode) : MvElementImpl(node), - MvSchemaLitField { +abstract class MvSchemaLitFieldMixin(node: ASTNode): MvElementImpl(node), + MvSchemaLitField { override fun getReference(): MvPolyVariantReference { if (this.isShorthand) { return MvSchemaFieldShorthandReferenceImpl(this) @@ -47,10 +46,25 @@ abstract class MvSchemaLitFieldMixin(node: ASTNode) : MvElementImpl(node), } } -private fun collectSchemaFieldResolveVariants(element: MvSchemaLitField): List { - val schemaLit = element.schemaLit ?: return emptyList() - val schema = schemaLit.path.maybeSchema ?: return emptyList() - val referenceName = element.referenceName - return schema - .fieldBindings.filter { it.name == referenceName } -} \ No newline at end of file +fun processSchemaLitFieldResolveVariants( + literalField: MvSchemaLitField, + processor: RsResolveProcessor +): Boolean { + val schemaLit = literalField.schemaLit ?: return false + val schema = schemaLit.path.maybeSchema ?: return false + return schema.fieldBindings + .any { field -> + processor.process(SimpleScopeEntry(field.name, field, setOf(Namespace.NAME))) + } +} + +fun collectSchemaLitFieldResolveVariants(literalField: MvSchemaLitField): List { + val referenceName = literalField.referenceName + val items = mutableListOf() + processSchemaLitFieldResolveVariants(literalField, createProcessor { e -> + if (e.name == referenceName) { + items.add(e.element) + } + }) + return items +} diff --git a/src/test/kotlin/org/move/lang/completion/names/SpecsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/SpecsCompletionTest.kt index f0a58422c..1bd7d9f2a 100644 --- a/src/test/kotlin/org/move/lang/completion/names/SpecsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/SpecsCompletionTest.kt @@ -209,7 +209,7 @@ class SpecsCompletionTest: CompletionTestCase() { module 0x1::M { fun call() {} spec call { - include MySchema { ad/*caret*/ } + include MySchema { ad/*caret*/ }; } spec schema MySchema { addr: address; @@ -219,7 +219,53 @@ class SpecsCompletionTest: CompletionTestCase() { module 0x1::M { fun call() {} spec call { - include MySchema { addr/*caret*/ } + include MySchema { addr/*caret*/ }; + } + spec schema MySchema { + addr: address; + } + } + """) + + fun `test autocomplete fields in include schema if full field name is provided`() = doSingleCompletion(""" + module 0x1::M { + fun call() {} + spec call { + include MySchema { addr/*caret*/ }; + } + spec schema MySchema { + addr: address; + } + } + """, """ + module 0x1::M { + fun call() {} + spec call { + include MySchema { addr/*caret*/ }; + } + spec schema MySchema { + addr: address; + } + } + """) + + fun `test no completion if field already used`() = checkNoCompletion(""" + module 0x1::M { + fun call() {} + spec call { + include MySchema { addr, ad/*caret*/ }; + } + spec schema MySchema { + addr: address; + } + } + """) + + fun `test no completion if field already used at the end`() = checkNoCompletion(""" + module 0x1::M { + fun call() {} + spec call { + include MySchema { ad/*caret*/, addr }; } spec schema MySchema { addr: address; From 55681727afe465361de4208027cc75b42f0ae3ad Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Wed, 31 Jul 2024 02:55:47 +0300 Subject: [PATCH 39/43] remove old code --- src/main/grammars/MoveParser.bnf | 4 +- .../ide/inspections/imports/AutoImportFix.kt | 14 +- .../lang/core/completion/LookupElements.kt | 9 +- .../MethodOrFieldCompletionProvider.kt | 3 - .../providers/MvPathCompletionProvider2.kt | 73 ++--- .../SchemaFieldsCompletionProvider.kt | 33 +-- .../StructFieldsCompletionProvider.kt | 1 - .../providers/StructPatCompletionProvider.kt | 27 +- .../lang/core/psi/ext/MvSchemaLitField.kt | 66 +++-- .../lang/core/psi/ext/MvStructLitField.kt | 79 ++++- .../lang/core/psi/ext/MvStructPatField.kt | 21 +- .../lang/core/resolve/LexicalDeclarations.kt | 259 ---------------- .../lang/core/resolve/MatchingProcessor.kt | 33 --- .../lang/core/resolve/ModuleItemResolution.kt | 106 ------- .../move/lang/core/resolve/NameResolution.kt | 280 ------------------ .../org/move/lang/core/resolve/Processors.kt | 36 ++- .../resolve/ref/MoveFQModuleReferenceImpl.kt | 24 -- .../resolve/ref/MoveModuleReferenceImpl.kt | 25 -- .../core/resolve/ref/MovePathReferenceImpl.kt | 71 ----- .../move/lang/core/resolve/ref/field_ref.kt | 51 ---- .../core/resolve2/LexicalDeclarations2.kt | 6 +- .../lang/core/resolve2/NameResolution2.kt | 77 ++++- .../core/resolve2/ref/Path2ReferenceImpl.kt | 28 +- .../completion/lookups/LookupElementTest.kt | 1 - 24 files changed, 282 insertions(+), 1045 deletions(-) delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt delete mode 100644 src/main/kotlin/org/move/lang/core/resolve/ref/field_ref.kt diff --git a/src/main/grammars/MoveParser.bnf b/src/main/grammars/MoveParser.bnf index 967f590bf..0dd885318 100644 --- a/src/main/grammars/MoveParser.bnf +++ b/src/main/grammars/MoveParser.bnf @@ -653,7 +653,7 @@ StructPatField ::= (BindingPat !':') | (IDENTIFIER StructPatFieldBinding) { implements = [ "org.move.lang.core.resolve.ref.MvStructPatFieldReferenceElement" - "org.move.lang.core.resolve.ref.MvStructRefField" + "org.move.lang.core.psi.ext.MvStructRefField" ] mixin = "org.move.lang.core.psi.ext.MvStructPatFieldMixin" } @@ -901,7 +901,7 @@ StructLitField ::= IDENTIFIER StructLitFieldInit? { implements = [ "org.move.lang.core.resolve.ref.MvStructFieldLitReferenceElement" - "org.move.lang.core.resolve.ref.MvStructRefField" + "org.move.lang.core.psi.ext.MvStructRefField" ] mixin = "org.move.lang.core.psi.ext.MvStructLitFieldMixin" } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt index 64b35303e..3fbbda648 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/AutoImportFix.kt @@ -9,13 +9,15 @@ import org.move.ide.inspections.DiagnosticFix import org.move.ide.utils.imports.ImportCandidate import org.move.ide.utils.imports.ImportCandidateCollector import org.move.ide.utils.imports.import -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.letStmtScope -import org.move.lang.core.resolve.ref.MvReferenceElement +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvPath +import org.move.lang.core.psi.MvUseSpeck +import org.move.lang.core.psi.MvUseStmt +import org.move.lang.core.psi.ext.ancestorStrict +import org.move.lang.core.psi.ext.hasAncestor +import org.move.lang.core.psi.ext.importCandidateNamespaces +import org.move.lang.core.psi.ext.qualifier import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility import org.move.openapiext.runWriteCommandAction class AutoImportFix(element: MvPath): DiagnosticFix(element), diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index 3a9075fca..3e06443b1 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -11,8 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil import org.move.ide.presentation.text import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.* import org.move.lang.core.types.ty.Ty import org.move.lang.core.types.ty.TyUnknown @@ -144,7 +143,8 @@ data class CompletionContext( // val contextScopeInfo: ContextScopeInfo, val msl: Boolean, val expectedTy: Ty? = null, - val resolutionCtx: PathResolutionContext? = null + val resolutionCtx: ResolutionContext? = null, + val structAsType: Boolean = false ) { // fun isMsl(): Boolean = contextScopeInfo.isMslScope fun isMsl(): Boolean = msl @@ -154,7 +154,6 @@ data class CompletionContext( fun MvNamedElement.createLookupElement( completionContext: CompletionContext, subst: Substitution = emptySubstitution, - structAsType: Boolean = false, priority: Double = DEFAULT_PRIORITY, insertHandler: InsertHandler = DefaultInsertHandler(completionContext), ): LookupElement { @@ -162,7 +161,7 @@ fun MvNamedElement.createLookupElement( this.getLookupElementBuilder( completionContext, subst = subst, - structAsType = structAsType + structAsType = completionContext.structAsType ) .withInsertHandler(insertHandler) .withPriority(priority) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index 3cbf2f229..bbb6d3896 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -10,10 +10,7 @@ import org.jetbrains.annotations.VisibleForTesting import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.ext.* -import org.move.lang.core.psi.refItemScopes import org.move.lang.core.psi.tyInfers -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.letStmtScope import org.move.lang.core.types.infer.InferenceContext import org.move.lang.core.types.infer.substitute import org.move.lang.core.types.ty.TyFunction diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 2555a9eba..1643abd91 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -16,13 +16,12 @@ import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* -import org.move.lang.core.resolve.LetStmtScope.EXPR_STMT import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.* import org.move.lang.core.resolve2.PathKind import org.move.lang.core.resolve2.pathKind -import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.resolve2.ref.processPathResolveVariants import org.move.lang.core.types.infer.inferExpectedTy import org.move.lang.core.types.infer.inference @@ -30,7 +29,7 @@ import org.move.lang.core.types.ty.Ty import org.move.lang.core.types.ty.TyUnknown fun interface CompletionFilter { - fun removeEntry(entry: ScopeEntry, ctx: PathResolutionContext): Boolean + fun removeEntry(entry: ScopeEntry, ctx: ResolutionContext): Boolean } object MvPathCompletionProvider2: MvCompletionProvider() { @@ -46,24 +45,10 @@ object MvPathCompletionProvider2: MvCompletionProvider() { if (parameters.position !== pathElement.referenceNameElement) return val parentElement = pathElement.rootPath().parent -// val contextScopeInfo = -// if (parentElement is MvSchemaLit) -// ContextScopeInfo( -// refItemScopes = pathElement.itemScopes, -// letStmtScope = EXPR_STMT -// ) else ContextScopeInfo.from(pathElement) - val resolutionCtx = PathResolutionContext(pathElement) + val resolutionCtx = ResolutionContext(pathElement) val msl = pathElement.isMslScope val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) - val completionContext = CompletionContext( - pathElement, -// contextScopeInfo, - msl, - expectedTy, - resolutionCtx = resolutionCtx - ) - // 0x1::m::{a, b, Self} // //^ if (resolutionCtx.isUseSpeck) { @@ -95,7 +80,15 @@ object MvPathCompletionProvider2: MvCompletionProvider() { } } } + val structAsType = TYPE in ns + val completionContext = CompletionContext( + pathElement, + msl, + expectedTy, + resolutionCtx = resolutionCtx, + structAsType, + ) addVariants( pathElement, parameters, completionContext, ns, result, listOf( @@ -121,37 +114,28 @@ object MvPathCompletionProvider2: MvCompletionProvider() { result: CompletionResultSet, completionFilters: List = emptyList() ) { - val structAsType = TYPE in ns val resolutionCtx = completionContext.resolutionCtx ?: error("always non-null in path completion") - - var completionCollector = createProcessor { e -> - val element = e.element as? MvNamedElement ?: return@createProcessor - // check for visibility - if (!e.isVisibleFrom(pathElement)) return@createProcessor - val lookup = - element.createLookupElement( - completionContext, - structAsType = structAsType, - priority = element.completionPriority - ) - result.addElement(lookup) - } - val processedNames = mutableSetOf() - completionCollector = completionCollector.wrapWithFilter { e -> - // custom filters - for (completionFilter in completionFilters) { - if (completionFilter.removeEntry(e, resolutionCtx)) return@wrapWithFilter false - } + collectCompletionVariants(result, completionContext) { + val processor = it + .wrapWithFilter { e -> + // custom completion filters + for (completionFilter in completionFilters) { + if (completionFilter.removeEntry(e, resolutionCtx)) return@wrapWithFilter false + } - if (processedNames.contains(e.name)) return@wrapWithFilter false - processedNames.add(e.name) + // drop already visited items + if (processedNames.contains(e.name)) return@wrapWithFilter false + processedNames.add(e.name) - true - } + // drop invisible items + if (!e.isVisibleFrom(pathElement)) return@wrapWithFilter false - val pathKind = pathElement.pathKind(overwriteNs = ns) - processPathResolveVariants(resolutionCtx, pathKind, completionCollector) + true + } + val pathKind = pathElement.pathKind(overwriteNs = ns) + processPathResolveVariants(resolutionCtx, pathKind, processor) + } // disable auto-import in module specs for now if (pathElement.containingModuleSpec != null) return @@ -175,7 +159,6 @@ object MvPathCompletionProvider2: MvCompletionProvider() { } val lookupElement = candidate.element.createLookupElement( completionContext, - structAsType = structAsType, priority = UNIMPORTED_ITEM_PRIORITY, insertHandler = ImportInsertHandler(parameters, candidate) ) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt index 1bcc08ea9..0712d200b 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt @@ -7,13 +7,14 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.createLookupElement import org.move.lang.core.completion.getOriginalOrSelf -import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.MvSchemaLitField -import org.move.lang.core.psi.completionPriority -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.createProcessor +import org.move.lang.core.psi.ext.fields +import org.move.lang.core.psi.ext.isMsl +import org.move.lang.core.psi.ext.processSchemaLitFieldResolveVariants +import org.move.lang.core.psi.ext.schemaLit +import org.move.lang.core.resolve.collectCompletionVariants +import org.move.lang.core.resolve.wrapWithFilter import org.move.lang.core.withParent object SchemaFieldsCompletionProvider: MvCompletionProvider() { @@ -35,25 +36,9 @@ object SchemaFieldsCompletionProvider: MvCompletionProvider() { .map { it.referenceName } val completionCtx = CompletionContext(literalField, literalField.isMsl()) - val completionCollector = createProcessor { e -> - val element = e.element as? MvNamedElement ?: return@createProcessor - // check for visibility -// if (!e.isVisibleFrom(pathElement)) return@createProcessor - if (e.name in existingFieldNames) return@createProcessor - val lookup = - element.createLookupElement( - completionCtx, - priority = element.completionPriority - ) - result.addElement(lookup) + collectCompletionVariants(result, completionCtx) { + val processor = it.wrapWithFilter { e -> e.name !in existingFieldNames } + processSchemaLitFieldResolveVariants(literalField, processor) } - processSchemaLitFieldResolveVariants(literalField, completionCollector) - -// val completionCtx = CompletionContext(element, ContextScopeInfo.msl()) -// for (fieldBinding in schema.fieldBindings.filter { it.name !in providedFieldNames }) { -// result.addElement( -// fieldBinding.createLookupElement(completionCtx) -// ) -// } } } diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt index 4110edcb0..738ecd0de 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt @@ -12,7 +12,6 @@ import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.withParent import org.move.lang.core.withSuperParent diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt index 735deea35..6bd099935 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt @@ -7,18 +7,14 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvBindingPat import org.move.lang.core.psi.MvLetStmt import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.isMsl -import org.move.lang.core.psi.namedItemScopes import org.move.lang.core.psiElement -import org.move.lang.core.resolve.ContextScopeInfo -import org.move.lang.core.resolve.LetStmtScope -import org.move.lang.core.resolve.processModuleItems +import org.move.lang.core.resolve.collectCompletionVariants import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve2.processItemDeclarations import org.move.lang.core.withParent object StructPatCompletionProvider: MvCompletionProvider() { @@ -35,22 +31,13 @@ object StructPatCompletionProvider: MvCompletionProvider() { ) { val bindingPat = parameters.position.parent as MvBindingPat val module = bindingPat.containingModule ?: return - - val namespaces = setOf(Namespace.TYPE) - val contextScopeInfo = - ContextScopeInfo( - letStmtScope = LetStmtScope.NONE, - refItemScopes = bindingPat.namedItemScopes, - ) val completionCtx = CompletionContext(bindingPat, bindingPat.isMsl()) - processModuleItems(module, namespaces, setOf(Visibility.Internal), contextScopeInfo) { - val lookup = - it.element.createLookupElement(completionCtx) - result.addElement(lookup) - false + val moduleBlock = module.moduleBlock + if (moduleBlock != null) { + collectCompletionVariants(result, completionCtx) { + processItemDeclarations(moduleBlock, setOf(Namespace.TYPE), it) + } } } - - } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt index a1e6d4efc..db6ef1169 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvSchemaLitField.kt @@ -3,10 +3,13 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode import org.move.lang.MvElementTypes import org.move.lang.core.psi.* -import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.SimpleScopeEntry +import org.move.lang.core.resolve.collectResolveVariants import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.resolveBindingForFieldShorthand val MvSchemaLitField.isShorthand get() = !hasChild(MvElementTypes.COLON) @@ -18,31 +21,42 @@ inline fun MvSchemaLitField.resolveToElement(): T? = fun MvSchemaLitField.resolveToDeclaration(): MvSchemaFieldStmt? = resolveToElement() fun MvSchemaLitField.resolveToBinding(): MvBindingPat? = resolveToElement() -class MvSchemaFieldReferenceImpl( - element: MvSchemaLitField -): MvPolyVariantReferenceCached(element) { - override fun multiResolveInner(): List = collectSchemaLitFieldResolveVariants(element) -} +//class MvSchemaFieldReferenceImpl( +// element: MvSchemaLitField +//): MvPolyVariantReferenceCached(element) { +// override fun multiResolveInner(): List = collectSchemaLitFieldResolveVariants(element) +//} -class MvSchemaFieldShorthandReferenceImpl( - element: MvSchemaLitField -): MvPolyVariantReferenceCached(element) { - override fun multiResolveInner(): List { - return listOf( - collectSchemaLitFieldResolveVariants(element), - resolveLocalItem(element, setOf(Namespace.NAME)) - ).flatten() - } -} +//class MvSchemaFieldShorthandReferenceImpl( +// element: MvSchemaLitField +//): MvPolyVariantReferenceCached(element) { +// override fun multiResolveInner(): List { +// return listOf( +// collectSchemaLitFieldResolveVariants(element), +// resolveLocalItem(element, setOf(Namespace.NAME)) +// ).flatten() +// } +//} abstract class MvSchemaLitFieldMixin(node: ASTNode): MvElementImpl(node), MvSchemaLitField { - override fun getReference(): MvPolyVariantReference { - if (this.isShorthand) { - return MvSchemaFieldShorthandReferenceImpl(this) - } else { - return MvSchemaFieldReferenceImpl(this) + override fun getReference(): MvPolyVariantReference = + MvSchemaLitFieldReferenceImpl(this, shorthand = this.isShorthand) +} + +class MvSchemaLitFieldReferenceImpl( + element: MvSchemaLitField, + val shorthand: Boolean, +): MvPolyVariantReferenceCached(element) { + override fun multiResolveInner(): List { + var variants = collectResolveVariants(element.referenceName) { + processSchemaLitFieldResolveVariants(element, it) } + if (shorthand) { + variants += resolveBindingForFieldShorthand(element) +// variants += resolveLocalItem(element, setOf(Namespace.NAME)) + } + return variants } } @@ -58,13 +72,3 @@ fun processSchemaLitFieldResolveVariants( } } -fun collectSchemaLitFieldResolveVariants(literalField: MvSchemaLitField): List { - val referenceName = literalField.referenceName - val items = mutableListOf() - processSchemaLitFieldResolveVariants(literalField, createProcessor { e -> - if (e.name == referenceName) { - items.add(e.element) - } - }) - return items -} diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt index ee8acd9af..cdccc0992 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt @@ -3,9 +3,14 @@ package org.move.lang.core.psi.ext import com.intellij.lang.ASTNode import org.move.lang.MvElementTypes import org.move.lang.core.psi.* +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.SimpleScopeEntry +import org.move.lang.core.resolve.collectResolveVariants +import org.move.lang.core.resolve.ref.MvMandatoryReferenceElement import org.move.lang.core.resolve.ref.MvPolyVariantReference -import org.move.lang.core.resolve.ref.MvStructLitShorthandFieldReferenceImpl -import org.move.lang.core.resolve.ref.MvStructRefFieldReferenceImpl +import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached +import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.resolveBindingForFieldShorthand val MvStructLitField.structLitExpr: MvStructLitExpr get() = ancestorStrict()!! @@ -13,16 +18,74 @@ val MvStructLitField.structLitExpr: MvStructLitExpr val MvStructLitField.isShorthand: Boolean get() = !hasChild(MvElementTypes.COLON) -inline fun MvStructLitField.resolveToElement(): T? = +inline fun MvStructLitField.resolveToElement(): T? = reference.multiResolve().filterIsInstance().singleOrNull() fun MvStructLitField.resolveToDeclaration(): MvStructField? = resolveToElement() fun MvStructLitField.resolveToBinding(): MvBindingPat? = resolveToElement() -abstract class MvStructLitFieldMixin(node: ASTNode) : MvElementImpl(node), - MvStructLitField { - override fun getReference(): MvPolyVariantReference { - if (!this.isShorthand) return MvStructRefFieldReferenceImpl(this) - return MvStructLitShorthandFieldReferenceImpl(this) +interface MvStructRefField: MvMandatoryReferenceElement + +abstract class MvStructLitFieldMixin(node: ASTNode): MvElementImpl(node), + MvStructLitField { + override fun getReference(): MvPolyVariantReference = + MvStructRefFieldReferenceImpl(this, shorthand = this.isShorthand) +// if (this.isShorthand) { +// return MvStructLitShorthandFieldReferenceImpl(this) +// } else { +// return MvStructRefFieldReferenceImpl(this) +// } +} + +class MvStructRefFieldReferenceImpl( + element: MvStructRefField, + var shorthand: Boolean, +): MvPolyVariantReferenceCached(element) { + + override fun multiResolveInner(): List { + val referenceName = element.referenceName ?: return emptyList() + var variants = collectResolveVariants(referenceName) { + processStructRefFieldResolveVariants(element, it) + } +// var variants = resolveIntoStructField(element) + if (shorthand) { + variants += resolveBindingForFieldShorthand(element) +// variants += resolveLocalItem(element, setOf(Namespace.NAME)) + } + return variants +// return listOf( +// resolveIntoStructField(element), +// resolveLocalItem(element, setOf(Namespace.NAME)) +// ).flatten() } } + +fun processStructRefFieldResolveVariants( + fieldRef: MvStructRefField, + processor: RsResolveProcessor +): Boolean { + val structItem = fieldRef.maybeStruct ?: return false + return structItem.fields + .any { field -> + processor.process(SimpleScopeEntry(field.name, field, setOf(Namespace.NAME))) + } +} + +fun resolveIntoStructField(element: MvStructRefField): List { + val structItem = element.maybeStruct ?: return emptyList() + val referenceName = element.referenceName + return structItem.fields + .filter { it.name == referenceName } +} + +private val MvStructRefField.maybeStruct: MvStruct? + get() { + return when (this) { + is MvStructPatField -> this.structPat.structItem + is MvStructLitField -> this.structLitExpr.path.maybeStruct + else -> null + } + } + + + diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPatField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPatField.kt index 5864b2984..325d1c0ed 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPatField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPatField.kt @@ -4,8 +4,6 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import org.move.lang.core.psi.* import org.move.lang.core.resolve.ref.MvPolyVariantReference -import org.move.lang.core.resolve.ref.MvStructPatShorthandFieldReferenceImpl -import org.move.lang.core.resolve.ref.MvStructRefFieldReferenceImpl val MvStructPatField.structPat: MvStructPat get() = ancestorStrict()!! @@ -29,6 +27,7 @@ sealed class PatFieldKind { * ~~~~~~~~~ */ data class Full(val ident: PsiElement, val pat: MvPat): PatFieldKind() + /** * struct S { a: i32 } * let S { ref a } = ... @@ -44,8 +43,8 @@ val PatFieldKind.fieldName: String } -abstract class MvStructPatFieldMixin(node: ASTNode) : MvElementImpl(node), - MvStructPatField { +abstract class MvStructPatFieldMixin(node: ASTNode): MvElementImpl(node), + MvStructPatField { override val referenceNameElement: PsiElement get() { val bindingPat = this.bindingPat @@ -56,11 +55,11 @@ abstract class MvStructPatFieldMixin(node: ASTNode) : MvElementImpl(node), } } - override fun getReference(): MvPolyVariantReference { - return if (this.isShorthand) { - MvStructPatShorthandFieldReferenceImpl(this) - } else { - MvStructRefFieldReferenceImpl(this) - } - } + override fun getReference(): MvPolyVariantReference = + MvStructRefFieldReferenceImpl(this, shorthand = this.isShorthand) +// return if (this.isShorthand) { +// MvStructPatShorthandFieldReferenceImpl(this) +// } else { +// MvStructRefFieldReferenceImpl(this) +// } } diff --git a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt b/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt deleted file mode 100644 index 12ea230ec..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/LexicalDeclarations.kt +++ /dev/null @@ -1,259 +0,0 @@ -package org.move.lang.core.resolve - -import com.intellij.psi.util.PsiTreeUtil -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ref.Namespace - -fun processItemsInScope( - scope: MvElement, - cameFrom: MvElement, - namespaces: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - for (namespace in namespaces) { - val stop = when (namespace) { - -// Namespace.CONST -> { -// val found = when (scope) { -// is MvModuleBlock -> { -// val module = scope.parent as MvModule -// processor.matchAll( -// contextScopeInfo, -// module.consts(), -// ) -// } -// else -> false -// } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true -// } -// } -// found -// } - - Namespace.NAME -> { - val found = when (scope) { - is MvModuleBlock -> { - val module = scope.parent as MvModule - processor.matchAll( - contextScopeInfo, - module.structs(), - module.consts(), - ) - } - is MvModuleSpecBlock -> processor.matchAll(contextScopeInfo, scope.schemaList) - is MvScript -> processor.matchAll(contextScopeInfo, scope.consts()) - is MvFunctionLike -> processor.matchAll(contextScopeInfo, scope.allParamsAsBindings) - is MvLambdaExpr -> processor.matchAll(contextScopeInfo, scope.bindingPatList) - is MvForExpr -> { - val iterConditionBindingPat = scope.forIterCondition?.bindingPat - if (iterConditionBindingPat != null) { - processor.match(iterConditionBindingPat) - } else { - false - } - } - is MvItemSpec -> { - val item = scope.item - when (item) { - is MvFunction -> { - processor.matchAll( - contextScopeInfo, - item.valueParamsAsBindings, - item.specResultParameters.map { it.bindingPat }, - ) - } - is MvStruct -> processor.matchAll(contextScopeInfo, item.fields) - else -> false - } - } - is MvSchema -> processor.matchAll(contextScopeInfo, scope.fieldBindings) - is MvQuantBindingsOwner -> processor.matchAll(contextScopeInfo, scope.bindings) - is MvCodeBlock, - is MvSpecCodeBlock -> { - val visibleLetStmts = when (scope) { - is MvCodeBlock -> { - scope.letStmts - // drops all let-statements after the current position - .filter { it.cameBefore(cameFrom) } - // drops let-statement that is ancestors of ref (on the same statement, at most one) - .filter { - cameFrom != it - && !PsiTreeUtil.isAncestor(cameFrom, it, true) - } - } - is MvSpecCodeBlock -> { - when (contextScopeInfo.letStmtScope) { - LetStmtScope.EXPR_STMT -> scope.allLetStmts - LetStmtScope.LET_STMT, LetStmtScope.LET_POST_STMT -> { - val letDecls = if (contextScopeInfo.letStmtScope == LetStmtScope.LET_POST_STMT) { - scope.allLetStmts - } else { - scope.letStmts(false) - } - letDecls - // drops all let-statements after the current position - .filter { it.cameBefore(cameFrom) } - // drops let-statement that is ancestors of ref (on the same statement, at most one) - .filter { - cameFrom != it - && !PsiTreeUtil.isAncestor(cameFrom, it, true) - } - } - LetStmtScope.NONE -> emptyList() - } - } - else -> error("unreachable") - } - // shadowing support (look at latest first) - val namedElements = visibleLetStmts - .asReversed() - .flatMap { it.pat?.bindings.orEmpty() } - - // skip shadowed (already visited) elements - val visited = mutableSetOf() - val processorWithShadowing = MatchingProcessor { entry -> - ((entry.name !in visited) - && processor.match(entry).also { visited += entry.name }) - } - var found = processorWithShadowing.matchAll(contextScopeInfo, namedElements) - if (!found && scope is MvSpecCodeBlock) { - // if inside SpecCodeBlock, match also with builtin spec consts and global variables - found = processorWithShadowing.matchAll( - contextScopeInfo, - scope.builtinSpecConsts(), - scope.globalVariables() - ) - } - found - } - else -> false - } - if (!found) { - if (scope is MvItemsOwner) { - if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true - } - } - found - } -// Namespace.FUNCTION -> { -// val found = when (scope) { -// is MvModuleBlock -> { -// val module = scope.parent as MvModule -// val specFunctions = if (contextScopeInfo.isMslScope) { -// listOf(module.specFunctions(), module.builtinSpecFunctions()).flatten() -// } else { -// emptyList() -// } -// val specInlineFunctions = if (contextScopeInfo.isMslScope) { -// module.moduleItemSpecs().flatMap { it.specInlineFunctions() } -// } else { -// emptyList() -// } -// processor.matchAll( -// contextScopeInfo, -// module.allNonTestFunctions(), -// module.builtinFunctions(), -// specFunctions, -// specInlineFunctions -// ) -// } -// is MvModuleSpecBlock -> { -// val specFunctions = scope.specFunctionList -// val specInlineFunctions = scope.moduleItemSpecList.flatMap { it.specInlineFunctions() } -// processor.matchAll( -// contextScopeInfo, -// specFunctions, -// specInlineFunctions -// ) -// } -// is MvFunctionLike -> processor.matchAll(contextScopeInfo, scope.lambdaParamsAsBindings) -// is MvLambdaExpr -> processor.matchAll(contextScopeInfo, scope.bindingPatList) -// is MvItemSpec -> { -// val item = scope.item -// when (item) { -// is MvFunction -> processor.matchAll(contextScopeInfo, item.lambdaParamsAsBindings) -// else -> false -// } -// } -// is MvSpecCodeBlock -> { -// val inlineFunctions = scope.specInlineFunctions().asReversed() -// return processor.matchAll(contextScopeInfo, inlineFunctions) -// } -// else -> false -// } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true -// } -// } -// found -// } - -// Namespace.TYPE -> { -// if (scope is MvTypeParametersOwner) { -// if (processor.matchAll(contextScopeInfo, scope.typeParameters)) return true -// } -// val found = when (scope) { -// is MvItemSpec -> { -// val funcItem = scope.funcItem -// if (funcItem != null) { -// processor.matchAll(contextScopeInfo, funcItem.typeParameters) -// } else { -// false -// } -// } -// is MvModuleBlock -> { -// val module = scope.parent as MvModule -// processor.matchAll( -// contextScopeInfo, -// scope.allUseItems(), -// module.structs() -// ) -// } -// is MvApplySchemaStmt -> { -// val toPatterns = scope.applyTo?.functionPatternList.orEmpty() -// val patternTypeParams = -// toPatterns.flatMap { it.typeParameterList?.typeParameterList.orEmpty() } -// processor.matchAll(contextScopeInfo, patternTypeParams) -// } -// -// else -> false -// } -// if (!found) { -// if (scope is MvItemsOwner) { -// if (processor.matchAll(contextScopeInfo, scope.allUseItems())) return true -// } -// } -// found -// } - -// Namespace.SCHEMA -> when (scope) { -// is MvModuleBlock -> processor.matchAll( -// contextScopeInfo, -// scope.allUseItems(), -// scope.schemaList -// ) -// is MvModuleSpecBlock -> processor.matchAll( -// contextScopeInfo, -// scope.allUseItems(), -// scope.schemaList, -// scope.specFunctionList -// ) -// else -> false -// } - -// Namespace.MODULE -> when (scope) { -// is MvItemsOwner -> -// processor.matchAll(contextScopeInfo, scope.moduleUseItems()) -// else -> false -// } - else -> false - } - if (stop) return true - } - return false -} diff --git a/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt b/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt index 35a5a691d..5e0d69ee1 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/MatchingProcessor.kt @@ -1,41 +1,8 @@ package org.move.lang.core.resolve import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.psi.ext.isMslOnlyItem -import org.move.lang.core.psi.isVisibleInContext data class ScopeItem( val name: String, val element: T ) - -fun interface MatchingProcessor { - fun match(entry: ScopeItem): Boolean - - fun match(itemElement: T): Boolean { - val name = itemElement.name ?: return false - val entry = ScopeItem(name, itemElement) - return match(entry) - } - - fun match(contextScopeInfo: ContextScopeInfo, itemElement: T): Boolean { - if ( - !contextScopeInfo.isMslScope && itemElement.isMslOnlyItem - ) return false - if (!itemElement.isVisibleInContext(contextScopeInfo.refItemScopes)) return false - - val name = itemElement.name ?: return false - val entry = ScopeItem(name, itemElement) - return match(entry) - } - - fun matchAll(contextScopeInfo: ContextScopeInfo, vararg collections: Iterable): Boolean = - sequenceOf(*collections) - .flatten() - .any { match(contextScopeInfo, it) } - -// fun matchAll(vararg collections: Iterable): Boolean = -// sequenceOf(*collections) -// .flatten() -// .any { match(it) } -} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt deleted file mode 100644 index bc42d594c..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/ModuleItemResolution.kt +++ /dev/null @@ -1,106 +0,0 @@ -package org.move.lang.core.resolve - -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility - -fun processModuleInnerItems( - module: MvModule, - namespaces: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - for (namespace in namespaces) { - val found = when (namespace) { - Namespace.NAME -> { - processor.matchAll( - contextScopeInfo, - if (contextScopeInfo.isMslScope) module.consts() else emptyList(), - if (contextScopeInfo.isMslScope) module.structs() else emptyList(), - if (contextScopeInfo.isMslScope) - module.allModuleSpecs() - .map { - it.moduleItemSpecs() - .flatMap { spec -> spec.itemSpecBlock?.globalVariables().orEmpty() } - } - .flatten() - else emptyList() - ) - } - Namespace.FUNCTION -> { - val functions = visibilities.flatMap { module.functionsVisibleInScope(it) } - val specFunctions = - if (contextScopeInfo.isMslScope) module.specFunctions() else emptyList() - val specInlineFunctions = - if (contextScopeInfo.isMslScope) module.specInlineFunctions() else emptyList() - processor.matchAll( - contextScopeInfo, - functions, specFunctions, specInlineFunctions - ) - } - Namespace.TYPE -> processor.matchAll(contextScopeInfo, module.structs()) - Namespace.SCHEMA -> processor.matchAll(contextScopeInfo, module.schemas()) - Namespace.CONST -> processor.matchAll(contextScopeInfo, module.consts()) - else -> continue - } - if (found) return true - } - return false -} - -fun processModuleSpecItems( - module: MvModule, - namespaces: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - for (namespace in namespaces) { - for (moduleSpec in module.allModuleSpecs()) { - val matched = when (namespace) { - Namespace.FUNCTION -> - processor.matchAll( - contextScopeInfo, - moduleSpec.specFunctions(), - moduleSpec.specInlineFunctions() - ) - Namespace.SCHEMA -> processor.matchAll(contextScopeInfo, moduleSpec.schemas()) - else -> false - } - if (matched) return true - } - } - return false -} - -fun processModuleItems( - module: MvModule, - namespaces: Set, - visibilities: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - return processModuleInnerItems(module, namespaces, visibilities, contextScopeInfo, processor) - || - contextScopeInfo.isMslScope && processModuleSpecItems(module, namespaces, contextScopeInfo, processor) -} - -//fun resolveModuleItem( -// module: MvModule, -// name: String, -// namespaces: Set, -// visibilities: Set, -// contextScopeInfo: ContextScopeInfo, -//): List { -// val resolved = mutableListOf() -// processModuleItems(module, namespaces, visibilities, contextScopeInfo) { -// if (it.name == name) { -// resolved.add(it.element) -// return@processModuleItems true -// } -// return@processModuleItems false -// } -// return resolved -//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt deleted file mode 100644 index 3238bb078..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/NameResolution.kt +++ /dev/null @@ -1,280 +0,0 @@ -package org.move.lang.core.resolve - -import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.LetStmtScope.NONE -import org.move.lang.core.resolve.ref.MvReferenceElement -import org.move.lang.core.resolve.ref.Namespace -import org.move.stdext.wrapWithList - -data class ContextScopeInfo( - val refItemScopes: Set, - val letStmtScope: LetStmtScope, -) { - val isMslScope get() = letStmtScope != NONE - - fun matches(itemElement: MvNamedElement): Boolean { - if ( - !this.isMslScope && itemElement.isMslOnlyItem - ) return false - if ( - !itemElement.isVisibleInContext(this.refItemScopes) - ) return false - return true - } -} - -fun processItems( - element: MvElement, - namespaces: Set, - contextScopeInfo: ContextScopeInfo, - processor: MatchingProcessor, -): Boolean { - return walkUpThroughScopes( - element, - stopAfter = { it is MvModule } - ) { cameFrom, scope -> - processItemsInScope( - scope, cameFrom, namespaces, contextScopeInfo, processor - ) - } -} - -fun resolveLocalItem( - element: MvReferenceElement, - namespaces: Set -): List { - val contextScopeInfo = - ContextScopeInfo( - letStmtScope = element.letStmtScope, - refItemScopes = element.refItemScopes, - ) - val referenceName = element.referenceName - var resolved: MvNamedElement? = null - processItems(element, namespaces, contextScopeInfo) { - if (it.name == referenceName) { - resolved = it.element - return@processItems true - } - return@processItems false - } - return resolved.wrapWithList() -} - -// go from local MODULE reference to corresponding FqModuleRef (from import) -//fun resolveIntoFQModuleRefInUseSpeck(moduleRef: MvModuleRef): MvFQModuleRef? { -// check(moduleRef !is MvFQModuleRef) { "Should be handled on the upper level" } -// -// // module refers to ModuleImport -// var resolved = resolveLocalItem(moduleRef, setOf(Namespace.MODULE)).firstOrNull() -// if (resolved is MvUseAlias) { -// resolved = resolved.moduleUseSpeck ?: resolved.useItem -// } -// if (resolved is MvUseItem && resolved.isSelf) { -// return resolved.itemUseSpeck.fqModuleRef -// } -//// if (resolved !is MvModuleUseSpeck) return null -// return (resolved as? MvModuleUseSpeck)?.fqModuleRef -//// return resolved.fqModuleRef -//} - -//fun processQualItem( -// item: MvNamedElement, -// namespaces: Set, -// visibilities: Set, -// contextScopeInfo: ContextScopeInfo, -// processor: MatchingProcessor, -//): Boolean { -// val matched = when { -// item is MvModule && Namespace.MODULE in namespaces -// || item is MvStruct && Namespace.TYPE in namespaces -// || item is MvSchema && Namespace.SCHEMA in namespaces -> -// processor.match(contextScopeInfo, item) -// -// item is MvFunction && Namespace.FUNCTION in namespaces -> { -// if (item.hasTestAttr) return false -// for (vis in visibilities) { -// when { -// vis is Visibility.Public -// && item.visibility == FunctionVisibility.PUBLIC -> processor.match( -// contextScopeInfo, -// item -// ) -// -// vis is Visibility.PublicScript -// && item.visibility == FunctionVisibility.PUBLIC_SCRIPT -> -// processor.match(contextScopeInfo, item) -// -// vis is Visibility.PublicFriend && item.visibility == FunctionVisibility.PUBLIC_FRIEND -> { -// val itemModule = item.module ?: return false -// val currentModule = vis.currentModule.element ?: return false -// if (currentModule.fqModule() in itemModule.declaredFriendModules) { -// processor.match(contextScopeInfo, item) -// } -// } -// -// vis is Visibility.PublicPackage && item.visibility == FunctionVisibility.PUBLIC_PACKAGE -> { -// if (!item.project.moveSettings.enablePublicPackage) { -// return false -// } -// val itemPackage = item.containingMovePackage ?: return false -// if (vis.originPackage == itemPackage) { -// processor.match(contextScopeInfo, item) -// } -// } -// -// vis is Visibility.Internal -> processor.match(contextScopeInfo, item) -// } -// } -// false -// } -// else -> false -// } -// return matched -//} - -//fun processModulesInFile(file: MoveFile, moduleProcessor: MatchingProcessor): Boolean { -// for (module in file.modules()) { -// if (moduleProcessor.match(module)) return true -// } -// return false -//} - -//fun processFQModuleRef( -// fqModuleRef: MvFQModuleRef, -// processor: MatchingProcessor, -//) { -// val moveProj = fqModuleRef.moveProject ?: return -// val refAddressText = fqModuleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) -// -// val contextScopeInfo = ContextScopeInfo( -// letStmtScope = fqModuleRef.letStmtScope, -// refItemScopes = fqModuleRef.refItemScopes, -// ) -// val moduleProcessor = MatchingProcessor { -// if (!contextScopeInfo.matches(it.element)) { -// return@MatchingProcessor false -// } -// val entry = ScopeItem(it.name, it.element as MvModule) -// val modAddressText = entry.element.address(moveProj)?.canonicalValue(moveProj) -// if (modAddressText != refAddressText) -// return@MatchingProcessor false -// processor.match(entry) -// } -// -// // first search modules in the current file -// val currentFile = fqModuleRef.containingMoveFile ?: return -// var stopped = processModulesInFile(currentFile, moduleProcessor) -//// var stopped = -//// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, moduleProcessor) -// if (stopped) return -// -// moveProj.processMoveFiles { moveFile -> -// // skip current file as it's processed already -// if (moveFile.toNioPathOrNull() == currentFile.toNioPathOrNull()) -// return@processMoveFiles true -// stopped = processModulesInFile(moveFile, moduleProcessor) -// // if not resolved, returns true to indicate that next file should be tried -// !stopped -// } -//} - -//fun processFQModuleRef( -// moduleRef: MvFQModuleRef, -// target: String, -// processor: MatchingProcessor, -//) { -// val project = moduleRef.project -// val moveProj = moduleRef.moveProject ?: return -// val refAddress = moduleRef.addressRef.address(moveProj)?.canonicalValue(moveProj) -// -// val contextScopeInfo = ContextScopeInfo( -// letStmtScope = moduleRef.letStmtScope, -// refItemScopes = moduleRef.refItemScopes, -// ) -// val matchModule = MatchingProcessor { -// if (!contextScopeInfo.matches(it.element)) return@MatchingProcessor false -// val entry = ScopeItem(it.name, it.element as MvModule) -// // TODO: check belongs to the current project -// val modAddress = entry.element.address(moveProj)?.canonicalValue(moveProj) -// -// if (modAddress != refAddress) return@MatchingProcessor false -// processor.match(entry) -// } -// -// // search modules in the current file first -// val currentFile = moduleRef.containingMoveFile ?: return -// val stopped = processModulesInFile(currentFile, matchModule) -//// processFileItems(currentFile, setOf(Namespace.MODULE), Visibility.local(), itemVis, matchModule) -// if (stopped) return -// -// val currentFileScope = GlobalSearchScope.fileScope(currentFile) -// val searchScope = -// moveProj.searchScope().intersectWith(GlobalSearchScope.notScope(currentFileScope)) -// -// MvNamedElementIndex -// .processElementsByName(project, target, searchScope) { -// val matched = -// processQualItem(it, setOf(Namespace.MODULE), Visibility.local(), contextScopeInfo, matchModule) -// if (matched) return@processElementsByName false -// -// true -// } -//} - -fun walkUpThroughScopes( - start: MvElement, - stopAfter: (MvElement) -> Boolean, - handleScope: (cameFrom: MvElement, scope: MvElement) -> Boolean, -): Boolean { - var cameFrom = start - var scope = start.context as MvElement? - while (scope != null) { - if (handleScope(cameFrom, scope)) return true - - // walk all items in original module block - if (scope is MvModuleBlock) { - // handle spec module {} - if (handleModuleItemSpecsInBlock(cameFrom, scope, handleScope)) return true - // walk over all spec modules - for (moduleSpec in scope.module.allModuleSpecs()) { - val moduleSpecBlock = moduleSpec.moduleSpecBlock ?: continue - if (handleScope(cameFrom, moduleSpecBlock)) return true - if (handleModuleItemSpecsInBlock(cameFrom, moduleSpecBlock, handleScope)) return true - } - } - - if (scope is MvModuleSpecBlock) { - val moduleBlock = scope.moduleSpec.moduleItem?.moduleBlock - if (moduleBlock != null) { - cameFrom = scope - scope = moduleBlock - continue - } - } - - if (stopAfter(scope)) break - - cameFrom = scope - scope = scope.context as? MvElement - } - - return false -} - -private fun handleModuleItemSpecsInBlock( - cameFrom: MvElement, - block: MvElement, - handleScope: (cameFrom: MvElement, scope: MvElement) -> Boolean -): Boolean { - val moduleItemSpecs = when (block) { - is MvModuleBlock -> block.moduleItemSpecList - is MvModuleSpecBlock -> block.moduleItemSpecList - else -> emptyList() - } - for (moduleItemSpec in moduleItemSpecs.filter { it != cameFrom }) { - val itemSpecBlock = moduleItemSpec.itemSpecBlock ?: continue - if (handleScope(cameFrom, itemSpecBlock)) return true - } - return false -} diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 3844fa954..e64297578 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -1,17 +1,15 @@ package org.move.lang.core.resolve import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.psi.ResolveResult import com.intellij.util.SmartList import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.psi.MvElement -import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.psi.MvPath +import org.move.lang.core.completion.createLookupElement +import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.MvItemElement +import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.createFilter -import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.resolve2.ref.RsPathResolveResult import org.move.lang.core.resolve2.visInfo import org.move.stdext.intersects @@ -266,7 +264,7 @@ private class ShadowingAndImmediatelyUpdateScopeProcessor( "ShadowingAndImmediatelyUpdateScopeProcessor($originalProcessor, ns = $ns)" } -fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Unit): List { +fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Unit): List { if (referenceName == null) return emptyList() val processor = ResolveVariantsCollector(referenceName) f(processor) @@ -275,7 +273,7 @@ fun collectResolveVariants(referenceName: String?, f: (RsResolveProcessor) -> Un private class ResolveVariantsCollector( private val referenceName: String, - val result: MutableList = SmartList(), + val result: MutableList = SmartList(), ): RsResolveProcessorBase { override val names: Set = setOf(referenceName) @@ -318,7 +316,7 @@ private class ResolveVariantsAsScopeEntriesCollector( } fun collectPathResolveVariants( - ctx: PathResolutionContext, + ctx: ResolutionContext, path: MvPath, f: (RsResolveProcessor) -> Unit ): List> { @@ -329,7 +327,7 @@ fun collectPathResolveVariants( } private class SinglePathResolveVariantsCollector( - private val ctx: PathResolutionContext, + private val ctx: ResolutionContext, private val referenceName: String, val result: MutableList> = SmartList(), ): RsResolveProcessorBase { @@ -344,13 +342,13 @@ private class SinglePathResolveVariantsCollector( } private fun collectPathScopeEntry( - ctx: PathResolutionContext, + ctx: ResolutionContext, result: MutableList>, e: ScopeEntry ) { val element = e.element - val visibilityStatus = e.getVisibilityStatusFrom(ctx.path) - val isVisible = visibilityStatus == VisibilityStatus.Visible + val visibilityStatus = ctx.path?.let { e.getVisibilityStatusFrom(it) } ?: Visible + val isVisible = visibilityStatus == Visible result += RsPathResolveResult(element, isVisible) } @@ -402,6 +400,14 @@ private class CompletionVariantsCollector( // addEnumVariantsIfNeeded(entry) // addAssociatedItemsIfNeeded(entry) + val element = entry.element as? MvNamedElement ?: return false + val lookup = + element.createLookupElement( + context, + priority = element.completionPriority + ) + result.addElement(lookup) + // (entry.element as? MvNamedElement)?.let { // it.createLookupElement(context) // } @@ -512,12 +518,12 @@ fun ScopeEntry.getVisibilityStatusFrom(path: MvPath): VisibilityStatus = if (this is ScopeEntryWithVisibility) { visibilityFilter.filter(path, this.namespaces) } else { - VisibilityStatus.Visible + Visible } fun ScopeEntry.isVisibleFrom(context: MvPath): Boolean = - getVisibilityStatusFrom(context) == VisibilityStatus.Visible + getVisibilityStatusFrom(context) == Visible enum class VisibilityStatus { Visible, diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt deleted file mode 100644 index 9b5ed81a4..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveFQModuleReferenceImpl.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.move.lang.core.resolve.ref - -//interface MvFQModuleReference : MvPolyVariantReference - -//class MvFQModuleReferenceImpl( -// element: MvFQModuleRef, -//) : MvPolyVariantReferenceCached(element), MvFQModuleReference { -// -// override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE -// -// override fun multiResolveInner(): List { -// val referenceName = element.referenceName ?: return emptyList() -// var resolved: MvModule? = null -// processFQModuleRef(element, referenceName) { -// if (it.name == referenceName) { -// resolved = it.element -// true -// } else { -// false -// } -// } -// return resolved.wrapWithList() -// } -//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt deleted file mode 100644 index 1d757ecfb..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.move.lang.core.resolve.ref - -//class MvModuleReferenceImpl( -// element: MvModuleRef, -//): MvPolyVariantReferenceCached(element) { -// -// override fun multiResolveInner(): List { -// if (element.isSelfModuleRef) return element.containingModule.wrapWithList() -// -// check(element !is MvFQModuleRef) { -// "That element has different reference item" -// } -// -// val resolved = resolveLocalItem(element, setOf(Namespace.MODULE)).firstOrNull() -// if (resolved is MvUseAlias) { -// return resolved.wrapWithList() -// } -// val moduleRef = when { -// resolved is MvUseItem && resolved.text == "Self" -> resolved.itemUseSpeck.fqModuleRef -// resolved is MvModuleUseSpeck -> resolved.fqModuleRef -// else -> return emptyList() -// } -// return moduleRef?.reference?.resolve().wrapWithList() -// } -//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt deleted file mode 100644 index d2b4b39d5..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt +++ /dev/null @@ -1,71 +0,0 @@ -package org.move.lang.core.resolve.ref - -//class MvPathReferenceImpl( -// element: MvPath, -//): MvPolyVariantReferenceCached(element), MvPathReference { -// -// override val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE -// -// override fun multiResolveInner(): List { -// val ns = element.allowedNamespaces() -// val vs = Visibility.visibilityScopesForElement(element) -// val contextScopeInfo = -// ContextScopeInfo( -// refItemScopes = element.refItemScopes, -// letStmtScope = element.letStmtScope, -// ) -// -// val refName = element.referenceName ?: return emptyList() -// val moduleRef = element.moduleRef -// // first, see whether it's a fully qualified path (ADDRESS::MODULE::NAME) and try to resolve those -// if (moduleRef is MvFQModuleRef) { -// // TODO: can be replaced with index call -// val module = moduleRef.reference?.resolve() as? MvModule ?: return emptyList() -// return resolveModuleItem(module, refName, ns, vs, contextScopeInfo) -// } -// // second, -// // if it's MODULE::NAME -> resolve MODULE into corresponding FQModuleRef using imports -// if (moduleRef != null) { -// if (moduleRef.isSelfModuleRef) { -// val containingModule = moduleRef.containingModule ?: return emptyList() -// return resolveModuleItem( -// containingModule, -// refName, -// ns, -// setOf(Visibility.Internal), -// contextScopeInfo -// ) -// } -// val useSpeckFQModuleRef = resolveIntoFQModuleRefInUseSpeck(moduleRef) ?: return emptyList() -// val useSpeckModule = -// useSpeckFQModuleRef.reference?.resolve() as? MvModule ?: return emptyList() -// return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) -// } else { -// // if it's NAME -// // special case second argument of update_field function in specs -// if (element.isUpdateFieldArg2) return emptyList() -// -// // try local names -// val item = resolveLocalItem(element, ns).firstOrNull() ?: return emptyList() -// // local name -> return -// return when (item) { -// // item import -// is MvUseItem -> { -// // find corresponding FQModuleRef from imports and resolve -//// // TODO: index call -// val useSpeckModule = -// item.itemUseSpeck.fqModuleRef.reference?.resolve() as? MvModule -// ?: return emptyList() -// return resolveModuleItem(useSpeckModule, refName, ns, vs, contextScopeInfo) -// } -// // module import -// is MvModuleUseSpeck -> { -// val module = item.fqModuleRef?.reference?.resolve() as? MvModule -// return listOfNotNull(module) -// } -// // local item -// else -> listOf(item) -// } -// } -// } -//} diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/field_ref.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/field_ref.kt deleted file mode 100644 index 22f17531a..000000000 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/field_ref.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.move.lang.core.resolve.ref - -import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.psi.MvStruct -import org.move.lang.core.psi.MvStructLitField -import org.move.lang.core.psi.MvStructPatField -import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.resolveLocalItem - -interface MvStructRefField: MvReferenceElement - -class MvStructRefFieldReferenceImpl( - element: MvStructRefField -) : MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner() = resolveIntoStructField(element) -} - -class MvStructLitShorthandFieldReferenceImpl( - element: MvStructLitField, -) : MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner(): List { - return listOf( - resolveIntoStructField(element), - resolveLocalItem(element, setOf(Namespace.NAME)) - ).flatten() - } -} - -class MvStructPatShorthandFieldReferenceImpl( - element: MvStructPatField -) : MvPolyVariantReferenceCached(element) { - - override fun multiResolveInner(): List = resolveIntoStructField(element) -} - -private val MvStructRefField.maybeStruct: MvStruct? get() { - return when (this) { - is MvStructPatField -> this.structPat.structItem - is MvStructLitField -> this.structLitExpr.path.maybeStruct - else -> null - } -} - -private fun resolveIntoStructField(element: MvStructRefField): List { - val structItem = element.maybeStruct ?: return emptyList() - val referenceName = element.referenceName - return structItem.fields - .filter { it.name == referenceName } -} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index e13ceac7d..ff58cc6be 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -7,14 +7,14 @@ import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.LetStmtScope.* import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.resolve2.util.forEachLeafSpeck fun processItemsInScope( scope: MvElement, cameFrom: MvElement, ns: Set, - ctx: PathResolutionContext, + ctx: ResolutionContext, processor: RsResolveProcessor, ): Boolean { for (namespace in ns) { @@ -71,7 +71,7 @@ fun processItemsInScope( } } is MvSpecCodeBlock -> { - val letStmtScope = ctx.path.letStmtScope + val letStmtScope = ctx.element.letStmtScope when (letStmtScope) { EXPR_STMT -> scope.allLetStmts LET_STMT, LET_POST_STMT -> { diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index a96c8bacc..29a41c7f8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -1,20 +1,29 @@ package org.move.lang.core.resolve2 import org.move.cli.MoveProject -import org.move.lang.core.psi.MvElement -import org.move.lang.core.psi.MvModule +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* +import org.move.lang.core.resolve.ref.MvMandatoryReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.MODULE -import org.move.lang.core.resolve2.ref.PathResolutionContext +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.Address import org.move.lang.core.types.address import org.move.lang.index.MvModuleIndex +fun resolveBindingForFieldShorthand( + element: MvMandatoryReferenceElement, +): List { + return collectResolveVariants(element.referenceName) { + processNestedScopesUpwards(element, setOf(Namespace.NAME), ResolutionContext(element), it) + } +} + fun processNestedScopesUpwards( scopeStart: MvElement, ns: Set, - ctx: PathResolutionContext, + ctx: ResolutionContext, processor: RsResolveProcessor ): Boolean { val prevScope = hashMapOf>() @@ -100,4 +109,62 @@ inline fun processWithShadowing( ): Boolean { val shadowingProcessor = processor.wrapWithShadowingProcessor(prevScope, ns) return f(shadowingProcessor) -} \ No newline at end of file +} + + +fun walkUpThroughScopes( + start: MvElement, + stopAfter: (MvElement) -> Boolean, + handleScope: (cameFrom: MvElement, scope: MvElement) -> Boolean, +): Boolean { + var cameFrom = start + var scope = start.context as MvElement? + while (scope != null) { + if (handleScope(cameFrom, scope)) return true + + // walk all items in original module block + if (scope is MvModuleBlock) { + // handle spec module {} + if (handleModuleItemSpecsInBlock(cameFrom, scope, handleScope)) return true + // walk over all spec modules + for (moduleSpec in scope.module.allModuleSpecs()) { + val moduleSpecBlock = moduleSpec.moduleSpecBlock ?: continue + if (handleScope(cameFrom, moduleSpecBlock)) return true + if (handleModuleItemSpecsInBlock(cameFrom, moduleSpecBlock, handleScope)) return true + } + } + + if (scope is MvModuleSpecBlock) { + val moduleBlock = scope.moduleSpec.moduleItem?.moduleBlock + if (moduleBlock != null) { + cameFrom = scope + scope = moduleBlock + continue + } + } + + if (stopAfter(scope)) break + + cameFrom = scope + scope = scope.context as? MvElement + } + + return false +} + +private fun handleModuleItemSpecsInBlock( + cameFrom: MvElement, + block: MvElement, + handleScope: (cameFrom: MvElement, scope: MvElement) -> Boolean +): Boolean { + val moduleItemSpecs = when (block) { + is MvModuleBlock -> block.moduleItemSpecList + is MvModuleSpecBlock -> block.moduleItemSpecList + else -> emptyList() + } + for (moduleItemSpec in moduleItemSpecs.filter { it != cameFrom }) { + val itemSpecBlock = moduleItemSpec.itemSpecBlock ?: continue + if (handleScope(cameFrom, itemSpecBlock)) return true + } + return false +} diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 15ca5d64c..e3974459b 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -46,14 +46,14 @@ class Path2ReferenceImpl(element: MvPath): override fun invoke(path: MvElement): List> { // should not really happen if (path !is MvPath) return emptyList() - val resolutionCtx = PathResolutionContext(path) + val resolutionCtx = ResolutionContext(path) return resolvePath(resolutionCtx, path) } } } fun processPathResolveVariants( - ctx: PathResolutionContext, + ctx: ResolutionContext, pathKind: PathKind, processor: RsResolveProcessor ): Boolean { @@ -65,10 +65,10 @@ fun processPathResolveVariants( // Self:: if (processor.lazy("Self") { ctx.containingModule }) return true // local - processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextProcessor) + processNestedScopesUpwards(ctx.element, pathKind.ns, ctx, contextProcessor) } is PathKind.QualifiedPath.Module -> { - processModulePathResolveVariants(ctx.path, ctx.moveProject, pathKind.address, contextProcessor) + processModulePathResolveVariants(ctx.element, ctx.moveProject, pathKind.address, contextProcessor) } is PathKind.QualifiedPath -> { processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) @@ -117,7 +117,7 @@ fun processPathResolveVariants( * [qualifier] */ fun processQualifiedPathResolveVariants( - ctx: PathResolutionContext, + ctx: ResolutionContext, ns: Set, path: MvPath, qualifier: MvPath, @@ -129,7 +129,7 @@ fun processQualifiedPathResolveVariants( // can be module, try for named address as a qualifier val addressName = qualifier.referenceName ?: return false val address = ctx.moveProject?.getNamedAddressTestAware(addressName) ?: return false - if (processModulePathResolveVariants(ctx.path, ctx.moveProject, address, processor)) return true + if (processModulePathResolveVariants(ctx.element, ctx.moveProject, address, processor)) return true } return false } @@ -144,27 +144,23 @@ fun processQualifiedPathResolveVariants( return false } -class PathResolutionContext(val path: MvPath) { +class ResolutionContext(val element: MvElement) { private var lazyContainingMoveProject: Lazy = lazy(NONE) { - path.moveProject + element.moveProject } val moveProject: MoveProject? get() = lazyContainingMoveProject.value private var lazyContainingModule: Lazy = lazy(NONE) { - path.containingModule + element.containingModule } val containingModule: MvModule? get() = lazyContainingModule.value - private var lazyUseSpeck: Lazy = lazy(NONE) { path.useSpeck } + private var lazyUseSpeck: Lazy = lazy(NONE) { path?.useSpeck } val useSpeck: MvUseSpeck? get() = lazyUseSpeck.value val isUseSpeck: Boolean get() = useSpeck != null -// var lazyContainingModInfo: Lazy = lazy(NONE) { -// val module = containingModule -// getModInfo(module) -// } - + val path: MvPath? get() = element as? MvPath } //// todo: use in inference later @@ -175,7 +171,7 @@ class PathResolutionContext(val path: MvPath) { //} private fun resolvePath( - ctx: PathResolutionContext, + ctx: ResolutionContext, path: MvPath, // kind: RsPathResolveKind ): List> { diff --git a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt index b70d1f5c0..fb3dc5059 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt @@ -15,7 +15,6 @@ import org.move.lang.core.completion.providers.MethodOrFieldCompletionProvider import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.ext.MvMethodOrField -import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.MvTestBase From f8e80d3acc6404708924365f98ed5a473bef2fff Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 1 Aug 2024 16:54:49 +0300 Subject: [PATCH 40/43] fix remaining address and module equality tests --- gradle.properties | 2 +- .../lang/core/completion/LookupElements.kt | 169 ++++++++---------- .../lang/core/completion/LookupElements2.kt | 92 ++++++++++ .../lang/core/completion/MvLookupElement.kt | 2 +- .../providers/MvPathCompletionProvider2.kt | 49 +++-- ...NamedAddressInUseStmtCompletionProvider.kt | 13 +- .../org/move/lang/core/psi/ext/MvModule.kt | 53 +++--- .../lang/core/psi/ext/MvStructLitField.kt | 2 +- .../org/move/lang/core/psi/ext/MvUseSpeck.kt | 4 +- .../lang/core/psi/ext/MvVisibilityOwner.kt | 4 +- .../org/move/lang/core/resolve/Processors.kt | 43 +---- .../move/lang/core/resolve/ref/Namespace.kt | 2 +- .../move/lang/core/resolve2/ItemResolution.kt | 2 +- .../lang/core/resolve2/NameResolution2.kt | 25 ++- .../move/lang/core/resolve2/Visibility2.kt | 8 +- .../core/resolve2/ref/Path2ReferenceImpl.kt | 49 +---- .../org/move/lang/core/types/Address.kt | 65 ++++--- .../org/move/lang/index/MvModuleSpecIndex.kt | 2 +- .../completion/names/ModulesCompletionTest.kt | 13 +- .../completion/names/StructsCompletionTest.kt | 1 - .../move/lang/resolve/ResolveModulesTest.kt | 10 ++ 21 files changed, 343 insertions(+), 267 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt diff --git a/gradle.properties b/gradle.properties index 4069694ba..522f940f3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,6 +18,6 @@ jbrVersion=17.0.7b1000.6 propertiesPluginEnvironmentNameProperty=shortPlatformVersion # properties files # pass ORG_GRADLE_PROJECT_shortPlatformVersion environment variable to overwrite -shortPlatformVersion=242 +shortPlatformVersion=233 useInstaller=true diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index 3e06443b1..019fe1f0b 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -11,6 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil import org.move.ide.presentation.text import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.ScopeEntry import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.* import org.move.lang.core.types.ty.Ty @@ -54,102 +55,13 @@ fun MvNamedElement.createLookupElementWithIcon(): LookupElementBuilder { .withLookupString(this.name ?: "") } -//@Suppress("UnusedReceiverParameter") -//fun MvModule.createSelfLookup(): LookupElement { -// return LookupElementBuilder -// .create("Self") -// .withBoldness(true) -//} - -fun MvNamedElement.getLookupElementBuilder( - completionCtx: CompletionContext, - subst: Substitution = emptySubstitution, - structAsType: Boolean = false -): LookupElementBuilder { - val lookupElementBuilder = this.createLookupElementWithIcon() - val msl = completionCtx.isMsl() - return when (this) { - is MvFunction -> { - val signature = FuncSignature.fromFunction(this, msl).substitute(subst) - if (completionCtx.contextElement is MvMethodOrField) { - lookupElementBuilder - .withTailText(signature.paramsText()) - .withTypeText(signature.retTypeText()) - } else { - lookupElementBuilder - .withTailText(this.signatureText) - .withTypeText(this.outerFileName) - } - } - is MvSpecFunction -> lookupElementBuilder - .withTailText(this.parameters.joinToSignature()) - .withTypeText(this.returnType?.type?.text ?: "()") - - is MvModule -> lookupElementBuilder - .withTailText(this.addressRef()?.let { " ${it.text}" } ?: "") - .withTypeText(this.containingFile?.name) - - is MvStruct -> { - val tailText = if (structAsType) "" else " { ... }" - lookupElementBuilder - .withTailText(tailText) - .withTypeText(this.containingFile?.name) - } - - is MvStructField -> { - val fieldTy = this.type?.loweredType(msl)?.substitute(subst) ?: TyUnknown - lookupElementBuilder - .withTypeText(fieldTy.text(false)) - } - is MvConst -> { -// val msl = this.isMslOnlyItem - val constTy = this.type?.loweredType(msl) ?: TyUnknown - lookupElementBuilder - .withTypeText(constTy.text(true)) - } - - is MvBindingPat -> { -// val msl = this.isMslOnlyItem - val bindingInference = this.inference(msl) - // race condition sometimes happens, when file is too big, inference is not finished yet - val ty = bindingInference?.getPatTypeOrUnknown(this) ?: TyUnknown - lookupElementBuilder - .withTypeText(ty.text(true)) - } - - is MvSchema -> lookupElementBuilder - .withTypeText(this.containingFile?.name) - - // we need to do the resolve here and in the next one to get the underlying item, - // but it should be cached in the most cases -// is MvModuleUseSpeck -> { -// this.fqModuleRef?.reference?.resolve() -// ?.getLookupElementBuilder(completionCtx, subst, structAsType) -// ?: lookupElementBuilder -// } - -// is MvUseItem -> { -// this.reference.resolve() -// ?.getLookupElementBuilder(completionCtx, subst, structAsType) -// ?: lookupElementBuilder -// } - - else -> lookupElementBuilder - } -} - data class CompletionContext( val contextElement: MvElement, -// val contextScopeInfo: ContextScopeInfo, val msl: Boolean, val expectedTy: Ty? = null, val resolutionCtx: ResolutionContext? = null, val structAsType: Boolean = false -) { -// fun isMsl(): Boolean = contextScopeInfo.isMslScope - fun isMsl(): Boolean = msl -} - +) fun MvNamedElement.createLookupElement( completionContext: CompletionContext, @@ -294,6 +206,83 @@ open class DefaultInsertHandler(val completionCtx: CompletionContext? = null): I } } +private fun MvNamedElement.getLookupElementBuilder( + completionCtx: CompletionContext, + subst: Substitution = emptySubstitution, + structAsType: Boolean = false +): LookupElementBuilder { + val lookupElementBuilder = this.createLookupElementWithIcon() + val msl = completionCtx.msl + return when (this) { + is MvFunction -> { + val signature = FuncSignature.fromFunction(this, msl).substitute(subst) + if (completionCtx.contextElement is MvMethodOrField) { + lookupElementBuilder + .withTailText(signature.paramsText()) + .withTypeText(signature.retTypeText()) + } else { + lookupElementBuilder + .withTailText(this.signatureText) + .withTypeText(this.outerFileName) + } + } + is MvSpecFunction -> lookupElementBuilder + .withTailText(this.parameters.joinToSignature()) + .withTypeText(this.returnType?.type?.text ?: "()") + + is MvModule -> lookupElementBuilder + .withTailText(this.addressRef()?.let { " ${it.text}" } ?: "") + .withTypeText(this.containingFile?.name) + + is MvStruct -> { + val tailText = if (structAsType) "" else " { ... }" + lookupElementBuilder + .withTailText(tailText) + .withTypeText(this.containingFile?.name) + } + + is MvStructField -> { + val fieldTy = this.type?.loweredType(msl)?.substitute(subst) ?: TyUnknown + lookupElementBuilder + .withTypeText(fieldTy.text(false)) + } + is MvConst -> { +// val msl = this.isMslOnlyItem + val constTy = this.type?.loweredType(msl) ?: TyUnknown + lookupElementBuilder + .withTypeText(constTy.text(true)) + } + + is MvBindingPat -> { +// val msl = this.isMslOnlyItem + val bindingInference = this.inference(msl) + // race condition sometimes happens, when file is too big, inference is not finished yet + val ty = bindingInference?.getPatTypeOrUnknown(this) ?: TyUnknown + lookupElementBuilder + .withTypeText(ty.text(true)) + } + + is MvSchema -> lookupElementBuilder + .withTypeText(this.containingFile?.name) + + // we need to do the resolve here and in the next one to get the underlying item, + // but it should be cached in the most cases +// is MvModuleUseSpeck -> { +// this.fqModuleRef?.reference?.resolve() +// ?.getLookupElementBuilder(completionCtx, subst, structAsType) +// ?: lookupElementBuilder +// } + +// is MvUseItem -> { +// this.reference.resolve() +// ?.getLookupElementBuilder(completionCtx, subst, structAsType) +// ?: lookupElementBuilder +// } + + else -> lookupElementBuilder + } +} + // When a user types `(` while completion, // `com.intellij.codeInsight.completion.DefaultCharFilter` invokes completion with selected item. // And if we insert `()` for the item (for example, function), a user get double parentheses diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt new file mode 100644 index 000000000..f6a4e9742 --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt @@ -0,0 +1,92 @@ +package org.move.lang.core.completion + +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import org.move.ide.presentation.text +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.MvMethodOrField +import org.move.lang.core.psi.ext.addressRef +import org.move.lang.core.psi.ext.joinToSignature +import org.move.lang.core.psi.ext.outerFileName +import org.move.lang.core.resolve.ScopeEntry +import org.move.lang.core.types.infer.* +import org.move.lang.core.types.ty.TyUnknown + +fun createLookupElement( + scopeEntry: ScopeEntry, + completionContext: CompletionContext, + subst: Substitution = emptySubstitution, + priority: Double = DEFAULT_PRIORITY, + insertHandler: InsertHandler = DefaultInsertHandler(completionContext) +): LookupElement { + val element = scopeEntry.element + val lookup = element.getLookupElementBuilder(completionContext, scopeEntry.name, subst) + .withInsertHandler(insertHandler) + .withPriority(priority) + val props = getLookupElementProperties(element, subst, completionContext) + return lookup.toMvLookupElement(properties = props) +} + +private fun MvNamedElement.getLookupElementBuilder( + context: CompletionContext, + scopeName: String, + subst: Substitution = emptySubstitution, +): LookupElementBuilder { + val msl = context.msl + val base = LookupElementBuilder.createWithSmartPointer(scopeName, this) + .withIcon(this.getIcon(0)) + return when (this) { + is MvFunction -> { + val signature = FuncSignature.fromFunction(this, msl).substitute(subst) + if (context.contextElement is MvMethodOrField) { + base + .withTailText(signature.paramsText()) + .withTypeText(signature.retTypeText()) + } else { + base + .withTailText(this.signatureText) + .withTypeText(this.outerFileName) + } + } + is MvSpecFunction -> base + .withTailText(this.parameters.joinToSignature()) + .withTypeText(this.returnType?.type?.text ?: "()") + + is MvModule -> base + .withTailText(this.addressRef()?.let { " ${it.text}" } ?: "") + .withTypeText(this.containingFile?.name) + + is MvStruct -> { + val tailText = if (context.structAsType) "" else " { ... }" + base + .withTailText(tailText) + .withTypeText(this.containingFile?.name) + } + + is MvStructField -> { + val fieldTy = this.type?.loweredType(msl)?.substitute(subst) ?: TyUnknown + base + .withTypeText(fieldTy.text(false)) + } + is MvConst -> { + val constTy = this.type?.loweredType(msl) ?: TyUnknown + base + .withTypeText(constTy.text(true)) + } + + is MvBindingPat -> { + val bindingInference = this.inference(msl) + // race condition sometimes happens, when file is too big, inference is not finished yet + val ty = bindingInference?.getPatTypeOrUnknown(this) ?: TyUnknown + base + .withTypeText(ty.text(true)) + } + + is MvSchema -> base + .withTypeText(this.containingFile?.name) + + else -> base + } +} + diff --git a/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt b/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt index 28188a662..a594b24f9 100644 --- a/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt +++ b/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt @@ -60,7 +60,7 @@ fun getLookupElementProperties( var props = LookupElementProperties() val expectedTy = context.expectedTy if (expectedTy != null) { - val msl = context.isMsl() + val msl = context.msl val declaredTy = when (element) { is MvFunctionLike -> element.declaredType(msl).retType diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 1643abd91..5e615c097 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -2,7 +2,6 @@ package org.move.lang.core.completion.providers import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.patterns.ElementPattern import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext @@ -45,19 +44,12 @@ object MvPathCompletionProvider2: MvCompletionProvider() { if (parameters.position !== pathElement.referenceNameElement) return val parentElement = pathElement.rootPath().parent - val resolutionCtx = ResolutionContext(pathElement) + val resolutionCtx = ResolutionContext(pathElement, isCompletion = true) val msl = pathElement.isMslScope val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(pathElement, msl) - // 0x1::m::{a, b, Self} - // //^ - if (resolutionCtx.isUseSpeck) { - val useGroup = resolutionCtx.useSpeck?.parent as? MvUseGroup - if (useGroup != null && "Self" !in useGroup.names) { - result.addElement(createSelfLookup()) - } - } - + val useGroup = resolutionCtx.useSpeck?.parent as? MvUseGroup + val existingNames = useGroup?.names.orEmpty().toSet() val ns = buildSet { val pathKind = pathElement.pathKind() if (resolutionCtx.isUseSpeck) { @@ -91,18 +83,23 @@ object MvPathCompletionProvider2: MvCompletionProvider() { ) addVariants( pathElement, parameters, completionContext, ns, result, - listOf( - CompletionFilter { e, ctx -> - // filter out current module, skips processing if true - val element = e.element.getOriginalOrSelf() - if (element is MvModule) { - val containingModule = ctx.containingModule?.getOriginalOrSelf() - if (containingModule != null) { - return@CompletionFilter containingModule.equalsTo(element) - } + CompletionFilter { e, ctx -> + // skip existing items, only non-empty for use groups + if (e.name in existingNames) return@CompletionFilter true + + // drop Self completion for non-UseGroup items + if (e.name == "Self" && useGroup == null) return@CompletionFilter true + + // filter out current module, skips processing (return true) + val element = e.element.getOriginalOrSelf() + if (element is MvModule) { + val containingModule = ctx.containingModule?.getOriginalOrSelf() + if (containingModule != null) { + return@CompletionFilter containingModule.equalsTo(element) } - false - }) + } + false + } ) } @@ -112,7 +109,7 @@ object MvPathCompletionProvider2: MvCompletionProvider() { completionContext: CompletionContext, ns: Set, result: CompletionResultSet, - completionFilters: List = emptyList() + completionFilter: CompletionFilter? = null ) { val resolutionCtx = completionContext.resolutionCtx ?: error("always non-null in path completion") val processedNames = mutableSetOf() @@ -120,7 +117,7 @@ object MvPathCompletionProvider2: MvCompletionProvider() { val processor = it .wrapWithFilter { e -> // custom completion filters - for (completionFilter in completionFilters) { + if (completionFilter != null) { if (completionFilter.removeEntry(e, resolutionCtx)) return@wrapWithFilter false } @@ -154,7 +151,7 @@ object MvPathCompletionProvider2: MvCompletionProvider() { ) candidates.forEach { candidate -> val entry = SimpleScopeEntry(candidate.qualName.itemName, candidate.element, ns) - for (completionFilter in completionFilters) { + if (completionFilter != null) { if (completionFilter.removeEntry(entry, resolutionCtx)) return@forEach } val lookupElement = candidate.element.createLookupElement( @@ -165,8 +162,6 @@ object MvPathCompletionProvider2: MvCompletionProvider() { result.addElement(lookupElement) } } - - private fun createSelfLookup() = LookupElementBuilder.create("Self").bold() } fun getExpectedTypeForEnclosingPathOrDotExpr(element: MvReferenceElement, msl: Boolean): Ty? { diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt index b9f4053e6..5487b336d 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt @@ -11,6 +11,7 @@ import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.cli.AddressVal import org.move.ide.MoveIcons +import org.move.lang.MvElementTypes.COLON_COLON import org.move.lang.core.MvPsiPatterns import org.move.lang.core.completion.alreadyHasColonColon import org.move.lang.core.psi.MvModule @@ -78,6 +79,15 @@ object NamedAddressInUseStmtCompletionProvider: MvCompletionProvider() { get() = MvPsiPatterns.path() .and( PlatformPatterns.psiElement() + // use path::ident:: + // ^ should not exist + .andNot( + PlatformPatterns.psiElement().afterLeaf("::") + ) + // use [ident::] + // ^ path (1) + // ^ use speck (2) + // ^ use stmt (3) .withSuperParent(3, psiElement()) ) @@ -86,7 +96,8 @@ object NamedAddressInUseStmtCompletionProvider: MvCompletionProvider() { context: ProcessingContext, result: CompletionResultSet ) { - val moveProject = parameters.position.moveProject ?: return + val element = parameters.position + val moveProject = element.moveProject ?: return val declaredNamedAddresses = moveProject.addresses().values for ((name, addressVal) in declaredNamedAddresses.entries.sortedBy { it.key }) { val lookup = addressVal.createCompletionLookupElement(name) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index d0ca218cd..db7250060 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -57,6 +57,17 @@ val MvModule.declaredFriendModules: Set return friends } +val MvModule.friendModules: Set get() { + val moduleBlock = this.moduleBlock ?: return emptySet() + val friendModulePaths = moduleBlock.friendDeclList.mapNotNull { it.path } + val friends = mutableSetOf() + for (modulePath in friendModulePaths) { + val module = modulePath.reference?.resolveFollowingAliases() as? MvModule ?: continue + friends.add(module) + } + return friends +} + fun MvModule.allFunctions(): List { val stub = greenStub return stub?.childrenStubsOfType()?.map { it.psi } @@ -230,32 +241,34 @@ fun MvModuleSpec.specInlineFunctions(): List = this.moduleItemSpecs().flatMap { it.specInlineFunctions() } fun MvModule.allModuleSpecs(): List { - return getProjectPsiDependentCache(this) { - val moveProject = it.moveProject ?: return@getProjectPsiDependentCache emptyList() - val moduleName = it.name ?: return@getProjectPsiDependentCache emptyList() -// val file = it.containingMoveFile ?: return@getProjectPsiDependentCache emptyList() - - val searchScope = moveProject.searchScope() - // all `spec 0x1::m {}` for the current module - val moduleSpecs = MvModuleSpecIndex.getElementsByModuleName(it.project, moduleName, searchScope) -// val moduleSpecs = file.moduleSpecs() + -// MvModuleSpecIndex.getElementsByModuleName(it.project, moduleName, searchScope) - if (moduleSpecs.isEmpty()) return@getProjectPsiDependentCache emptyList() - - val currentModule = it.fqModule() ?: return@getProjectPsiDependentCache emptyList() - moduleSpecs - .filter { moduleSpec -> - val module = moduleSpec.moduleItem ?: return@filter false - currentModule == module.fqModule() - } - .toList() - } + val moveProject = this.moveProject ?: return emptyList() + val moduleName = this.name ?: return emptyList() + + val searchScope = moveProject.searchScope() + // all `spec 0x1::m {}` for the current module + val moduleSpecs = MvModuleSpecIndex.getElementsByModuleName(this.project, moduleName, searchScope) + if (moduleSpecs.isEmpty()) return emptyList() + +// val currentModule = this.fqModule() ?: return emptyList() + return moduleSpecs + .filter { moduleSpec -> + val specModule = moduleSpec.moduleItem ?: return@filter false + isModulesEqual(this, specModule) +// currentModule == specModule.fqModule() + } + .toList() +// return getProjectPsiDependentCache(this) { +// } } fun MvModule.allModuleSpecBlocks(): List { return this.allModuleSpecs().mapNotNull { it.moduleSpecBlock } } +fun isModulesEqual(left: MvModule, right: MvModule): Boolean { + return left == right +} + abstract class MvModuleMixin : MvStubbedNamedElementImpl, MvModule { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt index cdccc0992..767076220 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt @@ -43,7 +43,7 @@ class MvStructRefFieldReferenceImpl( ): MvPolyVariantReferenceCached(element) { override fun multiResolveInner(): List { - val referenceName = element.referenceName ?: return emptyList() + val referenceName = element.referenceName var variants = collectResolveVariants(referenceName) { processStructRefFieldResolveVariants(element, it) } diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt index 159fdf5c2..c022248d4 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvUseSpeck.kt @@ -6,8 +6,6 @@ import org.move.lang.core.psi.MvUseSpeck val MvUseSpeck.qualifier: MvPath? get() { val parentUseSpeck = (context as? MvUseGroup)?.parentUseSpeck ?: return null - return parentUseSpeck.pathOrQualifier + return parentUseSpeck.path } -val MvUseSpeck.pathOrQualifier: MvPath? get() = path ?: qualifier - val MvUseSpeck.isSelf: Boolean get() = this.path.identifier?.textMatches("Self") ?: false diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt index 86f3d6b27..dc0fa1c18 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -4,7 +4,6 @@ import com.intellij.psi.util.PsiTreeUtil import org.move.cli.containingMovePackage import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvVisibilityModifier -import org.move.lang.core.psi.ScopeMslOnlyElement import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.VisKind.* import org.move.lang.core.resolve.ref.Visibility @@ -56,8 +55,7 @@ val MvVisibilityOwner.visibility2: Visibility2 FRIEND -> { val module = this.containingModule ?: return Visibility2.Private // todo: make lazy - val friendModules = module.declaredFriendModules - Visibility2.Restricted.Friend(friendModules) + Visibility2.Restricted.Friend(lazy { module.friendModules }) } SCRIPT -> Visibility2.Restricted.Script PUBLIC -> Visibility2.Public diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index e64297578..0b54d5d6b 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -398,22 +398,12 @@ private class CompletionVariantsCollector( override fun process(entry: ScopeEntry): Boolean { // addEnumVariantsIfNeeded(entry) -// addAssociatedItemsIfNeeded(entry) - - val element = entry.element as? MvNamedElement ?: return false - val lookup = - element.createLookupElement( - context, - priority = element.completionPriority - ) - result.addElement(lookup) - -// (entry.element as? MvNamedElement)?.let { -// it.createLookupElement(context) -// } -// result.addElement(createLookupElement( -// context = context -// )) + + result.addElement(createLookupElement( + scopeEntry = entry, + completionContext = context, + priority = entry.element.completionPriority + )) return false } @@ -437,27 +427,6 @@ private class CompletionVariantsCollector( // result.addAllElements(filtered) // } // } - -// private fun addAssociatedItemsIfNeeded(entry: ScopeEntry) { -// if (entry.name != "Self") return -// val entryTrait = when (val traitOrImpl = entry.element as? RsTraitOrImpl) { -// is RsTraitItem -> traitOrImpl as? RsTraitItem ?: return -// is RsImplItem -> traitOrImpl.traitRef?.path?.reference?.resolve() as? RsTraitItem ?: return -// else -> return -// } -// -// val associatedTypes = entryTrait -// .associatedTypesTransitively -// .mapNotNull { type -> -// val name = type.name ?: return@mapNotNull null -// val typeAlias = type.superItem ?: type -// createLookupElement( -// SimpleScopeEntry("Self::$name", typeAlias, TYPES), -// context, -// ) -// } -// result.addAllElements(associatedTypes) -// } } //fun collectNames(f: (RsResolveProcessor) -> Unit): Set { diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index 7279ad877..845050b26 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -17,7 +17,7 @@ sealed class Visibility2 { data object Public: Visibility2() data object Private: Visibility2() sealed class Restricted: Visibility2() { - class Friend(val friendModules: Set): Restricted() + class Friend(val friendModules: Lazy>): Restricted() class Package(val originPackage: MovePackage): Restricted() data object Script: Restricted() } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 3000e8d35..df16b624f 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -41,7 +41,7 @@ fun processItemDeclarations( // 2. for every item, use it's .visibility to create VisibilityFilter, even it's just a { false } val items = itemsOwner.itemElements + (itemsOwner as? MvModuleBlock)?.module?.innerSpecItems.orEmpty() + - (itemsOwner as? MvModuleBlock)?.let { getItemsFromModuleSpecs(it.module, ns) }.orEmpty() + (itemsOwner as? MvModuleBlock)?.module?.let { getItemsFromModuleSpecs(it, ns) }.orEmpty() for (item in items) { val name = item.name ?: continue diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 29a41c7f8..1e71eaf9e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -1,6 +1,5 @@ package org.move.lang.core.resolve2 -import org.move.cli.MoveProject import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* @@ -9,6 +8,7 @@ import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve.ref.Namespace.MODULE import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.Address +import org.move.lang.core.types.Address.Named import org.move.lang.core.types.address import org.move.lang.index.MvModuleIndex @@ -16,7 +16,12 @@ fun resolveBindingForFieldShorthand( element: MvMandatoryReferenceElement, ): List { return collectResolveVariants(element.referenceName) { - processNestedScopesUpwards(element, setOf(Namespace.NAME), ResolutionContext(element), it) + processNestedScopesUpwards( + element, + setOf(Namespace.NAME), + ResolutionContext(element, isCompletion = false), + it + ) } } @@ -40,21 +45,29 @@ fun processNestedScopesUpwards( } fun processModulePathResolveVariants( - element: MvElement, - moveProject: MoveProject?, + ctx: ResolutionContext, address: Address, processor: RsResolveProcessor, ): Boolean { // if no project, cannot use the index + val moveProject = ctx.moveProject if (moveProject == null) return false - val project = element.project + val project = ctx.element.project val searchScope = moveProject.searchScope() val addrProcessor = processor.wrapWithFilter { e -> val candidate = e.element as? MvModule ?: return@wrapWithFilter false val candidateAddress = candidate.address(moveProject) - address == candidateAddress + val sameValues = Address.equals(address, candidateAddress) + + if (ctx.isCompletion && sameValues) { + // compare named addresses by name in case of the same values for the completion + if (address is Named && candidateAddress is Named && address.name != candidateAddress.name) + return@wrapWithFilter false + } + + sameValues } val targetNames = addrProcessor.names diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index 7e78eef69..fc8be4f41 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -81,9 +81,11 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { is Restricted -> { when (visibility) { is Restricted.Friend -> { - val friends = visibility.friendModules - val modInfo = pathModule?.fqModule() - if (modInfo in friends) Visible else Invisible + if (pathModule != null) { + val friendModules = visibility.friendModules.value + if (friendModules.any { isModulesEqual(it, pathModule) }) return@VisibilityFilter Visible + } + Invisible } is Restricted.Script -> { val containingFunction = path.containingFunction diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index e3974459b..8588936a8 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -46,7 +46,7 @@ class Path2ReferenceImpl(element: MvPath): override fun invoke(path: MvElement): List> { // should not really happen if (path !is MvPath) return emptyList() - val resolutionCtx = ResolutionContext(path) + val resolutionCtx = ResolutionContext(path, isCompletion = false) return resolvePath(resolutionCtx, path) } } @@ -57,59 +57,23 @@ fun processPathResolveVariants( pathKind: PathKind, processor: RsResolveProcessor ): Boolean { -// val contextProcessor = ctx.contextScopeInfo.wrapWithContextFilter(processor) - val contextProcessor = processor return when (pathKind) { is NamedAddress, is ValueAddress -> false is PathKind.UnqualifiedPath -> { // Self:: if (processor.lazy("Self") { ctx.containingModule }) return true // local - processNestedScopesUpwards(ctx.element, pathKind.ns, ctx, contextProcessor) + processNestedScopesUpwards(ctx.element, pathKind.ns, ctx, processor) } is PathKind.QualifiedPath.Module -> { - processModulePathResolveVariants(ctx.element, ctx.moveProject, pathKind.address, contextProcessor) + processModulePathResolveVariants(ctx, pathKind.address, processor) } is PathKind.QualifiedPath -> { - processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) -// processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, contextProcessor) + processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.qualifier, processor) } } -// return when (pathKind) { -// is UnqualifiedPath -> { -// // Self:: -// if (processor.lazy("Self") { ctx.containingModule }) return true -// // local -// processNestedScopesUpwards(ctx.path, pathKind.ns, ctx, contextProcessor) -// } -// is ModulePath -> { -// // 0x1::bar -// processModulePathResolveVariants( -// ctx.path, -// ctx.moveProject, -// pathKind.address, -// contextProcessor -// ) -// } -// is QualifiedPath -> { -// // foo::bar -// processQualifiedPathResolveVariants(ctx, pathKind.ns, pathKind.path, pathKind.qualifier, processor) -// } -// is NamedAddressPath -> return false -// is ValueAddressPath -> return false -// } } -//fun processPathResolveVariants( -// path: MvPath, -// contextScopeInfo: ContextScopeInfo = ContextScopeInfo.from(path), -// processor: RsResolveProcessor, -//): Boolean { -// val ctx = PathResolutionContext(path, contextScopeInfo = contextScopeInfo) -// val pathKind = classifyPath(path) -// return processPathResolveVariants(ctx, pathKind, processor) -//} - /** * foo::bar * | | @@ -119,7 +83,6 @@ fun processPathResolveVariants( fun processQualifiedPathResolveVariants( ctx: ResolutionContext, ns: Set, - path: MvPath, qualifier: MvPath, processor: RsResolveProcessor ): Boolean { @@ -129,7 +92,7 @@ fun processQualifiedPathResolveVariants( // can be module, try for named address as a qualifier val addressName = qualifier.referenceName ?: return false val address = ctx.moveProject?.getNamedAddressTestAware(addressName) ?: return false - if (processModulePathResolveVariants(ctx.element, ctx.moveProject, address, processor)) return true + if (processModulePathResolveVariants(ctx, address, processor)) return true } return false } @@ -144,7 +107,7 @@ fun processQualifiedPathResolveVariants( return false } -class ResolutionContext(val element: MvElement) { +class ResolutionContext(val element: MvElement, val isCompletion: Boolean) { private var lazyContainingMoveProject: Lazy = lazy(NONE) { element.moveProject diff --git a/src/main/kotlin/org/move/lang/core/types/Address.kt b/src/main/kotlin/org/move/lang/core/types/Address.kt index 6b6a6765a..f5c8e3a19 100644 --- a/src/main/kotlin/org/move/lang/core/types/Address.kt +++ b/src/main/kotlin/org/move/lang/core/types/Address.kt @@ -7,6 +7,8 @@ import org.move.lang.core.psi.MvAddressRef import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.ext.addressRef import org.move.lang.core.psi.ext.greenStub +import org.move.lang.core.types.Address.Named +import org.move.lang.core.types.Address.Value import org.move.lang.core.types.AddressLit.Companion.normalizeValue const val MAX_LENGTH = 32 @@ -45,21 +47,21 @@ sealed class Address { val is0x0 get() = this is Value && this.addressLit().original == "0x0" - class Value(private val value: String) : Address() { + class Value(private val value: String): Address() { fun addressLit(): AddressLit = AddressLit(value) override fun canonicalValue(moveProject: MoveProject): String = this.addressLit().canonical() override fun text(): String = this.addressLit().original - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is Value) return false - if (this.hashCode() != other.hashCode()) return false - return eq(this, other) - } +// override fun equals(other: Any?): Boolean { +// if (this === other) return true +// if (other !is Value) return false +// if (this.hashCode() != other.hashCode()) return false +// return eq(this, other) +// } - override fun hashCode(): Int = normalizeValue(value).hashCode() +// override fun hashCode(): Int = normalizeValue(value).hashCode() override fun toString(): String = "Address.Value($value)" } @@ -68,7 +70,7 @@ sealed class Address { val name: String, val value: String?, private val declMoveProject: MoveProject? - ) : Address() { + ): Address() { fun value(moveProject: MoveProject? = null): String { return value ?: this.declMoveProject?.getNamedAddressValue(name) @@ -79,48 +81,57 @@ sealed class Address { fun addressLit(moveProject: MoveProject): AddressLit? = moveProject.getNamedAddressValue(this.name)?.let { AddressLit(it) } - override fun canonicalValue(moveProject: MoveProject): String? = this.addressLit(moveProject)?.canonical() + override fun canonicalValue(moveProject: MoveProject): String? = + this.addressLit(moveProject)?.canonical() override fun text(): String = "$name = ${value()}" - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is Named) return false -// if (this.hashCode() != other.hashCode()) return false - return eq(this, other) - } +// override fun equals(other: Any?): Boolean { +// if (this === other) return true +// if (other !is Named) return false +//// if (this.hashCode() != other.hashCode()) return false +// return eq(this, other) +// } - override fun hashCode(): Int = name.hashCode() +// override fun hashCode(): Int = name.hashCode() } companion object { const val UNKNOWN: String = "0x0" - fun eq(left: Address?, right: Address?): Boolean { + fun equals(left: Address?, right: Address?): Boolean { if (left === right) return true if (left == null && right == null) return true return when { - left is Value && right is Value -> left.addressLit().canonical() == right.addressLit().canonical() + left is Value && right is Value -> + left.addressLit().canonical() == right.addressLit().canonical() left is Named && right is Named -> { val leftValue = left.value?.let { normalizeValue(it) } val rightValue = right.value?.let { normalizeValue(it) } if (leftValue == null && rightValue == null) { // null items cannot be equal return false -// return left.name == right.name } return leftValue == rightValue } + left is Value && right is Named -> checkValueNamedEquals(left, right) + left is Named && right is Value -> checkValueNamedEquals(right, left) else -> false } } + + private fun checkValueNamedEquals(value: Value, named: Named): Boolean { + val normalizedValue = value.addressLit().canonical() + val normalizedNamed = named.value?.let { normalizeValue(it) } + return normalizedValue == normalizedNamed + } } } sealed class StubAddress { - object Unknown : StubAddress() - data class Value(val value: String) : StubAddress() - data class Named(val name: String) : StubAddress() + object Unknown: StubAddress() + data class Value(val value: String): StubAddress() + data class Named(val name: String): StubAddress() fun asInt(): Int { return when (this) { @@ -134,9 +145,13 @@ sealed class StubAddress { return when (this) { is Named -> { if (moveProject == null) { - Address.Named(this.name, null, null) + Named(this.name, null, null) } else { - moveProject.getNamedAddressTestAware(this.name) ?: Address.Named(this.name, null, moveProject) + moveProject.getNamedAddressTestAware(this.name) ?: Named( + this.name, + null, + moveProject + ) } } is Value -> Address.Value(this.value) diff --git a/src/main/kotlin/org/move/lang/index/MvModuleSpecIndex.kt b/src/main/kotlin/org/move/lang/index/MvModuleSpecIndex.kt index ec547ebe6..b34b9476f 100644 --- a/src/main/kotlin/org/move/lang/index/MvModuleSpecIndex.kt +++ b/src/main/kotlin/org/move/lang/index/MvModuleSpecIndex.kt @@ -9,7 +9,7 @@ import org.move.lang.core.stubs.impl.MvFileStub import org.move.openapiext.checkCommitIsNotInProgress import org.move.openapiext.getElements -class MvModuleSpecIndex : StringStubIndexExtension() { +class MvModuleSpecIndex: StringStubIndexExtension() { override fun getVersion(): Int = MvFileStub.Type.stubVersion override fun getKey(): StubIndexKey = KEY diff --git a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt index ec9df2681..a7e0736b3 100644 --- a/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/ModulesCompletionTest.kt @@ -121,6 +121,17 @@ class ModulesCompletionTest: CompletionTestCase() { """ ) + fun `test no item completion if already imported in use group`() = checkNoCompletion( + """ + module 0x1::Signer { + public fun address_of(): address { @0x1 } + } + module 0x1::M { + use 0x1::Signer::{address_of, addr/*caret*/}; + } + """ + ) + fun `test no Self completion if already imported in this block`() = checkNoCompletion( """ module 0x1::Signer {} @@ -225,7 +236,6 @@ class ModulesCompletionTest: CompletionTestCase() { """ ) - // todo: to fix this, I need to get rid of ContextScopeInfo processor filter fun `test test_only module completion is possible in non test context inside use speck`() = doSingleCompletion( """ #[test_only] @@ -254,7 +264,6 @@ class ModulesCompletionTest: CompletionTestCase() { """ ) - // todo: error from ::Self module completion, which is handled with the module name instead fun `test no modules completion for item position`() = checkNoCompletion(""" module 0x1::Transaction { } diff --git a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt index 51f568f83..f9923dd76 100644 --- a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt @@ -198,7 +198,6 @@ class StructsCompletionTest: CompletionTestCase() { } """) - // todo: error from ::Self module completion, which is handled with the module name instead fun `test module struct completion in type position`() = doSingleCompletion(""" module 0x1::Transaction { struct Type { diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt index 99a7db4e4..a011b26f3 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveModulesTest.kt @@ -422,6 +422,16 @@ module 0x1::string_tests { } """) + @NamedAddress("aptos_framework", "0x1") + fun `test resolve module from import with value address`() = checkByCode(""" + module aptos_framework::m1 {} + //X + module 0x1::m { + use 0x1::m1; + //^ + } + """) + fun `test cannot resolve module with unknown named address`() = checkByCode(""" module aptos_framework::m1 {} module 0x1::m { From b378af174a736d8f8303e77453223efc7979a746 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 1 Aug 2024 20:50:28 +0300 Subject: [PATCH 41/43] fix remaining tests --- .../ide/inspections/imports/BasePathType.kt | 2 +- .../ide/inspections/imports/ImportAnalyzer.kt | 2 +- .../MethodOrFieldCompletionProvider.kt | 39 +++++++++------ .../move/lang/core/psi/ext/MvMethodCall.kt | 14 +++--- .../org/move/lang/core/psi/ext/MvModule.kt | 9 ++-- .../org/move/lang/core/resolve/Processors.kt | 27 ++++++----- .../move/lang/core/resolve2/ItemResolution.kt | 31 ++++++++++-- .../core/resolve2/LexicalDeclarations2.kt | 4 +- .../move/lang/core/resolve2/Visibility2.kt | 37 ++++++++------- .../core/resolve2/ref/Path2ReferenceImpl.kt | 4 +- .../lang/core/types/infer/InferenceContext.kt | 41 ++++++++-------- .../core/types/infer/TypeInferenceWalker.kt | 14 ++++-- .../names/FunctionsCompletionTest.kt | 5 +- .../move/lang/parser/PartialParsingTest.kt | 2 +- .../compilerV2/ReceiverStyleFunctionTest.kt | 47 +++++++++++++++++++ 15 files changed, 185 insertions(+), 93 deletions(-) diff --git a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt index aa4d50d87..2f2d2df16 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt @@ -35,7 +35,7 @@ fun MvPath.basePathType(): BasePathType? { } // only Main/Test for now -val MvPath.pathUsageScope: NamedItemScope +val MvElement.usageScope: NamedItemScope get() { var parentElement = this.parent while (parentElement != null) { diff --git a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt index 0c8ad9bbe..d1d44de70 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt @@ -25,7 +25,7 @@ class ImportAnalyzer2(val holder: ProblemsHolder): MvVisitor() { val paths = rootItemOwnerWithSiblings .flatMap { it.descendantsOfType() } .filter { it.basePath() == it } - .filter { it.pathUsageScope == itemScope } + .filter { it.usageScope == itemScope } .filter { !it.hasAncestor() } for (path in paths) { diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index bbb6d3896..dc21d2285 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -9,8 +9,16 @@ import com.intellij.util.ProcessingContext import org.jetbrains.annotations.VisibleForTesting import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement -import org.move.lang.core.psi.ext.* +import org.move.lang.core.psi.MvFunction +import org.move.lang.core.psi.MvMethodCall +import org.move.lang.core.psi.ext.MvMethodOrField +import org.move.lang.core.psi.ext.getFieldVariants +import org.move.lang.core.psi.ext.inferReceiverTy +import org.move.lang.core.psi.ext.isMsl import org.move.lang.core.psi.tyInfers +import org.move.lang.core.resolve.createProcessor +import org.move.lang.core.resolve2.processMethodResolveVariants +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.InferenceContext import org.move.lang.core.types.infer.substitute import org.move.lang.core.types.ty.TyFunction @@ -61,23 +69,26 @@ object MethodOrFieldCompletionProvider: MvCompletionProvider() { result.addElement(lookupElement) } } - getMethodVariants(element, receiverTy, msl) - .forEach { (_, function) -> - val subst = function.tyInfers - val declaredFuncTy = function.declaredType(msl).substitute(subst) as TyFunction - val declaredSelfTy = declaredFuncTy.paramTypes.first() - val autoborrowedReceiverTy = - TyReference.autoborrow(receiverTy, declaredSelfTy) - ?: error("unreachable, references always compatible") - val inferenceCtx = InferenceContext(msl) - inferenceCtx.combineTypes(declaredSelfTy, autoborrowedReceiverTy) + processMethodResolveVariants(element, receiverTy, ctx.msl, createProcessor { e -> + val function = e.element as? MvFunction ?: return@createProcessor + val subst = function.tyInfers + val declaredFuncTy = function.declaredType(msl).substitute(subst) as TyFunction + val declaredSelfTy = declaredFuncTy.paramTypes.first() + val autoborrowedReceiverTy = + TyReference.autoborrow(receiverTy, declaredSelfTy) + ?: error("unreachable, references always compatible") - val lookupElement = function.createLookupElement( + val inferenceCtx = InferenceContext(msl) + inferenceCtx.combineTypes(declaredSelfTy, autoborrowedReceiverTy) + + result.addElement( + createLookupElement( + e, ctx, subst = inferenceCtx.resolveTypeVarsIfPossible(subst) ) - result.addElement(lookupElement) - } + ) + }) } } \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt index 1734b6982..aab6aeb1c 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt @@ -8,6 +8,7 @@ import org.move.lang.core.resolve.ScopeItem import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve.ref.MvPolyVariantReferenceBase import org.move.lang.core.resolve.ref.Visibility +import org.move.lang.core.resolve2.processItemDeclarations import org.move.lang.core.types.address import org.move.lang.core.types.infer.foldTyTypeParameterWith import org.move.lang.core.types.infer.inference @@ -41,17 +42,18 @@ fun MvModule.is0x1Address(moveProject: MoveProject): Boolean { return moduleAddress == "0x00000000000000000000000000000001" } -fun getMethodVariants(element: MvMethodOrField, receiverTy: Ty, msl: Boolean): MatchSequence { - val moveProject = element.moveProject ?: return emptySequence() - val receiverTyItemModule = receiverTy.itemModule(moveProject) ?: return emptySequence() +fun getMethodVariants(methodOrField: MvMethodOrField, receiverTy: Ty, msl: Boolean): MatchSequence { + val moveProject = methodOrField.moveProject ?: return emptySequence() + val itemModule = receiverTy.itemModule(moveProject) ?: return emptySequence() - val elementScopes = Visibility.visibilityScopesForElement(element).toMutableSet() - if (element.containingModule == receiverTyItemModule) { + val elementScopes = Visibility.visibilityScopesForElement(methodOrField).toMutableSet() + if (methodOrField.containingModule == itemModule) { elementScopes.add(Visibility.Internal) } + val functions = elementScopes - .flatMap { elementScope -> receiverTyItemModule.functionsVisibleInScope(elementScope) } + .flatMap { elementScope -> itemModule.functionsVisibleInScope(elementScope) } .filter { val selfTy = it.selfParamTy(msl) ?: return@filter false // need to use TyVar here, loweredType() erases them diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index db7250060..802c25c52 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -9,6 +9,7 @@ import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache import org.move.cli.containingMovePackage import org.move.cli.settings.moveSettings import org.move.ide.MoveIcons +import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.psi.* import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.stubs.MvFunctionStub @@ -76,9 +77,9 @@ fun MvModule.allFunctions(): List { fun MvModule.allNonTestFunctions(): List = // allFunctions().filter { f -> !f.isTest } - getProjectPsiDependentCache(this) { - it.allFunctions().filter { f -> !f.hasTestAttr } - } + this.allFunctions().filter { f -> !f.hasTestAttr } +// getProjectPsiDependentCache(this) { +// } fun MvModule.testFunctions(): List = getProjectPsiDependentCache(this) { @@ -266,7 +267,7 @@ fun MvModule.allModuleSpecBlocks(): List { } fun isModulesEqual(left: MvModule, right: MvModule): Boolean { - return left == right + return left.getOriginalOrSelf() == right.getOriginalOrSelf() } abstract class MvModuleMixin : MvStubbedNamedElementImpl, diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 0b54d5d6b..92917afcc 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -6,6 +6,7 @@ import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.MvItemElement +import org.move.lang.core.psi.ext.MvMethodOrPath import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.createFilter @@ -315,12 +316,13 @@ private class ResolveVariantsAsScopeEntriesCollector( } } -fun collectPathResolveVariants( +/// checks for visibility of items +fun collectMethodOrPathResolveVariants( + methodOrPath: MvMethodOrPath, ctx: ResolutionContext, - path: MvPath, f: (RsResolveProcessor) -> Unit ): List> { - val referenceName = path.referenceName ?: return emptyList() + val referenceName = methodOrPath.referenceName ?: return emptyList() val processor = SinglePathResolveVariantsCollector(ctx, referenceName) f(processor) return processor.result @@ -335,25 +337,25 @@ private class SinglePathResolveVariantsCollector( override fun process(entry: ScopeEntry): Boolean { if (entry.name == referenceName) { - collectPathScopeEntry(ctx, result, entry) + collectMethodOrPathScopeEntry(ctx, result, entry) } return false } } -private fun collectPathScopeEntry( +private fun collectMethodOrPathScopeEntry( ctx: ResolutionContext, result: MutableList>, e: ScopeEntry ) { val element = e.element - val visibilityStatus = ctx.path?.let { e.getVisibilityStatusFrom(it) } ?: Visible + val visibilityStatus = ctx.methodOrPath?.let { e.getVisibilityStatusFrom(it) } ?: Visible val isVisible = visibilityStatus == Visible result += RsPathResolveResult(element, isVisible) } -fun pickFirstResolveVariant(referenceName: String?, f: (RsResolveProcessor) -> Unit): MvElement? = - pickFirstResolveEntry(referenceName, f)?.element +//fun pickFirstResolveVariant(referenceName: String?, f: (RsResolveProcessor) -> Unit): MvElement? = +// pickFirstResolveEntry(referenceName, f)?.element fun pickFirstResolveEntry(referenceName: String?, f: (RsResolveProcessor) -> Unit): ScopeEntry? { if (referenceName == null) return null @@ -477,22 +479,21 @@ fun Map.entriesWithNames(names: Set?): Map { } fun interface VisibilityFilter { - fun filter(path: MvPath, ns: Set): VisibilityStatus + fun filter(methodOrPath: MvMethodOrPath, ns: Set): VisibilityStatus } //typealias VisibilityFilter = (MvPath, Set) -> VisibilityStatus //typealias VisibilityFilter = (MvElement, Lazy?) -> VisibilityStatus -fun ScopeEntry.getVisibilityStatusFrom(path: MvPath): VisibilityStatus = +fun ScopeEntry.getVisibilityStatusFrom(methodOrPath: MvMethodOrPath): VisibilityStatus = if (this is ScopeEntryWithVisibility) { - visibilityFilter.filter(path, this.namespaces) + visibilityFilter.filter(methodOrPath, this.namespaces) } else { Visible } -fun ScopeEntry.isVisibleFrom(context: MvPath): Boolean = - getVisibilityStatusFrom(context) == Visible +fun ScopeEntry.isVisibleFrom(context: MvPath): Boolean = getVisibilityStatusFrom(context) == Visible enum class VisibilityStatus { Visible, diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index df16b624f..9ab27e4ca 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -2,11 +2,14 @@ package org.move.lang.core.resolve2 import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.RsResolveProcessor -import org.move.lang.core.resolve.createProcessor -import org.move.lang.core.resolve.process -import org.move.lang.core.resolve.processAll +import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace +import org.move.lang.core.resolve2.ref.ResolutionContext +import org.move.lang.core.types.infer.foldTyTypeParameterWith +import org.move.lang.core.types.ty.Ty +import org.move.lang.core.types.ty.TyInfer +import org.move.lang.core.types.ty.TyReference +import org.move.lang.moveProject import java.util.* val MvNamedElement.namespaces: Set @@ -31,6 +34,26 @@ val MvNamedElement.namespace else -> error("when should be exhaustive, $this is not covered") } +fun processMethodResolveVariants( + methodOrField: MvMethodOrField, + receiverTy: Ty, + msl: Boolean, + processor: RsResolveProcessor +): Boolean { + val moveProject = methodOrField.moveProject ?: return false + val itemModule = receiverTy.itemModule(moveProject) ?: return false + return processor + .wrapWithFilter { e -> + val function = e.element as? MvFunction ?: return@wrapWithFilter false + val selfTy = function.selfParamTy(msl) ?: return@wrapWithFilter false + // need to use TyVar here, loweredType() erases them + val selfTyWithTyVars = + selfTy.foldTyTypeParameterWith { tp -> TyInfer.TyVar(tp) } + TyReference.isCompatibleWithAutoborrow(receiverTy, selfTyWithTyVars, msl) + } + .processAllItems(setOf(Namespace.FUNCTION), itemModule.allNonTestFunctions()) +} + fun processItemDeclarations( itemsOwner: MvItemsOwner, ns: Set, diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index ff58cc6be..716a5fa03 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -1,7 +1,7 @@ package org.move.lang.core.resolve2 import com.intellij.psi.util.PsiTreeUtil -import org.move.ide.inspections.imports.pathUsageScope +import org.move.ide.inspections.imports.usageScope import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* @@ -238,7 +238,7 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val element = alias ?: namedElement val namespace = namedElement.namespace - val useSpeckUsageScope = path.pathUsageScope + val useSpeckUsageScope = path.usageScope val visibilityFilter = namedElement.visInfo(adjustScope = useSpeckUsageScope).createFilter() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index fc8be4f41..dbe37c32e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -2,7 +2,7 @@ package org.move.lang.core.resolve2 import org.move.cli.containingMovePackage import org.move.cli.settings.moveSettings -import org.move.ide.inspections.imports.pathUsageScope +import org.move.ide.inspections.imports.usageScope import org.move.lang.core.psi.* import org.move.lang.core.psi.NamedItemScope.MAIN import org.move.lang.core.psi.ext.* @@ -31,30 +31,33 @@ fun MvNamedElement.visInfo(adjustScope: NamedItemScope = MAIN): ItemVisibilityIn /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { val (item, itemUsageScope, visibility) = this - return VisibilityFilter { path, namespaces -> + return VisibilityFilter { element, namespaces -> // inside msl everything is visible - if (path.isMsl()) return@VisibilityFilter Visible + if (element.isMsl()) return@VisibilityFilter Visible // types are always visible, their correct usage is checked in a separate inspection if (namespaces.contains(TYPE)) return@VisibilityFilter Visible // if inside MvAttrItem like abort_code= - val attrItem = path.ancestorStrict() + val attrItem = element.ancestorStrict() if (attrItem != null) return@VisibilityFilter Visible - val pathUsageScope = path.pathUsageScope + val pathUsageScope = element.usageScope - val useSpeck = path.useSpeck - if (useSpeck != null) { - // inside import, all visibilities except for private work - if (visibility !is Private) return@VisibilityFilter Visible + val path = element as? MvPath + if (path != null) { + val useSpeck = path.useSpeck + if (useSpeck != null) { + // inside import, all visibilities except for private work + if (visibility !is Private) return@VisibilityFilter Visible - // msl-only items are available from imports - if (item.isMslOnlyItem) return@VisibilityFilter Visible + // msl-only items are available from imports + if (item.isMslOnlyItem) return@VisibilityFilter Visible - // consts are importable in tests - if (pathUsageScope.isTest && namespaces.contains(NAME)) return@VisibilityFilter Visible + // consts are importable in tests + if (pathUsageScope.isTest && namespaces.contains(NAME)) return@VisibilityFilter Visible + } } // #[test] functions cannot be used from non-imports @@ -73,7 +76,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // we're in non-msl scope at this point, msl only items aren't available if (item is MslOnlyElement) return@VisibilityFilter Invisible - val pathModule = path.containingModule + val pathModule = element.containingModule // local methods, Self::method - everything is visible if (itemModule == pathModule) return@VisibilityFilter Visible @@ -88,19 +91,19 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { Invisible } is Restricted.Script -> { - val containingFunction = path.containingFunction + val containingFunction = element.containingFunction if (containingFunction != null) { if (containingFunction.isEntry || containingFunction.isPublicScript ) return@VisibilityFilter Visible } - if (path.containingScript != null) return@VisibilityFilter Visible + if (element.containingScript != null) return@VisibilityFilter Visible Invisible } is Restricted.Package -> { if (!item.project.moveSettings.enablePublicPackage) { return@VisibilityFilter Invisible } - val pathPackage = path.containingMovePackage ?: return@VisibilityFilter Invisible + val pathPackage = element.containingMovePackage ?: return@VisibilityFilter Invisible if (visibility.originPackage == pathPackage) Visible else Invisible } } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 8588936a8..9774c8bd2 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -3,6 +3,7 @@ package org.move.lang.core.resolve2.ref import com.intellij.psi.ResolveResult import org.move.cli.MoveProject import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.MvMethodOrPath import org.move.lang.core.psi.ext.useSpeck import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.* @@ -123,6 +124,7 @@ class ResolutionContext(val element: MvElement, val isCompletion: Boolean) { val useSpeck: MvUseSpeck? get() = lazyUseSpeck.value val isUseSpeck: Boolean get() = useSpeck != null + val methodOrPath: MvMethodOrPath? get() = element as? MvMethodOrPath val path: MvPath? get() = element as? MvPath } @@ -141,7 +143,7 @@ private fun resolvePath( val pathKind = path.pathKind() val result = // matches resolve variants against referenceName from path - collectPathResolveVariants(ctx, path) { + collectMethodOrPathResolveVariants(path, ctx) { // actually emits resolve variants processPathResolveVariants(ctx, pathKind, it) } diff --git a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt index d28a124f9..1d56e62d6 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt @@ -10,7 +10,6 @@ import org.move.ide.formatter.impl.location import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.ScopeEntry -import org.move.lang.core.resolve.isVisibleFrom import org.move.lang.core.types.ty.* import org.move.lang.core.types.ty.TyReference.Companion.coerceMutability import org.move.lang.toNioPathOrNull @@ -74,7 +73,7 @@ data class InferenceResult( private val exprTypes: Map, private val exprExpectedTypes: Map, private val methodOrPathTypes: Map, - private val resolvedPaths: Map>, +// private val resolvedPaths: Map>, private val resolvedFields: Map, private val resolvedMethodCalls: Map, val callableTypes: Map, @@ -93,8 +92,8 @@ data class InferenceResult( fun getCallableType(callable: MvCallable): Ty? = callableTypes[callable] fun getMethodOrPathType(methodOrPath: MvMethodOrPath): Ty? = methodOrPathTypes[methodOrPath] - fun getResolvedPath(path: MvPath): List = - resolvedPaths[path] ?: emptyList() +// fun getResolvedPath(path: MvPath): List = +// resolvedPaths[path] ?: emptyList() fun getResolvedField(field: MvStructDotField): MvNamedElement? = resolvedFields[field] fun getResolvedMethod(methodCall: MvMethodCall): MvNamedElement? = resolvedMethodCalls[methodCall] @@ -142,18 +141,18 @@ fun MvElement.inference(msl: Boolean): InferenceResult? { return contextOwner.inference(msl) } -data class ResolvedPath(val element: MvElement, val isVisible: Boolean) { - companion object { - fun from(entry: ScopeEntry, context: MvElement): ResolvedPath { -// return if (entry is AssocItemScopeEntry) { -// AssocItem(entry.element, entry.source) -// } else { -// val isVisible = entry.isVisibleFrom(context.containingModule) - return ResolvedPath(entry.element, true) -// } - } - } -} +//data class ResolvedPath(val element: MvElement, val isVisible: Boolean) { +// companion object { +// fun from(entry: ScopeEntry, context: MvElement): ResolvedPath { +//// return if (entry is AssocItemScopeEntry) { +//// AssocItem(entry.element, entry.source) +//// } else { +//// val isVisible = entry.isVisibleFrom(context.containingModule) +// return ResolvedPath(entry.element, true) +//// } +// } +// } +//} class InferenceContext( var msl: Boolean, @@ -169,7 +168,7 @@ class InferenceContext( // private val pathTypes = mutableMapOf() private val methodOrPathTypes = mutableMapOf() - val resolvedPaths = mutableMapOf>() +// val resolvedPaths = mutableMapOf>() val resolvedFields = mutableMapOf() val resolvedMethodCalls = mutableMapOf() @@ -229,7 +228,7 @@ class InferenceContext( exprTypes, exprExpectedTypes, methodOrPathTypes, - resolvedPaths, +// resolvedPaths, resolvedFields, resolvedMethodCalls, callableTypes, @@ -277,9 +276,9 @@ class InferenceContext( this.callableTypes[callable] = ty } - fun writePath(path: MvPath, resolved: List) { - resolvedPaths[path] = resolved - } +// fun writePath(path: MvPath, resolved: List) { +// resolvedPaths[path] = resolved +// } @Suppress("UNCHECKED_CAST") fun instantiateMethodOrPath( diff --git a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt index 19a912080..4abd2066f 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt @@ -9,8 +9,10 @@ import org.move.cli.settings.moveSettings import org.move.ide.formatter.impl.location import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* +import org.move.lang.core.resolve.collectMethodOrPathResolveVariants +import org.move.lang.core.resolve2.processMethodResolveVariants +import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.ty.* -import org.move.lang.core.types.ty.TyInfer.TyVar import org.move.lang.core.types.ty.TyReference.Companion.autoborrow import org.move.stdext.RsResult import org.move.stdext.chain @@ -413,10 +415,14 @@ class TypeInferenceWalker( } fun inferMethodCallTy(receiverTy: Ty, methodCall: MvMethodCall, expected: Expectation): Ty { - val refName = methodCall.referenceName - val methodVariants = getMethodVariants(methodCall, receiverTy, ctx.msl) - val genericItem = methodVariants.filterByName(refName).firstOrNull() + val resolutionCtx = ResolutionContext(methodCall, isCompletion = false) + val resolvedMethods = + collectMethodOrPathResolveVariants(methodCall, resolutionCtx) { + processMethodResolveVariants(methodCall, receiverTy, msl, it) + } + val genericItem = + resolvedMethods.filter { it.isVisible }.mapNotNull { it.element as? MvNamedElement }.firstOrNull() ctx.resolvedMethodCalls[methodCall] = genericItem val baseTy = diff --git a/src/test/kotlin/org/move/lang/completion/names/FunctionsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/FunctionsCompletionTest.kt index 67c0638e2..b5b4dfb85 100644 --- a/src/test/kotlin/org/move/lang/completion/names/FunctionsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/FunctionsCompletionTest.kt @@ -123,14 +123,11 @@ class FunctionsCompletionTest : CompletionTestCase() { fun `test public and public(friend) completions for module`() = completionFixture.checkContainsCompletion( """ - address 0x1 { - module Transaction { + module 0x1::Transaction { friend 0x1::M; public(friend) fun create_friend() {} public fun create() {} } - } - module 0x1::M { fun main() { 0x1::Transaction::cr/*caret*/ diff --git a/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt b/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt index fa4b56d50..8ed83461f 100644 --- a/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt +++ b/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt @@ -6,7 +6,7 @@ class PartialParsingTest: MvParsingTestCase("partial") { // top level items recovery fun `test top level items`() = doTest(true) fun `test module const`() = doTest(true) - fun `test module uses`() = doTest(true) +// fun `test module uses`() = doTest(true) fun `test spec`() = doTest(true) diff --git a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt index 0e22a3683..9b56b7493 100644 --- a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt @@ -1,5 +1,6 @@ package org.move.lang.resolve.compilerV2 +import org.move.ide.inspections.fixes.CompilerV2Feat.PUBLIC_PACKAGE import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.resolve.ResolveTestCase @@ -189,4 +190,50 @@ class ReceiverStyleFunctionTest: ResolveTestCase() { } } """) + + fun `test friend function method`() = checkByCode(""" + module 0x1::m { + friend 0x1::main; + struct S { x: u64 } + public(friend) fun receiver(self: &S): u64 { self.x } + //X + } + module 0x1::main { + use 0x1::m::S; + fun main(s: S) { + s.receiver(); + //^ + } + } + """) + + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS, PUBLIC_PACKAGE) + fun `test public package method`() = checkByCode(""" + module 0x1::m { + struct S { x: u64 } + public(package) fun receiver(self: &S): u64 { self.x } + //X + } + module 0x1::main { + use 0x1::m::S; + fun main(s: S) { + s.receiver(); + //^ + } + } + """) + + fun `test friend function method unresolved`() = checkByCode(""" + module 0x1::m { + struct S { x: u64 } + public(friend) fun receiver(self: &S): u64 { self.x } + } + module 0x1::main { + use 0x1::m::S; + fun main(s: S) { + s.receiver(); + //^ unresolved + } + } + """) } \ No newline at end of file From 317f861a8b2746120efc28bfdd13d03d968a3b43 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Thu, 1 Aug 2024 20:56:17 +0300 Subject: [PATCH 42/43] remove unused code --- .../ide/inspections/MvLocalInspectionTool.kt | 3 - .../move/ide/inspections/imports/UseItem.kt | 1 - .../move/ide/refactoring/MvImportOptimizer.kt | 1 - .../move/ide/utils/imports/ImportCandidate.kt | 28 ------ .../utils/imports/ImportCandidateCollector.kt | 2 - .../move/ide/utils/imports/UseStmtWrapper.kt | 5 +- src/main/kotlin/org/move/lang/MoveFile.kt | 1 - .../lang/core/completion/LookupElements.kt | 1 - .../MethodOrFieldCompletionProvider.kt | 2 - ...NamedAddressInUseStmtCompletionProvider.kt | 1 - .../move/lang/core/psi/ext/MvAddressRef.kt | 1 - .../org/move/lang/core/psi/ext/MvCallExpr.kt | 5 +- .../move/lang/core/psi/ext/MvMethodCall.kt | 32 +------ .../org/move/lang/core/psi/ext/MvModule.kt | 87 +++---------------- .../org/move/lang/core/psi/ext/MvPath.kt | 1 - .../lang/core/psi/ext/MvVisibilityOwner.kt | 14 +-- .../move/lang/core/resolve/ref/Namespace.kt | 42 +-------- .../move/lang/core/resolve2/ItemResolution.kt | 1 - .../org/move/lang/core/resolve2/PathKind.kt | 1 - .../move/lang/core/resolve2/util/PathUtil.kt | 1 - .../lang/core/types/infer/InferenceContext.kt | 1 - .../move/lang/index/MvNamedElementIndex.kt | 5 -- .../kotlin/org/move/lang/utils/Diagnostic.kt | 1 - src/main/resources/META-INF/plugin.xml | 2 +- src/main/resources/icons/move_logo.svg | 4 +- .../move/lang/NamedModulePathValuesTest.kt | 1 - .../lang/completion/KeywordCompletionTest.kt | 3 +- .../org/move/utils/tests/base/TestCase.kt | 1 - .../utils/tests/resolve/ResolveTestUtils.kt | 1 - 29 files changed, 28 insertions(+), 221 deletions(-) diff --git a/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt b/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt index c7931c6d2..fe33911db 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvLocalInspectionTool.kt @@ -2,9 +2,6 @@ package org.move.ide.inspections import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo import com.intellij.codeInspection.* -import com.intellij.model.SideEffectGuard -import com.intellij.model.SideEffectGuard.EffectType.EXEC -import com.intellij.model.SideEffectGuard.EffectType.SETTINGS import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement diff --git a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt index cada14411..4305a93af 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt @@ -1,7 +1,6 @@ package org.move.ide.inspections.imports import org.move.cli.settings.debugError -import org.move.cli.settings.debugErrorOrFallback import org.move.ide.inspections.imports.UseItemType.* import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt diff --git a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt index 95715fe2d..598106157 100644 --- a/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt +++ b/src/main/kotlin/org/move/ide/refactoring/MvImportOptimizer.kt @@ -9,7 +9,6 @@ import org.move.ide.inspections.imports.ImportAnalyzer2 import org.move.ide.utils.imports.COMPARATOR_FOR_ITEMS_IN_USE_GROUP import org.move.ide.utils.imports.UseStmtWrapper import org.move.lang.MoveFile -import org.move.lang.MvElementTypes.L_BRACE import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.stdext.withNext diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt index 76fec0daf..5c0face34 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidate.kt @@ -1,34 +1,6 @@ package org.move.ide.utils.imports -import org.move.lang.MoveFile import org.move.lang.core.psi.MvQualNamedElement -import org.move.lang.core.resolve.* -import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.types.ItemQualName -import org.move.openapiext.common.checkUnitTestMode data class ImportCandidate(val element: MvQualNamedElement, val qualName: ItemQualName) - -//fun processFileItemsForUnitTests( -// file: MoveFile, -// namespaces: Set, -// visibilities: Set, -// contextScopeInfo: ContextScopeInfo, -// processor: RsResolveProcessor, -//): Boolean { -// checkUnitTestMode() -// val contextProcessor = contextScopeInfo.wrapWithContextFilter(processor) -// for (module in file.modules()) { -// if ( -// Namespace.MODULE in namespaces && contextProcessor.process(module) -// ) { -// return true -// } -// val matchProcessor = MatchingProcessor { -// contextProcessor.process(it.name, it.element) -// } -// if (processModuleInnerItems(module, namespaces, visibilities, contextScopeInfo, matchProcessor)) return true -// } -// return false -//} diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt index 7696cc8b4..42e649bce 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt @@ -5,8 +5,6 @@ import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.psi.PsiElement import org.move.ide.inspections.imports.ImportContext import org.move.lang.core.psi.MvQualNamedElement -import org.move.lang.core.psi.ext.MvItemElement -import org.move.lang.core.resolve.VisibilityFilter import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve2.createFilter import org.move.lang.core.resolve2.namespace diff --git a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt index 2a2d0db44..9b1474c3b 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/UseStmtWrapper.kt @@ -8,7 +8,10 @@ package org.move.ide.utils.imports import org.move.cli.MoveProject import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt -import org.move.lang.core.psi.ext.* +import org.move.lang.core.psi.ext.basePath +import org.move.lang.core.psi.ext.hasTestOnlyAttr +import org.move.lang.core.psi.ext.hasVerifyOnlyAttr +import org.move.lang.core.psi.ext.isSelf import org.move.lang.moveProject class UseStmtWrapper(val useStmt: MvUseStmt): Comparable { diff --git a/src/main/kotlin/org/move/lang/MoveFile.kt b/src/main/kotlin/org/move/lang/MoveFile.kt index 054c7caeb..668aea168 100644 --- a/src/main/kotlin/org/move/lang/MoveFile.kt +++ b/src/main/kotlin/org/move/lang/MoveFile.kt @@ -4,7 +4,6 @@ import com.intellij.extapi.psi.PsiFileBase import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.ex.temp.TempFileSystem import com.intellij.psi.FileViewProvider import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index 019fe1f0b..4b247524a 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -11,7 +11,6 @@ import com.intellij.psi.util.PsiTreeUtil import org.move.ide.presentation.text import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ScopeEntry import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.* import org.move.lang.core.types.ty.Ty diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index dc21d2285..de5c37753 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -10,7 +10,6 @@ import org.jetbrains.annotations.VisibleForTesting import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvFunction -import org.move.lang.core.psi.MvMethodCall import org.move.lang.core.psi.ext.MvMethodOrField import org.move.lang.core.psi.ext.getFieldVariants import org.move.lang.core.psi.ext.inferReceiverTy @@ -18,7 +17,6 @@ import org.move.lang.core.psi.ext.isMsl import org.move.lang.core.psi.tyInfers import org.move.lang.core.resolve.createProcessor import org.move.lang.core.resolve2.processMethodResolveVariants -import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.InferenceContext import org.move.lang.core.types.infer.substitute import org.move.lang.core.types.ty.TyFunction diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt index 5487b336d..a2339234c 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/NamedAddressInUseStmtCompletionProvider.kt @@ -11,7 +11,6 @@ import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.move.cli.AddressVal import org.move.ide.MoveIcons -import org.move.lang.MvElementTypes.COLON_COLON import org.move.lang.core.MvPsiPatterns import org.move.lang.core.completion.alreadyHasColonColon import org.move.lang.core.psi.MvModule diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt index 6c15b1eaf..56c28500e 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvAddressRef.kt @@ -1,6 +1,5 @@ package org.move.lang.core.psi.ext import org.move.lang.core.psi.MvAddressRef -import org.move.lang.moveProject val MvAddressRef.normalizedText: String get() = this.text.lowercase() diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt index 12d74289b..aabe3ee09 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvCallExpr.kt @@ -1,6 +1,9 @@ package org.move.lang.core.psi.ext -import org.move.lang.core.psi.* +import org.move.lang.core.psi.MvElement +import org.move.lang.core.psi.MvExpr +import org.move.lang.core.psi.MvValueArgument +import org.move.lang.core.psi.MvValueArgumentList interface MvCallable: MvElement { val valueArgumentList: MvValueArgumentList? diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt index aab6aeb1c..3395740bc 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvMethodCall.kt @@ -7,13 +7,11 @@ import org.move.lang.core.psi.* import org.move.lang.core.resolve.ScopeItem import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve.ref.MvPolyVariantReferenceBase -import org.move.lang.core.resolve.ref.Visibility -import org.move.lang.core.resolve2.processItemDeclarations import org.move.lang.core.types.address -import org.move.lang.core.types.infer.foldTyTypeParameterWith import org.move.lang.core.types.infer.inference -import org.move.lang.core.types.ty.* -import org.move.lang.moveProject +import org.move.lang.core.types.ty.Ty +import org.move.lang.core.types.ty.TyStruct +import org.move.lang.core.types.ty.TyVector import org.move.stdext.wrapWithList typealias MatchSequence = Sequence> @@ -42,30 +40,6 @@ fun MvModule.is0x1Address(moveProject: MoveProject): Boolean { return moduleAddress == "0x00000000000000000000000000000001" } -fun getMethodVariants(methodOrField: MvMethodOrField, receiverTy: Ty, msl: Boolean): MatchSequence { - val moveProject = methodOrField.moveProject ?: return emptySequence() - val itemModule = receiverTy.itemModule(moveProject) ?: return emptySequence() - - val elementScopes = Visibility.visibilityScopesForElement(methodOrField).toMutableSet() - if (methodOrField.containingModule == itemModule) { - elementScopes.add(Visibility.Internal) - } - - val functions = - elementScopes - .flatMap { elementScope -> itemModule.functionsVisibleInScope(elementScope) } - .filter { - val selfTy = it.selfParamTy(msl) ?: return@filter false - // need to use TyVar here, loweredType() erases them - val selfTyWithTyVars = - selfTy.foldTyTypeParameterWith { tp -> TyInfer.TyVar(tp) } - TyReference.isCompatibleWithAutoborrow(receiverTy, selfTyWithTyVars, msl) - } - return functions - .filter { it.name != null } - .map { ScopeItem(it.name!!, it) }.asSequence() -} - class MvMethodCallReferenceImpl( element: MvMethodCall ): diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt index 802c25c52..6ff04f33a 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModule.kt @@ -6,12 +6,9 @@ import com.intellij.navigation.ItemPresentation import com.intellij.openapi.project.Project import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.util.CachedValuesManager.getProjectPsiDependentCache -import org.move.cli.containingMovePackage -import org.move.cli.settings.moveSettings import org.move.ide.MoveIcons import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.psi.* -import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.stubs.MvFunctionStub import org.move.lang.core.stubs.MvModuleStub import org.move.lang.core.stubs.MvStructStub @@ -29,46 +26,18 @@ fun MvModule.hasTestFunctions(): Boolean = this.testFunctions().isNotEmpty() fun MvModule.addressRef(): MvAddressRef? = this.addressRef ?: (this.ancestorStrict())?.addressRef -data class FQModule(val address: Address, val name: String) - -fun MvModule.fqModule(): FQModule? { - val moveProj = this.moveProject ?: return null - val address = this.address(moveProj) ?: return null - val name = this.name ?: return null - return FQModule(address, name) -} - -val MvModule.declaredFriendModules: Set +val MvModule.friendModules: Set get() { val moduleBlock = this.moduleBlock ?: return emptySet() val friendModulePaths = moduleBlock.friendDeclList.mapNotNull { it.path } -// val moveProj = moduleBlock.moveProject - - val friends = mutableSetOf() + val friends = mutableSetOf() for (modulePath in friendModulePaths) { - val module = modulePath.reference?.resolve() as? MvModule ?: continue - val fqModule = module.fqModule() ?: continue - friends.add(fqModule) -// val pathAddress = modulePath.qualifier?.pathAddress ?: continue -// val address = Address.Value(pathAddress.text) -//// val address = modulePath.addressRef.address(moveProj) ?: continue -// val identifier = modulePath.identifier?.text ?: continue -// friends.add(FQModule(address, identifier)) + val module = modulePath.reference?.resolveFollowingAliases() as? MvModule ?: continue + friends.add(module) } return friends } -val MvModule.friendModules: Set get() { - val moduleBlock = this.moduleBlock ?: return emptySet() - val friendModulePaths = moduleBlock.friendDeclList.mapNotNull { it.path } - val friends = mutableSetOf() - for (modulePath in friendModulePaths) { - val module = modulePath.reference?.resolveFollowingAliases() as? MvModule ?: continue - friends.add(module) - } - return friends -} - fun MvModule.allFunctions(): List { val stub = greenStub return stub?.childrenStubsOfType()?.map { it.psi } @@ -87,7 +56,8 @@ fun MvModule.testFunctions(): List = } val MvModule.isBuiltins: Boolean get() = this.name == "builtins" && (this.address(null)?.is0x0 ?: false) -val MvModule.isSpecBuiltins: Boolean get() = this.name == "spec_builtins" && (this.address(null)?.is0x0 ?: false) +val MvModule.isSpecBuiltins: Boolean + get() = this.name == "spec_builtins" && (this.address(null)?.is0x0 ?: false) fun MvModule.builtinFunctions(): List { return getProjectPsiDependentCache(this) { @@ -115,43 +85,6 @@ fun MvModule.builtinFunctions(): List { } } -fun MvModule.functionsVisibleInScope(visibility: Visibility): List { - return when (visibility) { - is Visibility.Public -> - allNonTestFunctions() - .filter { it.visibility == FunctionVisibility.PUBLIC } - is Visibility.PublicScript -> - allNonTestFunctions() - .filter { it.visibility == FunctionVisibility.PUBLIC_SCRIPT } - is Visibility.PublicFriend -> { - val friendFunctions = - allNonTestFunctions().filter { it.visibility == FunctionVisibility.PUBLIC_FRIEND } - if (friendFunctions.isEmpty()) return emptyList() - - val currentModule = visibility.currentModule.element - if (currentModule != null - && currentModule.fqModule() in this.declaredFriendModules - ) { - friendFunctions - } else { - emptyList() - } - } - is Visibility.PublicPackage -> { - if (!project.moveSettings.enablePublicPackage) { - return emptyList() - } - val modulePackage = this.containingMovePackage - if (visibility.originPackage == modulePackage) { - this.allNonTestFunctions() - } else { - emptyList() - } - } - is Visibility.Internal -> allNonTestFunctions() - } -} - fun MvModule.entryFunctions(): List = this.allFunctions().filter { it.isEntry } fun MvModule.viewFunctions(): List = this.allFunctions().filter { it.isView } @@ -270,12 +203,12 @@ fun isModulesEqual(left: MvModule, right: MvModule): Boolean { return left.getOriginalOrSelf() == right.getOriginalOrSelf() } -abstract class MvModuleMixin : MvStubbedNamedElementImpl, - MvModule { +abstract class MvModuleMixin: MvStubbedNamedElementImpl, + MvModule { - constructor(node: ASTNode) : super(node) + constructor(node: ASTNode): super(node) - constructor(stub: MvModuleStub, nodeType: IStubElementType<*, *>) : super(stub, nodeType) + constructor(stub: MvModuleStub, nodeType: IStubElementType<*, *>): super(stub, nodeType) override fun getIcon(flags: Int): Icon = MoveIcons.MODULE diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt index 89a7d87da..effaa9cdf 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvPath.kt @@ -9,7 +9,6 @@ import org.move.ide.inspections.imports.BasePathType import org.move.ide.inspections.imports.basePathType import org.move.lang.core.psi.* import org.move.lang.core.resolve.ref.MvPath2Reference -import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace import org.move.lang.core.resolve2.ref.Path2ReferenceImpl import java.util.* diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt index dc0fa1c18..f8b9e426f 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -6,22 +6,19 @@ import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvVisibilityModifier import org.move.lang.core.psi.containingModule import org.move.lang.core.psi.ext.VisKind.* -import org.move.lang.core.resolve.ref.Visibility import org.move.lang.core.resolve.ref.Visibility2 interface MvVisibilityOwner: MvElement { val visibilityModifier: MvVisibilityModifier? get() = PsiTreeUtil.getStubChildOfType(this, MvVisibilityModifier::class.java) -// val visibility2: Visibility2 get() = this.visibility22 - // restricted visibility considered as public val isPublic: Boolean get() = visibilityModifier != null } // todo: add VisibilityModifier to stubs, rename this one to VisStubKind enum class VisKind { -// PRIVATE, + // PRIVATE, PUBLIC, FRIEND, PACKAGE, @@ -37,15 +34,6 @@ val MvVisibilityModifier.stubKind: VisKind else -> error("unreachable") } -val MvVisibilityModifier.visibility: Visibility - get() = when (stubKind) { - SCRIPT -> Visibility.PublicScript - PACKAGE -> containingMovePackage?.let { Visibility.PublicPackage(it) } ?: Visibility.Public - FRIEND -> - containingModule?.let { Visibility.PublicFriend(it.asSmartPointer()) } ?: Visibility.Public - PUBLIC -> Visibility.Public - } - val MvVisibilityOwner.visibility2: Visibility2 get() { val kind = this.visibilityModifier?.stubKind ?: return Visibility2.Private diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index 845050b26..a92502c39 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -1,16 +1,7 @@ package org.move.lang.core.resolve.ref -import com.intellij.psi.SmartPsiElementPointer import org.move.cli.MovePackage -import org.move.cli.containingMovePackage -import org.move.lang.core.psi.MvElement import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.containingFunction -import org.move.lang.core.psi.containingModule -import org.move.lang.core.psi.ext.FQModule -import org.move.lang.core.psi.ext.FunctionVisibility -import org.move.lang.core.psi.ext.asSmartPointer -import org.move.lang.core.psi.ext.visibility import java.util.* sealed class Visibility2 { @@ -24,38 +15,6 @@ sealed class Visibility2 { } -sealed class Visibility { - object Public: Visibility() - object PublicScript: Visibility() - class PublicFriend(val currentModule: SmartPsiElementPointer): Visibility() - data class PublicPackage(val originPackage: MovePackage): Visibility() - object Internal: Visibility() - - companion object { - fun local(): Set = setOf(Public, Internal) - fun none(): Set = setOf() - - fun visibilityScopesForElement(element: MvElement): Set { - val vs = mutableSetOf(Public) - val containingModule = element.containingModule - if (containingModule != null) { - vs.add(PublicFriend(containingModule.asSmartPointer())) - } - val containingFun = element.containingFunction - if (containingModule == null - || (containingFun?.visibility == FunctionVisibility.PUBLIC_SCRIPT) - ) { - vs.add(PublicScript) - } - val containingMovePackage = element.containingMovePackage - if (containingMovePackage != null) { - vs.add(PublicPackage(containingMovePackage)) - } - return vs - } - } -} - enum class Namespace { NAME, FUNCTION, @@ -68,6 +27,7 @@ enum class Namespace { fun all(): Set { return EnumSet.of(NAME, FUNCTION, TYPE, SCHEMA, MODULE, CONST) } + fun items(): Set = EnumSet.of(NAME, FUNCTION, TYPE, SCHEMA, CONST) fun none(): Set = setOf() diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 9ab27e4ca..5a6c1e804 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -4,7 +4,6 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.Namespace -import org.move.lang.core.resolve2.ref.ResolutionContext import org.move.lang.core.types.infer.foldTyTypeParameterWith import org.move.lang.core.types.ty.Ty import org.move.lang.core.types.ty.TyInfer diff --git a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt index a139f6196..4366e9468 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/PathKind.kt @@ -1,6 +1,5 @@ package org.move.lang.core.resolve2 -import org.move.cli.MoveProject import org.move.lang.core.psi.MvPath import org.move.lang.core.psi.MvUseGroup import org.move.lang.core.psi.MvUseSpeck diff --git a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt index 3622ee5ef..d5a970a80 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/util/PathUtil.kt @@ -6,7 +6,6 @@ import org.move.lang.core.psi.MvUseSpeck import org.move.lang.core.psi.MvUseStmt import org.move.lang.core.psi.ext.childOfType import org.move.lang.core.psi.ext.childrenOfType -import org.move.lang.core.psi.ext.hasColonColon fun interface LeafUseSpeckConsumer { fun consume(path: MvPath, useAlias: MvUseAlias?): Boolean diff --git a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt index 1d56e62d6..ef287c69f 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/InferenceContext.kt @@ -9,7 +9,6 @@ import org.move.cli.settings.isDebugModeEnabled import org.move.ide.formatter.impl.location import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ScopeEntry import org.move.lang.core.types.ty.* import org.move.lang.core.types.ty.TyReference.Companion.coerceMutability import org.move.lang.toNioPathOrNull diff --git a/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt b/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt index fad808c44..ce91c7001 100644 --- a/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt +++ b/src/main/kotlin/org/move/lang/index/MvNamedElementIndex.kt @@ -5,12 +5,7 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndexKey -import com.intellij.util.Processor import org.move.lang.core.psi.MvNamedElement -import org.move.lang.core.resolve.RsResolveProcessor -import org.move.lang.core.resolve.RsResolveProcessorBase -import org.move.lang.core.resolve.ScopeEntry -import org.move.lang.core.resolve.lazy import org.move.lang.core.stubs.impl.MvFileStub import org.move.openapiext.checkCommitIsNotInProgress diff --git a/src/main/kotlin/org/move/lang/utils/Diagnostic.kt b/src/main/kotlin/org/move/lang/utils/Diagnostic.kt index 81451bd59..2e5a62933 100644 --- a/src/main/kotlin/org/move/lang/utils/Diagnostic.kt +++ b/src/main/kotlin/org/move/lang/utils/Diagnostic.kt @@ -16,7 +16,6 @@ import org.move.ide.annotator.pluralise import org.move.ide.inspections.fixes.CompilerV2Feat.* import org.move.ide.inspections.fixes.EnableCompilerV2FeatureFix import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.dotExpr import org.move.lang.core.psi.ext.endOffset import org.move.lang.core.psi.ext.itemSpecBlock import org.move.lang.core.psi.ext.startOffset diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index ad23413ae..e7bc6e6ed 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -1,6 +1,6 @@ +> org.move.lang Move on Aptos diff --git a/src/main/resources/icons/move_logo.svg b/src/main/resources/icons/move_logo.svg index 5ea4d1abd..baed098a5 100644 --- a/src/main/resources/icons/move_logo.svg +++ b/src/main/resources/icons/move_logo.svg @@ -1,7 +1,7 @@ - +