777 lines
20 KiB
C
777 lines
20 KiB
C
/* ide-diagnostic.c
|
|
*
|
|
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#define G_LOG_DOMAIN "ide-diagnostic"
|
|
|
|
#include "config.h"
|
|
|
|
#include "ide-code-enums.h"
|
|
#include "ide-diagnostic.h"
|
|
#include "ide-location.h"
|
|
#include "ide-range.h"
|
|
#include "ide-text-edit.h"
|
|
|
|
typedef struct
|
|
{
|
|
IdeDiagnosticSeverity severity;
|
|
guint hash;
|
|
gchar *text;
|
|
IdeLocation *location;
|
|
GPtrArray *ranges;
|
|
GPtrArray *fixits;
|
|
IdeMarkedKind marked_kind;
|
|
} IdeDiagnosticPrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_DISPLAY_TEXT,
|
|
PROP_LOCATION,
|
|
PROP_SEVERITY,
|
|
PROP_TEXT,
|
|
N_PROPS
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (IdeDiagnostic, ide_diagnostic, IDE_TYPE_OBJECT)
|
|
|
|
static GParamSpec *properties [N_PROPS];
|
|
|
|
static void
|
|
ide_diagnostic_set_location (IdeDiagnostic *self,
|
|
IdeLocation *location)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
|
|
g_set_object (&priv->location, location);
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_set_text (IdeDiagnostic *self,
|
|
const gchar *text)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
|
|
priv->text = g_strdup (text);
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_set_severity (IdeDiagnostic *self,
|
|
IdeDiagnosticSeverity severity)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
|
|
priv->severity = severity;
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_finalize (GObject *object)
|
|
{
|
|
IdeDiagnostic *self = (IdeDiagnostic *)object;
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_clear_pointer (&priv->text, g_free);
|
|
g_clear_pointer (&priv->ranges, g_ptr_array_unref);
|
|
g_clear_pointer (&priv->fixits, g_ptr_array_unref);
|
|
g_clear_object (&priv->location);
|
|
|
|
G_OBJECT_CLASS (ide_diagnostic_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
IdeDiagnostic *self = IDE_DIAGNOSTIC (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_LOCATION:
|
|
g_value_set_object (value, ide_diagnostic_get_location (self));
|
|
break;
|
|
|
|
case PROP_SEVERITY:
|
|
g_value_set_enum (value, ide_diagnostic_get_severity (self));
|
|
break;
|
|
|
|
case PROP_DISPLAY_TEXT:
|
|
g_value_take_string (value, ide_diagnostic_get_text_for_display (self));
|
|
break;
|
|
|
|
case PROP_TEXT:
|
|
g_value_set_string (value, ide_diagnostic_get_text (self));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
IdeDiagnostic *self = IDE_DIAGNOSTIC (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_LOCATION:
|
|
ide_diagnostic_set_location (self, g_value_get_object (value));
|
|
break;
|
|
|
|
case PROP_SEVERITY:
|
|
ide_diagnostic_set_severity (self, g_value_get_enum (value));
|
|
break;
|
|
|
|
case PROP_TEXT:
|
|
ide_diagnostic_set_text (self, g_value_get_string (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_class_init (IdeDiagnosticClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = ide_diagnostic_finalize;
|
|
object_class->get_property = ide_diagnostic_get_property;
|
|
object_class->set_property = ide_diagnostic_set_property;
|
|
|
|
properties [PROP_LOCATION] =
|
|
g_param_spec_object ("location",
|
|
"Location",
|
|
"The location of the diagnostic",
|
|
IDE_TYPE_LOCATION,
|
|
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_SEVERITY] =
|
|
g_param_spec_enum ("severity",
|
|
"Severity",
|
|
"The severity of the diagnostic",
|
|
IDE_TYPE_DIAGNOSTIC_SEVERITY,
|
|
IDE_DIAGNOSTIC_IGNORED,
|
|
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_TEXT] =
|
|
g_param_spec_string ("text",
|
|
"Text",
|
|
"The text of the diagnostic",
|
|
NULL,
|
|
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_DISPLAY_TEXT] =
|
|
g_param_spec_string ("display-text",
|
|
"Display Text",
|
|
"The text formatted for display",
|
|
NULL,
|
|
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
|
}
|
|
|
|
static void
|
|
ide_diagnostic_init (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
priv->marked_kind = IDE_MARKED_KIND_PLAINTEXT;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_get_location:
|
|
* @self: a #IdeDiagnostic
|
|
*
|
|
* Gets the location of the diagnostic.
|
|
*
|
|
* See also: ide_diagnostic_get_range().
|
|
*
|
|
* Returns: (transfer none) (nullable): an #IdeLocation or %NULL
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
IdeLocation *
|
|
ide_diagnostic_get_location (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
if (priv->location != NULL)
|
|
return priv->location;
|
|
|
|
if (priv->ranges != NULL && priv->ranges->len > 0)
|
|
{
|
|
IdeRange *range = g_ptr_array_index (priv->ranges, 0);
|
|
return ide_range_get_begin (range);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_get_file:
|
|
* @self: a #IdeDiagnostic
|
|
*
|
|
* Gets the file containing the diagnostic, if any.
|
|
*
|
|
* Returns: (transfer none) (nullable): an #IdeLocation or %NULL
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
GFile *
|
|
ide_diagnostic_get_file (IdeDiagnostic *self)
|
|
{
|
|
IdeLocation *location;
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
if ((location = ide_diagnostic_get_location (self)))
|
|
return ide_location_get_file (location);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_get_text_for_display:
|
|
* @self: an #IdeDiagnostic
|
|
*
|
|
* This creates a new string that is formatted using the diagnostics
|
|
* line number, column, severity, and message text in the format
|
|
* "line:column: severity: message".
|
|
*
|
|
* This can be convenient when wanting to quickly display a
|
|
* diagnostic such as in a tooltip.
|
|
*
|
|
* Returns: (transfer full): string containing the text formatted for
|
|
* display.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
gchar *
|
|
ide_diagnostic_get_text_for_display (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
IdeLocation *location;
|
|
const gchar *severity;
|
|
guint line = 0;
|
|
guint column = 0;
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
severity = ide_diagnostic_severity_to_string (priv->severity);
|
|
location = ide_diagnostic_get_location (self);
|
|
|
|
if (location != NULL)
|
|
{
|
|
line = ide_location_get_line (location) + 1;
|
|
column = ide_location_get_line_offset (location) + 1;
|
|
}
|
|
|
|
return g_strdup_printf ("%u:%u: %s: %s", line, column, severity, priv->text);
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_severity_to_string:
|
|
* @severity: a #IdeDiagnosticSeverity
|
|
*
|
|
* Returns a string suitable to represent the diagnsotic severity.
|
|
*
|
|
* Returns: a string
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
const gchar *
|
|
ide_diagnostic_severity_to_string (IdeDiagnosticSeverity severity)
|
|
{
|
|
switch (severity)
|
|
{
|
|
case IDE_DIAGNOSTIC_IGNORED:
|
|
return "ignored";
|
|
|
|
case IDE_DIAGNOSTIC_NOTE:
|
|
return "note";
|
|
|
|
case IDE_DIAGNOSTIC_UNUSED:
|
|
return "unused";
|
|
|
|
case IDE_DIAGNOSTIC_DEPRECATED:
|
|
return "deprecated";
|
|
|
|
case IDE_DIAGNOSTIC_WARNING:
|
|
return "warning";
|
|
|
|
case IDE_DIAGNOSTIC_ERROR:
|
|
return "error";
|
|
|
|
case IDE_DIAGNOSTIC_FATAL:
|
|
return "fatal";
|
|
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
guint
|
|
ide_diagnostic_get_n_ranges (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), 0);
|
|
|
|
return priv->ranges ? priv->ranges->len : 0;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_get_range:
|
|
*
|
|
* Retrieves the range found at @index. It is a programming error to call this
|
|
* function with a value greater or equal to ide_diagnostic_get_n_ranges().
|
|
*
|
|
* Returns: (transfer none) (nullable): An #IdeRange
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
IdeRange *
|
|
ide_diagnostic_get_range (IdeDiagnostic *self,
|
|
guint index)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
if (priv->ranges)
|
|
{
|
|
if (index < priv->ranges->len)
|
|
return g_ptr_array_index (priv->ranges, index);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
guint
|
|
ide_diagnostic_get_n_fixits (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), 0);
|
|
|
|
return (priv->fixits != NULL) ? priv->fixits->len : 0;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_get_fixit:
|
|
* @self: an #IdeDiagnostic.
|
|
* @index: The index of the fixit.
|
|
*
|
|
* Gets the fixit denoted by @index. This value should be less than the value
|
|
* returned from ide_diagnostic_get_n_fixits().
|
|
*
|
|
* Returns: (transfer none) (nullable): An #IdeTextEdit
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
IdeTextEdit *
|
|
ide_diagnostic_get_fixit (IdeDiagnostic *self,
|
|
guint index)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (self, NULL);
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
g_return_val_if_fail (priv->fixits, NULL);
|
|
|
|
if (priv->fixits != NULL)
|
|
{
|
|
if (index < priv->fixits->len)
|
|
return g_ptr_array_index (priv->fixits, index);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
gint
|
|
ide_diagnostic_compare (IdeDiagnostic *a,
|
|
IdeDiagnostic *b)
|
|
{
|
|
IdeDiagnosticPrivate *priv_a = ide_diagnostic_get_instance_private (a);
|
|
IdeDiagnosticPrivate *priv_b = ide_diagnostic_get_instance_private (b);
|
|
gint ret;
|
|
|
|
g_assert (IDE_IS_DIAGNOSTIC (a));
|
|
g_assert (IDE_IS_DIAGNOSTIC (b));
|
|
|
|
/* Severity is 0..N where N is more important. So reverse comparator. */
|
|
if (0 != (ret = (gint)priv_b->severity - (gint)priv_a->severity))
|
|
return ret;
|
|
|
|
if (priv_a->location && priv_b->location)
|
|
{
|
|
if (0 != (ret = ide_location_compare (priv_a->location, priv_b->location)))
|
|
return ret;
|
|
}
|
|
|
|
return g_strcmp0 (priv_a->text, priv_b->text);
|
|
}
|
|
|
|
const gchar *
|
|
ide_diagnostic_get_text (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
return priv->text;
|
|
}
|
|
|
|
IdeDiagnosticSeverity
|
|
ide_diagnostic_get_severity (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), 0);
|
|
|
|
return priv->severity;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_add_range:
|
|
* @self: a #IdeDiagnostic
|
|
* @range: an #IdeRange
|
|
*
|
|
* Adds a source range to the diagnostic.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_diagnostic_add_range (IdeDiagnostic *self,
|
|
IdeRange *range)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
g_return_if_fail (IDE_IS_RANGE (range));
|
|
|
|
if (priv->ranges == NULL)
|
|
priv->ranges = g_ptr_array_new_with_free_func (g_object_unref);
|
|
g_ptr_array_add (priv->ranges, g_object_ref (range));
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_take_range:
|
|
* @self: a #IdeDiagnostic
|
|
* @range: (transfer full): an #IdeRange
|
|
*
|
|
* Adds a source range to the diagnostic, but does not increment the
|
|
* reference count of @range.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_diagnostic_take_range (IdeDiagnostic *self,
|
|
IdeRange *range)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
g_return_if_fail (IDE_IS_RANGE (range));
|
|
|
|
if (priv->ranges == NULL)
|
|
priv->ranges = g_ptr_array_new_with_free_func (g_object_unref);
|
|
g_ptr_array_add (priv->ranges, g_steal_pointer (&range));
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_add_fixit:
|
|
* @self: a #IdeDiagnostic
|
|
* @fixit: an #IdeTextEdit
|
|
*
|
|
* Adds a source fixit to the diagnostic.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_diagnostic_add_fixit (IdeDiagnostic *self,
|
|
IdeTextEdit *fixit)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
g_return_if_fail (IDE_IS_TEXT_EDIT (fixit));
|
|
|
|
if (priv->fixits == NULL)
|
|
priv->fixits = g_ptr_array_new_with_free_func (g_object_unref);
|
|
g_ptr_array_add (priv->fixits, g_object_ref (fixit));
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_take_fixit:
|
|
* @self: a #IdeDiagnostic
|
|
* @fixit: (transfer full): an #IdeTextEdit
|
|
*
|
|
* Adds a source fixit to the diagnostic, but does not increment the
|
|
* reference count of @fixit.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_diagnostic_take_fixit (IdeDiagnostic *self,
|
|
IdeTextEdit *fixit)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
g_return_if_fail (IDE_IS_TEXT_EDIT (fixit));
|
|
|
|
if (priv->fixits == NULL)
|
|
priv->fixits = g_ptr_array_new_with_free_func (g_object_unref);
|
|
g_ptr_array_add (priv->fixits, g_steal_pointer (&fixit));
|
|
}
|
|
|
|
IdeDiagnostic *
|
|
ide_diagnostic_new (IdeDiagnosticSeverity severity,
|
|
const gchar *message,
|
|
IdeLocation *location)
|
|
{
|
|
return g_object_new (IDE_TYPE_DIAGNOSTIC,
|
|
"severity", severity,
|
|
"location", location,
|
|
"text", message,
|
|
NULL);
|
|
}
|
|
|
|
guint
|
|
ide_diagnostic_hash (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), 0);
|
|
|
|
if (priv->hash == 0)
|
|
{
|
|
guint hash = g_str_hash (priv->text ?: "");
|
|
if (priv->location)
|
|
hash ^= ide_location_hash (priv->location);
|
|
if (priv->fixits)
|
|
hash ^= g_int_hash (&priv->fixits->len);
|
|
if (priv->ranges)
|
|
hash ^= g_int_hash (&priv->ranges->len);
|
|
priv->hash = hash;
|
|
}
|
|
|
|
return priv->hash;
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_to_variant:
|
|
* @self: a #IdeDiagnostic
|
|
*
|
|
* Creates a #GVariant to represent the diagnostic. This can be useful when
|
|
* working in subprocesses to serialize the diagnostic.
|
|
*
|
|
* This function will never return a floating variant.
|
|
*
|
|
* Returns: (transfer full): a #GVariant
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
GVariant *
|
|
ide_diagnostic_to_variant (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
GVariantDict dict;
|
|
|
|
g_return_val_if_fail (self != NULL, NULL);
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), NULL);
|
|
|
|
g_variant_dict_init (&dict, NULL);
|
|
|
|
g_variant_dict_insert (&dict, "text", "s", priv->text ?: "");
|
|
g_variant_dict_insert (&dict, "severity", "u", priv->severity);
|
|
|
|
if (priv->location != NULL)
|
|
{
|
|
g_autoptr(GVariant) vloc = ide_location_to_variant (priv->location);
|
|
|
|
if (vloc != NULL)
|
|
g_variant_dict_insert_value (&dict, "location", vloc);
|
|
}
|
|
|
|
if (priv->ranges != NULL && priv->ranges->len > 0)
|
|
{
|
|
GVariantBuilder builder;
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
|
|
|
|
for (guint i = 0; i < priv->ranges->len; i++)
|
|
{
|
|
IdeRange *range = g_ptr_array_index (priv->ranges, i);
|
|
g_autoptr(GVariant) vrange = ide_range_to_variant (range);
|
|
|
|
g_variant_builder_add_value (&builder, vrange);
|
|
}
|
|
|
|
g_variant_dict_insert_value (&dict, "ranges", g_variant_builder_end (&builder));
|
|
}
|
|
|
|
if (priv->fixits != NULL && priv->fixits->len > 0)
|
|
{
|
|
GVariantBuilder builder;
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
|
|
|
|
for (guint i = 0; i < priv->fixits->len; i++)
|
|
{
|
|
IdeTextEdit *fixit = g_ptr_array_index (priv->fixits, i);
|
|
g_autoptr(GVariant) vfixit = ide_text_edit_to_variant (fixit);
|
|
|
|
g_variant_builder_add_value (&builder, vfixit);
|
|
}
|
|
|
|
g_variant_dict_insert_value (&dict, "fixits", g_variant_builder_end (&builder));
|
|
}
|
|
|
|
return g_variant_take_ref (g_variant_dict_end (&dict));
|
|
}
|
|
|
|
/**
|
|
* ide_diagnostic_new_from_variant:
|
|
* @variant: (nullable): a #GVariant or %NULL
|
|
*
|
|
* Creates a new #GVariant using the data contained in @variant.
|
|
*
|
|
* If @variant is %NULL or Upon failure, %NULL is returned.
|
|
*
|
|
* Returns: (nullable) (transfer full): a #IdeDiagnostic or %NULL
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
IdeDiagnostic *
|
|
ide_diagnostic_new_from_variant (GVariant *variant)
|
|
{
|
|
g_autoptr(IdeLocation) loc = NULL;
|
|
g_autoptr(GVariant) vloc = NULL;
|
|
g_autoptr(GVariant) unboxed = NULL;
|
|
g_autoptr(GVariant) ranges = NULL;
|
|
g_autoptr(GVariant) fixits = NULL;
|
|
IdeDiagnostic *self;
|
|
GVariantDict dict;
|
|
GVariantIter iter;
|
|
const gchar *text;
|
|
guint32 severity;
|
|
|
|
if (variant == NULL)
|
|
return NULL;
|
|
|
|
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARIANT))
|
|
variant = unboxed = g_variant_get_variant (variant);
|
|
|
|
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT))
|
|
return NULL;
|
|
|
|
g_variant_dict_init (&dict, variant);
|
|
|
|
if (!g_variant_dict_lookup (&dict, "text", "&s", &text))
|
|
text = NULL;
|
|
|
|
if (!g_variant_dict_lookup (&dict, "severity", "u", &severity))
|
|
severity = 0;
|
|
|
|
if ((vloc = g_variant_dict_lookup_value (&dict, "location", NULL)))
|
|
loc = ide_location_new_from_variant (vloc);
|
|
|
|
if (!(self = ide_diagnostic_new (severity, text, loc)))
|
|
goto failure;
|
|
|
|
/* Ranges */
|
|
if ((ranges = g_variant_dict_lookup_value (&dict, "ranges", NULL)))
|
|
{
|
|
GVariant *vrange;
|
|
|
|
g_variant_iter_init (&iter, ranges);
|
|
|
|
while ((vrange = g_variant_iter_next_value (&iter)))
|
|
{
|
|
IdeRange *range;
|
|
|
|
if ((range = ide_range_new_from_variant (vrange)))
|
|
ide_diagnostic_take_range (self, g_steal_pointer (&range));
|
|
|
|
g_variant_unref (vrange);
|
|
}
|
|
}
|
|
|
|
/* Fixits */
|
|
if ((fixits = g_variant_dict_lookup_value (&dict, "fixits", NULL)))
|
|
{
|
|
GVariant *vfixit;
|
|
|
|
g_variant_iter_init (&iter, fixits);
|
|
|
|
while ((vfixit = g_variant_iter_next_value (&iter)))
|
|
{
|
|
IdeTextEdit *fixit;
|
|
|
|
if ((fixit = ide_text_edit_new_from_variant (vfixit)))
|
|
ide_diagnostic_take_fixit (self, g_steal_pointer (&fixit));
|
|
|
|
g_variant_unref (vfixit);
|
|
}
|
|
}
|
|
|
|
failure:
|
|
|
|
g_variant_dict_clear (&dict);
|
|
|
|
return self;
|
|
}
|
|
|
|
IdeMarkedKind
|
|
ide_diagnostic_get_marked_kind (IdeDiagnostic *self)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_DIAGNOSTIC (self), IDE_MARKED_KIND_PLAINTEXT);
|
|
|
|
return priv->marked_kind;
|
|
}
|
|
|
|
void
|
|
ide_diagnostic_set_marked_kind (IdeDiagnostic *self,
|
|
IdeMarkedKind marked_kind)
|
|
{
|
|
IdeDiagnosticPrivate *priv = ide_diagnostic_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_DIAGNOSTIC (self));
|
|
|
|
priv->marked_kind = marked_kind;
|
|
}
|