diff --git a/build/all_projects.settings.targets b/build/all_projects.settings.targets index 872e74d5d..2adfaf275 100755 --- a/build/all_projects.settings.targets +++ b/build/all_projects.settings.targets @@ -21,6 +21,8 @@ $(MIEngineRoot)\tools $(MIEngineRoot)obj\$(Configuration)\$(MSBuildProjectName)\ $(ToolsHome)\NuGet\NuGet.exe + + 12.0 diff --git a/src/DebugEngineHost.Common/HostLogChannel.cs b/src/DebugEngineHost.Common/HostLogChannel.cs index 14bdc1b57..699cdb3ad 100644 --- a/src/DebugEngineHost.Common/HostLogChannel.cs +++ b/src/DebugEngineHost.Common/HostLogChannel.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. /* @@ -51,18 +51,18 @@ public interface ILogChannel public class HostLogChannel : ILogChannel { private readonly Action _log; - private StreamWriter _logFile; + private StreamWriter? _logFile; private LogLevel _minLevelToBeLogged; private readonly object _lock = new object(); - private HostLogChannel() { } + private HostLogChannel() { _log = null!; } - public HostLogChannel(Action logAction, string file, LogLevel logLevel) + public HostLogChannel(Action logAction, string? file, LogLevel logLevel) { _log = logAction; - if (!string.IsNullOrEmpty(file)) + if (!IsNullOrEmpty(file)) { _logFile = File.CreateText(file); } diff --git a/src/DebugEngineHost.Stub/DebugEngineHost.Stub.csproj b/src/DebugEngineHost.Stub/DebugEngineHost.Stub.csproj index d84411a11..197d85e9d 100755 --- a/src/DebugEngineHost.Stub/DebugEngineHost.Stub.csproj +++ b/src/DebugEngineHost.Stub/DebugEngineHost.Stub.csproj @@ -3,6 +3,7 @@ 1.0.0 + enable @@ -23,6 +24,12 @@ + + + Shared\%(Filename).cs + + + diff --git a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs index 3d4462044..7b7fae658 100644 --- a/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs +++ b/src/DebugEngineHost.Stub/DebugEngineHost.ref.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.Debugger.Interop; using System; using System.Collections.Generic; -using System.Diagnostics; +using ConditionalAttribute = global::System.Diagnostics.ConditionalAttribute; using System.Threading; @@ -88,7 +88,7 @@ public void Dispose() { } /// Name of the value to obtain /// [Optional] null if the value doesn't exist, otherwise the value /// - public object GetValue(string valueName) + public object? GetValue(string valueName) { throw new NotImplementedException(); } @@ -146,7 +146,7 @@ public string RegistryRoot /// /// The metric to read. /// [Optional] value of the metric. Null if the metric is not defined. - public object GetEngineMetric(string metric) + public object? GetEngineMetric(string metric) { throw new NotImplementedException(); } @@ -178,7 +178,7 @@ public T GetDebuggerConfigurationSetting(string settingName, T defaultValue) /// /// launch options type name /// - public object GetCustomLauncher(string launcherTypeName) + public object? GetCustomLauncher(string launcherTypeName) { throw new NotImplementedException(); } @@ -277,8 +277,8 @@ public static void EnableNatvisDiagnostics(Action callback, LogLevel lev /// /// Sets the log file to write to. /// - /// The file to write engine logs to. - public static void SetEngineLogFile(string logFile) + /// The file to write engine logs to, or null if none + public static void SetEngineLogFile(string? logFile) { throw new NotImplementedException(); } @@ -287,7 +287,7 @@ public static void SetEngineLogFile(string logFile) /// Gets the engine log channel created by 'EnableHostLogging' /// /// A logger object if logging is enabled, or null if it is not - public static ILogChannel GetEngineLogChannel() + public static ILogChannel? GetEngineLogChannel() { throw new NotImplementedException(); } @@ -296,7 +296,7 @@ public static ILogChannel GetEngineLogChannel() /// Gets the Natvis log channel if its been created. /// /// A logger object if logging is enabled, or null if it is not - public static ILogChannel GetNatvisLogChannel() + public static ILogChannel? GetNatvisLogChannel() { throw new NotImplementedException(); } @@ -339,7 +339,7 @@ public static class HostLoader /// CLSID to CoCreate /// [Optional] loaded object. Null if the type is not registered, or points to a type that doesn't exist [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Co")] - public static object VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) + public static object? VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) { throw new NotImplementedException(); } @@ -472,7 +472,7 @@ public static void FindNatvis(NatvisLoader loader) /// /// Enable's tracking the VS 'Natvis Diagnostic Messages (C++ only)' setting. /// - public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) + public static IDisposable? WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) { throw new NotImplementedException(); } @@ -480,7 +480,7 @@ public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore config /// /// Return the solution's root directory, null if no solution /// - public static string FindSolutionRoot() + public static string? FindSolutionRoot() { throw new NotImplementedException(); } @@ -663,7 +663,7 @@ public static void SendEvent(string eventName, params KeyValuePair /// Exception object to report. /// Name of the engine reporting the exception. Ex:Microsoft.MIEngine - public static void ReportCurrentException(Exception currentException, string engineName) + public static void ReportCurrentException(Exception currentException, string? engineName) { throw new NotImplementedException(); } diff --git a/src/DebugEngineHost.Stub/Shared/NullableHelpers.cs b/src/DebugEngineHost.Stub/Shared/NullableHelpers.cs new file mode 100644 index 000000000..9dc195616 --- /dev/null +++ b/src/DebugEngineHost.Stub/Shared/NullableHelpers.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +global using static global::Microsoft.DebugEngineHost.NullableHelpers; + +namespace Microsoft.DebugEngineHost +{ + using System.Diagnostics.CodeAnalysis; + using ConditionalAttribute = System.Diagnostics.ConditionalAttribute; + using SysDebug = System.Diagnostics.Debug; + +#pragma warning disable 8763 // A method marked [DoesNotReturn] should not return. + + /// + /// Helper class to support nullable reference work when compiling against .NET Standard / .NET Framework + /// + public static class NullableHelpers + { + /// + /// Wrapper around string.IsNullOrEmpty to add the `[NotNullWhen(false)]` annotation + /// + /// string to test + /// True if the string is null or empty + static public bool IsNullOrEmpty([NotNullWhen(false)] string? s) + { + return string.IsNullOrEmpty(s); + } + + /// + /// Wrapper around string.IsNullOrWhiteSpace to add the `[NotNullWhen(false)]` annotation + /// + /// string to test + /// True if the string is null, empty, or only whitespace + static public bool IsNullOrWhiteSpace([NotNullWhen(false)] string? s) + { + return string.IsNullOrWhiteSpace(s); + } + + /// + /// This is a shim on top of the class which adds attributes used + /// in nullability analysis. This is important because without the DoesNotReturnIf/DoesNotReturn attributes, + /// on Debug.Assert/Debug.Fail the C# compiler will see code like: + /// + /// Debug.Assert(myArg != null, "Invalid argument") + /// + /// And decide that because the code was attempting to handle 'myArg' being null, that it must be possible + /// for it to be null. + /// + [System.Diagnostics.DebuggerNonUserCode()] + public static class Debug + { + /// + /// Checks for a condition; if the condition is false, displays a message box that shows the call stack. + /// + /// The conditional expression to evaluate. If the condition is true, a failure message is not sent and the message box is not displayed. + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition) + { + SysDebug.Assert(condition); + } + + /// + /// Checks for a condition; if the condition is false, outputs a specified message and displays a message box that shows the call stack. + /// + /// The conditional expression to evaluate. If the condition is true, the specified message is not sent and the message box is not displayed. + /// The message to send to the collection. + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string message) + { + SysDebug.Assert(condition, message); + } + + /// + /// Checks for a condition; if the condition is false, outputs two specified messages and displays a message box that shows the call stack. + /// + /// The conditional expression to evaluate. If the condition is true, the specified messages are not sent and the message box is not displayed. + /// The message to send to the collection. + /// The detailed message to send to the collection. + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string message, string detailMessage) + { + SysDebug.Assert(condition, message, detailMessage); + } + + /// + /// Emits the specified error message. + /// + /// A message to emit. + [Conditional("DEBUG")] + [DoesNotReturn] + public static void Fail(string message) + { + SysDebug.Fail(message); + } + + /// + /// Emits an error message and a detailed error message. + /// + /// A message to emit. + /// A detailed message to emit. + [Conditional("DEBUG")] + [DoesNotReturn] + public static void Fail(string message, string detailMessage) + { + SysDebug.Fail(message, detailMessage); + } + + /// + /// Writes a message followed by a line terminator to the debugger. + /// + /// A message to write. + [Conditional("DEBUG")] + public static void WriteLine(string message) + { + SysDebug.WriteLine(message); + } + + /// + /// Writes the value of the object's method to the debugger. + /// + /// An object whose value is sent to the debugger. + [Conditional("DEBUG")] + public static void WriteLine(object value) + { + SysDebug.WriteLine(value); + } + + /// + /// Writes a category name and message to the debugger. + /// + /// A message to write. + /// A category name used to organize the output. + [Conditional("DEBUG")] + public static void WriteLine(string message, string category) + { + SysDebug.WriteLine(message, category); + } + + /// + /// Writes a category name and the value of the object's method to the debugger. + /// + /// An object whose value is sent to the debugger. + /// A category name used to organize the output. + [Conditional("DEBUG")] + public static void WriteLine(object value, string category) + { + SysDebug.WriteLine(value, category); + } + } + } +} \ No newline at end of file diff --git a/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj b/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj index 428c8b4ca..58c85fc60 100644 --- a/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj +++ b/src/DebugEngineHost.VSCode/DebugEngineHost.VSCode.csproj @@ -3,6 +3,7 @@ 1.0.0 + enable @@ -20,11 +21,16 @@ netstandard2.0 - - - - - + + + Shared\%(Filename).cs + + + Shared\%(Filename).cs + + + Shared\%(Filename).cs + diff --git a/src/DebugEngineHost.VSCode/HostConfigurationSection.cs b/src/DebugEngineHost.VSCode/HostConfigurationSection.cs index 632257540..5fe40a546 100644 --- a/src/DebugEngineHost.VSCode/HostConfigurationSection.cs +++ b/src/DebugEngineHost.VSCode/HostConfigurationSection.cs @@ -21,7 +21,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public object GetValue(string valueName) + public object? GetValue(string valueName) { ExceptionSettings.TriggerState state; if (_defaultTriggers.TryGetValue(valueName, out state)) diff --git a/src/DebugEngineHost.VSCode/HostConfigurationStore.cs b/src/DebugEngineHost.VSCode/HostConfigurationStore.cs index 9736c3735..2f391b70d 100644 --- a/src/DebugEngineHost.VSCode/HostConfigurationStore.cs +++ b/src/DebugEngineHost.VSCode/HostConfigurationStore.cs @@ -15,11 +15,12 @@ public sealed class HostConfigurationStore public HostConfigurationStore(string adapterId) { - _config = EngineConfiguration.TryGet(adapterId); - if (_config == null) + EngineConfiguration? config = EngineConfiguration.TryGet(adapterId); + if (config is null) { throw new ArgumentOutOfRangeException(nameof(adapterId)); } + _config = config; } public void SetEngineGuid(Guid value) @@ -35,12 +36,12 @@ public string RegistryRoot } } - public object GetCustomLauncher(string launcherTypeName) + public object? GetCustomLauncher(string launcherTypeName) { throw new NotImplementedException(); } - public object GetEngineMetric(string metric) + public object? GetEngineMetric(string metric) { if (string.CompareOrdinal("GlobalVisualizersDirectory", metric) == 0) { @@ -55,7 +56,7 @@ public object GetEngineMetric(string metric) public void GetExceptionCategorySettings(Guid categoryId, out HostConfigurationSection categoryConfigSection, out string categoryName) { var category = _config.ExceptionSettings.Categories.FirstOrDefault((x) => x.Id == categoryId); - if (category == null) + if (category is null) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, HostResources.Error_ExceptionCategoryMissing, categoryId)); } diff --git a/src/DebugEngineHost.VSCode/HostLoader.cs b/src/DebugEngineHost.VSCode/HostLoader.cs index 59d9d9f27..b3727e92b 100644 --- a/src/DebugEngineHost.VSCode/HostLoader.cs +++ b/src/DebugEngineHost.VSCode/HostLoader.cs @@ -7,7 +7,7 @@ namespace Microsoft.DebugEngineHost { public static class HostLoader { - public static object VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) + public static object? VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) { throw new NotImplementedException(); } diff --git a/src/DebugEngineHost.VSCode/HostLogger.cs b/src/DebugEngineHost.VSCode/HostLogger.cs index 1bd6805ab..9d784538e 100644 --- a/src/DebugEngineHost.VSCode/HostLogger.cs +++ b/src/DebugEngineHost.VSCode/HostLogger.cs @@ -7,14 +7,14 @@ namespace Microsoft.DebugEngineHost { public static class HostLogger { - private static ILogChannel s_natvisLogChannel; - private static ILogChannel s_engineLogChannel; + private static ILogChannel? s_natvisLogChannel; + private static ILogChannel? s_engineLogChannel; - private static string s_engineLogFile; + private static string? s_engineLogFile; public static void EnableNatvisDiagnostics(Action callback, LogLevel level = LogLevel.Verbose) { - if (s_natvisLogChannel == null) + if (s_natvisLogChannel is null) { // TODO: Support writing natvis logs to a file. s_natvisLogChannel = new HostLogChannel(callback, null, level); @@ -23,23 +23,23 @@ public static void EnableNatvisDiagnostics(Action callback, LogLevel lev public static void EnableHostLogging(Action callback, LogLevel level = LogLevel.Verbose) { - if (s_engineLogChannel == null) + if (s_engineLogChannel is null) { s_engineLogChannel = new HostLogChannel(callback, s_engineLogFile, level); } } - public static void SetEngineLogFile(string logFile) + public static void SetEngineLogFile(string? logFile) { s_engineLogFile = logFile; } - public static ILogChannel GetEngineLogChannel() + public static ILogChannel? GetEngineLogChannel() { return s_engineLogChannel; } - public static ILogChannel GetNatvisLogChannel() + public static ILogChannel? GetNatvisLogChannel() { return s_natvisLogChannel; } diff --git a/src/DebugEngineHost.VSCode/HostMarshal.cs b/src/DebugEngineHost.VSCode/HostMarshal.cs index 41f780164..f135307d0 100644 --- a/src/DebugEngineHost.VSCode/HostMarshal.cs +++ b/src/DebugEngineHost.VSCode/HostMarshal.cs @@ -80,8 +80,7 @@ public static IDebugDocumentPosition2 GetDocumentPositionForIntPtr(IntPtr docume { lock (s_documentPositions) { - IDebugDocumentPosition2 documentPosition; - if (!s_documentPositions.TryGet((int)documentPositionId, out documentPosition)) + if (!s_documentPositions.TryGet((int)documentPositionId, out IDebugDocumentPosition2? documentPosition)) { throw new ArgumentOutOfRangeException(nameof(documentPositionId)); } @@ -94,8 +93,7 @@ public static IDebugFunctionPosition2 GetDebugFunctionPositionForIntPtr(IntPtr f { lock (s_functionPositions) { - IDebugFunctionPosition2 functionPosition; - if (!s_functionPositions.TryGet((int)functionPositionId, out functionPosition)) + if (!s_functionPositions.TryGet((int)functionPositionId, out IDebugFunctionPosition2? functionPosition)) { throw new ArgumentOutOfRangeException(nameof(functionPositionId)); } @@ -134,8 +132,7 @@ public static IDebugCodeContext2 GetDebugCodeContextForIntPtr(IntPtr contextId) { lock (s_codeContexts) { - IDebugCodeContext2 codeContext; - if (!s_codeContexts.TryGet(contextId.ToInt32(), out codeContext)) + if (!s_codeContexts.TryGet(contextId.ToInt32(), out IDebugCodeContext2? codeContext)) { throw new ArgumentOutOfRangeException(nameof(contextId)); } diff --git a/src/DebugEngineHost.VSCode/HostNatvisProject.cs b/src/DebugEngineHost.VSCode/HostNatvisProject.cs index e24c4f812..a9c7855e2 100644 --- a/src/DebugEngineHost.VSCode/HostNatvisProject.cs +++ b/src/DebugEngineHost.VSCode/HostNatvisProject.cs @@ -14,13 +14,13 @@ public static void FindNatvis(NatvisLoader loader) // In-solution natvis is not supported for VS Code now, so do nothing. } - public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) + public static IDisposable? WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) { // VS Code does not have a registry setting for Natvis Diagnostics return null; } - public static string FindSolutionRoot() + public static string? FindSolutionRoot() { // This was added in MIEngine to support breakpoint sourcefile mapping. // TODO: Return the project root if we want a similar implementation. diff --git a/src/DebugEngineHost.VSCode/HostOutputWindow.cs b/src/DebugEngineHost.VSCode/HostOutputWindow.cs index 63b249ab6..eba011b40 100644 --- a/src/DebugEngineHost.VSCode/HostOutputWindow.cs +++ b/src/DebugEngineHost.VSCode/HostOutputWindow.cs @@ -2,13 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Diagnostics; namespace Microsoft.DebugEngineHost { public static class HostOutputWindow { - private static Action s_launchErrorCallback; + private static Action? s_launchErrorCallback; public static void InitializeLaunchErrorCallback(Action launchErrorCallback) { @@ -18,7 +17,7 @@ public static void InitializeLaunchErrorCallback(Action launchErrorCallb public static void WriteLaunchError(string outputMessage) { - if (s_launchErrorCallback != null) + if (s_launchErrorCallback is not null) { s_launchErrorCallback(outputMessage); } diff --git a/src/DebugEngineHost.VSCode/HostRunInTerminal.cs b/src/DebugEngineHost.VSCode/HostRunInTerminal.cs index b8c94e835..60dbcf109 100644 --- a/src/DebugEngineHost.VSCode/HostRunInTerminal.cs +++ b/src/DebugEngineHost.VSCode/HostRunInTerminal.cs @@ -3,14 +3,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; namespace Microsoft.DebugEngineHost { public static class HostRunInTerminal { - private static Action, Dictionary, Action, Action> s_runInTerminalCallback; + private static Action, Dictionary, Action, Action>? s_runInTerminalCallback; /// /// Checks to see if RunInTerminal is available @@ -18,7 +17,7 @@ public static class HostRunInTerminal /// public static bool IsRunInTerminalAvailable() { - return s_runInTerminalCallback != null; + return s_runInTerminalCallback is not null; } /// @@ -26,7 +25,7 @@ public static bool IsRunInTerminalAvailable() /// public static void RunInTerminal(string title, string cwd, bool useExternalConsole, IReadOnlyList commandArgs, IReadOnlyDictionary environmentVars, Action success, Action failure) { - if (s_runInTerminalCallback != null) + if (s_runInTerminalCallback is not null) { Dictionary env = new Dictionary(); foreach (var item in environmentVars) diff --git a/src/DebugEngineHost.VSCode/HostTelemetry.cs b/src/DebugEngineHost.VSCode/HostTelemetry.cs index 0eed205ce..0801a507e 100644 --- a/src/DebugEngineHost.VSCode/HostTelemetry.cs +++ b/src/DebugEngineHost.VSCode/HostTelemetry.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; +using ConditionalAttribute = global::System.Diagnostics.ConditionalAttribute; using System.Linq; using System.Reflection; @@ -29,11 +29,11 @@ public static class HostTelemetry private const string TelemetryHostVersion = @"VS.Diagnostics.Debugger.HostVersion"; private const string TelemetryAdapterId = @"VS.Diagnostics.Debugger.AdapterId"; - private static Action[]> s_telemetryCallback; - private static string s_engineName; - private static string s_engineVersion; - private static string s_hostVersion; - private static string s_adapterId; + private static Action[]>? s_telemetryCallback; + private static string? s_engineName; + private static string? s_engineVersion; + private static string? s_hostVersion; + private static string? s_adapterId; public static void InitializeTelemetry(Action[]> telemetryCallback, TypeInfo engineType, string adapterId) { @@ -56,7 +56,7 @@ public static void InitializeTelemetry(Action[] eventProperties) { #if LAB - if (s_telemetryCallback != null) + if (s_telemetryCallback is not null) { s_telemetryCallback(eventName, eventProperties); } @@ -70,34 +70,35 @@ public static void SendEvent(string eventName, params KeyValuePairException object to report. /// [Optional] Name of the engine reporting the exception. Ex:Microsoft.MIEngine. /// In OpenDebugAD7, this is optional. - public static void ReportCurrentException(Exception currentException, string engineName) + public static void ReportCurrentException(Exception currentException, string? engineName) { try { // Report the inner-most exception - while (currentException.InnerException != null) + while (currentException.InnerException is not null) { currentException = currentException.InnerException; } - if (s_hostVersion == null) + if (s_hostVersion is null) { // InitializeTelemetry not called yet return; } - if (engineName == null) + if (engineName is null) { + Debug.Assert(s_engineName is not null, "Should be impossible -- if we got past the previous check, InitializeTelemetry was already called"); engineName = s_engineName; } SendEvent(TelemetryNonFatalWatsonEventName, new KeyValuePair(TelemetryNonFatalErrorImplementationName, engineName), - new KeyValuePair(TelemetryNonFatalErrorExceptionTypeName, currentException.GetType().FullName), - new KeyValuePair(TelemetryNonFatalErrorExceptionStackName, currentException.StackTrace), + new KeyValuePair(TelemetryNonFatalErrorExceptionTypeName, currentException.GetType().FullName ?? string.Empty), + new KeyValuePair(TelemetryNonFatalErrorExceptionStackName, currentException.StackTrace ?? string.Empty), new KeyValuePair(TelemetryNonFatalErrorExceptionHResult, currentException.HResult), - new KeyValuePair(TelemetryEngineVersion, s_engineVersion), - new KeyValuePair(TelemetryAdapterId, s_adapterId), + new KeyValuePair(TelemetryEngineVersion, s_engineVersion ?? string.Empty), + new KeyValuePair(TelemetryAdapterId, s_adapterId ?? string.Empty), new KeyValuePair(TelemetryHostVersion, s_hostVersion) ); } @@ -110,7 +111,7 @@ public static void ReportCurrentException(Exception currentException, string eng private static string GetVersionAttributeValue(TypeInfo engineType) { var attribute = engineType.Assembly.GetCustomAttribute(typeof(System.Reflection.AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute; - if (attribute == null) + if (attribute is null) return string.Empty; return attribute.Version; diff --git a/src/DebugEngineHost.VSCode/VSCode/AssemblyResolver.cs b/src/DebugEngineHost.VSCode/VSCode/AssemblyResolver.cs index e8b46a10d..943379461 100644 --- a/src/DebugEngineHost.VSCode/VSCode/AssemblyResolver.cs +++ b/src/DebugEngineHost.VSCode/VSCode/AssemblyResolver.cs @@ -19,18 +19,18 @@ public static void Initialize() AssemblyLoadContext.Default.Resolving += OnAssemblyResolve; } - private static Assembly OnAssemblyResolve(AssemblyLoadContext loadContext, AssemblyName assemblyName) + private static Assembly? OnAssemblyResolve(AssemblyLoadContext loadContext, AssemblyName assemblyName) { - Assembly asm = InnerResolveHandler(assemblyName); + Assembly? asm = InnerResolveHandler(assemblyName); return asm; } - private static Assembly InnerResolveHandler(AssemblyName assemblyName) + private static Assembly? InnerResolveHandler(AssemblyName assemblyName) { string assemblyFileName = string.Concat(assemblyName.Name, ".dll"); - if (assemblyName.CultureInfo != null && !assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture)) + if (assemblyName.CultureInfo is not null && !assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture)) { //Prepend the culture directory (e.g. ja\Microsoft.VisualStudio.Test.resources.dll) assemblyFileName = Path.Combine(assemblyName.CultureInfo.Name, assemblyFileName); @@ -45,9 +45,9 @@ private static Assembly InnerResolveHandler(AssemblyName assemblyName) } } - Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyFileName)); + Assembly? asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyFileName)); - if (asm == null) + if (asm is null) { lock (s_unresolvedNames) { diff --git a/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs b/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs index 265d4246c..678a9d20d 100644 --- a/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs +++ b/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs @@ -21,14 +21,14 @@ namespace Microsoft.DebugEngineHost.VSCode { public sealed class EngineConfiguration { - private static string s_adapterDirectory; + private static string? s_adapterDirectory; private static readonly Dictionary s_dict = new Dictionary(); - public string AdapterId { get; private set; } + public string AdapterId { get; private set; } = null!; private bool _isReadOnly; - private string _assemblyName; - private string _engineClass; + private string _assemblyName = null!; + private string _engineClass = null!; private readonly ExceptionSettings _exceptionSettings = new ExceptionSettings(); private bool _conditionalBP; private bool _functionBP; @@ -89,14 +89,14 @@ public bool DataBP /// Path to the directory public static string GetAdapterDirectory() { - if (s_adapterDirectory == null) + if (s_adapterDirectory is null) { // Configuration goes in the directory of this assembly string thisModulePath = typeof(EngineConfiguration).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName; Interlocked.CompareExchange(ref s_adapterDirectory, Path.GetDirectoryName(thisModulePath), null); } - return s_adapterDirectory; + return s_adapterDirectory!; } /// @@ -107,7 +107,7 @@ public static string GetAdapterDirectory() /// The directory to use. public static void SetAdapterDirectory(string adapterDirectory) { - if (adapterDirectory == null) + if (adapterDirectory is null) { throw new ArgumentNullException(nameof(adapterDirectory)); } @@ -118,11 +118,11 @@ public static void SetAdapterDirectory(string adapterDirectory) } } - public static EngineConfiguration TryGet(string adapterId) + public static EngineConfiguration? TryGet(string adapterId) { lock (s_dict) { - EngineConfiguration result; + EngineConfiguration? result; if (s_dict.TryGetValue(adapterId, out result)) { return result; @@ -131,6 +131,10 @@ public static EngineConfiguration TryGet(string adapterId) string engineConfigPath = Path.Combine(GetAdapterDirectory(), adapterId + ".ad7Engine.json"); string engineConfigText = File.ReadAllText(engineConfigPath); result = JsonConvert.DeserializeObject(engineConfigText); + if (result is null) + { + return null; + } result.AdapterId = adapterId; result.ExceptionSettings.MakeReadOnly(); result._isReadOnly = true; @@ -149,15 +153,15 @@ public object LoadEngine() AssemblyName assemblyName = new System.Reflection.AssemblyName(this.EngineAssemblyName); Assembly engineAssembly = Assembly.Load(assemblyName); - Type engineClass = engineAssembly.GetType(this.EngineClassName); - if (engineClass == null) + Type? engineClass = engineAssembly.GetType(this.EngineClassName); + if (engineClass is null) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, HostResources.Error_ClassNotFound, this.EngineClassName, this.EngineAssemblyName)); } - object instance = Activator.CreateInstance(engineClass); + object? instance = Activator.CreateInstance(engineClass); - if (instance == null) + if (instance is null) { throw new InvalidDataException(string.Format(CultureInfo.CurrentCulture, HostResources.Error_ConstructorNotFound, this.EngineClassName, this.EngineAssemblyName)); } diff --git a/src/DebugEngineHost.VSCode/VSCode/ExceptionBreakpointFilter.cs b/src/DebugEngineHost.VSCode/VSCode/ExceptionBreakpointFilter.cs index 6e2064e84..618c28b7d 100644 --- a/src/DebugEngineHost.VSCode/VSCode/ExceptionBreakpointFilter.cs +++ b/src/DebugEngineHost.VSCode/VSCode/ExceptionBreakpointFilter.cs @@ -4,7 +4,6 @@ using Microsoft.VisualStudio.Debugger.Interop; using Newtonsoft.Json; using System; -using System.Diagnostics; namespace Microsoft.DebugEngineHost.VSCode { @@ -14,13 +13,13 @@ namespace Microsoft.DebugEngineHost.VSCode /// sealed public class ExceptionBreakpointFilter { - private string _filter; + private string _filter = null!; /// /// The label for the button that will appear in the UI /// [JsonRequired] - public string label { get; set; } + public string label { get; set; } = null!; /// /// The identifier for this filter. @@ -43,7 +42,7 @@ public string filter public bool supportsCondition { get; set; } [JsonRequired] - public string conditionDescription { get; set; } + public string conditionDescription { get; set; } = null!; [JsonRequired] public Guid categoryId { get; set; } diff --git a/src/DebugEngineHost.VSCode/VSCode/ExceptionSettings.cs b/src/DebugEngineHost.VSCode/VSCode/ExceptionSettings.cs index 2328784ff..980a18831 100644 --- a/src/DebugEngineHost.VSCode/VSCode/ExceptionSettings.cs +++ b/src/DebugEngineHost.VSCode/VSCode/ExceptionSettings.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Globalization; using System.Linq; @@ -26,7 +25,7 @@ public enum TriggerState sealed public class CategoryConfiguration { [JsonRequired] - public string Name; + public string Name = null!; [JsonRequired] public Guid Id; diff --git a/src/DebugEngineHost.VSCode/VSCode/HandleCollection.cs b/src/DebugEngineHost.VSCode/VSCode/HandleCollection.cs index 1d23ea8a7..902dc0b4e 100644 --- a/src/DebugEngineHost.VSCode/VSCode/HandleCollection.cs +++ b/src/DebugEngineHost.VSCode/VSCode/HandleCollection.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.DebugEngineHost.VSCode { @@ -34,7 +35,7 @@ public int Create(T value) return handle; } - public bool TryGet(int handle, out T value) + public bool TryGet(int handle, [MaybeNullWhen(false)] out T value) { if (_handleMap.TryGetValue(handle, out value)) { @@ -43,11 +44,11 @@ public bool TryGet(int handle, out T value) return false; } - public bool TryGetFirst(out T value) + public bool TryGetFirst([MaybeNullWhen(false)] out T value) { if (IsEmpty) { - value = default(T); + value = default; return false; } @@ -58,8 +59,7 @@ public T this[int handle] { get { - T value; - if (!TryGet(handle, out value)) + if (!TryGet(handle, out T? value)) { throw new ArgumentOutOfRangeException(nameof(handle)); } diff --git a/src/DebugEngineHost/DebugEngineHost.csproj b/src/DebugEngineHost/DebugEngineHost.csproj index a0f375ed7..66706dea0 100755 --- a/src/DebugEngineHost/DebugEngineHost.csproj +++ b/src/DebugEngineHost/DebugEngineHost.csproj @@ -3,6 +3,7 @@ 1.0.0 + enable @@ -26,11 +27,16 @@ $(VSSDKRoot)VisualStudioIntegration\Common\Assemblies\v4.0\Microsoft.VisualStudio.Debugger.Engine.dll - - - - - + + + Shared\%(Filename).cs + + + Shared\%(Filename).cs + + + Shared\%(Filename).cs + diff --git a/src/DebugEngineHost/FeedbackDiagnosticFileProvider.cs b/src/DebugEngineHost/FeedbackDiagnosticFileProvider.cs index db4a5f58b..07b9bb79e 100644 --- a/src/DebugEngineHost/FeedbackDiagnosticFileProvider.cs +++ b/src/DebugEngineHost/FeedbackDiagnosticFileProvider.cs @@ -1,13 +1,13 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using System.ComponentModel.Composition; -using System.Diagnostics; using System.IO; using System.Threading.Tasks; using Microsoft.Internal.VisualStudio.Shell.Embeddable.Feedback; +using Process = global::System.Diagnostics.Process; namespace Microsoft.DebugEngineHost { diff --git a/src/DebugEngineHost/Host.cs b/src/DebugEngineHost/Host.cs index 62e634ff8..40e1d8bf5 100644 --- a/src/DebugEngineHost/Host.cs +++ b/src/DebugEngineHost/Host.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; diff --git a/src/DebugEngineHost/HostConfigurationSection.cs b/src/DebugEngineHost/HostConfigurationSection.cs index 7f3f3f402..5a037f5ee 100644 --- a/src/DebugEngineHost/HostConfigurationSection.cs +++ b/src/DebugEngineHost/HostConfigurationSection.cs @@ -30,7 +30,7 @@ public void Dispose() /// /// Name of the value to obtain /// [Optional] null if the value doesn't exist, otherwise the value - public object GetValue(string valueName) + public object? GetValue(string valueName) { return _key.GetValue(valueName); } diff --git a/src/DebugEngineHost/HostConfigurationStore.cs b/src/DebugEngineHost/HostConfigurationStore.cs index 1f491a3d9..787d8359b 100644 --- a/src/DebugEngineHost/HostConfigurationStore.cs +++ b/src/DebugEngineHost/HostConfigurationStore.cs @@ -1,10 +1,9 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Win32; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -21,7 +20,7 @@ public sealed class HostConfigurationStore private const string LaunchersSectionName = "MILaunchers"; private const string NatvisDiagnosticsSectionName = "NatvisDiagnostics"; - private string _engineId; + private string? _engineId; private string _registryRoot; // HKLM RegistryKey @@ -29,15 +28,16 @@ public sealed class HostConfigurationStore public HostConfigurationStore(string registryRoot) { - if (string.IsNullOrEmpty(registryRoot)) + if (IsNullOrEmpty(registryRoot)) throw new ArgumentNullException(nameof(registryRoot)); _registryRoot = registryRoot; - _configKey = Registry.LocalMachine.OpenSubKey(registryRoot); - if (_configKey == null) + RegistryKey? configKey = Registry.LocalMachine.OpenSubKey(registryRoot); + if (configKey is null) { throw new HostConfigurationException(registryRoot); } + _configKey = configKey; } /// @@ -46,7 +46,7 @@ public HostConfigurationStore(string registryRoot) /// The new engine GUID to set public void SetEngineGuid(Guid value) { - if (_engineId != null) + if (_engineId is not null) { throw new InvalidOperationException(); } @@ -63,9 +63,9 @@ public string RegistryRoot } } - public object GetEngineMetric(string metric) + public object? GetEngineMetric(string metric) { - if (_engineId == null) + if (_engineId is null) { throw new InvalidOperationException(); } @@ -76,8 +76,8 @@ public object GetEngineMetric(string metric) public void GetExceptionCategorySettings(Guid categoryId, out HostConfigurationSection categoryConfigSection, out string categoryName) { string subKeyName = @"AD7Metrics\Exception\" + categoryId.ToString("B", CultureInfo.InvariantCulture); - RegistryKey categoryKey = _configKey.OpenSubKey(subKeyName); - if (categoryKey == null) + RegistryKey? categoryKey = _configKey.OpenSubKey(subKeyName); + if (categoryKey is null) { throw new HostConfigurationException("$RegRoot$\\" + subKeyName); } @@ -91,7 +91,7 @@ public T GetDebuggerConfigurationSetting(string settingName, T defaultValue) return GetDebuggerConfigurationSetting(DebuggerSectionName, settingName, defaultValue); } - public object GetCustomLauncher(string launcherTypeName) + public object? GetCustomLauncher(string launcherTypeName) { string guidstr = GetDebuggerConfigurationSetting(LaunchersSectionName, launcherTypeName, Guid.Empty.ToString()); Guid clsidLauncher = new Guid(guidstr); @@ -104,8 +104,8 @@ public object GetCustomLauncher(string launcherTypeName) private T GetDebuggerConfigurationSetting(string sectionName, string settingName, T defaultValue) { - object valueObj = GetOptionalValue(sectionName, settingName); - if (valueObj == null) + object? valueObj = GetOptionalValue(sectionName, settingName); + if (valueObj is null) { return defaultValue; } @@ -124,11 +124,11 @@ private T GetDebuggerConfigurationSetting(string sectionName, string settingN return result; } - private object GetOptionalValue(string section, string valueName) + private object? GetOptionalValue(string section, string valueName) { - using (RegistryKey key = _configKey.OpenSubKey(section)) + using (RegistryKey? key = _configKey.OpenSubKey(section)) { - if (key == null) + if (key is null) { return null; } @@ -141,12 +141,17 @@ private object GetOptionalValue(string section, string valueName) /// This method grabs the Debugger Subkey in HKCU /// /// The subkey of Debugger if it exists. Returns null otherwise. - public HostConfigurationSection GetCurrentUserDebuggerSection() + public HostConfigurationSection? GetCurrentUserDebuggerSection() { - using (RegistryKey hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot)) + using (RegistryKey? hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot)) { - RegistryKey debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName); - if (debuggerSection != null) + if (hkcuRoot is null) + { + return null; + } + + RegistryKey? debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName); + if (debuggerSection is not null) { return new HostConfigurationSection(debuggerSection); } @@ -158,16 +163,21 @@ public HostConfigurationSection GetCurrentUserDebuggerSection() /// Grabs the Debugger/NatvisDiagnostic subkey in HKCU /// /// The NatvisDiagnostic subkey if it exists. Returns null otherwise. - public HostConfigurationSection GetNatvisDiagnosticSection() + public HostConfigurationSection? GetNatvisDiagnosticSection() { - using (RegistryKey hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot)) + using (RegistryKey? hkcuRoot = Registry.CurrentUser.OpenSubKey(_registryRoot)) { - using (RegistryKey debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName)) + if (hkcuRoot is null) + { + return null; + } + + using (RegistryKey? debuggerSection = hkcuRoot.OpenSubKey(DebuggerSectionName)) { - if (debuggerSection != null) + if (debuggerSection is not null) { - RegistryKey natvisDiagnosticKey = debuggerSection.OpenSubKey(NatvisDiagnosticsSectionName); - if (natvisDiagnosticKey != null) + RegistryKey? natvisDiagnosticKey = debuggerSection.OpenSubKey(NatvisDiagnosticsSectionName); + if (natvisDiagnosticKey is not null) { return new HostConfigurationSection(natvisDiagnosticKey); } diff --git a/src/DebugEngineHost/HostLoader.cs b/src/DebugEngineHost/HostLoader.cs index 84d666298..f19f6bc97 100644 --- a/src/DebugEngineHost/HostLoader.cs +++ b/src/DebugEngineHost/HostLoader.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Win32; @@ -23,21 +23,24 @@ public static class HostLoader /// Registry root to lookup the type /// CLSID to CoCreate /// [Optional] loaded object. Null if the type is not registered, or points to a type that doesn't exist - public static object VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) + public static object? VsCoCreateManagedObject(HostConfigurationStore configStore, Guid clsid) { - string assemblyNameString, className, codeBase; + string? assemblyNameString, className, codeBase; if (!GetManagedTypeInfoForCLSID(configStore, clsid, out assemblyNameString, out className, out codeBase)) { return null; } - if (codeBase != null && !File.Exists(codeBase)) + Debug.Assert(assemblyNameString is not null, "assemblyNameString should be set when GetManagedTypeInfoForCLSID returns true"); + Debug.Assert(className is not null, "className should be set when GetManagedTypeInfoForCLSID returns true"); + + if (codeBase is not null && !File.Exists(codeBase)) { return null; } AssemblyName assemblyName = new AssemblyName(assemblyNameString); - if (codeBase != null) + if (codeBase is not null) { assemblyName.CodeBase = "file:///" + codeBase; } @@ -46,34 +49,34 @@ public static object VsCoCreateManagedObject(HostConfigurationStore configStore, return assemblyObject.CreateInstance(className); } - private static bool GetManagedTypeInfoForCLSID(HostConfigurationStore configStore, Guid clsid, out string assembly, out string className, out string codeBase) + private static bool GetManagedTypeInfoForCLSID(HostConfigurationStore configStore, Guid clsid, out string? assembly, out string? className, out string? codeBase) { assembly = null; className = null; codeBase = null; string keyPath = configStore.RegistryRoot + @"\CLSID\" + clsid.ToString("B"); - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyPath)) + using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(keyPath)) { - if (key == null) + if (key is null) return false; - object oAssembly = key.GetValue("Assembly"); - object oClassName = key.GetValue("Class"); - object oCodeBase = key.GetValue("CodeBase"); + object? oAssembly = key.GetValue("Assembly"); + object? oClassName = key.GetValue("Class"); + object? oCodeBase = key.GetValue("CodeBase"); - if (oAssembly == null || !(oAssembly is string)) + if (oAssembly is not string) return false; - if (oClassName == null || !(oClassName is string)) + if (oClassName is not string) return false; // CodeBase is not required, but it is an error if it isn't a string - if (oCodeBase != null && !(oCodeBase is string)) + if (oCodeBase is not null and not string) return false; assembly = (string)oAssembly; className = (string)oClassName; - codeBase = (string)oCodeBase; + codeBase = oCodeBase as string; return true; } diff --git a/src/DebugEngineHost/HostLogger.cs b/src/DebugEngineHost/HostLogger.cs index fbeca7eb4..ab29a977f 100644 --- a/src/DebugEngineHost/HostLogger.cs +++ b/src/DebugEngineHost/HostLogger.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -11,22 +11,22 @@ namespace Microsoft.DebugEngineHost { public static class HostLogger { - private static ILogChannel s_natvisLogChannel; - private static ILogChannel s_engineLogChannel; + private static ILogChannel? s_natvisLogChannel; + private static ILogChannel? s_engineLogChannel; - private static string s_engineLogFile; + private static string? s_engineLogFile; - private static FeedbackLogBuffer s_circularBuffer; - private static VSFeedbackLogger s_feedbackLogger; + private static FeedbackLogBuffer? s_circularBuffer; + private static VSFeedbackLogger? s_feedbackLogger; public static void EnableHostLogging(Action callback, LogLevel level = LogLevel.Verbose) { - if (s_engineLogChannel == null) + if (s_engineLogChannel is null) { s_engineLogChannel = new HostLogChannel(callback, s_engineLogFile, level); } - if (s_feedbackLogger == null) + if (s_feedbackLogger is null) { s_feedbackLogger = new VSFeedbackLogger(EnsureFeedbackBuffer()); } @@ -34,7 +34,7 @@ public static void EnableHostLogging(Action callback, LogLevel level = L public static void EnableNatvisDiagnostics(Action callback, LogLevel level = LogLevel.Verbose) { - if (s_natvisLogChannel== null) + if (s_natvisLogChannel is null) { s_natvisLogChannel = new HostLogChannel(callback, null, level); } @@ -45,17 +45,17 @@ public static void DisableNatvisDiagnostics() s_natvisLogChannel = null; } - public static void SetEngineLogFile(string logFile) + public static void SetEngineLogFile(string? logFile) { s_engineLogFile = logFile; } - public static ILogChannel GetEngineLogChannel() + public static ILogChannel? GetEngineLogChannel() { return s_engineLogChannel; } - public static ILogChannel GetNatvisLogChannel() + public static ILogChannel? GetNatvisLogChannel() { return s_natvisLogChannel; } @@ -65,7 +65,7 @@ public static ILogChannel GetNatvisLogChannel() /// public static bool IsFeedbackLogEnabled { - get { return s_circularBuffer != null; } + get { return s_circularBuffer is not null; } } /// @@ -73,7 +73,7 @@ public static bool IsFeedbackLogEnabled /// public static void WriteFeedbackLog(string message) { - if (string.IsNullOrEmpty(message)) + if (IsNullOrEmpty(message)) { return; } @@ -87,7 +87,7 @@ public static void WriteFeedbackLog(string message) private static FeedbackLogBuffer EnsureFeedbackBuffer() { - if (s_circularBuffer == null) + if (s_circularBuffer is null) { Interlocked.CompareExchange(ref s_circularBuffer, new FeedbackLogBuffer(), null); } @@ -102,8 +102,8 @@ internal static bool HasFeedbackEntries { get { - FeedbackLogBuffer buffer = s_circularBuffer; - return buffer != null && buffer.HasEntries; + FeedbackLogBuffer? buffer = s_circularBuffer; + return buffer is not null && buffer.HasEntries; } } diff --git a/src/DebugEngineHost/HostMarshal.cs b/src/DebugEngineHost/HostMarshal.cs index d3d6f1844..9c249c2af 100644 --- a/src/DebugEngineHost/HostMarshal.cs +++ b/src/DebugEngineHost/HostMarshal.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.Debugger.Interop; @@ -8,7 +8,6 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using System.Diagnostics; namespace Microsoft.DebugEngineHost { diff --git a/src/DebugEngineHost/HostNatvisProject.cs b/src/DebugEngineHost/HostNatvisProject.cs index 11c3510eb..a86b8063d 100644 --- a/src/DebugEngineHost/HostNatvisProject.cs +++ b/src/DebugEngineHost/HostNatvisProject.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -34,7 +34,7 @@ internal RegisterMonitorWrapper(RegistryMonitor currentMonitor) public void Dispose() { CurrentMonitor.Dispose(); - CurrentMonitor = null; + CurrentMonitor = null!; } } @@ -66,12 +66,12 @@ public static void FindNatvis(NatvisLoader loader) paths.ForEach((s) => loader(s)); } - public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) + public static IDisposable? WatchNatvisOptionSetting(HostConfigurationStore configStore, ILogChannel natvisLogger) { - RegisterMonitorWrapper rmw = null; + RegisterMonitorWrapper? rmw = null; - HostConfigurationSection natvisDiagnosticSection = configStore.GetNatvisDiagnosticSection(); - if (natvisDiagnosticSection != null) + HostConfigurationSection? natvisDiagnosticSection = configStore.GetNatvisDiagnosticSection(); + if (natvisDiagnosticSection is not null) { // DiagnosticSection exists, set current log level and watch for changes. SetNatvisLogLevel(natvisDiagnosticSection); @@ -81,9 +81,9 @@ public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore config else { // NatvisDiagnostic section has not been created, we need to watch for the creation. - HostConfigurationSection debuggerSection = configStore.GetCurrentUserDebuggerSection(); + HostConfigurationSection? debuggerSection = configStore.GetCurrentUserDebuggerSection(); - if (debuggerSection != null) + if (debuggerSection is not null) { // We only care about the debugger subkey's keys since we are waiting for the NatvisDiagnostics // section to be created. @@ -93,9 +93,9 @@ public static IDisposable WatchNatvisOptionSetting(HostConfigurationStore config rm.RegChanged += (sender, e) => { - HostConfigurationSection checkForSection = configStore.GetNatvisDiagnosticSection(); + HostConfigurationSection? checkForSection = configStore.GetNatvisDiagnosticSection(); - if (checkForSection != null) + if (checkForSection is not null) { // NatvisDiagnostic section found. Update the logger SetNatvisLogLevel(checkForSection); @@ -134,8 +134,8 @@ private static RegistryMonitor CreateAndStartNatvisDiagnosticMonitor(HostConfigu private static void SetNatvisLogLevel(HostConfigurationSection natvisDiagnosticSection) { - string level = natvisDiagnosticSection.GetValue("Level") as string; - if (level != null) + string? level = natvisDiagnosticSection.GetValue("Level") as string; + if (level is not null) { level = level.ToLower(CultureInfo.InvariantCulture); } @@ -169,13 +169,13 @@ private static void SetNatvisLogLevel(HostConfigurationSection natvisDiagnosticS string formattedMessage = string.Format(CultureInfo.InvariantCulture, "Natvis: {0}", message); HostOutputWindow.WriteLaunchError(formattedMessage); }, logLevel); - HostLogger.GetNatvisLogChannel().SetLogLevel(logLevel); + HostLogger.GetNatvisLogChannel()!.SetLogLevel(logLevel); } } - public static string FindSolutionRoot() + public static string? FindSolutionRoot() { - string path = null; + string? path = null; try { ThreadHelper.JoinableTaskFactory.Run(async () => @@ -217,14 +217,14 @@ internal enum VSENUMPROJFLAGS /// Gets the WorkspaceService from Microsoft.VisualStudio.Workspace /// /// This package won't be automatically loaded by MEF, so we need to manually acquire exported MEF Parts. - private static IVsFolderWorkspaceService GetWorkspaceService() + private static IVsFolderWorkspaceService? GetWorkspaceService() { - IComponentModel componentModel = ServiceProvider.GlobalProvider.GetService(typeof(SComponentModel).GUID) as IComponentModel; - if (componentModel != null) + IComponentModel? componentModel = ServiceProvider.GlobalProvider.GetService(typeof(SComponentModel).GUID) as IComponentModel; + if (componentModel is not null) { var workspaceServices = componentModel.DefaultExportProvider.GetExports(); - if (workspaceServices != null && workspaceServices.Any()) + if (workspaceServices is not null && workspaceServices.Any()) { return workspaceServices.First().Value; } @@ -237,11 +237,11 @@ private async static Task> GetOpenFolderSourceLocationsAsync var workspaceService = GetWorkspaceService(); IEnumerable sourcesArray = new List(); - if (workspaceService != null) + if (workspaceService is not null) { - IWorkspace currentWorkspace = workspaceService.CurrentWorkspace; - IIndexWorkspaceService indexWorkspaceService = currentWorkspace?.GetService(throwIfNotFound: false); - if (indexWorkspaceService != null) + IWorkspace? currentWorkspace = workspaceService.CurrentWorkspace; + IIndexWorkspaceService? indexWorkspaceService = currentWorkspace?.GetService(throwIfNotFound: false); + if (indexWorkspaceService is not null) { if (indexWorkspaceService.State != IndexWorkspaceState.Completed) { @@ -280,8 +280,8 @@ public void Report(string value) public async static System.Threading.Tasks.Task FindNatvisInSolutionImplAsync(List paths) { - var solution = (IVsSolution)Package.GetGlobalService(typeof(SVsSolution)); - if (solution == null) + var solution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution; + if (solution is null) { return; // failed to find a solution } @@ -321,8 +321,8 @@ public async static System.Threading.Tasks.Task FindNatvisInSolutionImplAsync(Li public static void FindNatvisInVSIXImpl(List paths) { - var extManager = (IVsExtensionManagerPrivate)Package.GetGlobalService(typeof(SVsExtensionManager)); - if (extManager == null) + var extManager = Package.GetGlobalService(typeof(SVsExtensionManager)) as IVsExtensionManagerPrivate; + if (extManager is null) { return; // failed to find the extension manager } @@ -330,13 +330,13 @@ public static void FindNatvisInVSIXImpl(List paths) BuildEnvironmentPath("NativeCrossPlatformVisualizer", extManager, paths); } - public static string FindSolutionRootImpl() + public static string? FindSolutionRootImpl() { - string root = null; - string slnFile; - string slnUserFile; - var solution = (IVsSolution)Package.GetGlobalService(typeof(SVsSolution)); - if (solution == null) + string? root = null; + string? slnFile; + string? slnUserFile; + var solution = (IVsSolution?)Package.GetGlobalService(typeof(SVsSolution)); + if (solution is null) { return null; // failed to find a solution } @@ -363,8 +363,8 @@ private static void BuildEnvironmentPath(string name, IVsExtensionManagerPrivate private static void LoadNatvisFromProject(IVsHierarchy hier, List paths, bool solutionLevel) { - IVsProject4 proj = hier as IVsProject4; - if (proj == null) + IVsProject4? proj = hier as IVsProject4; + if (proj is null) { return; } diff --git a/src/DebugEngineHost/HostOutputWindow.cs b/src/DebugEngineHost/HostOutputWindow.cs index 9dec6445a..b2c54b671 100644 --- a/src/DebugEngineHost/HostOutputWindow.cs +++ b/src/DebugEngineHost/HostOutputWindow.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; @@ -13,9 +12,9 @@ namespace Microsoft.DebugEngineHost { internal static class VsOutputWindowWrapper { - private static Lazy outputWindowLazy = new Lazy(() => + private static Lazy outputWindowLazy = new Lazy(() => { - IVsOutputWindow outputWindow = null; + IVsOutputWindow? outputWindow = null; try { ThreadHelper.ThrowIfNotOnUIThread(); @@ -28,9 +27,9 @@ internal static class VsOutputWindowWrapper return outputWindow; }, LazyThreadSafetyMode.PublicationOnly); - private static Lazy shellLazy = new Lazy(() => + private static Lazy shellLazy = new Lazy(() => { - IVsUIShell shell = null; + IVsUIShell? shell = null; try { ThreadHelper.ThrowIfNotOnUIThread(); @@ -75,8 +74,8 @@ public static void Write(string message, string pane = DefaultOutputPane) try { // Get the Output window - IVsOutputWindow outputWindow = outputWindowLazy.Value; - if (outputWindow == null) + IVsOutputWindow? outputWindow = outputWindowLazy.Value; + if (outputWindow is null) { return; } @@ -108,10 +107,10 @@ public static void Write(string message, string pane = DefaultOutputPane) outputPane.Activate(); // Show the output window - IVsUIShell shell = shellLazy.Value; - if (shell != null) + IVsUIShell? shell = shellLazy.Value; + if (shell is not null) { - object inputVariant = null; + object? inputVariant = null; shell.PostExecCommand(VSConstants.GUID_VSStandardCommandSet97, (uint)VSConstants.VSStd97CmdID.OutputWindow, 0, ref inputVariant); } } diff --git a/src/DebugEngineHost/HostRunInTerminal.cs b/src/DebugEngineHost/HostRunInTerminal.cs index db666042f..05079fdd1 100644 --- a/src/DebugEngineHost/HostRunInTerminal.cs +++ b/src/DebugEngineHost/HostRunInTerminal.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/DebugEngineHost/HostTelemetry.cs b/src/DebugEngineHost/HostTelemetry.cs index eea4a0004..39729b7aa 100644 --- a/src/DebugEngineHost/HostTelemetry.cs +++ b/src/DebugEngineHost/HostTelemetry.cs @@ -1,14 +1,14 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System.Globalization; using Microsoft.Internal.VisualStudio.Shell; +using Conditional = global::System.Diagnostics.ConditionalAttribute; namespace Microsoft.DebugEngineHost { @@ -56,7 +56,7 @@ public static void SendEvent(string eventName, params KeyValuePair /// Exception object to report. /// Name of the engine reporting the exception. Ex:Microsoft.MIEngine - public static void ReportCurrentException(Exception currentException, string engineName) + public static void ReportCurrentException(Exception currentException, string? engineName) { Debug.Fail(string.Format(CultureInfo.InvariantCulture, "{0} was raised and would normally be reported to telemetry.\n\nStack trace: {1}", currentException.GetType(), currentException.StackTrace)); diff --git a/src/DebugEngineHost/HostWaitDialog.cs b/src/DebugEngineHost/HostWaitDialog.cs index 5de1eafe0..96216b196 100644 --- a/src/DebugEngineHost/HostWaitDialog.cs +++ b/src/DebugEngineHost/HostWaitDialog.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -17,7 +17,7 @@ namespace Microsoft.DebugEngineHost /// public sealed class HostWaitDialog : IDisposable { - private VSImpl.VSWaitDialog _theDialog; + private VSImpl.VSWaitDialog? _theDialog; public HostWaitDialog(string format, string caption) { try @@ -31,7 +31,7 @@ public HostWaitDialog(string format, string caption) } public void ShowWaitDialog(string item) { - if (_theDialog != null) + if (_theDialog is not null) { _theDialog.ShowWaitDialog(item); } @@ -39,7 +39,7 @@ public void ShowWaitDialog(string item) public void EndWaitDialog() { - if (_theDialog != null) + if (_theDialog is not null) { _theDialog.EndWaitDialog(); } diff --git a/src/DebugEngineHost/HostWaitLoop.cs b/src/DebugEngineHost/HostWaitLoop.cs index f1edbd281..e6153eef7 100644 --- a/src/DebugEngineHost/HostWaitLoop.cs +++ b/src/DebugEngineHost/HostWaitLoop.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -14,7 +14,7 @@ namespace Microsoft.DebugEngineHost public sealed class HostWaitLoop { private readonly object _progressLock = new object(); - private VSImpl.VsWaitLoop _vsWaitLoop; + private VSImpl.VsWaitLoop? _vsWaitLoop; public HostWaitLoop(string message) { @@ -34,7 +34,7 @@ public HostWaitLoop(string message) /// Text to set. public void SetText(string text) { - _vsWaitLoop.SetText(text); + _vsWaitLoop?.SetText(text); } /// @@ -46,7 +46,7 @@ public void SetText(string text) /// Thrown by the JIT if Visual Studio is not installed public void Wait(WaitHandle launchCompleteHandle, CancellationTokenSource cancellationSource) { - if (_vsWaitLoop != null) + if (_vsWaitLoop is not null) { _vsWaitLoop.Wait(launchCompleteHandle, cancellationSource); @@ -65,7 +65,7 @@ public void SetProgress(int totalSteps, int currentStep, string progressText) { lock (_progressLock) { - if (_vsWaitLoop != null) + if (_vsWaitLoop is not null) { _vsWaitLoop.SetProgress(totalSteps, currentStep, progressText); } diff --git a/src/DebugEngineHost/RegistryMonitor.cs b/src/DebugEngineHost/RegistryMonitor.cs index 0281bc371..d733e2569 100644 --- a/src/DebugEngineHost/RegistryMonitor.cs +++ b/src/DebugEngineHost/RegistryMonitor.cs @@ -1,4 +1,4 @@ -// // Copyright (c) Microsoft. All rights reserved. +// // Copyright (c) Microsoft. All rights reserved. // // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Win32; @@ -9,7 +9,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; -using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -51,7 +50,7 @@ private static extern int RegNotifyChangeKeyValue(SafeRegistryHandle hKey, bool private readonly bool _watchSubtree; // Set when monitoring is stopped - private AutoResetEvent _stoppedEvent; + private AutoResetEvent? _stoppedEvent; // Members to handle multiple stop calls. private bool _isStopped = false; @@ -60,7 +59,7 @@ private static extern int RegNotifyChangeKeyValue(SafeRegistryHandle hKey, bool /// /// Occurs when the specified registry key has changed. /// - public event EventHandler RegChanged; + public event EventHandler? RegChanged; private readonly ILogChannel _nativsLogger; @@ -126,7 +125,7 @@ private void Monitor() _nativsLogger?.WriteLine(LogLevel.Error, Resource.Error_WatchRegistry, errorCode); break; } - RegChanged?.Invoke(this, null); + RegChanged?.Invoke(this, EventArgs.Empty); } } } @@ -134,7 +133,7 @@ private void Monitor() } finally { - _stoppedEvent.Dispose(); + _stoppedEvent?.Dispose(); _stoppedEvent = null; _section.Dispose(); diff --git a/src/DebugEngineHost/VSFeedbackLogger.cs b/src/DebugEngineHost/VSFeedbackLogger.cs index 30dd240cb..bb7eb4852 100644 --- a/src/DebugEngineHost/VSFeedbackLogger.cs +++ b/src/DebugEngineHost/VSFeedbackLogger.cs @@ -1,11 +1,11 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Newtonsoft.Json.Linq; +using Process = global::System.Diagnostics.Process; namespace Microsoft.DebugEngineHost { @@ -21,10 +21,10 @@ internal class VSFeedbackLogger private readonly System.DateTime _vsStartTime; private bool _enabled; - private readonly FileSystemWatcher _vsFeedbackFileWatcher; + private readonly FileSystemWatcher? _vsFeedbackFileWatcher; private readonly FeedbackLogBuffer _circularBuffer; - private StreamWriter _logWriter; + private StreamWriter? _logWriter; private readonly object _syncObj = new object(); internal VSFeedbackLogger(FeedbackLogBuffer circularBuffer) @@ -103,7 +103,7 @@ private void OnFeedbackSemaphoreDeleted(object sender, FileSystemEventArgs e) _enabled = false; _circularBuffer.FlushNewEntries(); - if (_logWriter != null) + if (_logWriter is not null) { _logWriter.Dispose(); _logWriter = null; @@ -128,8 +128,8 @@ private bool IsLoggingEnabledForThisVSInstance(string semaphoreFilePath) string content = File.ReadAllText(semaphoreFilePath); JObject root = JObject.Parse(content); - JContainer pidCollection = root["processIds"] as JContainer; - if (pidCollection != null) + JContainer? pidCollection = root["processIds"] as JContainer; + if (pidCollection is not null) { return pidCollection.Values().Contains(_vsPid); } diff --git a/src/DebugEngineHost/VSImpl/VSEventCallbackWrapper.cs b/src/DebugEngineHost/VSImpl/VSEventCallbackWrapper.cs index cd1ded32b..98f7a7535 100644 --- a/src/DebugEngineHost/VSImpl/VSEventCallbackWrapper.cs +++ b/src/DebugEngineHost/VSImpl/VSEventCallbackWrapper.cs @@ -1,11 +1,10 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.VisualStudio.Debugger.Interop; using Microsoft.VisualStudio.OLE.Interop; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -31,7 +30,7 @@ internal class VSEventCallbackWrapper : IDebugEventCallback2 private readonly object _cacheLock = new object(); private int _cachedEventCallbackThread; - private IDebugEventCallback2 _cacheEventCallback; + private IDebugEventCallback2? _cacheEventCallback; internal VSEventCallbackWrapper(IDebugEventCallback2 ad7Callback) { @@ -90,11 +89,11 @@ private IDebugEventCallback2 GetAD7EventCallback() // We send esentially all events from the same thread, so lets optimize the common case int currentThreadId = Thread.CurrentThread.ManagedThreadId; - if (_cacheEventCallback != null && _cachedEventCallbackThread == currentThreadId) + if (_cacheEventCallback is not null && _cachedEventCallbackThread == currentThreadId) { lock (_cacheLock) { - if (_cacheEventCallback != null && _cachedEventCallbackThread == currentThreadId) + if (_cacheEventCallback is not null && _cachedEventCallbackThread == currentThreadId) { return _cacheEventCallback; } diff --git a/src/DebugEngineHost/VSImpl/VsWaitDialog.cs b/src/DebugEngineHost/VSImpl/VsWaitDialog.cs index 1dc56fcd2..402450ddc 100644 --- a/src/DebugEngineHost/VSImpl/VsWaitDialog.cs +++ b/src/DebugEngineHost/VSImpl/VsWaitDialog.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -11,7 +11,7 @@ namespace Microsoft.DebugEngineHost.VSImpl { internal class VSWaitDialog { - private readonly IVsThreadedWaitDialog2 _waitDialog; + private readonly IVsThreadedWaitDialog2? _waitDialog; private const int m_delayShowDialogTimeInSeconds = 2; private bool _started; private string _format; @@ -36,7 +36,7 @@ public VSWaitDialog(string format, string caption) } public void ShowWaitDialog(string item) { - if (_waitDialog == null) + if (_waitDialog is null) { return; } @@ -69,7 +69,7 @@ public void ShowWaitDialog(string item) public void EndWaitDialog() { - if (_waitDialog == null) + if (_waitDialog is null) { return; } diff --git a/src/DebugEngineHost/VSImpl/VsWaitLoop.cs b/src/DebugEngineHost/VSImpl/VsWaitLoop.cs index 8cba857d5..afd691899 100644 --- a/src/DebugEngineHost/VSImpl/VsWaitLoop.cs +++ b/src/DebugEngineHost/VSImpl/VsWaitLoop.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -11,7 +11,6 @@ using System.Threading; using Microsoft.Win32.SafeHandles; using Microsoft.VisualStudio; -using System.Diagnostics; using System.Runtime.InteropServices; namespace Microsoft.DebugEngineHost.VSImpl @@ -24,7 +23,7 @@ namespace Microsoft.DebugEngineHost.VSImpl // ************************************************************ internal class VsWaitLoop { - private readonly IVsCommonMessagePump _messagePump; + private readonly IVsCommonMessagePump? _messagePump; private VsWaitLoop(string text) { @@ -52,10 +51,10 @@ private VsWaitLoop(string text) _messagePump = messagePump; } - static public VsWaitLoop TryCreate(string text) + static public VsWaitLoop? TryCreate(string text) { VsWaitLoop waitLoop = new VsWaitLoop(text); - if (waitLoop._messagePump == null) + if (waitLoop._messagePump is null) return null; return waitLoop; @@ -71,6 +70,7 @@ static public VsWaitLoop TryCreate(string text) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle")] public void Wait(WaitHandle launchCompleteHandle, CancellationTokenSource cancellationSource) { + Debug.Assert(_messagePump is not null, "Wait should only be called on instances created via TryCreate that returned non-null"); int hr; SafeWaitHandle safeWaitHandle = launchCompleteHandle.SafeWaitHandle; @@ -118,11 +118,13 @@ public void Wait(WaitHandle launchCompleteHandle, CancellationTokenSource cancel public void SetProgress(int totalSteps, int currentStep, string progressText) { + Debug.Assert(_messagePump is not null, "SetProgress should only be called on a valid VsWaitLoop instance"); _messagePump.SetProgressInfo(totalSteps, currentStep, progressText); } public void SetText(string text) { + Debug.Assert(_messagePump is not null, "SetText should only be called on a valid VsWaitLoop instance"); _messagePump.SetWaitText(text); } } diff --git a/src/Shared/NullableAttributes.cs b/src/Shared/NullableAttributes.cs new file mode 100644 index 000000000..63d4ca7f2 --- /dev/null +++ b/src/Shared/NullableAttributes.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// Source: + +// This file is a tweaked version of https://github.com/dotnet/runtime/blob/c95aa3f48aa591dca870ee00c31c3d8bdc740b5a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +#pragma warning disable CA1019 // Define accessors for attribute arguments + +// Currently, we always need these definitions, but it can be removed if we ever compile against .NET 5 or newer +#if !NETCOREAPP + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + internal sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } +} + +#endif \ No newline at end of file