Skip to content

Commit

Permalink
Add more actions:
Browse files Browse the repository at this point in the history
- AddThrowsDeclaration to add an error to the declaration of a method/constructor
- AddTryCatch around statements
- AddTryCatch around variable declarations
  • Loading branch information
JCWasmx86 committed Jul 14, 2022
1 parent b461b94 commit 93743aa
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 4 deletions.
68 changes: 68 additions & 0 deletions src/codeaction/addthrowsdeclaration.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* addthrowsdeclaration.vala
*
* Copyright 2022 JCWasmx86 <[email protected]>
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

using Gee;
using Lsp;

class Vls.AddThrowsDeclaration : CodeAction {
public AddThrowsDeclaration (VersionedTextDocumentIdentifier document, string error_name, Vala.CodeNode where) {

var error_types = new Vala.HashSet<Vala.DataType> ();
if (where is Vala.Constructor)
((Vala.Constructor)where).body.get_error_types (error_types, null);
else
where.get_error_types (error_types, null);

var sb = new StringBuilder ();
if (error_types.is_empty) {
sb.append (" throws ");
} else {
sb.append (", ");
}
sb.append (error_name);
sb.append (" ");
var sref = where.source_reference;
var range = new Range ();
for (var i = sref.begin.line; i <= sref.end.line; i++) {
var line = sref.file.get_source_line (i);
if (line.contains ("{")) {
var idx = line.index_of ("{");
range.start = new Lsp.Position () {
line = i - 1,
character = idx - 1,
};
range.end = new Lsp.Position () {
line = i - 1,
character = idx - 1,
};
}
}
var workspace_edit = new WorkspaceEdit ();
var document_edit = new TextDocumentEdit (document);
var text_edit = new TextEdit (range);
text_edit.range.end.character++;
text_edit.newText = sb.str;
document_edit.edits.add (text_edit);
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
workspace_edit.documentChanges.add (document_edit);
this.edit = workspace_edit;
this.title = "Add to error list";
}
}
68 changes: 68 additions & 0 deletions src/codeaction/addtrycatchassignmentaction.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* AddTryCatchAssignmentAction.vala
*
* Copyright 2022 JCWasmx86 <[email protected]>
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

using Gee;
using Lsp;

class Vls.AddTryCatchAssignmentAction : CodeAction {
public AddTryCatchAssignmentAction (VersionedTextDocumentIdentifier document, Vala.ArrayList<Vala.Variable> variables, string error_name, string indent, Vala.CodeNode rhs) {
var sref = rhs.source_reference;
var assignment_line = sref.file.get_source_line (sref.begin.line);
var copied_indent = assignment_line.substring (0, assignment_line.length - assignment_line.chug ().length);
var sb = new StringBuilder ();
foreach (var v in variables) {
sb.append (copied_indent).append (v.variable_type.to_string ()).append (" ").append (v.name).append (";\n");
}
sb.append (copied_indent).append ("try {\n");
sb.append (copied_indent).append (indent).append (variables[0].name).append (" = ");
var s1 = variables[0].initializer.source_reference;
for (var i = s1.begin.line; i <= s1.end.line; i++) {
var len = -1;
var offset = 0;
if (i == s1.begin.line && i != s1.end.line) {
offset = s1.begin.column - 1;
} else if (i == s1.end.line && i != s1.begin.line) {
len = s1.end.column;
} else if (i == s1.begin.line && i == s1.end.line) {
offset = s1.begin.column - 1;
len = s1.end.column - s1.begin.column + 1;
}
if (i != s1.begin.line)
sb.append (copied_indent).append (indent);
sb.append (s1.file.get_source_line (i).substring (offset, len).strip ());
sb.append (i == s1.end.line ? ";" : "").append ("\n");
}
// TODO: Deduplicate error name
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
sb.append (copied_indent).append ("}\n");
var workspace_edit = new WorkspaceEdit ();
var document_edit = new TextDocumentEdit (document);
var text_edit = new TextEdit (new Range.from_sourceref (sref));
text_edit.range.start.character = 0;
text_edit.range.end.character++;
text_edit.newText = sb.str;
document_edit.edits.add (text_edit);
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
workspace_edit.documentChanges.add (document_edit);
this.edit = workspace_edit;
this.title = "Wrap with try-catch";
}
}
61 changes: 61 additions & 0 deletions src/codeaction/addtrycatchstatementaction.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* addtrycatchstatementaction.vala
*
* Copyright 2022 JCWasmx86 <[email protected]>
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

using Gee;
using Lsp;

class Vls.AddTryCatchStatementAction : CodeAction {
public AddTryCatchStatementAction (VersionedTextDocumentIdentifier document, string error_name, string indent, Vala.CodeNode node) {
var sref = node.source_reference;
var sb = new StringBuilder ();
var line = sref.file.get_source_line (sref.begin.line);
var copied_indent = line.substring (0, line.length - line.chug ().length);
sb.append (copied_indent).append ("try {\n");
for (var i = sref.begin.line; i <= sref.end.line; i++) {
var len = -1;
var offset = 0;
if (i == sref.begin.line && i != sref.end.line) {
offset = sref.begin.column - 1;
} else if (i == sref.end.line && i != sref.begin.line) {
len = sref.end.column;
} else if (i == sref.begin.line && i == sref.end.line) {
offset = sref.begin.column - 1;
len = sref.end.column - sref.begin.column + 1;
}
sb.append (copied_indent).append (indent);
sb.append (sref.file.get_source_line (i).substring (offset, len).strip ());
sb.append (i == sref.end.line ? ";" : "").append ("\n");
}
sb.append (copied_indent).append ("} catch (").append (error_name).append (" e) {\n");
sb.append (copied_indent).append (indent).append ("error (\"Caught error ").append (error_name).append (": %s\", e.message);\n");
sb.append (copied_indent).append ("}\n");
var workspace_edit = new WorkspaceEdit ();
var document_edit = new TextDocumentEdit (document);
var text_edit = new TextEdit (new Range.from_sourceref (sref));
text_edit.range.start.character = 0;
text_edit.range.end.character++;
text_edit.newText = sb.str;
document_edit.edits.add (text_edit);
workspace_edit.documentChanges = new ArrayList<TextDocumentEdit> ();
workspace_edit.documentChanges.add (document_edit);
this.edit = workspace_edit;
this.title = "Wrap with try-catch";
}
}
53 changes: 52 additions & 1 deletion src/codehelp/codeaction.vala
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ namespace Vls.CodeActions {
* @param file the current document
* @param range the range to show code actions for
* @param uri the document URI
* @param diags the diagnostics to use
*/
Collection<CodeAction> extract (Compilation compilation, TextDocument file, Range range, string uri) {
Collection<CodeAction> extract (Compilation compilation, TextDocument file, Range range, string uri, Gee.List<Diagnostic> diags) {
// search for nodes containing the query range
var finder = new NodeSearch (file, range.start, true, range.end);
var code_actions = new ArrayList<CodeAction> ();
Expand Down Expand Up @@ -60,6 +61,56 @@ namespace Vls.CodeActions {
}
}

finder = new NodeSearch.with_filter (file, null, (a, b) => true, true);
var code_style = compilation.get_analysis_for_file<CodeStyleAnalyzer> (file);
foreach (var d in diags) {
if (d.message.has_prefix ("unhandled error ")) {
foreach (var node in finder.result) {
var tmp_range = new Range.from_sourceref (node.source_reference);
if ((tmp_range.contains (d.range.start) && tmp_range.contains (d.range.end))
&& !(node is Vala.Block)) {
var error_name = d.message.replace ("unhandled error `", "").replace ("'", "").strip ();
if (node is DeclarationStatement) {
var variables = new Vala.ArrayList<Variable> ();
((DeclarationStatement)node).get_defined_variables (variables);
if (variables.size == 1)
code_actions.add (new AddTryCatchAssignmentAction (document, variables, error_name, code_style.indentation, node));
var parent = node.parent_node;
while (parent != null) {
if (parent is Vala.ForeachStatement || parent is Vala.LambdaExpression) {
parent = null;
break;
}
if (parent is Vala.Method || parent is Vala.Constructor)
break;
parent = parent.parent_node;
}
if (parent != null) {
code_actions.add (new AddThrowsDeclaration (document, error_name, parent));
}
} else if (node is ExpressionStatement && !(node.parent_node is Vala.ForeachStatement)) {
var es = (ExpressionStatement) node;
code_actions.add (new AddTryCatchStatementAction (document, error_name, code_style.indentation, es.expression));
} else {
var parent = node.parent_node;
while (parent != null) {
if (parent is Vala.ForeachStatement || parent is Vala.LambdaExpression) {
parent = null;
break;
}
if (parent is Vala.Method || parent is Vala.Constructor)
break;
parent = parent.parent_node;
}
if (parent != null) {
code_actions.add (new AddThrowsDeclaration (document, error_name, parent));
}
}
}
}
}
}

return code_actions;
}

Expand Down
4 changes: 2 additions & 2 deletions src/codehelp/nodesearch.vala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Vls.NodeSearch : Vala.CodeVisitor {
private Gee.HashSet<Vala.CodeNode> seen = new Gee.HashSet<Vala.CodeNode> ();

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

private Vala.CodeNode? needle;
private Filter? filter;
Expand Down Expand Up @@ -122,7 +122,7 @@ class Vls.NodeSearch : Vala.CodeVisitor {
this.visit_source_file (file);
}

public NodeSearch.with_filter (Vala.SourceFile file, Vala.CodeNode needle, Filter filter_func,
public NodeSearch.with_filter (Vala.SourceFile file, Vala.CodeNode? needle, Filter filter_func,
bool include_declaration = true) {
this.file = file;
this.needle = needle;
Expand Down
3 changes: 3 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ vls_src = files([
'analysis/codestyleanalyzer.vala',
'analysis/inlayhintnodes.vala',
'analysis/symbolenumerator.vala',
'codeaction/addtrycatchassignmentaction.vala',
'codeaction/addtrycatchstatementaction.vala',
'codeaction/addthrowsdeclaration.vala',
'codeaction/baseconverteraction.vala',
'codeaction/implementmissingprereqsaction.vala',
'codehelp/callhierarchy.vala',
Expand Down
2 changes: 1 addition & 1 deletion src/server.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1664,7 +1664,7 @@ class Vls.Server : Jsonrpc.Server {
var json_array = new Json.Array ();

Vala.CodeContext.push (compilation.code_context);
var code_actions = CodeActions.extract (compilation, (TextDocument) source_file, p.range, Uri.unescape_string (p.textDocument.uri));
var code_actions = CodeActions.extract (compilation, (TextDocument) source_file, p.range, Uri.unescape_string (p.textDocument.uri), p.context.diagnostics);
foreach (var action in code_actions)
json_array.add_element (Json.gobject_serialize (action));
Vala.CodeContext.pop ();
Expand Down

0 comments on commit 93743aa

Please sign in to comment.