File: Protocol\Diagnostic.cs
Web Access
Project: src\src\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj (Microsoft.CodeAnalysis.LanguageServer.Protocol)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
namespace Roslyn.LanguageServer.Protocol;
 
using System;
using System.Linq;
using System.Text.Json.Serialization;
using Roslyn.Utilities;
 
/// <summary>
/// Class which represents a source code diagnostic message.
///
/// See the <see href="https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic">Language Server Protocol specification</see> for additional information.
/// </summary>
internal class Diagnostic : IEquatable<Diagnostic>
{
    /// <summary>
    /// Gets or sets the source code range.
    /// </summary>
    [JsonPropertyName("range")]
    public Range Range
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets the diagnostic severity.
    /// </summary>
    [JsonPropertyName("severity")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public DiagnosticSeverity? Severity
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets the diagnostic's code, which usually appear in the user interface.
    /// </summary>
    /// <remarks>
    /// The value can be an <see cref="int"/>, <see cref="string"/>.
    /// </remarks>
    [JsonPropertyName("code")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public SumType<int, string>? Code
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets an optional value that describes the error code.
    /// </summary>
    /// <remarks>Since LSP 3.16</remarks>
    [JsonPropertyName("codeDescription")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public CodeDescription? CodeDescription
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets a human-readable string describing the source of this
    /// diagnostic, e.g. 'typescript' or 'super lint'. It usually appears in the user interface.
    /// </summary>
    [JsonPropertyName("source")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Source
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets the diagnostic's message.
    /// </summary>
    [JsonPropertyName("message")]
    public string Message
    {
        get;
        set;
    }
 
    /// <summary>
    /// Additional metadata about the diagnostic.
    /// </summary>
    /// <remarks>Since 3.16</remarks>
    [JsonPropertyName("tags")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public DiagnosticTag[]? Tags
    {
        get;
        set;
    }
 
    /// <summary>
    /// Gets or sets the diagnostic related information
    /// </summary>
    [JsonPropertyName("relatedInformation")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public DiagnosticRelatedInformation[]? RelatedInformation
    {
        get;
        set;
    }
 
    /// <summary>
    /// Data that is preserved for a <c>textDocument/codeAction</c> request
    /// </summary>
    /// <remarks>Since 3.16</remarks>
    [JsonPropertyName("data")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public object? Data { get; init; }
 
    public static bool operator ==(Diagnostic? value1, Diagnostic? value2)
    {
        if (ReferenceEquals(value1, value2))
        {
            return true;
        }
 
        // Is null?
        if (ReferenceEquals(null, value2))
        {
            return false;
        }
 
        return value1?.Equals(value2) ?? false;
    }
 
    public static bool operator !=(Diagnostic? value1, Diagnostic? value2)
    {
        return !(value1 == value2);
    }
 
    /// <inheritdoc/>
    public bool Equals(Diagnostic other)
    {
        return other is not null
            && this.Range == other.Range
            && this.Severity == other.Severity
            && object.Equals(this.Code, other.Code)
            && this.CodeDescription == other.CodeDescription
            && string.Equals(this.Source, other.Source, StringComparison.Ordinal)
            && string.Equals(this.Message, other.Message, StringComparison.Ordinal)
            && (this.Tags == null
                    ? other.Tags == null
                    : this.Tags.Equals(other.Tags) || this.Tags.SequenceEqual(other.Tags))
            && (this.Data is null
                    ? other.Data is null
                    : this.Data.Equals(other.Data));
    }
 
    /// <inheritdoc/>
    public override bool Equals(object obj)
    {
        if (obj is Diagnostic other)
        {
            return this.Equals(other);
        }
        else
        {
            return false;
        }
    }
 
    /// <inheritdoc/>
    public override int GetHashCode() =>
#if NET
        HashCode.Combine(Range, Severity, Code, Source, Message, Hash.CombineValues(Tags), CodeDescription, Data);
#else
        Hash.Combine(Range,
        Hash.Combine((int)(Severity ?? 0),
        Hash.Combine(Code?.GetHashCode() ?? 0,
        Hash.Combine(Source,
        Hash.Combine(Message,
        Hash.Combine(Hash.CombineValues(Tags),
        Hash.Combine(CodeDescription?.GetHashCode() ?? 0, Data?.GetHashCode() ?? 0)))))));
#endif
}