From da1883c355902402bdfecb8ae12139ebd1560332 Mon Sep 17 00:00:00 2001 From: kavindu Date: Mon, 7 Aug 2023 15:10:24 +0530 Subject: [PATCH] Support create function code action for var type decleration and select expr --- .../FunctionCallExpressionTypeFinder.java | 36 ++++++++++-- .../codeaction/CreateFunctionTest.java | 7 +++ .../config/undefinedFunctionCodeAction25.json | 57 +++++++++++++++++++ .../config/undefinedFunctionCodeAction26.json | 57 +++++++++++++++++++ .../config/undefinedFunctionCodeAction27.json | 57 +++++++++++++++++++ .../config/undefinedFunctionCodeAction28.json | 57 +++++++++++++++++++ .../config/undefinedFunctionCodeAction29.json | 57 +++++++++++++++++++ .../config/undefinedFunctionCodeAction30.json | 57 +++++++++++++++++++ .../source/createUndefinedFunction14.bal | 3 + .../source/createUndefinedFunction15.bal | 3 + .../source/createUndefinedFunction16.bal | 3 + .../source/createUndefinedFunction17.bal | 1 + .../source/createUndefinedFunction18.bal | 1 + .../source/createUndefinedFunction19.bal | 1 + 14 files changed, 391 insertions(+), 6 deletions(-) create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction25.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction26.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction27.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction28.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction29.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction30.json create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction14.bal create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction15.bal create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction16.bal create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction17.bal create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction18.bal create mode 100644 language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction19.bal 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 3009015a1de6..b6511d3fb107 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 @@ -20,6 +20,7 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.TypeBuilder; import io.ballerina.compiler.api.Types; +import io.ballerina.compiler.api.symbols.ArrayTypeSymbol; import io.ballerina.compiler.api.symbols.ClassSymbol; import io.ballerina.compiler.api.symbols.ErrorTypeSymbol; import io.ballerina.compiler.api.symbols.FunctionTypeSymbol; @@ -63,11 +64,13 @@ import io.ballerina.compiler.syntax.tree.RecordFieldWithDefaultValueNode; import io.ballerina.compiler.syntax.tree.RemoteMethodCallActionNode; import io.ballerina.compiler.syntax.tree.ReturnStatementNode; +import io.ballerina.compiler.syntax.tree.SelectClauseNode; import io.ballerina.compiler.syntax.tree.SeparatedNodeList; import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; import io.ballerina.compiler.syntax.tree.StartActionNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.compiler.syntax.tree.TypedBindingPatternNode; import io.ballerina.compiler.syntax.tree.UnaryExpressionNode; import io.ballerina.compiler.syntax.tree.VariableDeclarationNode; import io.ballerina.compiler.syntax.tree.WhileStatementNode; @@ -114,9 +117,7 @@ public void visit(RecordFieldWithDefaultValueNode recordFieldWithDefaultValueNod @Override public void visit(ModuleVariableDeclarationNode moduleVariableDeclarationNode) { - Symbol symbol = semanticModel.symbol(moduleVariableDeclarationNode).orElse(null); - TypeSymbol typeDescriptor = SymbolUtil.getTypeDescriptor(symbol).orElse(null); - checkAndSetTypeResult(typeDescriptor); + visitVariableDeclaration(moduleVariableDeclarationNode, moduleVariableDeclarationNode.typedBindingPattern()); } @Override @@ -134,9 +135,7 @@ public void visit(AssignmentStatementNode assignmentStatementNode) { @Override public void visit(VariableDeclarationNode variableDeclarationNode) { - Symbol symbol = semanticModel.symbol(variableDeclarationNode).orElse(null); - TypeSymbol typeDescriptor = SymbolUtil.getTypeDescriptor(symbol).orElse(null); - checkAndSetTypeResult(typeDescriptor); + visitVariableDeclaration(variableDeclarationNode, variableDeclarationNode.typedBindingPattern()); } @Override @@ -486,6 +485,16 @@ public void visit(GroupingKeyVarDeclarationNode groupingKeyVarDeclarationNode) { TypeSymbol typeDescriptor = SymbolUtil.getTypeDescriptor(symbol).orElse(null); checkAndSetTypeResult(typeDescriptor); } + + @Override + public void visit(SelectClauseNode selectClauseNode) { + selectClauseNode.parent().parent().accept(this); + if (resultFound) { + if (this.returnTypeSymbol.typeKind() == TypeDescKind.ARRAY) { + checkAndSetTypeResult(((ArrayTypeSymbol) returnTypeSymbol).memberTypeDescriptor()); + } + } + } @Override public void visit(PanicStatementNode panicStatementNode) { @@ -522,4 +531,19 @@ private void resetResult() { public Optional getReturnTypeSymbol() { return Optional.ofNullable(returnTypeSymbol); } + + private void visitVariableDeclaration(Node variableDeclarationNode, TypedBindingPatternNode typedBindingNode) { + Symbol symbol = semanticModel.symbol(variableDeclarationNode).orElse(null); + Optional typeDescriptor = SymbolUtil.getTypeDescriptor(symbol); + TypeSymbol ts = null; + if (typeDescriptor.isPresent()) { + ts = typeDescriptor.get(); + if (ts.typeKind() == TypeDescKind.COMPILATION_ERROR && + typedBindingNode.typeDescriptor().kind() == SyntaxKind.VAR_TYPE_DESC) { + Types types = semanticModel.types(); + ts = types.builder().UNION_TYPE.withMemberTypes(types.ANY, types.ERROR).build(); + } + } + checkAndSetTypeResult(ts); + } } 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 97032e3eca41..53d691b0edc3 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 @@ -175,6 +175,13 @@ public Object[][] dataProvider() { {"create_function_in_local_var1.json"}, {"create_function_in_local_var2.json"}, {"create_function_in_start_action1.json"}, + + {"undefinedFunctionCodeAction25.json"}, + {"undefinedFunctionCodeAction26.json"}, + {"undefinedFunctionCodeAction27.json"}, + {"undefinedFunctionCodeAction28.json"}, + {"undefinedFunctionCodeAction29.json"}, + {"undefinedFunctionCodeAction30.json"}, }; } diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction25.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction25.json new file mode 100644 index 000000000000..b8cb0fef87b2 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction25.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 1, + "character": 52 + }, + "source": "createUndefinedFunction14.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 2, + "character": 1 + }, + "end": { + "line": 2, + "character": 1 + } + }, + "newText": "\n\nfunction toUpperCase(string letter) returns any|error {\n return ;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction14.bal", + "range": { + "start": { + "line": 1, + "character": 46 + }, + "end": { + "line": 1, + "character": 65 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 1.0, + "character": 46.0 + }, + "end": { + "line": 1.0, + "character": 65.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction26.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction26.json new file mode 100644 index 000000000000..65e8f55b6101 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction26.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 1, + "character": 54 + }, + "source": "createUndefinedFunction15.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 2, + "character": 1 + }, + "end": { + "line": 2, + "character": 1 + } + }, + "newText": "\n\nfunction toUpperCase(string letter) returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction15.bal", + "range": { + "start": { + "line": 1, + "character": 48 + }, + "end": { + "line": 1, + "character": 67 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 1.0, + "character": 48.0 + }, + "end": { + "line": 1.0, + "character": 67.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction27.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction27.json new file mode 100644 index 000000000000..f1e970211618 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction27.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 1, + "character": 18 + }, + "source": "createUndefinedFunction16.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 2, + "character": 1 + }, + "end": { + "line": 2, + "character": 1 + } + }, + "newText": "\n\nfunction toUpperCase(any a) returns any|error {\n return ;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction16.bal", + "range": { + "start": { + "line": 1, + "character": 11 + }, + "end": { + "line": 1, + "character": 30 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 1.0, + "character": 11.0 + }, + "end": { + "line": 1.0, + "character": 30.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction28.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction28.json new file mode 100644 index 000000000000..58e5fc323303 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction28.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 0, + "character": 16 + }, + "source": "createUndefinedFunction17.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 28 + }, + "end": { + "line": 0, + "character": 28 + } + }, + "newText": "\n\nfunction toUpperCase(any a) returns any|error {\n return ;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction17.bal", + "range": { + "start": { + "line": 0, + "character": 8 + }, + "end": { + "line": 0, + "character": 27 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 0.0, + "character": 8.0 + }, + "end": { + "line": 0.0, + "character": 27.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction29.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction29.json new file mode 100644 index 000000000000..c4a369e73a1d --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction29.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 0, + "character": 50 + }, + "source": "createUndefinedFunction18.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 64 + }, + "end": { + "line": 0, + "character": 64 + } + }, + "newText": "\n\nfunction toUpperCase(string letter) returns int {\n return 0;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction18.bal", + "range": { + "start": { + "line": 0, + "character": 44 + }, + "end": { + "line": 0, + "character": 63 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 0.0, + "character": 44.0 + }, + "end": { + "line": 0.0, + "character": 63.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction30.json b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction30.json new file mode 100644 index 000000000000..ca672557e38c --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/config/undefinedFunctionCodeAction30.json @@ -0,0 +1,57 @@ +{ + "position": { + "line": 0, + "character": 51 + }, + "source": "createUndefinedFunction19.bal", + "expected": [ + { + "title": "Create function 'toUpperCase(...)'", + "kind": "quickfix", + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 62 + }, + "end": { + "line": 0, + "character": 62 + } + }, + "newText": "\n\nfunction toUpperCase(string letter) returns any|error {\n return ;\n}" + } + ], + "resolvable": true, + "data": { + "extName": "org.ballerinalang.langserver.codeaction.BallerinaCodeActionExtension", + "codeActionName": "Create Function", + "fileUri": "createUndefinedFunction19.bal", + "range": { + "start": { + "line": 0, + "character": 42 + }, + "end": { + "line": 0, + "character": 61 + } + }, + "actionData": { + "key": "node.range", + "value": { + "start": { + "line": 0.0, + "character": 42.0 + }, + "end": { + "line": 0.0, + "character": 61.0 + } + } + } + } + } + ] +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction14.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction14.bal new file mode 100644 index 000000000000..d27a2d100920 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction14.bal @@ -0,0 +1,3 @@ +function func() { + var x = from var letter in "Saman" select toUpperCase(letter); +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction15.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction15.bal new file mode 100644 index 000000000000..b897efdcbfe8 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction15.bal @@ -0,0 +1,3 @@ +function func() { + int[] x = from var letter in "Saman" select toUpperCase(letter); +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction16.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction16.bal new file mode 100644 index 000000000000..c2398b9f66a5 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction16.bal @@ -0,0 +1,3 @@ +function func() { + var x = toUpperCase(letter); +} diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction17.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction17.bal new file mode 100644 index 000000000000..49d616fd023a --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction17.bal @@ -0,0 +1 @@ +var x = toUpperCase(letter); diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction18.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction18.bal new file mode 100644 index 000000000000..e887146d9100 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction18.bal @@ -0,0 +1 @@ +int[] x = from var letter in "Saman" select toUpperCase(letter); diff --git a/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction19.bal b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction19.bal new file mode 100644 index 000000000000..b78e95695c71 --- /dev/null +++ b/language-server/modules/langserver-core/src/test/resources/codeaction/create-function/source/createUndefinedFunction19.bal @@ -0,0 +1 @@ +var x = from var letter in "Saman" select toUpperCase(letter);