From 2e17b308ee0541da99dc62d6ed664eb8aad788fc Mon Sep 17 00:00:00 2001 From: Nipuna Fernando Date: Thu, 2 Nov 2023 14:19:46 +0530 Subject: [PATCH 1/3] Provide completions after variable resource param --- .../semantics/analyzer/TypeChecker.java | 3 ++ ...lient_resource_access_action_config44.json | 40 +++++++++++++++++++ ...client_resource_access_action_source37.bal | 9 +++++ 3 files changed, 52 insertions(+) create mode 100644 language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json create mode 100644 language-server/modules/langserver-core/src/test/resources/completion/action_node_context/source/client_resource_access_action_source37.bal diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index 862182a3ff13..53fb819705dd 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -3823,6 +3823,7 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn } if (resourceFunctions.size() == 0) { + checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); dlog.error(resourceAccessInvocation.resourceAccessPathSegments.pos, DiagnosticErrorCode.UNDEFINED_RESOURCE, lhsExprType); data.resultType = symTable.semanticError; @@ -3833,10 +3834,12 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn resourceFunctions.removeIf(func -> !func.accessor.value.equals(resourceAccessInvocation.name.value)); int targetResourceFuncCount = resourceFunctions.size(); if (targetResourceFuncCount == 0) { + checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); dlog.error(resourceAccessInvocation.name.pos, DiagnosticErrorCode.UNDEFINED_RESOURCE_METHOD, resourceAccessInvocation.name, lhsExprType); data.resultType = symTable.semanticError; } else if (targetResourceFuncCount > 1) { + checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); dlog.error(resourceAccessInvocation.pos, DiagnosticErrorCode.AMBIGUOUS_RESOURCE_ACCESS_NOT_YET_SUPPORTED); data.resultType = symTable.semanticError; } else { diff --git a/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json new file mode 100644 index 000000000000..2f3801fcc192 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json @@ -0,0 +1,40 @@ +{ + "position": { + "line": 7, + "character": 25 + }, + "source": "action_node_context/source/client_resource_access_action_source37.bal", + "description": "", + "items": [ + { + "label": "/third", + "kind": "Function", + "detail": "()", + "documentation": { + "right": { + "kind": "markdown", + "value": "**Package:** _._ \n \n \n**Params** \n- `string` second" + } + }, + "sortText": "C", + "filterText": "third|get", + "insertText": "/third;", + "insertTextFormat": "Snippet", + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 7, + "character": 24 + }, + "end": { + "line": 7, + "character": 25 + } + }, + "newText": "" + } + ] + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/source/client_resource_access_action_source37.bal b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/source/client_resource_access_action_source37.bal new file mode 100644 index 000000000000..b48acd886e4c --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/source/client_resource_access_action_source37.bal @@ -0,0 +1,9 @@ +client class MyClient { + resource function get first/[string second]/third() {} +} + +public function main() { + string someVar = "check"; + MyClient cl = new; + cl->/first/[someVar]/; +} From 0ddaa559e54d8946fc9b8f184961ec5dd58df317 Mon Sep 17 00:00:00 2001 From: Nipuna Fernando Date: Mon, 6 Nov 2023 09:57:16 +0530 Subject: [PATCH 2/3] Add typeof tests for resource segments --- .../TypeOfInResourceAccessActionTest.java | 10 ++++++++ .../actions/resource_access_action.bal | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/typeof/TypeOfInResourceAccessActionTest.java b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/typeof/TypeOfInResourceAccessActionTest.java index ff174ba97f77..290c53455b73 100644 --- a/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/typeof/TypeOfInResourceAccessActionTest.java +++ b/tests/ballerina-compiler-api-test/src/test/java/io/ballerina/semantic/api/test/typeof/TypeOfInResourceAccessActionTest.java @@ -30,6 +30,8 @@ import java.util.Optional; +import static io.ballerina.compiler.api.symbols.TypeDescKind.INT; +import static io.ballerina.compiler.api.symbols.TypeDescKind.STRING; import static io.ballerina.compiler.api.symbols.TypeDescKind.TYPE_REFERENCE; import static io.ballerina.compiler.api.symbols.TypeDescKind.UNION; import static org.testng.Assert.assertEquals; @@ -60,6 +62,14 @@ public Object[][] getPos() { return new Object[][]{ {42, 23, 42, 54, UNION}, {42, 23, 42, 32, TYPE_REFERENCE}, + {110, 9, 110, 12, STRING}, + {111, 9, 111, 14, STRING}, + {111, 17, 111, 25, STRING}, + {112, 17, 111, 19, STRING}, + {113, 15, 113, 19, INT}, + {114, 15, 114, 16, INT}, + {115, 9, 115, 14, STRING}, + {115, 17, 115, 24, STRING}, }; } diff --git a/tests/ballerina-compiler-api-test/src/test/resources/test-src/actions/resource_access_action.bal b/tests/ballerina-compiler-api-test/src/test/resources/test-src/actions/resource_access_action.bal index 8ced189ea6a6..2af9eb311b0c 100644 --- a/tests/ballerina-compiler-api-test/src/test/resources/test-src/actions/resource_access_action.bal +++ b/tests/ballerina-compiler-api-test/src/test/resources/test-src/actions/resource_access_action.bal @@ -91,3 +91,27 @@ public function testPathSegmentOfAmbiguousResourceFunction() { Bam bam = new; bam->/path1/path2.post(); } + +client class Resc { + resource function post user() {} + + resource function post [string name]() {} + + resource function get sports/[string name]() {} + + resource function get pets/[int id]() {} + + resource function get sports/[string name]/info () {} +} + +function testTypeOfResourceSegments() { + Resc cl = new; + string myString = ""; + int myInt = 0; + cl->/user.post(); + cl->/sports/[myString](); + cl->/sports/["A"](); + cl->/pets/[myInt](); + cl->/pets/[1](); + cl->/sports/[myString]/ +} From a2f69d7fe00131fe40d14529af807a6747578ec4 Mon Sep 17 00:00:00 2001 From: Nipuna Fernando Date: Fri, 10 Nov 2023 16:43:52 +0530 Subject: [PATCH 3/3] Add common method for resource access error --- .../semantics/analyzer/TypeChecker.java | 27 +++++++++++-------- ...lient_resource_access_action_config44.json | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index 53fb819705dd..40fbad6c0f37 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -3823,10 +3823,9 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn } if (resourceFunctions.size() == 0) { - checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); - dlog.error(resourceAccessInvocation.resourceAccessPathSegments.pos, DiagnosticErrorCode.UNDEFINED_RESOURCE, - lhsExprType); - data.resultType = symTable.semanticError; + handleResourceAccessError(resourceAccessInvocation.resourceAccessPathSegments, + resourceAccessInvocation.resourceAccessPathSegments.pos, DiagnosticErrorCode.UNDEFINED_RESOURCE, + data, lhsExprType); return; } @@ -3834,14 +3833,12 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn resourceFunctions.removeIf(func -> !func.accessor.value.equals(resourceAccessInvocation.name.value)); int targetResourceFuncCount = resourceFunctions.size(); if (targetResourceFuncCount == 0) { - checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); - dlog.error(resourceAccessInvocation.name.pos, - DiagnosticErrorCode.UNDEFINED_RESOURCE_METHOD, resourceAccessInvocation.name, lhsExprType); - data.resultType = symTable.semanticError; + handleResourceAccessError(resourceAccessInvocation.resourceAccessPathSegments, + resourceAccessInvocation.name.pos, DiagnosticErrorCode.UNDEFINED_RESOURCE_METHOD, data, + resourceAccessInvocation.name, lhsExprType); } else if (targetResourceFuncCount > 1) { - checkExpr(resourceAccessInvocation.resourceAccessPathSegments, data); - dlog.error(resourceAccessInvocation.pos, DiagnosticErrorCode.AMBIGUOUS_RESOURCE_ACCESS_NOT_YET_SUPPORTED); - data.resultType = symTable.semanticError; + handleResourceAccessError(resourceAccessInvocation.resourceAccessPathSegments, resourceAccessInvocation.pos, + DiagnosticErrorCode.AMBIGUOUS_RESOURCE_ACCESS_NOT_YET_SUPPORTED, data, lhsExprType); } else { BResourceFunction targetResourceFunc = resourceFunctions.get(0); checkExpr(resourceAccessInvocation.resourceAccessPathSegments, @@ -3852,6 +3849,14 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn } } + private void handleResourceAccessError(BLangListConstructorExpr resourceAccessPathSegments, + Location diagnosticLocation, DiagnosticErrorCode errorCode, + AnalyzerData data, Object... dlogArgs) { + checkExpr(resourceAccessPathSegments, data); + dlog.error(diagnosticLocation, errorCode, dlogArgs); + data.resultType = symTable.semanticError; + } + private BTupleType getResourcePathType(List pathSegmentSymbols) { BType restType = null; int pathSegmentCount = pathSegmentSymbols.size(); diff --git a/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json index 2f3801fcc192..c8d1489e7524 100644 --- a/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json +++ b/language-server/modules/langserver-core/src/test/resources/completion/action_node_context/config/client_resource_access_action_config44.json @@ -4,7 +4,7 @@ "character": 25 }, "source": "action_node_context/source/client_resource_access_action_source37.bal", - "description": "", + "description": "Test completions after a variable resource path", "items": [ { "label": "/third",