Skip to content

Commit 9e98cfd

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 9e98cfd

7 files changed

+242
-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: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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, string variable_name, string type, string error_name, string indent, Vala.CodeNode rhs) {
26+
var sref = rhs.parent_node.parent_node.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 - 1);
29+
var sb = new StringBuilder ();
30+
sb.append (copied_indent).append (type).append (" ").append (variable_name).append (";\n");
31+
sb.append (copied_indent).append ("try {\n");
32+
sb.append (copied_indent).append (indent).append (variable_name).append (" = ");
33+
var flag = false;
34+
for (var i = rhs.source_reference.begin.line; i <= rhs.source_reference.end.line; i++) {
35+
var len = -1;
36+
var offset = 0;
37+
if (i == rhs.source_reference.begin.line && i != rhs.source_reference.end.line) {
38+
offset = rhs.source_reference.begin.column;
39+
} else if (i == rhs.source_reference.end.line && i != rhs.source_reference.begin.line) {
40+
len = rhs.source_reference.end.column;
41+
} else if (i == rhs.source_reference.begin.line && i == rhs.source_reference.end.line) {
42+
offset = rhs.source_reference.begin.column - 1;
43+
len = rhs.source_reference.end.column - rhs.source_reference.begin.column + 1;
44+
}
45+
if (!flag)
46+
sb.append (copied_indent).append (indent);
47+
sb.append (rhs.source_reference.file.get_source_line (i).substring (offset, len).strip ());
48+
sb.append (i == rhs.source_reference.end.line ? ";" : "").append ("\n");
49+
flag = true;
50+
}
51+
// TODO: Deduplicate error name
52+
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
53+
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
54+
sb.append (copied_indent).append ("}\n");
55+
var workspace_edit = new WorkspaceEdit ();
56+
var document_edit = new TextDocumentEdit (document);
57+
var text_edit = new TextEdit (new Range.from_sourceref (sref));
58+
text_edit.range.end.character++;
59+
text_edit.newText = sb.str;
60+
document_edit.edits.add (text_edit);
61+
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
62+
workspace_edit.documentChanges.add (document_edit);
63+
this.edit = workspace_edit;
64+
this.title = "Wrap with try-catch";
65+
}
66+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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 - 1);
30+
sb.append (copied_indent).append ("try {\n");
31+
var flag = false;
32+
for (var i = sref.begin.line; i <= sref.end.line; i++) {
33+
var len = -1;
34+
var offset = 0;
35+
if (i == sref.begin.line && i != sref.end.line) {
36+
offset = sref.begin.column;
37+
} else if (i == sref.end.line && i != sref.begin.line) {
38+
len = sref.end.column;
39+
} else if (i == sref.begin.line && i == sref.end.line) {
40+
offset = sref.begin.column - 1;
41+
len = sref.end.column - sref.begin.column + 1;
42+
}
43+
if (!flag)
44+
sb.append (copied_indent).append (indent);
45+
sb.append (sref.file.get_source_line (i).substring (offset, len).strip ());
46+
sb.append (i == sref.end.line ? ";" : "").append ("\n");
47+
flag = true;
48+
}
49+
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
50+
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
51+
sb.append (copied_indent).append ("}\n");
52+
var workspace_edit = new WorkspaceEdit ();
53+
var document_edit = new TextDocumentEdit (document);
54+
var text_edit = new TextEdit (new Range.from_sourceref (sref));
55+
text_edit.range.end.character++;
56+
text_edit.newText = sb.str;
57+
document_edit.edits.add (text_edit);
58+
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
59+
workspace_edit.documentChanges.add (document_edit);
60+
this.edit = workspace_edit;
61+
this.title = "Wrap with try-catch";
62+
}
63+
}

src/codehelp/codeaction.vala

Lines changed: 39 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,43 @@ 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 Expression && node.parent_node is LocalVariable && node.parent_node.parent_node is DeclarationStatement) {
74+
var name = ((LocalVariable) node.parent_node).name;
75+
var target_type = ((Expression) node).target_type.to_string ();
76+
if (!name.has_prefix ("."))
77+
code_actions.add (new AddTryCatchAssignmentAction (document, name, target_type, error_name, code_style.indentation, node));
78+
} else if (node is ExpressionStatement && !(node.parent_node is Vala.ForeachStatement)) {
79+
var es = (ExpressionStatement) node;
80+
code_actions.add (new AddTryCatchStatementAction (document, error_name, code_style.indentation, es.expression));
81+
} else {
82+
var parent = node.parent_node;
83+
while (parent != null) {
84+
if (parent is Vala.ForeachStatement || parent is Vala.LambdaExpression) {
85+
parent = null;
86+
break;
87+
}
88+
if (parent is Vala.Method || parent is Vala.Constructor)
89+
break;
90+
parent = parent.parent_node;
91+
}
92+
if (parent != null) {
93+
code_actions.add (new AddThrowsDeclaration (document, error_name, parent));
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
63101
return code_actions;
64102
}
65103

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)