Commit b65ef426 authored by Corentin Noël's avatar Corentin Noël

Avoid crashes at some time

parent ddba7798
Pipeline #68884 canceled with stages
in 1 minute and 13 seconds
......@@ -49,7 +49,7 @@ namespace Ide
SHUTDOWN
}
GLib.Queue<Ide.Task> get_client;
GLib.Queue<GetContextCB> get_client;
Ide.SubprocessSupervisor supervisor;
Jsonrpc.Client rpc_client;
GLib.File root_uri;
......@@ -65,11 +65,16 @@ namespace Ide
}
}
[Compact]
public class GetContextCB {
public SourceFunc source_func;
}
public override void parent_set (Ide.Object? parent) {
if (parent == null)
return;
get_client = new GLib.Queue<Ide.Task> ();
get_client = new GLib.Queue<GetContextCB> ();
unowned Ide.Context? context = get_context ();
root_uri = context.ref_workdir ();
......@@ -93,9 +98,6 @@ namespace Ide
state = State.SPAWNING;
rpc_client = null;
/*lock (seq_by_file) {
seq_by_file = null;
}*/
}
public void subprocess_spawned (Ide.Subprocess subprocess) {
......@@ -116,9 +118,11 @@ namespace Ide
rpc_client = new Jsonrpc.Client (stream);
rpc_client.set_use_gvariant (true);
Ide.Task task = null;
while ((task = get_client.pop_head ()) != null) {
task.return_object (rpc_client);
GetContextCB cb = null;
lock (get_client) {
while ((cb = get_client.pop_head ()) != null) {
cb.source_func ();
}
}
var @params = Jsonrpc.Message.@new (
......@@ -325,7 +329,9 @@ namespace Ide
var reply = yield call_async ("vala/complete",
params,
cancellable);
//return new Ide.Symbol.from_variant (reply);
if (reply != null) {
return new Ide.Symbol.from_variant (reply);
}
return null;
} catch (Error e) {
throw e;
......@@ -336,20 +342,22 @@ namespace Ide
switch (state) {
default:
state = State.SPAWNING;
Idle.add (() => {
supervisor.start ();
var task = new Ide.Task (this, cancellable, (GLib.TaskReadyCallback)get_client_async.callback);
get_client.push_tail (task);
return false;
});
supervisor.start ();
var cb = new GetContextCB ();
cb.source_func = get_client_async.callback;
lock (get_client) {
get_client.push_tail ((owned) cb);
}
yield;
return rpc_client;
case State.SPAWNING:
Idle.add (() => {
var task = new Ide.Task (this, cancellable, (GLib.TaskReadyCallback)get_client_async.callback);
get_client.push_tail (task);
return false;
});
var cb = new GetContextCB ();
cb.source_func = get_client_async.callback;
lock (get_client) {
get_client.push_tail ((owned) cb);
}
yield;
return rpc_client;
case State.RUNNING:
......@@ -381,17 +389,12 @@ namespace Ide
*/
unsaved_files.foreach ((unsaved_file) => {
unowned GLib.File file = unsaved_file.get_file ();
//int64? prev = seq_by_file[file];
int64 seq = unsaved_file.get_sequence ();
/*if (prev != null && seq <= prev)
return;*/
string? name = file.get_basename ();
if (name == null || !(name.has_suffix (".vala") ||
name.has_suffix (".vapi")))
return;
//seq_by_file.insert (file, seq);
set_buffer_async.begin (file, unsaved_file.get_content ());
});
//}
......
......@@ -21,11 +21,6 @@ using Ide;
namespace Ide
{
bool is_null_or_empty (string? s)
{
return s == null || s[0] == '\0';
}
public class ValaCodeIndexer : Ide.Object, Ide.CodeIndexer
{
public async Ide.CodeIndexEntries index_file_async (GLib.File file,
......
......@@ -75,12 +75,6 @@ namespace Ide
return null;
}
string? esc_angle_brackets (string? in) {
if (in == null)
return null;
return in.replace ("<", "&lt;").replace (">", "&gt;");
}
public string get_markup (string? typed_text)
{
/*GLib.StringBuilder str = new GLib.StringBuilder ();
......
......@@ -77,10 +77,11 @@ namespace Ide
var line_offset = iter.get_line_offset ();
var proposals = yield client.proposals_populate_async (file, line + 1, line_offset + 1, line_text, cancellable);
if (cancellable.is_cancelled () || results == null)
if (cancellable.is_cancelled ())
throw new GLib.IOError.CANCELLED ("operation was cancelled");
results = new Ide.ValaCompletionResults ();
return results;
}
......
......@@ -84,13 +84,15 @@ namespace Ide
Jsonrpc.Message.parse (params, "flags", Jsonrpc.Message.GetStrv.create (ref flags));
flags.length = (int) GLib.strv_length (flags);
var diagnostics = index.get_file_diagnostics (path, flags);
var builder = new VariantBuilder (new VariantType ("aa{sv}") );
var size = diagnostics.get_n_items ();
for (int i = 0; i < size; i++) {
Ide.Diagnostic diag = diagnostics.get_item (i) as Ide.Diagnostic;
if (diag != null) {
builder.add_value (diag.to_variant ());
lock (index) {
var diagnostics = index.get_file_diagnostics (path, flags);
var size = diagnostics.get_n_items ();
for (int i = 0; i < size; i++) {
Ide.Diagnostic diag = diagnostics.get_item (i) as Ide.Diagnostic;
if (diag != null) {
builder.add_value (diag.to_variant ());
}
}
}
......@@ -109,11 +111,10 @@ namespace Ide
unowned string content = null;
params.lookup ("contents", "^&ay", ref content);
GLib.Bytes? bytes = null;
if (content != null)
bytes = new GLib.Bytes.take (content.data);
lock (index) {
index.set_unsaved_file (path, content);
}
index.set_unsaved_file (path, bytes);
reply_to_client.begin (client, id, new GLib.Variant.boolean (true));
}
......@@ -131,7 +132,11 @@ namespace Ide
Jsonrpc.Message.parse (params, "flags", Jsonrpc.Message.GetStrv.create (ref flags));
flags.length = (int) GLib.strv_length (flags);
var symbol_tree = index.get_symbol_tree (path, flags);
GLib.Variant symbol_tree;
lock (index) {
symbol_tree = index.get_symbol_tree (path, flags);
}
reply_to_client.begin (client, id, symbol_tree);
}
......@@ -151,10 +156,12 @@ namespace Ide
"column", Jsonrpc.Message.GetInt64.create (ref column)))
{
flags.length = (int) GLib.strv_length (flags);
var symbol = index.locate_symbol (path, flags, (uint)line, (uint)column);
Variant? symbol_variant = null;
if (symbol != null)
symbol_variant = symbol.to_variant ();
Variant? symbol_variant = null;
lock (index) {
var symbol = index.locate_symbol (path, flags, (uint)line, (uint)column);
if (symbol != null)
symbol_variant = symbol.to_variant ();
}
reply_to_client.begin (client, id, symbol_variant);
} else {
......@@ -178,10 +185,12 @@ namespace Ide
"column", Jsonrpc.Message.GetInt64.create (ref column)))
{
flags.length = (int) GLib.strv_length (flags);
var symbol = index.find_nearest_scope (path, flags, (uint)line, (uint)column);
Variant? symbol_variant = null;
if (symbol != null)
symbol_variant = symbol.to_variant ();
Variant? symbol_variant = null;
lock (index) {
var symbol = index.find_nearest_scope (path, flags, (uint)line, (uint)column);
if (symbol != null)
symbol_variant = symbol.to_variant ();
}
reply_to_client.begin (client, id, symbol_variant);
} else {
......@@ -204,7 +213,11 @@ namespace Ide
"column", Jsonrpc.Message.GetInt64.create (ref column),
"line_text", Jsonrpc.Message.GetString.create (ref line_text)))
{
var results = index.code_complete (path, (uint)line, (uint)column, line_text);
GLib.Variant results;
lock (index) {
results = index.code_complete (path, (uint)line, (uint)column, line_text);
}
reply_to_client.begin (client, id, results);
} else {
reply_error_to_client.begin (client, id);
......@@ -225,7 +238,11 @@ namespace Ide
Jsonrpc.Message.parse (params, "flags", Jsonrpc.Message.GetStrv.create (ref flags));
flags.length = (int) GLib.strv_length (flags);
var index_entries = index.get_index_entries (path, flags);
GLib.Variant index_entries;
lock (index) {
index_entries = index.get_index_entries (path, flags);
}
reply_to_client.begin (client, id, index_entries);
}
......
......@@ -85,15 +85,19 @@ namespace Ide {
public static string? vala_symbol_name (Vala.Symbol symbol)
{
if (symbol is Vala.Variable) {
unowned Vala.Variable variable = (Vala.Variable) symbol;
var variable = (symbol as Vala.Variable);
if (variable.variable_type != null) {
return variable.variable_type.to_prototype_string () + " " + symbol.name;
} else {
return "var " + symbol.name;
}
} else if (symbol is Vala.Property) {
return symbol.name;
} else if (symbol is Vala.CreationMethod) {
return (symbol as Vala.CreationMethod).class_name;
} else if (symbol is Vala.Method) {
var type = new Vala.MethodType ((Vala.Method) symbol);
return type.to_prototype_string ();
var type = new Vala.MethodType (symbol as Vala.Method);
return type.to_prototype_string (null);
}
return symbol.to_string ();
......
......@@ -24,96 +24,55 @@ namespace Ide
{
public class ValaIndex: GLib.Object
{
Vala.CodeContext code_context;
Ide.ValaCodeContext code_context;
Vala.Parser parser;
Ide.ValaDiagnostics report;
GLib.File workdir;
GLib.HashTable<string, GLib.Bytes> unsaved_files;
public ValaIndex (GLib.File workdir)
{
this.workdir = workdir;
code_context = new Vala.CodeContext ();
unsaved_files = new GLib.HashTable<string, GLib.Bytes> (str_hash, str_equal);
code_context = new Ide.ValaCodeContext ();
Vala.CodeContext.push (code_context);
/*
* TODO: Some of the following options could be extracted by parsing
* the contents of *_VALAFLAGS or AM_VALAFLAGS in automake.
* We need to do this in a somewhat build system agnostic fashion
* since there seems to a cargo cult of cmake/vala.
*/
code_context.assert = true;
code_context.checking = false;
code_context.deprecated = false;
code_context.hide_internal = false;
code_context.experimental = false;
code_context.experimental_non_null = false;
code_context.gobject_tracing = false;
code_context.nostdpkg = false;
code_context.ccode_only = true;
code_context.compile_only = true;
code_context.use_header = false;
code_context.includedir = null;
code_context.basedir = workdir.get_path ();
code_context.directory = GLib.Environment.get_current_dir ();
code_context.debug = false;
code_context.mem_profiler = false;
code_context.save_temps = false;
code_context.profile = Vala.Profile.GOBJECT;
code_context.add_define ("GOBJECT");
code_context.entry_point_name = null;
code_context.run_output = false;
int minor = 36;
var tokens = ValaConfig.VALA_VERSION.split(".", 2);
if (tokens[1] != null) {
minor = int.parse(tokens[1]);
}
code_context.vapi_directories = {};
/* $prefix/share/vala-0.32/vapi */
string versioned_vapidir = get_versioned_vapidir ();
if (versioned_vapidir != null) {
add_vapidir_locked (versioned_vapidir);
}
/* $prefix/share/vala/vapi */
string unversioned_vapidir = get_unversioned_vapidir ();
if (unversioned_vapidir != null) {
add_vapidir_locked (unversioned_vapidir);
}
code_context.add_external_package ("glib-2.0");
code_context.add_external_package ("gobject-2.0");
report = new Ide.ValaDiagnostics ();
code_context.report = report;
parser = new Vala.Parser ();
parser.parse (code_context);
code_context.check ();
load_directory (workdir);
Vala.CodeContext.pop ();
}
public void set_unsaved_file (string path,
GLib.Bytes? bytes)
string? content)
{
if (bytes == null) {
unsaved_files.remove (path);
} else {
unsaved_files[path] = bytes;
Vala.CodeContext.push (this.code_context);
Vala.SourceFile? source_file = code_context.get_source (path);
if (source_file != null) {
if (source_file.content != content) {
source_file.content = content;
unowned Vala.Method? entry_point = code_context.entry_point;
if (entry_point != null && entry_point.source_reference != null && entry_point.source_reference.file == source_file) {
code_context.entry_point = null;
}
// Copy the node list since we will be mutating while iterating
var copy = new Vala.ArrayList<Vala.CodeNode> ();
copy.add_all (source_file.get_nodes ());
foreach (var node in copy) {
source_file.remove_node (node);
}
}
} else if (content != null) {
source_file = new Vala.SourceFile (code_context, Vala.SourceFileType.SOURCE, path, content);
code_context.add_source_file (source_file);
}
Vala.CodeContext.pop ();
}
public Ide.Diagnostics get_file_diagnostics (string path,
......@@ -121,12 +80,13 @@ namespace Ide
{
lock (this.code_context) {
Vala.CodeContext.push (this.code_context);
load_build_flags (flags);
add_file (GLib.File.new_for_path (path));
reparse ();
if (report.get_errors () == 0) {
code_context.check ();
}
code_context.parse_arguments (flags);
code_context.add_source (path);
critical ("Diagnostics %s", path);
report.clear ();
code_context.check ();
Vala.CodeContext.pop ();
}
......@@ -140,17 +100,14 @@ namespace Ide
GLib.Variant symbol_tree;
lock (this.code_context) {
Vala.CodeContext.push (this.code_context);
load_build_flags (flags);
if (add_file (GLib.File.new_for_path (path)))
reparse ();
code_context.parse_arguments (flags);
code_context.add_source (path);
reparse ();
var tree_builder = new Ide.ValaSymbolTreeVisitor ();
foreach (var source_file in code_context.get_source_files ()) {
if (source_file.filename == path) {
source_file.accept_children (tree_builder);
break;
}
Vala.SourceFile? source_file = code_context.get_source (path);
if (source_file != null) {
source_file.accept_children (tree_builder);
}
symbol_tree = tree_builder.build_tree ();
......@@ -167,17 +124,14 @@ namespace Ide
GLib.Variant index_entries;
lock (this.code_context) {
Vala.CodeContext.push (this.code_context);
load_build_flags (flags);
if (add_file (GLib.File.new_for_path (path)))
reparse ();
code_context.parse_arguments (flags);
code_context.add_source (path);
reparse ();
var tree_builder = new Ide.ValaSymbolTreeVisitor ();
foreach (var source_file in code_context.get_source_files ()) {
if (source_file.filename == path) {
source_file.accept_children (tree_builder);
break;
}
Vala.SourceFile? source_file = code_context.get_source (path);
if (source_file != null) {
source_file.accept_children (tree_builder);
}
index_entries = tree_builder.build_index_entries ();
......@@ -196,21 +150,16 @@ namespace Ide
Ide.Symbol? symbol = null;
lock (this.code_context) {
Vala.CodeContext.push (this.code_context);
load_build_flags (flags);
if (add_file (GLib.File.new_for_path (path)))
reparse ();
foreach (var source_file in code_context.get_source_files ()) {
if (source_file.filename == path) {
var locator = new Ide.ValaLocator ();
var vala_node = locator.locate (source_file, line, column);
if (vala_node != null) {
symbol = Ide.vala_to_ide_symbol (vala_node);
}
code_context.parse_arguments (flags);
code_context.add_source (path);
reparse ();
break;
Vala.SourceFile? source_file = code_context.get_source (path);
if (source_file != null) {
var locator = new Ide.ValaLocator ();
var vala_node = locator.locate (source_file, line, column);
if (vala_node != null) {
symbol = Ide.vala_to_ide_symbol (vala_node);
}
}
......@@ -228,7 +177,7 @@ namespace Ide
Ide.Symbol? ide_symbol = null;
lock (this.code_context) {
Vala.CodeContext.push (this.code_context);
load_build_flags (flags);
code_context.parse_arguments (flags);
var symbol = find_nearest_symbol (path, line, column);
if (symbol != null) {
ide_symbol = Ide.vala_to_ide_symbol (symbol);
......@@ -348,69 +297,22 @@ namespace Ide
}
private Vala.CodeNode? find_nearest_symbol (string path,
uint line,
uint column)
uint line,
uint column)
{
Vala.CodeNode? symbol = null;
if (add_file (GLib.File.new_for_path (path)))
reparse ();
apply_unsaved_files ();
foreach (var source_file in code_context.get_source_files ()) {
if (source_file.filename == path) {
var locator = new Ide.ValaLocator ();
symbol = locator.locate (source_file, line, column);
/*while (vala_node != null) {
if (vala_node is Vala.Class ||
vala_node is Vala.Subroutine ||
vala_node is Vala.Namespace ||
vala_node is Vala.Struct)
break;
if (vala_node.owner != null)
vala_node = vala_node.owner.owner;
else
vala_node = vala_node.parent_symbol;
}
code_context.add_source (path);
reparse ();
symbol = vala_node;*/
break;
}
Vala.SourceFile? source_file = code_context.get_source (path);
if (source_file != null) {
var locator = new Ide.ValaLocator ();
symbol = locator.locate (source_file, line, column);
}
return symbol;
}
private bool add_file (GLib.File file)
{
var path = file.get_path ();
if (path == null)
return false;
foreach (var source_file in code_context.get_source_files ()) {
if (source_file.filename == path)
return false;
}
var type = Vala.SourceFileType.SOURCE;
if (path.has_suffix ("vapi"))
type = Vala.SourceFileType.PACKAGE;
var source_file = new Ide.ValaSourceFile (code_context, type, path, null, false);
code_context.add_source_file (source_file);
return true;
}
private void apply_unsaved_files () {
foreach (var source_file in code_context.get_source_files ()) {
if (source_file is Ide.ValaSourceFile) {
GLib.Bytes? content = unsaved_files[source_file.filename];
(source_file as Ide.ValaSourceFile).sync (content);
unsaved_files.remove (source_file.filename);
}
}
}
private void load_directory (GLib.File directory,
GLib.Cancellable? cancellable = null)
{
......@@ -427,8 +329,9 @@ namespace Ide
if (file_info.get_file_type () == GLib.FileType.DIRECTORY) {
var child = directory.get_child (file_info.get_name ());
load_directory (child, cancellable);
} else if (name.has_suffix (".vala") || name.has_suffix (".vapi")) {
add_file (directory.get_child (file_info.get_name ()));
} else if (name.has_suffix (".vala") || name.has_suffix (".vapi") || name.has_suffix (".gs") || name.has_suffix (".c")) {
var child = directory.get_child (file_info.get_name ());
code_context.add_source (child.get_path ());
}
}
......@@ -437,125 +340,5 @@ namespace Ide
warning (err.message);
}
}
private void load_build_flags (string[] flags)
{
lock (code_context) {
Vala.CodeContext.push (code_context);
var packages = new Vala.ArrayList<string> ();
var len = flags.length;
for (var i = 0; i < len; i++) {
string next_param = null;
string param = flags[i];
if (param.contains ("=")) {
var offset = param.index_of("=") + 1;
next_param = param.offset(offset);
} else if (i + 1 < len) {
next_param = flags[i + 1];
}
if (next_param != null) {
if (param.has_prefix("--pkg")) {
packages.add (next_param);
} else if (param.has_prefix ("--vapidir")) {
add_vapidir_locked (next_param);
} else if (param.has_prefix ("--vapi")) {
packages.add (next_param);
} else if (param.has_prefix ("--girdir")) {
add_girdir_locked (next_param);
} else if (param.has_prefix ("--metadatadir")) {
add_metadatadir_locked (next_param);
} else if (param.has_prefix ("--target-glib")) {
/* TODO: Parse glib version ~= 2.44 */
}
continue;
}
else if (param.has_suffix (".vapi")) {
if (!GLib.Path.is_absolute (param)) {
var child = workdir.get_child (param);
add_file (child);
} else {
add_file (GLib.File.new_for_path (param));
}
}
}
/* Now add external packages after vapidir/girdir have been added */
foreach (var package in packages) {
code_context.add_external_package (package);
}
Vala.CodeContext.pop ();
}
}
/* Caller is expected to hold code_context lock */
private void add_vapidir_locked (string vapidir)
{
var dirs = code_context.vapi_directories;
if (vapidir in dirs)
return;
debug ("Adding vapidir %s", vapidir);
dirs += vapidir;
code_context.vapi_directories = dirs;
}
/* Caller is expected to hold code_context lock */
private void add_girdir_locked (string girdir)
{
var dirs = code_context.gir_directories;
if (girdir in dirs)
return;
dirs += girdir;
code_context.gir_directories = dirs;
}
/* Caller is expected to hold code_context lock */
private void add_metadatadir_locked (string metadata_dir)
{
var dirs = code_context.metadata_directories;
if (metadata_dir in dirs)
return;
dirs += metadata_dir;
code_context.metadata_directories = dirs;
}
static string? get_versioned_vapidir ()