Skip to content

Commit 93743aa

Browse files
committed
Add more actions:
- AddThrowsDeclaration to add an error to the declaration of a method/constructor - AddTryCatch around statements - AddTryCatch around variable declarations
1 parent b461b94 commit 93743aa

7 files changed

+255
-4
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* addthrowsdeclaration.vala
2+
*
3+
* Copyright 2022 JCWasmx86 <JCWasmx86@t-online.de>
4+
*
5+
* This file is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This file is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* SPDX-License-Identifier: LGPL-3.0-or-later
19+
*/
20+
21+
using Gee;
22+
using Lsp;
23+
24+
class Vls.AddThrowsDeclaration : CodeAction {
25+
public AddThrowsDeclaration (VersionedTextDocumentIdentifier document, string error_name, Vala.CodeNode where) {
26+
27+
var error_types = new Vala.HashSet<Vala.DataType> ();
28+
if (where is Vala.Constructor)
29+
((Vala.Constructor)where).body.get_error_types (error_types, null);
30+
else
31+
where.get_error_types (error_types, null);
32+
33+
var sb = new StringBuilder ();
34+
if (error_types.is_empty) {
35+
sb.append (" throws ");
36+
} else {
37+
sb.append (", ");
38+
}
39+
sb.append (error_name);
40+
sb.append (" ");
41+
var sref = where.source_reference;
42+
var range = new Range ();
43+
for (var i = sref.begin.line; i <= sref.end.line; i++) {
44+
var line = sref.file.get_source_line (i);
45+
if (line.contains ("{")) {
46+
var idx = line.index_of ("{");
47+
range.start = new Lsp.Position () {
48+
line = i - 1,
49+
character = idx - 1,
50+
};
51+
range.end = new Lsp.Position () {
52+
line = i - 1,
53+
character = idx - 1,
54+
};
55+
}
56+
}
57+
var workspace_edit = new WorkspaceEdit ();
58+
var document_edit = new TextDocumentEdit (document);
59+
var text_edit = new TextEdit (range);
60+
text_edit.range.end.character++;
61+
text_edit.newText = sb.str;
62+
document_edit.edits.add (text_edit);
63+
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
64+
workspace_edit.documentChanges.add (document_edit);
65+
this.edit = workspace_edit;
66+
this.title = "Add to error list";
67+
}
68+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* AddTryCatchAssignmentAction.vala
2+
*
3+
* Copyright 2022 JCWasmx86 <JCWasmx86@t-online.de>
4+
*
5+
* This file is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This file is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* SPDX-License-Identifier: LGPL-3.0-or-later
19+
*/
20+
21+
using Gee;
22+
using Lsp;
23+
24+
class Vls.AddTryCatchAssignmentAction : CodeAction {
25+
public AddTryCatchAssignmentAction (VersionedTextDocumentIdentifier document, Vala.ArrayList<Vala.Variable> variables, string error_name, string indent, Vala.CodeNode rhs) {
26+
var sref = rhs.source_reference;
27+
var assignment_line = sref.file.get_source_line (sref.begin.line);
28+
var copied_indent = assignment_line.substring (0, assignment_line.length - assignment_line.chug ().length);
29+
var sb = new StringBuilder ();
30+
foreach (var v in variables) {
31+
sb.append (copied_indent).append (v.variable_type.to_string ()).append (" ").append (v.name).append (";\n");
32+
}
33+
sb.append (copied_indent).append ("try {\n");
34+
sb.append (copied_indent).append (indent).append (variables[0].name).append (" = ");
35+
var s1 = variables[0].initializer.source_reference;
36+
for (var i = s1.begin.line; i <= s1.end.line; i++) {
37+
var len = -1;
38+
var offset = 0;
39+
if (i == s1.begin.line && i != s1.end.line) {
40+
offset = s1.begin.column - 1;
41+
} else if (i == s1.end.line && i != s1.begin.line) {
42+
len = s1.end.column;
43+
} else if (i == s1.begin.line && i == s1.end.line) {
44+
offset = s1.begin.column - 1;
45+
len = s1.end.column - s1.begin.column + 1;
46+
}
47+
if (i != s1.begin.line)
48+
sb.append (copied_indent).append (indent);
49+
sb.append (s1.file.get_source_line (i).substring (offset, len).strip ());
50+
sb.append (i == s1.end.line ? ";" : "").append ("\n");
51+
}
52+
// TODO: Deduplicate error name
53+
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
54+
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
55+
sb.append (copied_indent).append ("}\n");
56+
var workspace_edit = new WorkspaceEdit ();
57+
var document_edit = new TextDocumentEdit (document);
58+
var text_edit = new TextEdit (new Range.from_sourceref (sref));
59+
text_edit.range.start.character = 0;
60+
text_edit.range.end.character++;
61+
text_edit.newText = sb.str;
62+
document_edit.edits.add (text_edit);
63+
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
64+
workspace_edit.documentChanges.add (document_edit);
65+
this.edit = workspace_edit;
66+
this.title = "Wrap with try-catch";
67+
}
68+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* addtrycatchstatementaction.vala
2+
*
3+
* Copyright 2022 JCWasmx86 <JCWasmx86@t-online.de>
4+
*
5+
* This file is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This file is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* SPDX-License-Identifier: LGPL-3.0-or-later
19+
*/
20+
21+
using Gee;
22+
using Lsp;
23+
24+
class Vls.AddTryCatchStatementAction : CodeAction {
25+
public AddTryCatchStatementAction (VersionedTextDocumentIdentifier document, string error_name, string indent, Vala.CodeNode node) {
26+
var sref = node.source_reference;
27+
var sb = new StringBuilder ();
28+
var line = sref.file.get_source_line (sref.begin.line);
29+
var copied_indent = line.substring (0, line.length - line.chug ().length);
30+
sb.append (copied_indent).append ("try {\n");
31+
for (var i = sref.begin.line; i <= sref.end.line; i++) {
32+
var len = -1;
33+
var offset = 0;
34+
if (i == sref.begin.line && i != sref.end.line) {
35+
offset = sref.begin.column - 1;
36+
} else if (i == sref.end.line && i != sref.begin.line) {
37+
len = sref.end.column;
38+
} else if (i == sref.begin.line && i == sref.end.line) {
39+
offset = sref.begin.column - 1;
40+
len = sref.end.column - sref.begin.column + 1;
41+
}
42+
sb.append (copied_indent).append (indent);
43+
sb.append (sref.file.get_source_line (i).substring (offset, len).strip ());
44+
sb.append (i == sref.end.line ? ";" : "").append ("\n");
45+
}
46+
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
47+
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
48+
sb.append (copied_indent).append ("}\n");
49+
var workspace_edit = new WorkspaceEdit ();
50+
var document_edit = new TextDocumentEdit (document);
51+
var text_edit = new TextEdit (new Range.from_sourceref (sref));
52+
text_edit.range.start.character = 0;
53+
text_edit.range.end.character++;
54+
text_edit.newText = sb.str;
55+
document_edit.edits.add (text_edit);
56+
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
57+
workspace_edit.documentChanges.add (document_edit);
58+
this.edit = workspace_edit;
59+
this.title = "Wrap with try-catch";
60+
}
61+
}

src/codehelp/codeaction.vala

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ namespace Vls.CodeActions {
2828
* @param file the current document
2929
* @param range the range to show code actions for
3030
* @param uri the document URI
31+
* @param diags the diagnostics to use
3132
*/
32-
Collection<CodeAction> extract (Compilation compilation, TextDocument file, Range range, string uri) {
33+
Collection<CodeAction> extract (Compilation compilation, TextDocument file, Range range, string uri, Gee.List<Diagnostic> diags) {
3334
// search for nodes containing the query range
3435
var finder = new NodeSearch (file, range.start, true, range.end);
3536
var code_actions = new ArrayList<CodeAction> ();
@@ -60,6 +61,56 @@ namespace Vls.CodeActions {
6061
}
6162
}
6263

64+
finder = new NodeSearch.with_filter (file, null, (a, b) => true, true);
65+
var code_style = compilation.get_analysis_for_file<CodeStyleAnalyzer> (file);
66+
foreach (var d in diags) {
67+
if (d.message.has_prefix ("unhandled error ")) {
68+
foreach (var node in finder.result) {
69+
var tmp_range = new Range.from_sourceref (node.source_reference);
70+
if ((tmp_range.contains (d.range.start) && tmp_range.contains (d.range.end))
71+
&& !(node is Vala.Block)) {
72+
var error_name = d.message.replace ("unhandled error `", "").replace ("'", "").strip ();
73+
if (node is DeclarationStatement) {
74+
var variables = new Vala.ArrayList<Variable> ();
75+
((DeclarationStatement)node).get_defined_variables (variables);
76+
if (variables.size == 1)
77+
code_actions.add (new AddTryCatchAssignmentAction (document, variables, error_name, code_style.indentation, node));
78+
var parent = node.parent_node;
79+
while (parent != null) {
80+
if (parent is Vala.ForeachStatement || parent is Vala.LambdaExpression) {
81+
parent = null;
82+
break;
83+
}
84+
if (parent is Vala.Method || parent is Vala.Constructor)
85+
break;
86+
parent = parent.parent_node;
87+
}
88+
if (parent != null) {
89+
code_actions.add (new AddThrowsDeclaration (document, error_name, parent));
90+
}
91+
} else if (node is ExpressionStatement && !(node.parent_node is Vala.ForeachStatement)) {
92+
var es = (ExpressionStatement) node;
93+
code_actions.add (new AddTryCatchStatementAction (document, error_name, code_style.indentation, es.expression));
94+
} else {
95+
var parent = node.parent_node;
96+
while (parent != null) {
97+
if (parent is Vala.ForeachStatement || parent is Vala.LambdaExpression) {
98+
parent = null;
99+
break;
100+
}
101+
if (parent is Vala.Method || parent is Vala.Constructor)
102+
break;
103+
parent = parent.parent_node;
104+
}
105+
if (parent != null) {
106+
code_actions.add (new AddThrowsDeclaration (document, error_name, parent));
107+
}
108+
}
109+
}
110+
}
111+
}
112+
}
113+
63114
return code_actions;
64115
}
65116

src/codehelp/nodesearch.vala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class Vls.NodeSearch : Vala.CodeVisitor {
3333
private Gee.HashSet<Vala.CodeNode> seen = new Gee.HashSet<Vala.CodeNode> ();
3434

3535
[CCode (has_target = false)]
36-
public delegate bool Filter (Vala.CodeNode needle, Vala.CodeNode hay_node);
36+
public delegate bool Filter (Vala.CodeNode? needle, Vala.CodeNode hay_node);
3737

3838
private Vala.CodeNode? needle;
3939
private Filter? filter;
@@ -122,7 +122,7 @@ class Vls.NodeSearch : Vala.CodeVisitor {
122122
this.visit_source_file (file);
123123
}
124124

125-
public NodeSearch.with_filter (Vala.SourceFile file, Vala.CodeNode needle, Filter filter_func,
125+
public NodeSearch.with_filter (Vala.SourceFile file, Vala.CodeNode? needle, Filter filter_func,
126126
bool include_declaration = true) {
127127
this.file = file;
128128
this.needle = needle;

src/meson.build

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ vls_src = files([
44
'analysis/codestyleanalyzer.vala',
55
'analysis/inlayhintnodes.vala',
66
'analysis/symbolenumerator.vala',
7+
'codeaction/addtrycatchassignmentaction.vala',
8+
'codeaction/addtrycatchstatementaction.vala',
9+
'codeaction/addthrowsdeclaration.vala',
710
'codeaction/baseconverteraction.vala',
811
'codeaction/implementmissingprereqsaction.vala',
912
'codehelp/callhierarchy.vala',

src/server.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1664,7 +1664,7 @@ class Vls.Server : Jsonrpc.Server {
16641664
var json_array = new Json.Array ();
16651665

16661666
Vala.CodeContext.push (compilation.code_context);
1667-
var code_actions = CodeActions.extract (compilation, (TextDocument) source_file, p.range, Uri.unescape_string (p.textDocument.uri));
1667+
var code_actions = CodeActions.extract (compilation, (TextDocument) source_file, p.range, Uri.unescape_string (p.textDocument.uri), p.context.diagnostics);
16681668
foreach (var action in code_actions)
16691669
json_array.add_element (Json.gobject_serialize (action));
16701670
Vala.CodeContext.pop ();

0 commit comments

Comments
 (0)