diff --git a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/visitors/FunctionCallExpressionTypeFinder.java b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/visitors/FunctionCallExpressionTypeFinder.java index f846bba1b8f2..18d52939201d 100644 --- a/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/visitors/FunctionCallExpressionTypeFinder.java +++ b/language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/command/visitors/FunctionCallExpressionTypeFinder.java @@ -36,12 +36,14 @@ import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; import io.ballerina.compiler.api.symbols.VariableSymbol; +import io.ballerina.compiler.api.symbols.WorkerSymbol; import io.ballerina.compiler.syntax.tree.AssignmentStatementNode; import io.ballerina.compiler.syntax.tree.BinaryExpressionNode; import io.ballerina.compiler.syntax.tree.BlockStatementNode; import io.ballerina.compiler.syntax.tree.CheckExpressionNode; import io.ballerina.compiler.syntax.tree.ConditionalExpressionNode; import io.ballerina.compiler.syntax.tree.ErrorConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.ExplicitAnonymousFunctionExpressionNode; import io.ballerina.compiler.syntax.tree.ExplicitNewExpressionNode; import io.ballerina.compiler.syntax.tree.FailStatementNode; import io.ballerina.compiler.syntax.tree.FunctionArgumentNode; @@ -57,6 +59,7 @@ import io.ballerina.compiler.syntax.tree.MethodCallExpressionNode; import io.ballerina.compiler.syntax.tree.ModuleVariableDeclarationNode; import io.ballerina.compiler.syntax.tree.NamedArgumentNode; +import io.ballerina.compiler.syntax.tree.NamedWorkerDeclarationNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.ObjectFieldNode; @@ -402,6 +405,12 @@ public void visit(BlockStatementNode node) { node.parent().accept(this); } + @Override + public void visit(NamedWorkerDeclarationNode namedWorkerDeclarationNode) { + semanticModel.symbol(namedWorkerDeclarationNode) + .ifPresent(value -> checkAndSetTypeResult(((WorkerSymbol) value).returnType())); + } + @Override public void visit(ReturnStatementNode returnStatementNode) { this.semanticModel.typeOf(returnStatementNode).ifPresent(this::checkAndSetTypeResult); @@ -411,11 +420,14 @@ public void visit(ReturnStatementNode returnStatementNode) { // Get function type symbol and get return type descriptor from it returnStatementNode.parent().accept(this); - if (resultFound && returnTypeSymbol.typeKind() == TypeDescKind.FUNCTION) { + + if (!resultFound) { + resetResult(); + return; + } + if (returnTypeSymbol.typeKind() == TypeDescKind.FUNCTION) { FunctionTypeSymbol functionTypeSymbol = (FunctionTypeSymbol) returnTypeSymbol; functionTypeSymbol.returnTypeDescriptor().ifPresentOrElse(this::checkAndSetTypeResult, this::resetResult); - } else { - resetResult(); } } @@ -512,6 +524,11 @@ public void visit(ImplicitAnonymousFunctionExpressionNode expr) { } } + @Override + public void visit(ExplicitAnonymousFunctionExpressionNode explicitAnonymousFunctionExpressionNode) { + semanticModel.typeOf(explicitAnonymousFunctionExpressionNode).ifPresent(this::checkAndSetTypeResult); + } + @Override public void visit(PanicStatementNode panicStatementNode) { checkAndSetTypeResult(semanticModel.types().ERROR); diff --git a/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CreateFunctionTest.java b/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CreateFunctionTest.java index a451910e5282..3f80af11e19d 100644 --- a/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CreateFunctionTest.java +++ b/language-server/modules/langserver-core/src/test/java/org/ballerinalang/langserver/codeaction/CreateFunctionTest.java @@ -186,6 +186,18 @@ public Object[][] dataProvider() { {"create_function_in_anonymous_function1.json"}, {"create_function_in_anonymous_function2.json"}, + + {"create_function_in_worker1.json"}, + {"create_function_in_worker2.json"}, + {"create_function_in_worker3.json"}, + {"create_function_in_worker4.json"}, + {"create_function_in_worker5.json"}, + + {"create_function_in_explicit_anonymous_function1.json"}, + {"create_function_in_explicit_anonymous_function2.json"}, + {"create_function_in_explicit_anonymous_function3.json"}, + {"create_function_in_explicit_anonymous_function4.json"}, + {"create_function_in_explicit_anonymous_function5.json"} }; } diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function1.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function1.json new file mode 100644 index 000000000000..8a5bd5ce911e --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function1.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 4, + "character": 16 + }, + "source": "create_function_in_explicit_anonymous_function.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_explicit_anonymous_function.bal", + "range": { + "start": { + "line": 4, + "character": 15 + }, + "end": { + "line": 4, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 4.0, + "character": 15.0 + }, + "end": { + "line": 4.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function2.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function2.json new file mode 100644 index 000000000000..cb29a4c1db21 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function2.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 8, + "character": 10 + }, + "source": "create_function_in_explicit_anonymous_function.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo(int i) {\n \n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_explicit_anonymous_function.bal", + "range": { + "start": { + "line": 8, + "character": 8 + }, + "end": { + "line": 8, + "character": 15 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 8.0, + "character": 8.0 + }, + "end": { + "line": 8.0, + "character": 15.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function3.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function3.json new file mode 100644 index 000000000000..578f6dfa919f --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function3.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 13, + "character": 17 + }, + "source": "create_function_in_explicit_anonymous_function.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() {\n \n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_explicit_anonymous_function.bal", + "range": { + "start": { + "line": 13, + "character": 15 + }, + "end": { + "line": 13, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 13.0, + "character": 15.0 + }, + "end": { + "line": 13.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function4.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function4.json new file mode 100644 index 000000000000..4d499c7f50d1 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function4.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 17, + "character": 17 + }, + "source": "create_function_in_explicit_anonymous_function.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns module1:TestRecord2 {\n return {};\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_explicit_anonymous_function.bal", + "range": { + "start": { + "line": 17, + "character": 15 + }, + "end": { + "line": 17, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 17.0, + "character": 15.0 + }, + "end": { + "line": 17.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function5.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function5.json new file mode 100644 index 000000000000..008a88e1e092 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_explicit_anonymous_function5.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 22, + "character": 22 + }, + "source": "create_function_in_explicit_anonymous_function.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_explicit_anonymous_function.bal", + "range": { + "start": { + "line": 22, + "character": 19 + }, + "end": { + "line": 22, + "character": 24 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 22.0, + "character": 19.0 + }, + "end": { + "line": 22.0, + "character": 24.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker1.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker1.json new file mode 100644 index 000000000000..d7dd1dd1e95b --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker1.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 4, + "character": 16 + }, + "source": "create_function_in_worker.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_worker.bal", + "range": { + "start": { + "line": 4, + "character": 15 + }, + "end": { + "line": 4, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 4.0, + "character": 15.0 + }, + "end": { + "line": 4.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker2.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker2.json new file mode 100644 index 000000000000..7374fb76cf78 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker2.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 8, + "character": 10 + }, + "source": "create_function_in_worker.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo(int i) {\n \n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_worker.bal", + "range": { + "start": { + "line": 8, + "character": 8 + }, + "end": { + "line": 8, + "character": 15 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 8.0, + "character": 8.0 + }, + "end": { + "line": 8.0, + "character": 15.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker3.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker3.json new file mode 100644 index 000000000000..641f38fc3fb9 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker3.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 13, + "character": 17 + }, + "source": "create_function_in_worker.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() {\n \n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_worker.bal", + "range": { + "start": { + "line": 13, + "character": 15 + }, + "end": { + "line": 13, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 13.0, + "character": 15.0 + }, + "end": { + "line": 13.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker4.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker4.json new file mode 100644 index 000000000000..55276910a9b4 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker4.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 17, + "character": 17 + }, + "source": "create_function_in_worker.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns module1:TestRecord2 {\n return {};\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_worker.bal", + "range": { + "start": { + "line": 17, + "character": 15 + }, + "end": { + "line": 17, + "character": 20 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 17.0, + "character": 15.0 + }, + "end": { + "line": 17.0, + "character": 20.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker5.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker5.json new file mode 100644 index 000000000000..fd4ff61bc968 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/create_function_in_worker5.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 22, + "character": 22 + }, + "source": "create_function_in_worker.bal", + "expected": [ + { + "title": "Create function 'foo(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 25, + "character": 1 + }, + "end": { + "line": 25, + "character": 1 + } + }, + "newText": "\n\nfunction foo() returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "create_function_in_worker.bal", + "range": { + "start": { + "line": 22, + "character": 19 + }, + "end": { + "line": 22, + "character": 24 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 22.0, + "character": 19.0 + }, + "end": { + "line": 22.0, + "character": 24.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_explicit_anonymous_function.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_explicit_anonymous_function.bal new file mode 100644 index 000000000000..19bee2900b25 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_explicit_anonymous_function.bal @@ -0,0 +1,26 @@ +import ballerina/module1; + +function createFunctionInWorker() { + var fn1 = function() returns int { + return foo(); + }; + + var fn2 = function() returns string { + foo(32); + return "bar"; + }; + + var fn3 = function() { + return foo(); + }; + + var fn4 = function() returns module1:TestRecord2 { + return foo(); + }; + + var fn5 = function() returns function () returns int { + return function () returns int { + return foo(); + }; + }; +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_worker.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_worker.bal new file mode 100644 index 000000000000..d889e6371fc8 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/create_function_in_worker.bal @@ -0,0 +1,26 @@ +import ballerina/module1; + +function createFunctionInWorker() { + worker A returns int { + return foo(); + } + + worker B returns string { + foo(32); + return "bar"; + } + + worker C { + return foo(); + } + + worker D returns module1:TestRecord2 { + return foo(); + } + + fork { + worker E returns int { + return foo(); + } + } +}