From 13681b7a3f1952cefe25527048c8dfc20de3842f Mon Sep 17 00:00:00 2001 From: slozier Date: Mon, 6 Sep 2021 17:07:58 -0400 Subject: [PATCH] Support for implementation specific options using -X (#254) * Update .editorconfig * Make PrintUsage/PrintVersion virtual * Add implementation-specific options * Check that val is set * Make PrintLanguageHelp virtual * Remove UseImplementationSpecificOptions handling * Note unparsed options * Do SaveAssemblies in HandleImplementationSpecificOption --- .editorconfig | 26 +++ .../Hosting/Shell/ConsoleHost.cs | 10 +- .../Hosting/Shell/OptionsParser.cs | 156 ++++++++++++------ .../Hosting/Shell/Remote/RemoteConsoleHost.cs | 4 +- .../Shell/Remote/RemoteRuntimeServer.cs | 4 +- 5 files changed, 138 insertions(+), 62 deletions(-) diff --git a/.editorconfig b/.editorconfig index d58015be..29342f80 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,6 +18,12 @@ csharp_new_line_before_catch = false csharp_new_line_before_finally = false csharp_space_after_keywords_in_control_flow_statements = true +csharp_style_prefer_index_operator = false +csharp_style_prefer_range_operator = false + +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = true + # use language keywords instead of BCL types dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion @@ -38,7 +44,11 @@ csharp_preferred_modifier_order = public, private, protected, internal, static, dotnet_analyzer_diagnostic.severity = warning dotnet_analyzer_diagnostic.category-style.severity = default +dotnet_diagnostic.CA1000.severity = none # CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1001.severity = suggestion # CA1001: Types that own disposable fields should be disposable +dotnet_diagnostic.CA1010.severity = suggestion # CA1010: Generic interface should also be implemented dotnet_diagnostic.CA1018.severity = suggestion # CA1018: Mark attributes with AttributeUsageAttribute +dotnet_diagnostic.CA1036.severity = suggestion # CA1036: Override methods on comparable types dotnet_diagnostic.CA1051.severity = none # CA1051: Do not declare visible instance fields dotnet_diagnostic.CA1069.severity = suggestion # CA1069: Enums values should not be duplicated dotnet_diagnostic.CA1200.severity = suggestion # CA1200: Avoid using cref tags with a prefix @@ -47,20 +57,36 @@ dotnet_diagnostic.CA1305.severity = none # CA1305: Specify IFormatProvide dotnet_diagnostic.CA1307.severity = suggestion # CA1307: Specify StringComparison for clarity dotnet_diagnostic.CA1309.severity = suggestion # CA1309: Use ordinal string comparison dotnet_diagnostic.CA1310.severity = warning # CA1310: Specify StringComparison for correctness +dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores +dotnet_diagnostic.CA1708.severity = none # CA1708: Identifiers should differ by more than case dotnet_diagnostic.CA1710.severity = none # CA1710: Identifiers should have correct suffix dotnet_diagnostic.CA1711.severity = none # CA1711: Identifiers should not have incorrect suffix dotnet_diagnostic.CA1712.severity = none # CA1712: Do not prefix enum values with type name dotnet_diagnostic.CA1715.severity = none # CA1715: Identifiers should have correct prefix +dotnet_diagnostic.CA1716.severity = none # CA1716: Identifiers should not match keywords dotnet_diagnostic.CA1720.severity = none # CA1720: Identifier contains type name dotnet_diagnostic.CA1725.severity = suggestion # CA1725: Parameter names should match base declaration dotnet_diagnostic.CA1805.severity = suggestion # CA1805: Do not initialize unnecessarily dotnet_diagnostic.CA1806.severity = none # CA1806: Do not ignore method results +dotnet_diagnostic.CA1816.severity = suggestion # CA1816: Dispose methods should call SuppressFinalize dotnet_diagnostic.CA1822.severity = none # CA1822: Mark members as static dotnet_diagnostic.CA1825.severity = none # CA1825: Avoid zero-length array allocations +dotnet_diagnostic.CA1830.severity = suggestion # CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder dotnet_diagnostic.CA1834.severity = suggestion # CA1834: Consider using 'StringBuilder.Append(char)' when applicable +dotnet_diagnostic.CA1837.severity = suggestion # CA1837: Use 'Environment.ProcessId' +dotnet_diagnostic.CA1838.severity = suggestion # CA1838: Avoid 'StringBuilder' parameters for P/Invokes +dotnet_diagnostic.CA1845.severity = none # CA1845: Use span-based 'string.Concat' +dotnet_diagnostic.CA1846.severity = none # CA1846: Prefer 'AsSpan' over 'Substring' +dotnet_diagnostic.CA1847.severity = none # CA1847: Use char literal for a single character lookup +dotnet_diagnostic.CA2101.severity = suggestion # CA2101: Specify marshaling for P/Invoke string arguments dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types dotnet_diagnostic.CA2208.severity = suggestion # CA2208: Instantiate argument exceptions correctly dotnet_diagnostic.CA2211.severity = none # CA2211: Non-constant fields should not be visible dotnet_diagnostic.CA2219.severity = suggestion # CA2219: Do not raise exceptions in finally clauses dotnet_diagnostic.CA2229.severity = suggestion # CA2229: Implement serialization constructors dotnet_diagnostic.CA2249.severity = suggestion # CA2249: Consider using 'string.Contains' instead of 'string.IndexOf' +dotnet_diagnostic.CA3075.severity = suggestion # CA3075: Insecure DTD processing in XML +dotnet_diagnostic.CA5350.severity = suggestion # CA5350: Do Not Use Weak Cryptographic Algorithms +dotnet_diagnostic.CA5351.severity = suggestion # CA5351: Do Not Use Broken Cryptographic Algorithms +dotnet_diagnostic.CA5359.severity = suggestion # CA5359: Do Not Disable Certificate Validation +dotnet_diagnostic.CA5372.severity = suggestion # CA5372: Use XmlReader For XPathDocument diff --git a/Src/Microsoft.Dynamic/Hosting/Shell/ConsoleHost.cs b/Src/Microsoft.Dynamic/Hosting/Shell/ConsoleHost.cs index f5a9f02c..64d66f6c 100644 --- a/Src/Microsoft.Dynamic/Hosting/Shell/ConsoleHost.cs +++ b/Src/Microsoft.Dynamic/Hosting/Shell/ConsoleHost.cs @@ -249,7 +249,7 @@ protected virtual string GetHelp() { return sb.ToString(); } - public void PrintLanguageHelp(StringBuilder output) { + public virtual void PrintLanguageHelp(StringBuilder output) { ContractUtils.RequiresNotNull(output, nameof(output)); CreateOptionsParser().GetHelp(out string commandLine, out string[,] options, out string[,] environmentVariables, out string comments); @@ -300,7 +300,7 @@ private void Execute() { protected virtual void ExecuteInternal() { Debug.Assert(_engine != null); - if (_consoleOptions.PrintVersion){ + if (_consoleOptions.PrintVersion) { PrintVersion(); } @@ -409,7 +409,7 @@ private int RunCommandLine() { return exitCodeOverride.Value; } - private void PrintUsage() + protected virtual void PrintUsage() { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Usage: {0}.exe ", ExeName); @@ -417,7 +417,7 @@ private void PrintUsage() Console.Write(sb.ToString()); } - protected void PrintVersion() { + protected virtual void PrintVersion() { Console.WriteLine("{0} {1} on {2}", Engine.Setup.DisplayName, Engine.LanguageVersion, GetRuntime()); } @@ -448,4 +448,4 @@ protected static void PrintException(TextWriter output, Exception e) { } } -#endif \ No newline at end of file +#endif diff --git a/Src/Microsoft.Dynamic/Hosting/Shell/OptionsParser.cs b/Src/Microsoft.Dynamic/Hosting/Shell/OptionsParser.cs index 07a4e108..57e13f79 100644 --- a/Src/Microsoft.Dynamic/Hosting/Shell/OptionsParser.cs +++ b/Src/Microsoft.Dynamic/Hosting/Shell/OptionsParser.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Runtime.Serialization; using Microsoft.Scripting.Generation; @@ -49,13 +48,13 @@ public PlatformAdaptationLayer Platform { } #if FEATURE_FULL_CONSOLE - public abstract ConsoleOptions CommonConsoleOptions { - get; + public abstract ConsoleOptions CommonConsoleOptions { + get; } #endif public IList IgnoredArgs { get { return _ignoredArgs; } - } + } /// On error. public void Parse(string[] args, ScriptRuntimeSetup setup, LanguageSetup languageSetup, PlatformAdaptationLayer platform) { @@ -109,11 +108,7 @@ protected string PeekNextArg() { if (_current < _args.Length) return _args[_current]; - throw new InvalidOptionException( - String.Format( - CultureInfo.CurrentCulture, - "Argument expected for the {0} option.", - _current > 0 ? _args[_current - 1] : string.Empty)); + throw new InvalidOptionException($"Argument expected for the {(_current > 0 ? _args[_current - 1] : string.Empty)} option."); } protected string PopNextArg() { @@ -137,10 +132,10 @@ protected static Exception InvalidOptionValue(string option, string value) { #if FEATURE_FULL_CONSOLE public class OptionsParser : OptionsParser where TConsoleOptions : ConsoleOptions, new() { - + private TConsoleOptions _consoleOptions; -#if FEATURE_REFEMIT +#if FEATURE_REFEMIT && DEBUG private bool _saveAssemblies = false; private string _assembliesDir = null; #endif @@ -149,13 +144,13 @@ public TConsoleOptions ConsoleOptions { get { if (_consoleOptions == null) { _consoleOptions = new TConsoleOptions(); - } - - return _consoleOptions; + } + + return _consoleOptions; } set { ContractUtils.RequiresNotNull(value, nameof(value)); - _consoleOptions = value; + _consoleOptions = value; } } @@ -178,73 +173,129 @@ protected override void ParseArgument(string arg) { IgnoreRemainingArgs(); break; - case "-D": - RuntimeSetup.DebugMode = true; + case "-D": + RuntimeSetup.DebugMode = true; + break; + + case "-X:PrivateBinding": + case "-X:PassExceptions": + // TODO: #if !IRONPYTHON_WINDOW + case "-X:ColorfulConsole": + case "-X:TabCompletion": + case "-X:AutoIndent": + // #endif +#if DEBUG +#if FEATURE_REFEMIT + case "-X:SaveAssemblies": +#endif + case "-X:TrackPerformance": +#endif + case "-X:Interpret": + case "-X:NoAdaptiveCompilation": + case "-X:ExceptionDetail": + case "-X:ShowClrExceptions": +#if DEBUG + case "-X:PerfStats": +#endif + HandleImplementationSpecificOption(arg.Substring(3), null); + break; + +#if DEBUG && FEATURE_REFEMIT + case "-X:AssembliesDir": +#endif + case "-X:CompilationThreshold": +#if FEATURE_REMOTING + case "-X:" + Remote.RemoteRuntimeServer.RemoteRuntimeArg: +#endif + HandleImplementationSpecificOption(arg.Substring(3), PopNextArg()); + break; + + default: + ConsoleOptions.FileName = arg.Trim(); + break; + } + } + + protected virtual void HandleImplementationSpecificOption(string arg, string val) { + switch (arg) { + case "PrivateBinding": + RuntimeSetup.PrivateBinding = true; break; - - case "-X:PrivateBinding": - RuntimeSetup.PrivateBinding = true; + + case "PassExceptions": + ConsoleOptions.HandleExceptions = false; break; - case "-X:PassExceptions": ConsoleOptions.HandleExceptions = false; break; // TODO: #if !IRONPYTHON_WINDOW - case "-X:ColorfulConsole": ConsoleOptions.ColorfulConsole = true; break; - case "-X:TabCompletion": ConsoleOptions.TabCompletion = true; break; - case "-X:AutoIndent": ConsoleOptions.AutoIndent = true; break; + + case "ColorfulConsole": + ConsoleOptions.ColorfulConsole = true; + break; + + case "TabCompletion": + ConsoleOptions.TabCompletion = true; + break; + + case "AutoIndent": + ConsoleOptions.AutoIndent = true; + break; + //#endif #if DEBUG #if FEATURE_REFEMIT - case "-X:AssembliesDir": - _assembliesDir = PopNextArg(); + + case "AssembliesDir": + if (string.IsNullOrEmpty(val)) throw new InvalidOptionException($"Argument expected for the -X:{arg} option."); + _assembliesDir = val; + if (_saveAssemblies) { + Snippets.SetSaveAssemblies(true, _assembliesDir); + } break; - case "-X:SaveAssemblies": + case "SaveAssemblies": _saveAssemblies = true; + Snippets.SetSaveAssemblies(true, _assembliesDir); break; #endif - case "-X:TrackPerformance": - SetDlrOption(arg.Substring(3)); + case "TrackPerformance": + SetDlrOption(arg); break; #endif + // TODO: remove - case "-X:Interpret": + case "Interpret": LanguageSetup.Options["InterpretedMode"] = ScriptingRuntimeHelpers.True; break; - case "-X:NoAdaptiveCompilation": + case "NoAdaptiveCompilation": LanguageSetup.Options["NoAdaptiveCompilation"] = true; break; - case "-X:CompilationThreshold": - LanguageSetup.Options["CompilationThreshold"] = Int32.Parse(PopNextArg()); + case "CompilationThreshold": + int threshold; + if (!int.TryParse(val, out threshold)) { + throw new InvalidOptionException($"The argument for the -X:{arg} option must be an integer."); + } + LanguageSetup.Options["CompilationThreshold"] = threshold; break; - case "-X:ExceptionDetail": - case "-X:ShowClrExceptions": + case "ExceptionDetail": + case "ShowClrExceptions": #if DEBUG - case "-X:PerfStats": + case "PerfStats": #endif - // TODO: separate options dictionary? - LanguageSetup.Options[arg.Substring(3)] = ScriptingRuntimeHelpers.True; + LanguageSetup.Options[arg] = ScriptingRuntimeHelpers.True; break; #if FEATURE_REMOTING case Remote.RemoteRuntimeServer.RemoteRuntimeArg: - ConsoleOptions.RemoteRuntimeChannel = PopNextArg(); + if (string.IsNullOrEmpty(val)) throw new InvalidOptionException($"Argument expected for the -X:{arg} option."); + ConsoleOptions.RemoteRuntimeChannel = val; break; #endif - default: - ConsoleOptions.FileName = arg.Trim(); - break; - } - -#if FEATURE_REFEMIT - if (_saveAssemblies) { - Snippets.SetSaveAssemblies(true, _assembliesDir); } -#endif } internal static void SetDlrOption(string option) { @@ -259,14 +310,13 @@ internal static void SetDlrOption(string option, string value) { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional")] // TODO: fix public override void GetHelp(out string commandLine, out string[,] options, out string[,] environmentVariables, out string comments) { - commandLine = "[options] [file|- [arguments]]"; options = new string[,] { { "-c cmd", "Program passed in as string (terminates option list)" }, { "-h", "Display usage" }, - { "-i", "Inspect interactively after running script" }, - { "-V", "Print the version number and exit" }, + { "-i", "Inspect interactively after running script" }, // TODO: remove this? not handled by OptionsParser.ParseArgument + { "-V", "Print the version number and exit" }, // TODO: remove this? not handled by OptionsParser.ParseArgument { "-D", "Enable application debugging" }, { "-X:AutoIndent", "Enable auto-indenting in the REPL loop" }, @@ -284,11 +334,11 @@ public override void GetHelp(out string commandLine, out string[,] options, out { "-X:TrackPerformance", "Track performance sensitive areas [debug only]" }, { "-X:PerfStats", "Print performance stats when the process exists [debug only]" }, #if FEATURE_REMOTING - { Remote.RemoteRuntimeServer.RemoteRuntimeArg + " ", + { $"-X:{Remote.RemoteRuntimeServer.RemoteRuntimeArg} ", "Start a remoting server for a remote console session." }, #endif #endif - }; + }; environmentVariables = new string[0, 0]; diff --git a/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteConsoleHost.cs b/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteConsoleHost.cs index e5433776..13f1cf29 100644 --- a/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteConsoleHost.cs +++ b/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteConsoleHost.cs @@ -39,7 +39,7 @@ private static string GetChannelName() { private ProcessStartInfo GetProcessStartInfo() { ProcessStartInfo processInfo = new ProcessStartInfo(); - processInfo.Arguments = RemoteRuntimeServer.RemoteRuntimeArg + " " + _channelName; + processInfo.Arguments = "-X:" + RemoteRuntimeServer.RemoteRuntimeArg + " " + _channelName; processInfo.CreateNoWindow = true; // Set UseShellExecute to false to enable redirection. @@ -271,4 +271,4 @@ protected RemoteRuntimeStartupException(SerializationInfo info, StreamingContext } } -#endif \ No newline at end of file +#endif diff --git a/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteRuntimeServer.cs b/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteRuntimeServer.cs index 26d309cc..4f28f3d2 100644 --- a/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteRuntimeServer.cs +++ b/Src/Microsoft.Dynamic/Hosting/Shell/Remote/RemoteRuntimeServer.cs @@ -18,7 +18,7 @@ namespace Microsoft.Scripting.Hosting.Shell.Remote { /// public static class RemoteRuntimeServer { internal const string CommandDispatcherUri = "CommandDispatcherUri"; - internal const string RemoteRuntimeArg = "-X:RemoteRuntimeChannel"; + internal const string RemoteRuntimeArg = "RemoteRuntimeChannel"; private static TimeSpan GetSevenDays() { return new TimeSpan(7, 0, 0, 0); // days,hours,mins,secs @@ -81,4 +81,4 @@ internal static void StartServer(string remoteRuntimeChannelName, ScriptScope sc } } -#endif \ No newline at end of file +#endif