diff --git a/debug-adapter-protocol.sha.txt b/debug-adapter-protocol.sha.txt new file mode 100644 index 000000000..38cf3d25f --- /dev/null +++ b/debug-adapter-protocol.sha.txt @@ -0,0 +1,4 @@ +-- This is the last commit we caught up with https://github.com/microsoft/debug-adapter-protocol/commits/gh-pages +lastSha: fd7d38013c9e13e92c0ca4dfa83048d355cb057d + +https://github.com/microsoft/debug-adapter-protocol/compare/fd7d38013c9e13e92c0ca4dfa83048d355cb057d..gh-pages diff --git a/src/Dap.Client/DebugAdapterClientOptions.cs b/src/Dap.Client/DebugAdapterClientOptions.cs index 027c89750..d8febbee6 100644 --- a/src/Dap.Client/DebugAdapterClientOptions.cs +++ b/src/Dap.Client/DebugAdapterClientOptions.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json.Linq; using OmniSharp.Extensions.DebugAdapter.Protocol; using OmniSharp.Extensions.DebugAdapter.Protocol.Client; +using OmniSharp.Extensions.DebugAdapter.Protocol.Models; using OmniSharp.Extensions.DebugAdapter.Protocol.Requests; using OmniSharp.Extensions.DebugAdapter.Shared; using OmniSharp.Extensions.JsonRpc; @@ -24,12 +25,13 @@ public DebugAdapterClientOptions() public string? Locale { get; set; } public bool LinesStartAt1 { get; set; } public bool ColumnsStartAt1 { get; set; } - public string? PathFormat { get; set; } + public PathFormat? PathFormat { get; set; } public bool SupportsVariableType { get; set; } public bool SupportsVariablePaging { get; set; } public bool SupportsRunInTerminalRequest { get; set; } public bool SupportsMemoryReferences { get; set; } public bool SupportsProgressReporting { get; set; } + public bool SupportsInvalidatedEvent { get; set; } IDebugAdapterClientRegistry IJsonRpcHandlerRegistry.AddHandler(string method, IJsonRpcHandler handler, JsonRpcHandlerOptions? options) => AddHandler(method, handler, options); diff --git a/src/Dap.Protocol/Events/EventNames.cs b/src/Dap.Protocol/Events/EventNames.cs index 0edf45262..01ea38658 100644 --- a/src/Dap.Protocol/Events/EventNames.cs +++ b/src/Dap.Protocol/Events/EventNames.cs @@ -4,6 +4,7 @@ public static class EventNames { public const string Initialized = "initialized"; public const string Stopped = "stopped"; + public const string Invalidated = "invalidated"; public const string Continued = "continued"; public const string Exited = "exited"; public const string Terminated = "terminated"; diff --git a/src/Dap.Protocol/Feature/Events/BreakpointFeature.cs b/src/Dap.Protocol/Feature/Events/BreakpointFeature.cs index 90f035d68..e5668b8f5 100644 --- a/src/Dap.Protocol/Feature/Events/BreakpointFeature.cs +++ b/src/Dap.Protocol/Feature/Events/BreakpointFeature.cs @@ -77,6 +77,7 @@ public record Breakpoint public int? Offset { get; init; } } } + namespace Events { [Parallel] @@ -92,12 +93,21 @@ public record BreakpointEvent : IRequest /// The reason for the event. /// Values: 'changed', 'new', 'removed', etc. /// - public string Reason { get; init; } + public BreakpointEventReason Reason { get; init; } /// /// The 'id' attribute is used to find the target breakpoint and the other attributes are used as the new values. /// public Breakpoint Breakpoint { get; init; } } + + + [StringEnum] + public readonly partial struct BreakpointEventReason + { + public static BreakpointEventReason Changed { get; } = new BreakpointEventReason("changed"); + public static BreakpointEventReason New { get; } = new BreakpointEventReason("new"); + public static BreakpointEventReason Removed { get; } = new BreakpointEventReason("removed"); + } } } diff --git a/src/Dap.Protocol/Feature/Events/CapabilitiesFeature.cs b/src/Dap.Protocol/Feature/Events/CapabilitiesFeature.cs index 351270700..77699c0b9 100644 --- a/src/Dap.Protocol/Feature/Events/CapabilitiesFeature.cs +++ b/src/Dap.Protocol/Feature/Events/CapabilitiesFeature.cs @@ -221,8 +221,16 @@ public record Capabilities /// [Optional] public bool SupportsInstructionBreakpoints { get; set; } + + /// + /// The debug adapter supports 'filterOptions' as an argument on the + /// 'setExceptionBreakpoints' request. + /// + [Optional] + public bool SupportsExceptionFilterOptions { get; set; } } } + namespace Events { [Parallel] diff --git a/src/Dap.Protocol/Feature/Events/InvalidatedFeature.cs b/src/Dap.Protocol/Feature/Events/InvalidatedFeature.cs new file mode 100644 index 000000000..91400276f --- /dev/null +++ b/src/Dap.Protocol/Feature/Events/InvalidatedFeature.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using MediatR; +using Newtonsoft.Json; +using OmniSharp.Extensions.DebugAdapter.Protocol.Models; +using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; +using OmniSharp.Extensions.JsonRpc; +using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; + +// ReSharper disable once CheckNamespace +namespace OmniSharp.Extensions.DebugAdapter.Protocol +{ + namespace Events + { + [Parallel] + [Method(EventNames.Invalidated, Direction.ServerToClient)] + [ + GenerateHandler, + GenerateHandlerMethods, + GenerateRequestMethods + ] + public record InvalidatedEvent : IRequest + { + /// + /// Optional set of logical areas that got invalidated. This property has a + /// hint characteristic: a client can only be expected to make a 'best + /// effort' in honouring the areas but there are no guarantees. If this + /// property is missing, empty, or if values are not understand the client + /// should assume a single value 'all'. + /// + [Optional] + public Container? Areas { get; init; } + + /// + /// If specified, the client only needs to refetch data related to this + /// thread. + /// + [Optional] + public int? ThreadId { get; init; } + + /// + /// If specified, the client only needs to refetch data related to this stack + /// frame (and the 'threadId' is ignored). + /// + [Optional] + public int? StackFrameId { get; init; } + } + } +} diff --git a/src/Dap.Protocol/Feature/Events/LoadedSourceFeature.cs b/src/Dap.Protocol/Feature/Events/LoadedSourceFeature.cs index 48ad4b3ae..fd48009a5 100644 --- a/src/Dap.Protocol/Feature/Events/LoadedSourceFeature.cs +++ b/src/Dap.Protocol/Feature/Events/LoadedSourceFeature.cs @@ -32,10 +32,12 @@ public record LoadedSourceEvent : IRequest public Source Source { get; init; } } - [JsonConverter(typeof(StringEnumConverter))] - public enum LoadedSourceReason + [StringEnum] + public readonly partial struct LoadedSourceReason { - New, Changed, Removed + public static LoadedSourceReason Changed { get; } = new LoadedSourceReason("changed"); + public static LoadedSourceReason New { get; } = new LoadedSourceReason("new"); + public static LoadedSourceReason Removed { get; } = new LoadedSourceReason("removed"); } } } diff --git a/src/Dap.Protocol/Feature/Events/ModuleFeature.cs b/src/Dap.Protocol/Feature/Events/ModuleFeature.cs index 7a1f48bcc..2406a57fc 100644 --- a/src/Dap.Protocol/Feature/Events/ModuleFeature.cs +++ b/src/Dap.Protocol/Feature/Events/ModuleFeature.cs @@ -32,10 +32,12 @@ public record ModuleEvent : IRequest public Module Module { get; init; } } - [JsonConverter(typeof(StringEnumConverter))] - public enum ModuleEventReason + [StringEnum] + public readonly partial struct ModuleEventReason { - New, Changed, Removed + public static ModuleEventReason Changed { get; } = new ModuleEventReason("changed"); + public static ModuleEventReason New { get; } = new ModuleEventReason("new"); + public static ModuleEventReason Removed { get; } = new ModuleEventReason("removed"); } } } diff --git a/src/Dap.Protocol/Feature/Events/OutputFeature.cs b/src/Dap.Protocol/Feature/Events/OutputFeature.cs index bae0db92b..8c75441b5 100644 --- a/src/Dap.Protocol/Feature/Events/OutputFeature.cs +++ b/src/Dap.Protocol/Feature/Events/OutputFeature.cs @@ -26,7 +26,7 @@ public record OutputEvent : IRequest /// Values: 'console', 'stdout', 'stderr', 'telemetry', etc. /// [Optional] - public string? Category { get; init; } + public OutputEventCategory Category { get; init; } = OutputEventCategory.Console; /// /// The output to report. @@ -34,7 +34,29 @@ public record OutputEvent : IRequest public string Output { get; init; } /// - /// If an attribute 'variablesReference' exists and its value is > 0, the output contains objects which can be retrieved by passing 'variablesReference' to the 'variables' request. + /// Support for keeping an output log organized by grouping related messages. + /// Values: + /// 'start': Start a new group in expanded mode. Subsequent output events are + /// members of the group and should be shown indented. + /// The 'output' attribute becomes the name of the group and is not indented. + /// 'startCollapsed': Start a new group in collapsed mode. Subsequent output + /// events are members of the group and should be shown indented (as soon as + /// the group is expanded). + /// The 'output' attribute becomes the name of the group and is not indented. + /// 'end': End the current group and decreases the indentation of subsequent + /// output events. + /// A non empty 'output' attribute is shown as the unindented end of the + /// group. + /// etc. + /// + [Optional] + public OutputEventGroup Group { get; set; } + + /// + /// If an attribute 'variablesReference' exists and its value is > 0, the + /// output contains objects which can be retrieved by passing + /// 'variablesReference' to the 'variables' request. The value should be less + /// than or equal to 2147483647 (2^31-1). /// [Optional] public long? VariablesReference { get; init; } @@ -63,5 +85,22 @@ public record OutputEvent : IRequest [Optional] public JToken? Data { get; init; } } + + [StringEnum] + public readonly partial struct OutputEventCategory + { + public static OutputEventCategory Console { get; } = new OutputEventCategory("console"); + public static OutputEventCategory StandardOutput { get; } = new OutputEventCategory("stdout"); + public static OutputEventCategory StandardError { get; } = new OutputEventCategory("stderr"); + public static OutputEventCategory Telemetry { get; } = new OutputEventCategory("telemetry"); + } + + [StringEnum] + public readonly partial struct OutputEventGroup + { + public static OutputEventGroup Start { get; } = new OutputEventGroup("start"); + public static OutputEventGroup StartCollapsed { get; } = new OutputEventGroup("startCollapsed"); + public static OutputEventGroup End { get; } = new OutputEventGroup("end"); + } } } diff --git a/src/Dap.Protocol/Feature/Events/ProcessFeature.cs b/src/Dap.Protocol/Feature/Events/ProcessFeature.cs index c896f0cd8..66c5ee249 100644 --- a/src/Dap.Protocol/Feature/Events/ProcessFeature.cs +++ b/src/Dap.Protocol/Feature/Events/ProcessFeature.cs @@ -54,10 +54,12 @@ public record ProcessEvent : IRequest public long? PointerSize { get; init; } } - [JsonConverter(typeof(StringEnumConverter))] - public enum ProcessEventStartMethod + [StringEnum] + public readonly partial struct ProcessEventStartMethod { - Launch, Attach, AttachForSuspendedLaunch + public static ProcessEventStartMethod Launch { get; } = new ProcessEventStartMethod("launch"); + public static ProcessEventStartMethod Attach { get; } = new ProcessEventStartMethod("attach"); + public static ProcessEventStartMethod AttachForSuspendedLaunch { get; } = new ProcessEventStartMethod("attachForSuspendedLaunch"); } } } diff --git a/src/Dap.Protocol/Feature/Events/StoppedFeature.cs b/src/Dap.Protocol/Feature/Events/StoppedFeature.cs index 36596b5fb..f4d954c09 100644 --- a/src/Dap.Protocol/Feature/Events/StoppedFeature.cs +++ b/src/Dap.Protocol/Feature/Events/StoppedFeature.cs @@ -1,9 +1,16 @@ -using System.Threading; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading; using System.Threading.Tasks; using MediatR; +using Newtonsoft.Json; using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; // ReSharper disable once CheckNamespace namespace OmniSharp.Extensions.DebugAdapter.Protocol @@ -24,7 +31,7 @@ public record StoppedEvent : IRequest /// For backward compatibility this string is shown in the UI if the 'description' attribute is missing (but it must not be translated). /// Values: 'step', 'breakpoint', 'exception', 'pause', 'entry', 'goto', 'function breakpoint', 'data breakpoint', etc. /// - public string Reason { get; init; } + public StoppedEventReason Reason { get; init; } /// /// The full reason for the event, e.g. 'Paused on exception'. This string is shown in the UI as is and must be translated. @@ -58,5 +65,19 @@ public record StoppedEvent : IRequest [Optional] public bool AllThreadsStopped { get; init; } } + + [StringEnum] + public readonly partial struct StoppedEventReason + { + public static StoppedEventReason Step { get; } = new StoppedEventReason("step"); + public static StoppedEventReason Breakpoint { get; } = new StoppedEventReason("breakpoint"); + public static StoppedEventReason Exception { get; } = new StoppedEventReason("exception"); + public static StoppedEventReason Pause { get; } = new StoppedEventReason("pause"); + public static StoppedEventReason Entry { get; } = new StoppedEventReason("entry"); + public static StoppedEventReason Goto { get; } = new StoppedEventReason("goto"); + public static StoppedEventReason FunctionBreakpoint { get; } = new StoppedEventReason("function breakpoint"); + public static StoppedEventReason DataBreakpoint { get; } = new StoppedEventReason("data breakpoint"); + public static StoppedEventReason InstructionBreakpoint { get; } = new StoppedEventReason("instruction breakpoint"); + } } } diff --git a/src/Dap.Protocol/Feature/Events/ThreadFeature.cs b/src/Dap.Protocol/Feature/Events/ThreadFeature.cs index a28bfe5aa..217f388d8 100644 --- a/src/Dap.Protocol/Feature/Events/ThreadFeature.cs +++ b/src/Dap.Protocol/Feature/Events/ThreadFeature.cs @@ -1,8 +1,16 @@ -using System.Threading; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading; using System.Threading.Tasks; using MediatR; +using Newtonsoft.Json; +using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; // ReSharper disable once CheckNamespace namespace OmniSharp.Extensions.DebugAdapter.Protocol @@ -22,12 +30,19 @@ public record ThreadEvent : IRequest /// The reason for the event. /// Values: 'started', 'exited', etc. /// - public string Reason { get; init; } + public ThreadEventReason Reason { get; init; } /// /// The identifier of the thread. /// public long ThreadId { get; init; } } + + [StringEnum] + public readonly partial struct ThreadEventReason + { + public static ThreadEventReason Started { get; } = new ThreadEventReason("started"); + public static ThreadEventReason Exited { get; } = new ThreadEventReason("exited"); + } } } diff --git a/src/Dap.Protocol/Feature/Requests/DisassembleFeature.cs b/src/Dap.Protocol/Feature/Requests/DisassembleFeature.cs index cbe89a5bf..44dec2a10 100644 --- a/src/Dap.Protocol/Feature/Requests/DisassembleFeature.cs +++ b/src/Dap.Protocol/Feature/Requests/DisassembleFeature.cs @@ -85,7 +85,7 @@ public record DisassembledInstruction public string Instruction { get; init; } /// - /// Name of the symbol that correponds with the location of this instruction, if any. + /// Name of the symbol that corresponds with the location of this instruction, if any. /// [Optional] public string? Symbol { get; init; } diff --git a/src/Dap.Protocol/Feature/Requests/EvaluateFeature.cs b/src/Dap.Protocol/Feature/Requests/EvaluateFeature.cs index d39232c73..5dc3f558c 100644 --- a/src/Dap.Protocol/Feature/Requests/EvaluateFeature.cs +++ b/src/Dap.Protocol/Feature/Requests/EvaluateFeature.cs @@ -40,7 +40,7 @@ public record EvaluateArguments : IRequest /// etc. /// [Optional] - public string? Context { get; init; } + public EvaluateArgumentsContext? Context { get; init; } /// /// Specifies details on how to format the Evaluate result. @@ -49,6 +49,15 @@ public record EvaluateArguments : IRequest public ValueFormat? Format { get; init; } } + [StringEnum] + public readonly partial struct EvaluateArgumentsContext + { + public static EvaluateArgumentsContext Watch { get; } = new EvaluateArgumentsContext("watch"); + public static EvaluateArgumentsContext Repl { get; } = new EvaluateArgumentsContext("repl"); + public static EvaluateArgumentsContext Hover { get; } = new EvaluateArgumentsContext("hover"); + public static EvaluateArgumentsContext Clipboard { get; } = new EvaluateArgumentsContext("clipboard"); + } + public record EvaluateResponse { /// diff --git a/src/Dap.Protocol/Feature/Requests/InitializeRequestFeature.cs b/src/Dap.Protocol/Feature/Requests/InitializeRequestFeature.cs index 733808a7e..14105207d 100644 --- a/src/Dap.Protocol/Feature/Requests/InitializeRequestFeature.cs +++ b/src/Dap.Protocol/Feature/Requests/InitializeRequestFeature.cs @@ -63,7 +63,7 @@ public record InitializeRequestArguments : IRequest, IInitia /// Values: 'path', 'uri', etc. /// [Optional] - public string? PathFormat { get; set; } + public PathFormat? PathFormat { get; set; } /// /// Client supports the optional type attribute for variables. @@ -94,6 +94,12 @@ public record InitializeRequestArguments : IRequest, IInitia /// [Optional] public bool SupportsProgressReporting { get; set; } + + /// + /// Client supports the invalidated event. + /// + [Optional] + public bool SupportsInvalidatedEvent { get; set; } } public record InitializeResponse : Capabilities diff --git a/src/Dap.Protocol/Feature/Requests/SetExceptionBreakpointsFeature.cs b/src/Dap.Protocol/Feature/Requests/SetExceptionBreakpointsFeature.cs index 8d7782f3e..18e29f6da 100644 --- a/src/Dap.Protocol/Feature/Requests/SetExceptionBreakpointsFeature.cs +++ b/src/Dap.Protocol/Feature/Requests/SetExceptionBreakpointsFeature.cs @@ -26,6 +26,15 @@ public record SetExceptionBreakpointsArguments : IRequest public Container Filters { get; init; } + /// + /// Set of exception filters and their options. The set of all possible + /// exception filters is defined by the 'exceptionBreakpointFilters' + /// capability. This attribute is only honored by a debug adapter if the + /// capability 'supportsExceptionFilterOptions' is true. The 'filter' and + /// 'filterOptions' sets are additive. + /// + [Optional] + public Container? FilterOptions { get; init; } /// /// Configuration options for selected exceptions. diff --git a/src/Dap.Protocol/Feature/Requests/SetInstructionBreakpointsFeature.cs b/src/Dap.Protocol/Feature/Requests/SetInstructionBreakpointsFeature.cs index 0552298f4..0833a9964 100644 --- a/src/Dap.Protocol/Feature/Requests/SetInstructionBreakpointsFeature.cs +++ b/src/Dap.Protocol/Feature/Requests/SetInstructionBreakpointsFeature.cs @@ -22,7 +22,7 @@ public record SetInstructionBreakpointsArguments : IRequest /// The contents of this array replaces all existing data breakpoints. An empty array clears all data breakpoints. /// - public Container Breakpoints { get; init; } + public Container Breakpoints { get; init; } } public record SetInstructionBreakpointsResponse diff --git a/src/Dap.Protocol/Models/ChecksumAlgorithm.cs b/src/Dap.Protocol/Models/ChecksumAlgorithm.cs index b19ece30c..9040e4a8d 100644 --- a/src/Dap.Protocol/Models/ChecksumAlgorithm.cs +++ b/src/Dap.Protocol/Models/ChecksumAlgorithm.cs @@ -1,14 +1,18 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using OmniSharp.Extensions.JsonRpc.Generation; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { /// /// Names of checksum algorithms that may be supported by a debug adapter. /// - [JsonConverter(typeof(StringEnumConverter))] - public enum ChecksumAlgorithm + [StringEnum] + public readonly partial struct ChecksumAlgorithm { - Md5, Sha1, Sha256, Timestamp + public static ChecksumAlgorithm Md5 { get; } = new ChecksumAlgorithm("MD5"); + public static ChecksumAlgorithm Sha1 { get; } = new ChecksumAlgorithm("SHA1"); + public static ChecksumAlgorithm Sha256 { get; } = new ChecksumAlgorithm("SHA256"); + public static ChecksumAlgorithm Timestamp { get; } = new ChecksumAlgorithm("timestamp"); } } diff --git a/src/Dap.Protocol/Models/ColumnDescriptorType.cs b/src/Dap.Protocol/Models/ColumnDescriptorType.cs index 3e6482e36..49ecca3ce 100644 --- a/src/Dap.Protocol/Models/ColumnDescriptorType.cs +++ b/src/Dap.Protocol/Models/ColumnDescriptorType.cs @@ -1,15 +1,15 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using OmniSharp.Extensions.JsonRpc.Generation; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { - [JsonConverter(typeof(StringEnumConverter))] - public enum ColumnDescriptorType + [StringEnum] + public readonly partial struct ColumnDescriptorType { - String, - - Long, - Bool, - UnixTimestampUtc, + public static ColumnDescriptorType String { get; } = new ColumnDescriptorType("string"); + public static ColumnDescriptorType Long { get; } = new ColumnDescriptorType("long"); + public static ColumnDescriptorType Bool { get; } = new ColumnDescriptorType("boolean"); + public static ColumnDescriptorType UnixTimestampUtc { get; } = new ColumnDescriptorType("unixTimestampUTC"); } } diff --git a/src/Dap.Protocol/Models/ExceptionBreakpointsFilter.cs b/src/Dap.Protocol/Models/ExceptionBreakpointsFilter.cs index eb92701f9..5100a89f7 100644 --- a/src/Dap.Protocol/Models/ExceptionBreakpointsFilter.cs +++ b/src/Dap.Protocol/Models/ExceptionBreakpointsFilter.cs @@ -23,5 +23,12 @@ public record ExceptionBreakpointsFilter /// [Optional] public bool Default { get; init; } + + /// + /// Controls whether a condition can be specified for this filter option. If + /// false or missing, a condition can not be set. + /// + [Optional] + public bool SupportsCondition { get; init; } } } diff --git a/src/Dap.Protocol/Models/ExceptionFilterOptions.cs b/src/Dap.Protocol/Models/ExceptionFilterOptions.cs new file mode 100644 index 000000000..a7046d04a --- /dev/null +++ b/src/Dap.Protocol/Models/ExceptionFilterOptions.cs @@ -0,0 +1,21 @@ +using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; + +namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models +{ + public record ExceptionFilterOptions + { + /// + /// ID of an exception filter returned by the 'exceptionBreakpointFilters' + /// capability. + /// + public string FilterId { get; init; } + + /// + /// An optional expression for conditional exceptions. + /// The exception will break into the debugger if the result of the condition + /// is true. + /// + [Optional] + public string? Condition { get; init; } + } +} diff --git a/src/Dap.Protocol/Models/InvalidatedAreas.cs b/src/Dap.Protocol/Models/InvalidatedAreas.cs new file mode 100644 index 000000000..22177c562 --- /dev/null +++ b/src/Dap.Protocol/Models/InvalidatedAreas.cs @@ -0,0 +1,13 @@ +using OmniSharp.Extensions.JsonRpc.Generation; + +namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models +{ + [StringEnum] + public readonly partial struct InvalidatedAreas + { + public static InvalidatedAreas All { get; } = new InvalidatedAreas("all"); + public static InvalidatedAreas Stacks { get; } = new InvalidatedAreas("stacks"); + public static InvalidatedAreas Threads { get; } = new InvalidatedAreas("threads"); + public static InvalidatedAreas Variables { get; } = new InvalidatedAreas("variables"); + } +} diff --git a/src/Dap.Protocol/Models/PathFormat.cs b/src/Dap.Protocol/Models/PathFormat.cs new file mode 100644 index 000000000..c5cbe8190 --- /dev/null +++ b/src/Dap.Protocol/Models/PathFormat.cs @@ -0,0 +1,11 @@ +using OmniSharp.Extensions.JsonRpc.Generation; + +namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models +{ + [StringEnum] + public readonly partial struct PathFormat + { + public static PathFormat Path { get; } = new PathFormat("path"); + public static PathFormat Uri { get; } = new PathFormat("uri"); + } +} diff --git a/src/Dap.Protocol/Models/Source.cs b/src/Dap.Protocol/Models/Source.cs index cfa2b7c1d..b4012b8fd 100644 --- a/src/Dap.Protocol/Models/Source.cs +++ b/src/Dap.Protocol/Models/Source.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json.Linq; using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; +using OmniSharp.Extensions.JsonRpc.Generation; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { @@ -58,4 +59,12 @@ public record Source [Optional] public Container? Checksums { get; init; } } + + [StringEnum()] + public readonly partial struct SourcePresentationHint + { + public static SourcePresentationHint Normal { get; } = new SourcePresentationHint("normal"); + public static SourcePresentationHint Emphasize { get; } = new SourcePresentationHint("emphasize"); + public static SourcePresentationHint Deemphasize { get; } = new SourcePresentationHint("deemphasize"); + } } diff --git a/src/Dap.Protocol/Models/SourcePresentationHint.cs b/src/Dap.Protocol/Models/SourcePresentationHint.cs index 774d6f270..9c70248da 100644 --- a/src/Dap.Protocol/Models/SourcePresentationHint.cs +++ b/src/Dap.Protocol/Models/SourcePresentationHint.cs @@ -3,11 +3,4 @@ namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { - [JsonConverter(typeof(StringEnumConverter))] - public enum SourcePresentationHint - { - Normal, - Emphasize, - Deemphasize, - } } diff --git a/src/Dap.Protocol/Models/StackFrame.cs b/src/Dap.Protocol/Models/StackFrame.cs index 32fd0c746..29b09753c 100644 --- a/src/Dap.Protocol/Models/StackFrame.cs +++ b/src/Dap.Protocol/Models/StackFrame.cs @@ -1,4 +1,5 @@ using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; +using OmniSharp.Extensions.JsonRpc.Generation; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { @@ -65,4 +66,12 @@ public record StackFrame [Optional] public StackFramePresentationHint? PresentationHint { get; init; } } + + [StringEnum] + public readonly partial struct StackFramePresentationHint + { + public static SourcePresentationHint Normal { get; } = new SourcePresentationHint("normal"); + public static SourcePresentationHint Label { get; } = new SourcePresentationHint("label"); + public static SourcePresentationHint Subtle { get; } = new SourcePresentationHint("subtle"); + } } diff --git a/src/Dap.Protocol/Models/StackFramePresentationHint.cs b/src/Dap.Protocol/Models/StackFramePresentationHint.cs index ecc21d8db..9c70248da 100644 --- a/src/Dap.Protocol/Models/StackFramePresentationHint.cs +++ b/src/Dap.Protocol/Models/StackFramePresentationHint.cs @@ -3,11 +3,4 @@ namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { - [JsonConverter(typeof(StringEnumConverter))] - public enum StackFramePresentationHint - { - Normal, - Label, - Subtle, - } } diff --git a/src/Dap.Protocol/Models/VariablePresentationHint.cs b/src/Dap.Protocol/Models/VariablePresentationHint.cs index d7b31eeef..1efbc73fb 100644 --- a/src/Dap.Protocol/Models/VariablePresentationHint.cs +++ b/src/Dap.Protocol/Models/VariablePresentationHint.cs @@ -1,4 +1,5 @@ using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; +using OmniSharp.Extensions.JsonRpc.Generation; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Models { @@ -25,7 +26,7 @@ public record VariablePresentationHint /// etc. /// [Optional] - public string? Kind { get; init; } + public VariablePresentationHintKind? Kind { get; init; } /// /// Set of attributes represented as an array of strings. Before introducing additional values, try to use the listed values. @@ -40,13 +41,51 @@ public record VariablePresentationHint /// etc. /// [Optional] - public Container? Attributes { get; init; } + public Container? Attributes { get; init; } /// /// Visibility of variable. Before introducing additional values, try to use the listed values. /// Values: 'public', 'private', 'protected', 'internal', 'final', etc. /// [Optional] - public string? Visibility { get; init; } + public VariableVisibility? Visibility { get; init; } + } + + [StringEnum] + public readonly partial struct VariablePresentationHintKind + { + public static VariablePresentationHintKind Property { get; } = new("property"); + public static VariablePresentationHintKind Method { get; } = new("method"); + public static VariablePresentationHintKind Class { get; } = new("class"); + public static VariablePresentationHintKind Data { get; } = new("data"); + public static VariablePresentationHintKind Event { get; } = new("event"); + public static VariablePresentationHintKind BaseClass { get; } = new("baseClass"); + public static VariablePresentationHintKind InnerClass { get; } = new("innerClass"); + public static VariablePresentationHintKind Interface { get; } = new("interface"); + public static VariablePresentationHintKind MostDerivedClass { get; } = new("mostDerivedClass"); + public static VariablePresentationHintKind Virtual { get; } = new("virtual"); + public static VariablePresentationHintKind DataBreakpoint { get; } = new("dataBreakpoint"); + } + + [StringEnum] + public readonly partial struct VariableAttributes + { + public static VariableAttributes Static { get; } = new("static"); + public static VariableAttributes Constant { get; } = new("constant"); + public static VariableAttributes ReadOnly { get; } = new("readOnly"); + public static VariableAttributes RawString { get; } = new("rawString"); + public static VariableAttributes HasObjectId { get; } = new("hasObjectId"); + public static VariableAttributes CanHaveObjectId { get; } = new("canHaveObjectId"); + public static VariableAttributes HasSideEffects { get; } = new("hasSideEffects"); + } + + [StringEnum] + public readonly partial struct VariableVisibility + { + public static VariableVisibility Public { get; } = new("public"); + public static VariableVisibility Private { get; } = new("private"); + public static VariableVisibility Protected { get; } = new("protected"); + public static VariableVisibility Internal { get; } = new("internal"); + public static VariableVisibility Final { get; } = new("final"); } } diff --git a/src/Dap.Protocol/Requests/IInitializeRequestArguments.cs b/src/Dap.Protocol/Requests/IInitializeRequestArguments.cs index 5097e26f2..4afc53188 100644 --- a/src/Dap.Protocol/Requests/IInitializeRequestArguments.cs +++ b/src/Dap.Protocol/Requests/IInitializeRequestArguments.cs @@ -1,4 +1,5 @@ -using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; +using OmniSharp.Extensions.DebugAdapter.Protocol.Models; +using OmniSharp.Extensions.DebugAdapter.Protocol.Serialization; namespace OmniSharp.Extensions.DebugAdapter.Protocol.Requests { @@ -44,7 +45,7 @@ public interface IInitializeRequestArguments /// Values: 'path', 'uri', etc. /// [Optional] - string? PathFormat { get; set; } + PathFormat? PathFormat { get; set; } /// /// Client supports the optional type attribute for variables. @@ -75,5 +76,11 @@ public interface IInitializeRequestArguments /// [Optional] bool SupportsProgressReporting { get; set; } + + /// + /// Client supports the invalidated event. + /// + [Optional] + bool SupportsInvalidatedEvent { get; set; } } } diff --git a/src/JsonRpc.Generators/EnumLikeStringGenerator.cs b/src/JsonRpc.Generators/EnumLikeStringGenerator.cs new file mode 100644 index 000000000..d4ec9ed96 --- /dev/null +++ b/src/JsonRpc.Generators/EnumLikeStringGenerator.cs @@ -0,0 +1,915 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; +using OmniSharp.Extensions.JsonRpc.Generators.Cache; +using OmniSharp.Extensions.JsonRpc.Generators.Contexts; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static OmniSharp.Extensions.JsonRpc.Generators.CommonElements; + +namespace OmniSharp.Extensions.JsonRpc.Generators +{ + [Generator] + public class EnumLikeStringGenerator : CachedSourceGenerator + { + protected override void Execute( + GeneratorExecutionContext context, SyntaxReceiver syntaxReceiver, AddCacheSource addCacheSource, + ReportCacheDiagnostic cacheDiagnostic + ) + { + foreach (var candidate in syntaxReceiver.Candidates) + { + var model = context.Compilation.GetSemanticModel(candidate.SyntaxTree); + var symbol = model.GetDeclaredSymbol(candidate); + if (symbol is null) continue; + + if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword))) + { + cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBePartial, c.Identifier.GetLocation(), c.Identifier.Text)); + continue; + } + + if (!candidate.Modifiers.Any(z => z.IsKind(SyntaxKind.ReadOnlyKeyword))) + { + cacheDiagnostic(candidate, static c => Diagnostic.Create(GeneratorDiagnostics.MustBeReadOnly, c.Identifier.GetLocation(), c.Identifier.Text)); + continue; + } + + var cu = CompilationUnit( + List(), + List(), + List(), + SingletonList( + NamespaceDeclaration(ParseName(symbol.ContainingNamespace.ToDisplayString())) + .WithMembers(SingletonList(GetImplementation(candidate))) + ) + ) + .AddUsings( + UsingDirective(ParseName("System")), + UsingDirective(ParseName("System.Collections.Generic")), + UsingDirective(ParseName("System.Diagnostics")), + UsingDirective(ParseName("System.Linq")), + UsingDirective(ParseName("System.Reflection")), + UsingDirective(ParseName("Newtonsoft.Json")), + UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc")), + UsingDirective(ParseName("OmniSharp.Extensions.JsonRpc.Serialization.Converters")) + ) + .WithLeadingTrivia() + .WithTrailingTrivia() + .WithLeadingTrivia(Comment(Preamble.GeneratedByATool), Trivia(NullableDirectiveTrivia(Token(SyntaxKind.EnableKeyword), true))) + .WithTrailingTrivia(Trivia(NullableDirectiveTrivia(Token(SyntaxKind.RestoreKeyword), true)), CarriageReturnLineFeed); + + addCacheSource( + $"{Path.GetFileNameWithoutExtension(candidate.SyntaxTree.FilePath)}_{candidate.Identifier.Text}{( candidate.Arity > 0 ? candidate.Arity.ToString() : "" )}.cs", + candidate, + cu.NormalizeWhitespace().GetText(Encoding.UTF8) + ); + } + } + + private static StructDeclarationSyntax GetImplementation(StructDeclarationSyntax syntax) + { + return syntax + .WithBaseList( + BaseList( + SeparatedList( + new BaseTypeSyntax[] { + SimpleBaseType( + GenericName(Identifier("IEquatable")) + .WithTypeArgumentList(TypeArgumentList(SingletonSeparatedList(PredefinedType(Token(SyntaxKind.StringKeyword))))) + ), + SimpleBaseType( + GenericName(Identifier("IEquatable")) + .WithTypeArgumentList(TypeArgumentList(SingletonSeparatedList(IdentifierName(syntax.Identifier.Text)))) + ), + SimpleBaseType(IdentifierName("IEnumLikeString")) + } + ) + ) + ) + .WithAttributeLists( + List( + new[] { + AttributeList( + SingletonSeparatedList( + Attribute(IdentifierName("JsonConverter")) + .WithArgumentList( + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument( + TypeOfExpression( + IdentifierName("EnumLikeStringConverter") + ) + ) + ) + ) + ) + ) + ), + AttributeList( + SingletonSeparatedList( + Attribute(IdentifierName("DebuggerDisplay")) + .WithArgumentList( + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal("{_value}"))) + ) + ) + ) + ) + ) + } + ) + ) + .WithMembers( + List( + new MemberDeclarationSyntax[] { + FieldDeclaration( + VariableDeclaration( + GenericName(Identifier("Lazy")) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + GenericName(Identifier("IReadOnlyList")) + .WithTypeArgumentList( + TypeArgumentList(SingletonSeparatedList(IdentifierName(syntax.Identifier.Text))) + ) + ) + ) + ) + ) + .WithVariables( + SingletonSeparatedList( + VariableDeclarator(Identifier("_defaults")) + .WithInitializer( + EqualsValueClause( + ObjectCreationExpression( + GenericName(Identifier("Lazy")) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + GenericName(Identifier("IReadOnlyList")) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList(IdentifierName(syntax.Identifier.Text)) + ) + ) + ) + ) + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + ParenthesizedLambdaExpression() + .WithBlock( + Block( + SingletonList( + ReturnStatement( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + InvocationExpression( + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + InvocationExpression( + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + TypeOfExpression( + IdentifierName( + syntax.Identifier + .Text + ) + ), + IdentifierName( + "GetProperties" + ) + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList< + ArgumentSyntax>( + Argument( + BinaryExpression( + SyntaxKind + .BitwiseOrExpression, + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + IdentifierName( + "BindingFlags" + ), + IdentifierName( + "Static" + ) + ), + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + IdentifierName( + "BindingFlags" + ), + IdentifierName( + "Public" + ) + ) + ) + ) + ) + ) + ), + IdentifierName("Where") + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + SimpleLambdaExpression( + Parameter( + Identifier("z") + ) + ) + .WithExpressionBody( + BinaryExpression( + SyntaxKind + .NotEqualsExpression, + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + IdentifierName( + "z" + ), + IdentifierName( + "Name" + ) + ), + InvocationExpression( + IdentifierName( + "nameof" + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList + ( + Argument( + IdentifierName( + "Defaults" + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ), + IdentifierName("Select") + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + SimpleLambdaExpression( + Parameter( + Identifier("z") + ) + ) + .WithExpressionBody( + InvocationExpression( + MemberAccessExpression( + SyntaxKind + .SimpleMemberAccessExpression, + IdentifierName("z"), + IdentifierName( + "GetValue" + ) + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList + ( + Argument( + LiteralExpression( + SyntaxKind + .NullLiteralExpression + ) + ) + ) + ) + ) + ) + ) + ) + ) + ), + GenericName( + Identifier("Cast") + ) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + IdentifierName(syntax.Identifier.Text) + ) + ) + ) + ) + ), + IdentifierName("ToArray") + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword), + Token(SyntaxKind.ReadOnlyKeyword) + } + ) + ), + PropertyDeclaration( + GenericName( + Identifier("IEnumerable") + ) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + IdentifierName(syntax.Identifier.Text) + ) + ) + ), + Identifier("Defaults") + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) + } + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("_defaults"), + IdentifierName("Value") + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + FieldDeclaration( + VariableDeclaration( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ) + ) + .WithVariables( + SingletonSeparatedList( + VariableDeclarator( + Identifier("_value") + ) + ) + ) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.ReadOnlyKeyword) + } + ) + ), + ConstructorDeclaration( + Identifier(syntax.Identifier.Text) + ) + .WithModifiers( + TokenList( + Token(SyntaxKind.PublicKeyword) + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("type") + ) + .WithType( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ) + ) + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName("_value"), + IdentifierName("type") + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + ConversionOperatorDeclaration( + Token(SyntaxKind.ImplicitKeyword), + IdentifierName(syntax.Identifier.Text) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) + } + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("kind") + ) + .WithType( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ) + ) + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + ObjectCreationExpression( + IdentifierName(syntax.Identifier.Text) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + IdentifierName("kind") + ) + ) + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + ConversionOperatorDeclaration( + Token(SyntaxKind.ImplicitKeyword), + PredefinedType( + Token(SyntaxKind.StringKeyword) + ) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) + } + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("kind") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ) + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("kind"), + IdentifierName("_value") + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ), + Identifier("ToString") + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.OverrideKeyword) + } + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + IdentifierName("_value") + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.BoolKeyword) + ), + Identifier("Equals") + ) + .WithModifiers( + TokenList( + Token(SyntaxKind.PublicKeyword) + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("other") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ) + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + BinaryExpression( + SyntaxKind.EqualsExpression, + IdentifierName("_value"), + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("other"), + IdentifierName("_value") + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.BoolKeyword) + ), + Identifier("Equals") + ) + .WithModifiers( + TokenList( + Token(SyntaxKind.PublicKeyword) + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("other") + ) + .WithType( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ) + ) + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + BinaryExpression( + SyntaxKind.EqualsExpression, + IdentifierName("_value"), + IdentifierName("other") + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.BoolKeyword) + ), + Identifier("Equals") + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.OverrideKeyword) + } + ) + ) + .WithParameterList( + ParameterList( + SingletonSeparatedList( + Parameter( + Identifier("obj") + ) + .WithType( + PredefinedType( + Token(SyntaxKind.ObjectKeyword) + ) + ) + ) + ) + ).WithExpressionBody( + ArrowExpressionClause( + BinaryExpression( + SyntaxKind.LogicalOrExpression, + BinaryExpression( + SyntaxKind.LogicalAndExpression, + IsPatternExpression( + IdentifierName("obj"), + DeclarationPattern( + PredefinedType( + Token(SyntaxKind.StringKeyword) + ), + SingleVariableDesignation( + Identifier("s") + ) + ) + ), + InvocationExpression( + IdentifierName("Equals") + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + IdentifierName("s") + ) + ) + ) + ) + ), + BinaryExpression( + SyntaxKind.LogicalAndExpression, + IsPatternExpression( + IdentifierName("obj"), + DeclarationPattern( + IdentifierName(syntax.Identifier.Text), + SingleVariableDesignation( + Identifier("other") + ) + ) + ), + InvocationExpression( + IdentifierName("Equals") + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + IdentifierName("other") + ) + ) + ) + ) + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.IntKeyword) + ), + Identifier("GetHashCode") + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.OverrideKeyword) + } + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("_value"), + IdentifierName("GetHashCode") + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + OperatorDeclaration( + PredefinedType( + Token(SyntaxKind.BoolKeyword) + ), + Token(SyntaxKind.EqualsEqualsToken) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) + } + ) + ) + .WithParameterList( + ParameterList( + SeparatedList( + new SyntaxNodeOrToken[] { + Parameter( + Identifier("left") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ), + Token(SyntaxKind.CommaToken), + Parameter( + Identifier("right") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ) + } + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("left"), + IdentifierName("Equals") + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + IdentifierName("right") + ) + ) + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ), + OperatorDeclaration( + PredefinedType( + Token(SyntaxKind.BoolKeyword) + ), + Token(SyntaxKind.ExclamationEqualsToken) + ) + .WithModifiers( + TokenList( + new[] { + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.StaticKeyword) + } + ) + ) + .WithParameterList( + ParameterList( + SeparatedList( + new SyntaxNodeOrToken[] { + Parameter( + Identifier("left") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ), + Token(SyntaxKind.CommaToken), + Parameter( + Identifier("right") + ) + .WithType( + IdentifierName(syntax.Identifier.Text) + ) + } + ) + ) + ) + .WithExpressionBody( + ArrowExpressionClause( + PrefixUnaryExpression( + SyntaxKind.LogicalNotExpression, + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("left"), + IdentifierName("Equals") + ) + ) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument( + IdentifierName("right") + ) + ) + ) + ) + ) + ) + ) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken) + ) + } + ) + ) + ; + } + + public EnumLikeStringGenerator() : base(() => new SyntaxReceiver(Cache)) + { + } + + public static CacheContainer Cache = new(); + + public class SyntaxReceiver : SyntaxReceiverCache + { + public List Candidates { get; } = new(); + + public SyntaxReceiver(CacheContainer cacheContainer) : base(cacheContainer) + { + } + + public override string? GetKey(StructDeclarationSyntax syntax) + { + var hasher = new CacheKeyHasher(); + hasher.Append(syntax.SyntaxTree.FilePath); + hasher.Append(syntax.Keyword.Text); + hasher.Append(syntax.Identifier.Text); + hasher.Append(syntax.TypeParameterList); + hasher.Append(syntax.AttributeLists); + hasher.Append(syntax.BaseList); + + return hasher; + } + + /// + /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation + /// + public override void OnVisitNode(StructDeclarationSyntax syntaxNode) + { + // any field with at least one attribute is a candidate for property generation + if (syntaxNode.AttributeLists.ContainsAttribute("StringEnum")) + { + Candidates.Add(syntaxNode); + } + } + } + } +} diff --git a/src/JsonRpc.Generators/GeneratorDiagnostics.cs b/src/JsonRpc.Generators/GeneratorDiagnostics.cs index 92ddff9b7..b93e808c5 100644 --- a/src/JsonRpc.Generators/GeneratorDiagnostics.cs +++ b/src/JsonRpc.Generators/GeneratorDiagnostics.cs @@ -36,6 +36,11 @@ internal static class GeneratorDiagnostics "Type {0} must be made partial.", "JsonRPC", DiagnosticSeverity.Error, true ); + public static DiagnosticDescriptor MustBeReadOnly { get; } = new DiagnosticDescriptor( + "JRPC1005", "Type must be made readonly", + "Type {0} must be made readonly.", "JsonRPC", DiagnosticSeverity.Error, true + ); + public static DiagnosticDescriptor MustInheritFromCanBeResolved { get; } = new DiagnosticDescriptor( "LSP1001", "The target class must implement ICanBeResolved", "The target class must implement ICanBeResolved", "LSP", DiagnosticSeverity.Error, true diff --git a/src/JsonRpc/Events.cs b/src/JsonRpc/Events.cs index c7c72df6b..64a8742a9 100644 --- a/src/JsonRpc/Events.cs +++ b/src/JsonRpc/Events.cs @@ -4,8 +4,8 @@ namespace OmniSharp.Extensions.JsonRpc { public static class Events { - public static EventId UnhandledException = new EventId(1337_100); - public static EventId UnhandledRequest = new EventId(1337_101); - public static EventId UnhandledNotification = new EventId(1337_102); + public static EventId UnhandledException { get; } = new EventId(1337_100); + public static EventId UnhandledRequest { get; } = new EventId(1337_101); + public static EventId UnhandledNotification { get; } = new EventId(1337_102); } } diff --git a/src/JsonRpc/Generation/StringEnumAttribute.cs b/src/JsonRpc/Generation/StringEnumAttribute.cs new file mode 100644 index 000000000..799b04cba --- /dev/null +++ b/src/JsonRpc/Generation/StringEnumAttribute.cs @@ -0,0 +1,15 @@ +using System; +using System.Diagnostics; + +namespace OmniSharp.Extensions.JsonRpc.Generation +{ + /// + /// Generates a string based enum for the given readonly struct + /// + [AttributeUsage(AttributeTargets.Struct)] + [Conditional("CodeGeneration")] + public class StringEnumAttribute : Attribute + { + public StringEnumAttribute(string? @namespace = null) { } + } +} diff --git a/src/JsonRpc/IEnumLikeString.cs b/src/JsonRpc/IEnumLikeString.cs new file mode 100644 index 000000000..f6da8475f --- /dev/null +++ b/src/JsonRpc/IEnumLikeString.cs @@ -0,0 +1,6 @@ +namespace OmniSharp.Extensions.JsonRpc +{ + public interface IEnumLikeString + { + } +} diff --git a/src/JsonRpc/NoopResponseRouter.cs b/src/JsonRpc/NoopResponseRouter.cs index 0c6b584b3..52a78648f 100644 --- a/src/JsonRpc/NoopResponseRouter.cs +++ b/src/JsonRpc/NoopResponseRouter.cs @@ -15,7 +15,7 @@ private NoopResponseRouter() { } - public static NoopResponseRouter Instance = new NoopResponseRouter(); + public static NoopResponseRouter Instance { get; } = new NoopResponseRouter(); public void SendNotification(string method) { diff --git a/src/Protocol/Serialization/Converters/EnumLikeStringConverter.cs b/src/JsonRpc/Serialization/Converters/EnumLikeStringConverter.cs similarity index 85% rename from src/Protocol/Serialization/Converters/EnumLikeStringConverter.cs rename to src/JsonRpc/Serialization/Converters/EnumLikeStringConverter.cs index 16eac0212..54908ccff 100644 --- a/src/Protocol/Serialization/Converters/EnumLikeStringConverter.cs +++ b/src/JsonRpc/Serialization/Converters/EnumLikeStringConverter.cs @@ -1,9 +1,8 @@ using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using OmniSharp.Extensions.LanguageServer.Protocol.Models; -namespace OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters +namespace OmniSharp.Extensions.JsonRpc.Serialization.Converters { internal class EnumLikeStringConverter : JsonConverter { diff --git a/src/Protocol/Features/Document/CodeActionFeature.cs b/src/Protocol/Features/Document/CodeActionFeature.cs index 584b77306..3390d9827 100644 --- a/src/Protocol/Features/Document/CodeActionFeature.cs +++ b/src/Protocol/Features/Document/CodeActionFeature.cs @@ -17,6 +17,7 @@ using Newtonsoft.Json.Linq; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; using OmniSharp.Extensions.LanguageServer.Protocol.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Document; @@ -328,37 +329,23 @@ public override StaticOptions Convert(CodeActionRegistrationOptions source) /// /// A set of predefined code action kinds /// - [DebuggerDisplay("{" + nameof(_value) + "}")] - [JsonConverter(typeof(EnumLikeStringConverter))] - public readonly struct CodeActionKind : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct CodeActionKind { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(CodeActionKind) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - /// /// Base kind for quickfix actions: '' /// - public static readonly CodeActionKind Empty = new CodeActionKind(""); + public static CodeActionKind Empty { get; } = new CodeActionKind(""); /// /// Base kind for quickfix actions: 'quickfix' /// - public static readonly CodeActionKind QuickFix = new CodeActionKind("quickfix"); + public static CodeActionKind QuickFix { get; } = new CodeActionKind("quickfix"); /// /// Base kind for refactoring actions: 'refactor' /// - public static readonly CodeActionKind Refactor = new CodeActionKind("refactor"); + public static CodeActionKind Refactor { get; } = new CodeActionKind("refactor"); /// /// Base kind for refactoring extraction actions: 'refactor.extract' @@ -371,7 +358,7 @@ public override StaticOptions Convert(CodeActionRegistrationOptions source) /// - Extract interface from class /// - ... /// - public static readonly CodeActionKind RefactorExtract = new CodeActionKind("refactor.extract"); + public static CodeActionKind RefactorExtract { get; } = new CodeActionKind("refactor.extract"); /// /// Base kind for refactoring inline actions: 'refactor.inline' @@ -383,7 +370,7 @@ public override StaticOptions Convert(CodeActionRegistrationOptions source) /// - Inline constant /// - ... /// - public static readonly CodeActionKind RefactorInline = new CodeActionKind("refactor.inline"); + public static CodeActionKind RefactorInline { get; } = new CodeActionKind("refactor.inline"); /// /// Base kind for refactoring rewrite actions: 'refactor.rewrite' @@ -397,40 +384,19 @@ public override StaticOptions Convert(CodeActionRegistrationOptions source) /// - Move method to base class /// - ... /// - public static readonly CodeActionKind RefactorRewrite = new CodeActionKind("refactor.rewrite"); + public static CodeActionKind RefactorRewrite { get; } = new CodeActionKind("refactor.rewrite"); /// /// Base kind for source actions: `source` /// /// Source code actions apply to the entire file. /// - public static readonly CodeActionKind Source = new CodeActionKind("source"); + public static CodeActionKind Source { get; } = new CodeActionKind("source"); /// /// Base kind for an organize imports source action: `source.organizeImports` /// - public static readonly CodeActionKind SourceOrganizeImports = new CodeActionKind("source.organizeImports"); - - private readonly string? _value; - - public CodeActionKind(string kind) => _value = kind; - - public static implicit operator CodeActionKind(string kind) => new CodeActionKind(kind); - - public static implicit operator string(CodeActionKind kind) => kind._value ?? string.Empty; - - /// - public override string ToString() => _value ?? string.Empty; - - public bool Equals(CodeActionKind other) => _value == other._value; - - public override bool Equals(object obj) => obj is CodeActionKind other && Equals(other); - - public override int GetHashCode() => _value != null ? _value.GetHashCode() : 0; - - public static bool operator ==(CodeActionKind left, CodeActionKind right) => left.Equals(right); - - public static bool operator !=(CodeActionKind left, CodeActionKind right) => !left.Equals(right); + public static CodeActionKind SourceOrganizeImports { get; } = new CodeActionKind("source.organizeImports"); } } diff --git a/src/Protocol/Features/Document/Proposals/MonikerFeature.cs b/src/Protocol/Features/Document/Proposals/MonikerFeature.cs index 210fef30d..44c151399 100644 --- a/src/Protocol/Features/Document/Proposals/MonikerFeature.cs +++ b/src/Protocol/Features/Document/Proposals/MonikerFeature.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; using OmniSharp.Extensions.LanguageServer.Protocol.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Generation; @@ -32,13 +33,16 @@ namespace Models.Proposals /// [Obsolete(Constants.Proposal)] [Parallel] - [Method(TextDocumentNames.Moniker, Direction.ClientToServer)][ + [Method(TextDocumentNames.Moniker, Direction.ClientToServer)] + [ GenerateHandler("OmniSharp.Extensions.LanguageServer.Protocol.Document.Proposals"), GenerateHandlerMethods, GenerateRequestMethods(typeof(ITextDocumentLanguageClient), typeof(ILanguageClient)) ] [RegistrationOptions(typeof(MonikerRegistrationOptions)), Capability(typeof(MonikerCapability))] - public partial record MonikerParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialItemsRequest?, Moniker> { } + public partial record MonikerParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialItemsRequest?, Moniker> + { + } /// /// Moniker definition to match LSIF 0.5 moniker definition. @@ -72,9 +76,8 @@ public partial record Moniker /// /// Moniker uniqueness level to define scope of the moniker. /// - [DebuggerDisplay("{" + nameof(_value) + "}")] - [JsonConverter(typeof(EnumLikeStringConverter))] - public readonly struct MonikerKind : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct MonikerKind { /// /// The moniker represent a symbol that is imported into a project @@ -91,95 +94,55 @@ public partial record Moniker /// variable of a function, a class not visible outside the project, ...) /// public static readonly MonikerKind Local = new MonikerKind("local"); - - private readonly string? _value; - - public MonikerKind(string kind) => _value = kind; - - public static implicit operator MonikerKind(string kind) => new MonikerKind(kind); - - public static implicit operator string(MonikerKind kind) => kind._value ?? string.Empty; - - /// - public override string ToString() => _value ?? string.Empty; - - public bool Equals(MonikerKind other) => _value == other._value; - - public override bool Equals(object obj) => obj is MonikerKind other && Equals(other); - - public override int GetHashCode() => _value != null ? _value.GetHashCode() : 0; - - public static bool operator ==(MonikerKind left, MonikerKind right) => left.Equals(right); - - public static bool operator !=(MonikerKind left, MonikerKind right) => !left.Equals(right); } - /// - /// A set of predefined code action kinds - /// - [DebuggerDisplay("{" + nameof(_value) + "}")] - [JsonConverter(typeof(EnumLikeStringConverter))] - public readonly struct UniquenessLevel : IEquatable, IEnumLikeString - { - /// - /// The moniker is only unique inside a document - /// - public static readonly UniquenessLevel Document = new UniquenessLevel("document"); - - /// - /// The moniker is unique inside a project for which a dump got created - /// - public static readonly UniquenessLevel Project = new UniquenessLevel("project"); - - /// - /// The moniker is unique inside the group to which a project belongs - /// - public static readonly UniquenessLevel Group = new UniquenessLevel("group"); - - /// - /// The moniker is unique inside the moniker scheme. - /// - public static readonly UniquenessLevel Scheme = new UniquenessLevel("scheme"); - /// - /// The moniker is globally unique + /// A set of predefined code action kinds /// - public static readonly UniquenessLevel Global = new UniquenessLevel("global"); - - private readonly string? _value; - - public UniquenessLevel(string kind) => _value = kind; - - public static implicit operator UniquenessLevel(string kind) => new UniquenessLevel(kind); - - public static implicit operator string(UniquenessLevel kind) => kind._value ?? string.Empty; - - /// - public override string ToString() => _value ?? string.Empty; - - public bool Equals(UniquenessLevel other) => _value == other._value; + [StringEnum] + public readonly partial struct UniquenessLevel : IEquatable, IEnumLikeString + { + /// + /// The moniker is only unique inside a document + /// + public static readonly UniquenessLevel Document = new UniquenessLevel("document"); - public override bool Equals(object obj) => obj is UniquenessLevel other && Equals(other); + /// + /// The moniker is unique inside a project for which a dump got created + /// + public static readonly UniquenessLevel Project = new UniquenessLevel("project"); - public override int GetHashCode() => _value != null ? _value.GetHashCode() : 0; + /// + /// The moniker is unique inside the group to which a project belongs + /// + public static readonly UniquenessLevel Group = new UniquenessLevel("group"); - public static bool operator ==(UniquenessLevel left, UniquenessLevel right) => left.Equals(right); + /// + /// The moniker is unique inside the moniker scheme. + /// + public static readonly UniquenessLevel Scheme = new UniquenessLevel("scheme"); - public static bool operator !=(UniquenessLevel left, UniquenessLevel right) => !left.Equals(right); - } + /// + /// The moniker is globally unique + /// + public static readonly UniquenessLevel Global = new UniquenessLevel("global"); + } [Obsolete(Constants.Proposal)] [GenerateRegistrationOptions(nameof(ServerCapabilities.MonikerProvider))] - public partial class MonikerRegistrationOptions : ITextDocumentRegistrationOptions, IWorkDoneProgressOptions { } - + public partial class MonikerRegistrationOptions : ITextDocumentRegistrationOptions, IWorkDoneProgressOptions + { + } } namespace Client.Capabilities { [Obsolete(Constants.Proposal)] [CapabilityKey(nameof(ClientCapabilities.TextDocument), nameof(TextDocumentClientCapabilities.Moniker))] - public partial class MonikerCapability : DynamicCapability { } + public partial class MonikerCapability : DynamicCapability + { + } } namespace Document.Proposals diff --git a/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs b/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs index 68b65ecc2..0c635f1f1 100644 --- a/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs +++ b/src/Protocol/Features/Document/Proposals/SemanticTokensFeature.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; using OmniSharp.Extensions.LanguageServer.Protocol.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Document.Proposals; @@ -493,44 +494,11 @@ private void EnsureTokenModifiers() => /// /// @since 3.16.0 /// - [JsonConverter(typeof(EnumLikeStringConverter))] [Obsolete(Constants.Proposal)] - [DebuggerDisplay("{_value}")] - public readonly struct SemanticTokenFormat : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct SemanticTokenFormat { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(SemanticTokenFormat) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - - public static readonly SemanticTokenFormat Relative = new SemanticTokenFormat("relative"); - - private readonly string _value; - - public SemanticTokenFormat(string modifier) => _value = modifier; - - public static implicit operator SemanticTokenFormat(string kind) => new SemanticTokenFormat(kind); - - public static implicit operator string(SemanticTokenFormat kind) => kind._value; - - public override string ToString() => _value; - public bool Equals(SemanticTokenFormat other) => _value == other._value; - - public override bool Equals(object obj) => obj is SemanticTokenFormat other && Equals(other); - - public override int GetHashCode() => _value.GetHashCode(); - - public static bool operator ==(SemanticTokenFormat left, SemanticTokenFormat right) => left.Equals(right); - - public static bool operator !=(SemanticTokenFormat left, SemanticTokenFormat right) => !left.Equals(right); + public static SemanticTokenFormat Relative { get; } = new SemanticTokenFormat("relative"); } /// @@ -540,53 +508,20 @@ private void EnsureTokenModifiers() => /// /// @since 3.16.0 /// - [JsonConverter(typeof(EnumLikeStringConverter))] [Obsolete(Constants.Proposal)] - [DebuggerDisplay("{_value}")] - public readonly struct SemanticTokenModifier : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct SemanticTokenModifier { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(SemanticTokenModifier) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - - public static readonly SemanticTokenModifier Documentation = new SemanticTokenModifier("documentation"); - public static readonly SemanticTokenModifier Declaration = new SemanticTokenModifier("declaration"); - public static readonly SemanticTokenModifier Definition = new SemanticTokenModifier("definition"); - public static readonly SemanticTokenModifier Static = new SemanticTokenModifier("static"); - public static readonly SemanticTokenModifier Async = new SemanticTokenModifier("async"); - public static readonly SemanticTokenModifier Abstract = new SemanticTokenModifier("abstract"); - public static readonly SemanticTokenModifier Deprecated = new SemanticTokenModifier("deprecated"); - public static readonly SemanticTokenModifier Readonly = new SemanticTokenModifier("readonly"); - public static readonly SemanticTokenModifier Modification = new SemanticTokenModifier("modification"); - public static readonly SemanticTokenModifier DefaultLibrary = new SemanticTokenModifier("defaultLibrary"); - - private readonly string _value; - - public SemanticTokenModifier(string modifier) => _value = modifier; - - public static implicit operator SemanticTokenModifier(string kind) => new SemanticTokenModifier(kind); - - public static implicit operator string(SemanticTokenModifier kind) => kind._value; - - public override string ToString() => _value; - public bool Equals(SemanticTokenModifier other) => _value == other._value; - - public override bool Equals(object obj) => obj is SemanticTokenModifier other && Equals(other); - - public override int GetHashCode() => _value.GetHashCode(); - - public static bool operator ==(SemanticTokenModifier left, SemanticTokenModifier right) => left.Equals(right); - - public static bool operator !=(SemanticTokenModifier left, SemanticTokenModifier right) => !left.Equals(right); + public static SemanticTokenModifier Documentation { get; } = new SemanticTokenModifier("documentation"); + public static SemanticTokenModifier Declaration { get; } = new SemanticTokenModifier("declaration"); + public static SemanticTokenModifier Definition { get; } = new SemanticTokenModifier("definition"); + public static SemanticTokenModifier Static { get; } = new SemanticTokenModifier("static"); + public static SemanticTokenModifier Async { get; } = new SemanticTokenModifier("async"); + public static SemanticTokenModifier Abstract { get; } = new SemanticTokenModifier("abstract"); + public static SemanticTokenModifier Deprecated { get; } = new SemanticTokenModifier("deprecated"); + public static SemanticTokenModifier Readonly { get; } = new SemanticTokenModifier("readonly"); + public static SemanticTokenModifier Modification { get; } = new SemanticTokenModifier("modification"); + public static SemanticTokenModifier DefaultLibrary { get; } = new SemanticTokenModifier("defaultLibrary"); } @@ -597,66 +532,33 @@ private void EnsureTokenModifiers() => /// /// @since 3.16.0 /// - [JsonConverter(typeof(EnumLikeStringConverter))] [Obsolete(Constants.Proposal)] - [DebuggerDisplay("{_value}")] - public readonly struct SemanticTokenType : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct SemanticTokenType { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(SemanticTokenType) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - - public static readonly SemanticTokenType Comment = new SemanticTokenType("comment"); - public static readonly SemanticTokenType Keyword = new SemanticTokenType("keyword"); - public static readonly SemanticTokenType String = new SemanticTokenType("string"); - public static readonly SemanticTokenType Number = new SemanticTokenType("number"); - public static readonly SemanticTokenType Regexp = new SemanticTokenType("regexp"); - public static readonly SemanticTokenType Operator = new SemanticTokenType("operator"); - public static readonly SemanticTokenType Namespace = new SemanticTokenType("namespace"); - public static readonly SemanticTokenType Type = new SemanticTokenType("type"); - public static readonly SemanticTokenType Struct = new SemanticTokenType("struct"); - public static readonly SemanticTokenType Class = new SemanticTokenType("class"); - public static readonly SemanticTokenType Interface = new SemanticTokenType("interface"); - public static readonly SemanticTokenType Enum = new SemanticTokenType("enum"); - public static readonly SemanticTokenType TypeParameter = new SemanticTokenType("typeParameter"); - public static readonly SemanticTokenType Function = new SemanticTokenType("function"); - public static readonly SemanticTokenType Method = new SemanticTokenType("method"); - public static readonly SemanticTokenType Property = new SemanticTokenType("property"); - public static readonly SemanticTokenType Macro = new SemanticTokenType("macro"); - public static readonly SemanticTokenType Variable = new SemanticTokenType("variable"); - public static readonly SemanticTokenType Parameter = new SemanticTokenType("parameter"); - public static readonly SemanticTokenType Label = new SemanticTokenType("label"); - public static readonly SemanticTokenType Modifier = new SemanticTokenType("modifier"); - public static readonly SemanticTokenType Event = new SemanticTokenType("event"); - public static readonly SemanticTokenType EnumMember = new SemanticTokenType("enumMember"); - - private readonly string _value; - - public SemanticTokenType(string type) => _value = type; - - public static implicit operator SemanticTokenType(string kind) => new SemanticTokenType(kind); - - public static implicit operator string(SemanticTokenType kind) => kind._value; - - public override string ToString() => _value; - public bool Equals(SemanticTokenType other) => _value == other._value; - - public override bool Equals(object obj) => obj is SemanticTokenType other && Equals(other); - - public override int GetHashCode() => _value.GetHashCode(); - - public static bool operator ==(SemanticTokenType left, SemanticTokenType right) => left.Equals(right); - - public static bool operator !=(SemanticTokenType left, SemanticTokenType right) => !left.Equals(right); + public static SemanticTokenType Comment { get; } = new SemanticTokenType("comment"); + public static SemanticTokenType Keyword { get; } = new SemanticTokenType("keyword"); + public static SemanticTokenType String { get; } = new SemanticTokenType("string"); + public static SemanticTokenType Number { get; } = new SemanticTokenType("number"); + public static SemanticTokenType Regexp { get; } = new SemanticTokenType("regexp"); + public static SemanticTokenType Operator { get; } = new SemanticTokenType("operator"); + public static SemanticTokenType Namespace { get; } = new SemanticTokenType("namespace"); + public static SemanticTokenType Type { get; } = new SemanticTokenType("type"); + public static SemanticTokenType Struct { get; } = new SemanticTokenType("struct"); + public static SemanticTokenType Class { get; } = new SemanticTokenType("class"); + public static SemanticTokenType Interface { get; } = new SemanticTokenType("interface"); + public static SemanticTokenType Enum { get; } = new SemanticTokenType("enum"); + public static SemanticTokenType TypeParameter { get; } = new SemanticTokenType("typeParameter"); + public static SemanticTokenType Function { get; } = new SemanticTokenType("function"); + public static SemanticTokenType Method { get; } = new SemanticTokenType("method"); + public static SemanticTokenType Property { get; } = new SemanticTokenType("property"); + public static SemanticTokenType Macro { get; } = new SemanticTokenType("macro"); + public static SemanticTokenType Variable { get; } = new SemanticTokenType("variable"); + public static SemanticTokenType Parameter { get; } = new SemanticTokenType("parameter"); + public static SemanticTokenType Label { get; } = new SemanticTokenType("label"); + public static SemanticTokenType Modifier { get; } = new SemanticTokenType("modifier"); + public static SemanticTokenType Event { get; } = new SemanticTokenType("event"); + public static SemanticTokenType EnumMember { get; } = new SemanticTokenType("enumMember"); } [Obsolete(Constants.Proposal)] diff --git a/src/Protocol/Features/Window/WorkDoneProgressFeature.cs b/src/Protocol/Features/Window/WorkDoneProgressFeature.cs index e5f8f86d2..c7e8b4485 100644 --- a/src/Protocol/Features/Window/WorkDoneProgressFeature.cs +++ b/src/Protocol/Features/Window/WorkDoneProgressFeature.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Generation; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; using OmniSharp.Extensions.LanguageServer.Protocol.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; @@ -72,44 +73,12 @@ public abstract record WorkDoneProgress public string? Message { get; init; } } - [JsonConverter(typeof(EnumLikeStringConverter))] - public readonly struct WorkDoneProgressKind : IEquatable, IEnumLikeString + [StringEnum] + public readonly partial struct WorkDoneProgressKind { - private static readonly Lazy> _defaults = - new Lazy>( - () => { - return typeof(WorkDoneProgressKind) - .GetFields(BindingFlags.Static | BindingFlags.Public) - .Select(z => z.GetValue(null)) - .Cast() - .ToArray(); - } - ); - - public static IEnumerable Defaults => _defaults.Value; - - public static WorkDoneProgressKind Begin = new WorkDoneProgressKind("begin"); - public static WorkDoneProgressKind End = new WorkDoneProgressKind("end"); - public static WorkDoneProgressKind Report = new WorkDoneProgressKind("report"); - - private readonly string _value; - - public WorkDoneProgressKind(string modifier) => _value = modifier; - - public static implicit operator WorkDoneProgressKind(string kind) => new WorkDoneProgressKind(kind); - - public static implicit operator string(WorkDoneProgressKind kind) => kind._value; - - public override string ToString() => _value; - public bool Equals(WorkDoneProgressKind other) => _value == other._value; - - public override bool Equals(object obj) => obj is WorkDoneProgressKind other && Equals(other); - - public override int GetHashCode() => _value.GetHashCode(); - - public static bool operator ==(WorkDoneProgressKind left, WorkDoneProgressKind right) => left.Equals(right); - - public static bool operator !=(WorkDoneProgressKind left, WorkDoneProgressKind right) => !left.Equals(right); + public static WorkDoneProgressKind Begin { get; } = new WorkDoneProgressKind("begin"); + public static WorkDoneProgressKind End { get; } = new WorkDoneProgressKind("end"); + public static WorkDoneProgressKind Report { get; } = new WorkDoneProgressKind("report"); } /// diff --git a/src/Protocol/Models/IEnumLikeString.cs b/src/Protocol/Models/IEnumLikeString.cs deleted file mode 100644 index cbaa32aa7..000000000 --- a/src/Protocol/Models/IEnumLikeString.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace OmniSharp.Extensions.LanguageServer.Protocol.Models -{ - public interface IEnumLikeString - { - } -} diff --git a/src/Protocol/Serialization/Serializer.cs b/src/Protocol/Serialization/Serializer.cs index 1e1f343b3..9c1b9bd25 100644 --- a/src/Protocol/Serialization/Serializer.cs +++ b/src/Protocol/Serialization/Serializer.cs @@ -5,6 +5,7 @@ using System.Reflection; using Newtonsoft.Json; using OmniSharp.Extensions.JsonRpc.Serialization; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals; diff --git a/test/Generation.Tests/EnumLikeStringGeneratorTests.cs b/test/Generation.Tests/EnumLikeStringGeneratorTests.cs new file mode 100644 index 000000000..a55a74410 --- /dev/null +++ b/test/Generation.Tests/EnumLikeStringGeneratorTests.cs @@ -0,0 +1,64 @@ +using System.Threading.Tasks; +using OmniSharp.Extensions.JsonRpc.Generators; +using OmniSharp.Extensions.JsonRpc.Generators.Cache; +using TestingUtils; + +namespace Generation.Tests +{ + public class EnumLikeStringGeneratorTests + { + [FactWithSkipOn(SkipOnPlatform.Windows)] + public async Task Auto_Magically_Implements_IEnumLikeString() + { + var source = @" +using OmniSharp.Extensions.JsonRpc.Generation; +namespace Test { + [StringEnum] + public readonly partial struct ThreadEventReason + { + public static ThreadEventReason Started { get; } = new ThreadEventReason(""started""); + public static ThreadEventReason Exited { get; } = new ThreadEventReason(""exited""); + } +} +"; + var expected = @" +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using OmniSharp.Extensions.JsonRpc; +using OmniSharp.Extensions.JsonRpc.Serialization.Converters; + +namespace Test +{ + [JsonConverter(typeof(EnumLikeStringConverter))] + [DebuggerDisplay(""{_value}"")] + public readonly partial struct ThreadEventReason : IEquatable, IEquatable, IEnumLikeString + { + private static readonly Lazy> _defaults = new Lazy>(() => + { + return typeof(ThreadEventReason).GetProperties(BindingFlags.Static | BindingFlags.Public).Where(z => z.Name != nameof(Defaults)).Select(z => z.GetValue(null)).Cast().ToArray(); + }); + public static IEnumerable Defaults => _defaults.Value; + private readonly string _value; + public ThreadEventReason(string type) => _value = type; + public static implicit operator ThreadEventReason(string kind) => new ThreadEventReason(kind); + public static implicit operator string (ThreadEventReason kind) => kind._value; + public override string ToString() => _value; + public bool Equals(ThreadEventReason other) => _value == other._value; + public bool Equals(string other) => _value == other; + public override bool Equals(object obj) => obj is string s && Equals(s) || obj is ThreadEventReason other && Equals(other); + public override int GetHashCode() => _value.GetHashCode(); + public static bool operator ==(ThreadEventReason left, ThreadEventReason right) => left.Equals(right); + public static bool operator !=(ThreadEventReason left, ThreadEventReason right) => !left.Equals(right); + } +} +#nullable restore"; + CacheKeyHasher.Cache = true; + await GenerationHelpers.AssertGeneratedAsExpected(source, expected); + } + } +} diff --git a/test/JsonRpc.Tests/IntegrationTests.cs b/test/JsonRpc.Tests/IntegrationTests.cs index 6e6422015..748892b56 100644 --- a/test/JsonRpc.Tests/IntegrationTests.cs +++ b/test/JsonRpc.Tests/IntegrationTests.cs @@ -9,6 +9,7 @@ using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.JsonRpc.Server; using OmniSharp.Extensions.JsonRpc.Testing; +using TestingUtils; using Xunit; using Xunit.Abstractions; @@ -29,7 +30,7 @@ private class Data public string Value { get; set; } = null!; } - [Fact] + [RetryFact] public async Task Should_Send_and_receive_requests() { var (client, server) = await Initialize( @@ -44,7 +45,7 @@ public async Task Should_Send_and_receive_requests() clientResponse.Value.Should().Be("myresponse"); } - [Fact] + [RetryFact] public async Task Should_throw_when_sending_requests() { var (client, server) = await Initialize( @@ -59,7 +60,7 @@ public async Task Should_throw_when_sending_requests() serverRequest.Should().Throw(); } - [Fact] + [RetryFact] public async Task Should_throw_when_receiving_requests() { var (client, server) = await Initialize( @@ -74,7 +75,7 @@ public async Task Should_throw_when_receiving_requests() serverRequest.Should().Throw(); } - [Fact] + [RetryFact] public async Task Should_Send_and_receive_notifications() { var clientNotification = new AsyncSubject(); @@ -107,7 +108,7 @@ public async Task Should_Send_and_receive_notifications() clientResponse.Value.Should().Be("esnopserym"); } - [Fact] + [RetryFact] public async Task Should_Send_and_cancel_requests_immediate() { var (client, server) = await Initialize( @@ -143,7 +144,7 @@ public async Task Should_Send_and_cancel_requests_immediate() } } - [Fact] + [RetryFact] public async Task Should_Send_and_cancel_requests_from_otherside() { var (client, server) = await Initialize( @@ -180,7 +181,7 @@ public async Task Should_Send_and_cancel_requests_from_otherside() } } - [Fact] + [RetryFact] public async Task Should_Cancel_Parallel_Requests_When_Options_Are_Given() { var (client, server) = await Initialize( @@ -231,7 +232,7 @@ public async Task Should_Cancel_Parallel_Requests_When_Options_Are_Given() } } - [Fact] + [RetryFact] public async Task Should_Link_Request_A_to_Request_B() { var (client, server) = await Initialize( diff --git a/test/Lsp.Tests/Integration/InitializationTests.cs b/test/Lsp.Tests/Integration/InitializationTests.cs index 383034eb9..e7acc04bb 100644 --- a/test/Lsp.Tests/Integration/InitializationTests.cs +++ b/test/Lsp.Tests/Integration/InitializationTests.cs @@ -21,6 +21,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Window; using OmniSharp.Extensions.LanguageServer.Server; using Serilog.Events; +using TestingUtils; using Xunit; using Xunit.Abstractions; @@ -32,7 +33,7 @@ public InitializationTests(ITestOutputHelper outputHelper) : base(new JsonRpcTes { } - [Fact] + [RetryFact] public async Task Logs_should_be_allowed_during_startup() { await Initialize(ConfigureClient, ConfigureServer); @@ -41,7 +42,7 @@ public async Task Logs_should_be_allowed_during_startup() _logs.Should().ContainInOrder("OnInitialize", "OnInitialized"); } - [Fact] + [RetryFact] public async Task Facades_should_be_resolvable() { var (client, server) = await Initialize(ConfigureClient, ConfigureServer); @@ -53,7 +54,7 @@ public async Task Facades_should_be_resolvable() response.Should().NotBeNull(); } - [Fact] + [RetryFact] public async Task Should_Not_Be_Able_To_Send_Messages_Unit_Initialization() { if (!(TestOptions.ClientLoggerFactory is TestLoggerFactory loggerFactory)) throw new Exception("wtf"); @@ -95,7 +96,7 @@ public async Task Should_Not_Be_Able_To_Send_Messages_Unit_Initialization() onInitializedNotify.Received(1).Invoke(); } - [Fact] + [RetryFact] public async Task Should_Be_Able_To_Register_Before_Initialize() { var (client, server) = Create(options => options.EnableDynamicRegistration().EnableAllCapabilities(), options => { }); diff --git a/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs b/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs index 08a55a724..0e85ed2ad 100644 --- a/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs +++ b/test/Lsp.Tests/Integration/LanguageServerConfigurationTests.cs @@ -31,7 +31,7 @@ public LanguageServerConfigurationTests(ITestOutputHelper outputHelper) : base(n { } - [Fact] + [RetryFact] public async Task Should_Not_Support_Configuration_It_Not_Configured() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, o => { }); @@ -45,7 +45,7 @@ public async Task Should_Not_Support_Configuration_It_Not_Configured() server.Configuration.AsEnumerable().Should().BeEmpty(); } - [Fact] + [RetryFact] public async Task Should_Allow_Null_Response() { var (client, server) = await Initialize( @@ -59,7 +59,7 @@ public async Task Should_Allow_Null_Response() a.Should().NotThrow(); } - [Fact] + [RetryFact] public async Task Should_Update_Configuration_On_Server() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer); @@ -74,7 +74,7 @@ public async Task Should_Update_Configuration_On_Server() server.Configuration["othersection:value"].Should().Be("key"); } - [Fact] + [RetryFact] public async Task Should_Update_Configuration_On_Server_After_Starting() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, options => {}); @@ -90,7 +90,7 @@ public async Task Should_Update_Configuration_On_Server_After_Starting() server.Configuration["othersection:value"].Should().Be("key"); } - [Fact] + [RetryFact] public async Task Should_Update_Configuration_Should_Stop_Watching_Sections() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer); @@ -112,7 +112,7 @@ public async Task Should_Update_Configuration_Should_Stop_Watching_Sections() server.Configuration["othersection:value"].Should().BeNull(); } - [Fact] + [RetryFact] public async Task Should_Update_Scoped_Configuration() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer); @@ -134,7 +134,7 @@ public async Task Should_Update_Scoped_Configuration() scopedConfiguration["othersection:value"].Should().Be("scopedkey"); } - [Fact] + [RetryFact] public async Task Should_Fallback_To_Original_Configuration() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer); @@ -166,7 +166,7 @@ public async Task Should_Fallback_To_Original_Configuration() scopedConfiguration["othersection:value"].Should().Be("key"); } - [Fact] + [RetryFact] public async Task Should_Only_Update_Configuration_Items_That_Are_Defined() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, ConfigureServer); @@ -208,7 +208,7 @@ public async Task Should_Support_Configuration_Binding() data.Port.Should().Be(80); } - [Fact] + [RetryFact] public async Task Should_Support_Options() { var (_, server, configuration) = await InitializeWithConfiguration(ConfigureClient, options => { diff --git a/test/Lsp.Tests/Integration/ProgressTests.cs b/test/Lsp.Tests/Integration/ProgressTests.cs index c7841d015..ca23f1701 100644 --- a/test/Lsp.Tests/Integration/ProgressTests.cs +++ b/test/Lsp.Tests/Integration/ProgressTests.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; +using TestingUtils; using Xunit; using Xunit.Abstractions; @@ -25,7 +26,7 @@ private class Data public string Value { get; set; } = "Value"; } - [Fact] + [RetryFact] public async Task Should_Send_Progress_From_Server_To_Client() { var token = new ProgressToken(Guid.NewGuid().ToString()); @@ -73,7 +74,7 @@ await Observable.Create( data.Should().ContainInOrder(new[] { "1", "3", "2", "4", "5" }); } - [Fact] + [RetryFact] public async Task Should_Send_Progress_From_Client_To_Server() { var token = new ProgressToken(Guid.NewGuid().ToString()); @@ -121,14 +122,14 @@ await Observable.Create( data.Should().ContainInOrder(new[] { "1", "3", "2", "4", "5" }); } - [Fact] + [RetryFact] public void WorkDone_Should_Be_Supported() { Server.WorkDoneManager.IsSupported.Should().BeTrue(); Client.WorkDoneManager.IsSupported.Should().BeTrue(); } - [Fact] + [RetryFact] public async Task Should_Support_Creating_Work_Done_From_Sever_To_Client() { var token = new ProgressToken(Guid.NewGuid().ToString()); @@ -190,7 +191,7 @@ public async Task Should_Support_Creating_Work_Done_From_Sever_To_Client() results.Should().ContainInOrder("Begin", "Report 1", "Report 2", "Report 3", "Report 4", "End"); } - [Fact] + [RetryFact] public async Task Should_Support_Observing_Work_Done_From_Client_To_Server_Request() { var token = new ProgressToken(Guid.NewGuid().ToString()); @@ -252,7 +253,7 @@ public async Task Should_Support_Observing_Work_Done_From_Client_To_Server_Reque results.Should().ContainInOrder("Begin", "Report 1", "Report 2", "Report 3", "Report 4", "End"); } - [Fact] + [RetryFact] public async Task Should_Support_Cancelling_Work_Done_From_Client_To_Server_Request() { var token = new ProgressToken(Guid.NewGuid().ToString()); diff --git a/test/Lsp.Tests/Integration/RenameTests.cs b/test/Lsp.Tests/Integration/RenameTests.cs index 1ea72c999..182df71f3 100644 --- a/test/Lsp.Tests/Integration/RenameTests.cs +++ b/test/Lsp.Tests/Integration/RenameTests.cs @@ -32,7 +32,7 @@ public RenameTests(ITestOutputHelper outputHelper) : base(new JsonRpcTestOptions _rename = Substitute.For>>(); } - [Fact] + [RetryFact] public async Task Should_Handle_Rename_With_No_Value() { _prepareRename.Invoke(Arg.Any(), Arg.Any(), Arg.Any()) @@ -88,7 +88,7 @@ public async Task Should_Handle_Rename_With_No_Value() capability1.Should().BeSameAs(capability2); } - [Fact] + [RetryFact] public async Task Should_Handle_Prepare_Rename_With_No_Value() { _prepareRename.Invoke(Arg.Any(), Arg.Any(), Arg.Any()) @@ -106,7 +106,7 @@ public async Task Should_Handle_Prepare_Rename_With_No_Value() result.Should().BeNull(); } - [Fact] + [RetryFact] public async Task Should_Handle_Prepare_Rename_With_Range() { _prepareRename.Invoke(Arg.Any(), Arg.Any(), Arg.Any()) @@ -135,7 +135,7 @@ public async Task Should_Handle_Prepare_Rename_With_Range() result!.IsRange.Should().BeTrue(); } - [Fact] + [RetryFact] public async Task Should_Handle_Prepare_Rename_With_PlaceholderRange() { _prepareRename.Invoke(Arg.Any(), Arg.Any(), Arg.Any()) @@ -168,7 +168,7 @@ public async Task Should_Handle_Prepare_Rename_With_PlaceholderRange() result!.IsPlaceholderRange.Should().BeTrue(); } - [Fact] + [RetryFact] public async Task Should_Handle_Prepare_Rename_With_DefaultBehavior() { _prepareRename.Invoke(Arg.Any(), Arg.Any(), Arg.Any()) @@ -193,7 +193,7 @@ public async Task Should_Handle_Prepare_Rename_With_DefaultBehavior() result!.IsDefaultBehavior.Should().BeTrue(); } - [Fact] + [RetryFact] public async Task Should_Not_Register_Prepare_Rename() { var (client, _) = await Initialize(ClientOptionsAction, ServerOptionsAction); diff --git a/test/coverlet.runsettings b/test/coverlet.runsettings index b13b639e4..46a49a78a 100644 --- a/test/coverlet.runsettings +++ b/test/coverlet.runsettings @@ -5,7 +5,7 @@ json,lcov,cobertura,opencover [Bogus*]*,[Autofac*]*,[FakeItEasy*]*,[Moq*]*,[xunit*]*,[Microsoft.*]*,[XunitXml*]*,[coverlet.*]*,[System.*]*,[*]JetBrains.Annotations* - [Omnisharp.*]* + [OmniSharp.*]* Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute