From 1e59387ce58893246285d21c784b519ffe4c4224 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Fri, 18 Nov 2016 23:36:44 -0800 Subject: [PATCH] Implement /NoWarn switch Warnings are logged as low importance messages instead. This way they can still be seen with more verbosity but are essentially suppressed. Closes #68 --- ref/net46/Microsoft.Build/Microsoft.Build.cs | 1 + .../BackEnd/BuildManager/BuildManager.cs | 5 ++- .../BackEnd/BuildManager/BuildParameters.cs | 15 ++++++++ .../BuildRequestEngine/BuildRequestEngine.cs | 16 ++++---- .../Logging/BuildEventArgTransportSink.cs | 10 +++++ .../Components/Logging/EventSourceSink.cs | 37 ++++++++++++++++++- .../Components/Logging/ILoggingService.cs | 18 +++++++++ .../Components/Logging/LoggingService.cs | 20 +++++++++- .../UnitTests/BackEnd/MockLoggingService.cs | 8 ++++ src/XMakeCommandLine/CommandLineSwitches.cs | 2 + src/XMakeCommandLine/Resources/Strings.resx | 27 +++++++++++++- .../UnitTests/CommandLineSwitches_Tests.cs | 3 +- src/XMakeCommandLine/XMake.cs | 35 +++++++++++++++++- 13 files changed, 178 insertions(+), 19 deletions(-) diff --git a/ref/net46/Microsoft.Build/Microsoft.Build.cs b/ref/net46/Microsoft.Build/Microsoft.Build.cs index 3f049e8b470..e8b44a42a81 100644 --- a/ref/net46/Microsoft.Build/Microsoft.Build.cs +++ b/ref/net46/Microsoft.Build/Microsoft.Build.cs @@ -939,6 +939,7 @@ public BuildParameters(Microsoft.Build.Evaluation.ProjectCollection projectColle public System.Globalization.CultureInfo UICulture { get { throw null; } set { } } public bool UseSynchronousLogging { get { throw null; } set { } } public System.Collections.Generic.ISet WarningsAsErrors { get { throw null; } set { } } + public System.Collections.Generic.ISet WarningsAsMessages { get { throw null; } set { } } public Microsoft.Build.Execution.BuildParameters Clone() { throw null; } public Microsoft.Build.Evaluation.Toolset GetToolset(string toolsVersion) { throw null; } } diff --git a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs index 92872a5e736..0cb3cdd8a8d 100644 --- a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs +++ b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs @@ -424,7 +424,7 @@ public void BeginBuild(BuildParameters parameters) } // Set up the logging service. - ILoggingService loggingService = CreateLoggingService(_buildParameters.Loggers, _buildParameters.ForwardingLoggers, _buildParameters.WarningsAsErrors); + ILoggingService loggingService = CreateLoggingService(_buildParameters.Loggers, _buildParameters.ForwardingLoggers, _buildParameters.WarningsAsErrors, _buildParameters.WarningsAsMessages); _nodeManager.RegisterPacketHandler(NodePacketType.LogMessage, LogMessagePacket.FactoryForDeserialization, loggingService as INodePacketHandler); try @@ -1736,7 +1736,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) /// /// Creates a logging service around the specified set of loggers. /// - private ILoggingService CreateLoggingService(IEnumerable loggers, IEnumerable forwardingLoggers, ISet warningsAsErrors) + private ILoggingService CreateLoggingService(IEnumerable loggers, IEnumerable forwardingLoggers, ISet warningsAsErrors, ISet warningsAsMessages) { int cpuCount = _buildParameters.MaxNodeCount; @@ -1764,6 +1764,7 @@ private ILoggingService CreateLoggingService(IEnumerable loggers, IEnum loggingService.OnProjectStarted += _projectStartedEventHandler; loggingService.OnProjectFinished += _projectFinishedEventHandler; loggingService.WarningsAsErrors = warningsAsErrors; + loggingService.WarningsAsMessages = warningsAsMessages; try { diff --git a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs index 34459823cfc..5ef4bda7a87 100644 --- a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs +++ b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs @@ -205,6 +205,11 @@ public class BuildParameters : INodePacketTranslatable /// private ISet _warningsAsErrors = null; + /// + /// A list of warnings to treat as low importance messages. + /// + private ISet _warningsAsMessages = null; + /// /// The location of the toolset definitions. /// @@ -326,6 +331,7 @@ private BuildParameters(BuildParameters other) _logTaskInputs = other._logTaskInputs; _logInitialPropertiesAndItems = other._logInitialPropertiesAndItems; _warningsAsErrors = other._warningsAsErrors == null ? null : new HashSet(other._warningsAsErrors, StringComparer.OrdinalIgnoreCase); + _warningsAsMessages = other._warningsAsMessages == null ? null : new HashSet(other._warningsAsMessages, StringComparer.OrdinalIgnoreCase); } #if FEATURE_THREAD_PRIORITY @@ -598,6 +604,15 @@ public ISet WarningsAsErrors set { _warningsAsErrors = value; } } + /// + /// A list of warnings to treat as low importance messages. + /// + public ISet WarningsAsMessages + { + get { return _warningsAsMessages; } + set { _warningsAsMessages = value; } + } + /// /// Locations to search for toolsets. /// diff --git a/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 783dce0b727..b817c3d3fa8 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -840,14 +840,14 @@ private void CheckMemoryUsage() { if (!NativeMethodsShared.IsWindows || BuildEnvironmentHelper.Instance.RunningInVisualStudio) { - /// Since this causes synchronous I/O and a stop-the-world GC, it can be very expensive. If - /// something other than build results is taking up the bulk of the memory space, it may not - /// free any space. That's caused customer reports of VS hangs resulting from build requests - /// that are very slow because something in VS is taking all of the memory, but every - /// project build is slowed down by this codepath. To mitigate this, don't perform these - /// checks in devenv.exe. On the command line, 32-bit MSBuild may still need to cache build - /// results on very large builds, but build results are much more likely to be the bulk of - /// memory usage there. + // Since this causes synchronous I/O and a stop-the-world GC, it can be very expensive. If + // something other than build results is taking up the bulk of the memory space, it may not + // free any space. That's caused customer reports of VS hangs resulting from build requests + // that are very slow because something in VS is taking all of the memory, but every + // project build is slowed down by this codepath. To mitigate this, don't perform these + // checks in devenv.exe. On the command line, 32-bit MSBuild may still need to cache build + // results on very large builds, but build results are much more likely to be the bulk of + // memory usage there. return; } diff --git a/src/XMakeBuildEngine/BackEnd/Components/Logging/BuildEventArgTransportSink.cs b/src/XMakeBuildEngine/BackEnd/Components/Logging/BuildEventArgTransportSink.cs index bce7890e6de..64e1d9e8f6c 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/Logging/BuildEventArgTransportSink.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/Logging/BuildEventArgTransportSink.cs @@ -90,6 +90,16 @@ public ISet WarningsAsErrors set; } + /// + /// This property is ignored by this event sink and relies on the receiver to treat warnings as low importance messages. + /// + public ISet WarningsAsMessages + { + get; + set; + } + + /// /// This property is ignored by this event sink and relies on the receiver to keep track of whether or not any errors have been logged. /// diff --git a/src/XMakeBuildEngine/BackEnd/Components/Logging/EventSourceSink.cs b/src/XMakeBuildEngine/BackEnd/Components/Logging/EventSourceSink.cs index c023231b9bf..c13dcb89f32 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/Logging/EventSourceSink.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/Logging/EventSourceSink.cs @@ -140,6 +140,15 @@ public ISet WarningsAsErrors set; } + /// + /// A list of warnings to treat as low importance messages. + /// + public ISet WarningsAsMessages + { + get; + set; + } + /// /// A list of build submission IDs that have logged errors. If an error is logged outside of a submission, the submission ID is . /// @@ -224,9 +233,33 @@ public void Consume(BuildEventArgs buildEvent) { BuildWarningEventArgs warningEvent = (BuildWarningEventArgs) buildEvent; - // Treat this warning as an error if an empty set of warnings was specified or this code was specified - if (WarningsAsErrors != null && (WarningsAsErrors.Count == 0 || WarningsAsErrors.Contains(warningEvent.Code))) + if (WarningsAsMessages != null && WarningsAsMessages.Contains(warningEvent.Code)) + { + // Treat this warning as a message with low importance if its in the list + BuildMessageEventArgs errorEvent = new BuildMessageEventArgs( + warningEvent.Subcategory, + warningEvent.Code, + warningEvent.File, + warningEvent.LineNumber, + warningEvent.ColumnNumber, + warningEvent.EndLineNumber, + warningEvent.EndColumnNumber, + warningEvent.Message, + warningEvent.HelpKeyword, + warningEvent.SenderName, + MessageImportance.Low, + warningEvent.Timestamp) + { + BuildEventContext = warningEvent.BuildEventContext, + ProjectFile = warningEvent.ProjectFile, + }; + + this.RaiseMessageEvent(null, errorEvent); + + } + else if (WarningsAsErrors != null && (WarningsAsErrors.Count == 0 || WarningsAsErrors.Contains(warningEvent.Code))) { + // Treat this warning as an error if an empty set of warnings was specified or this code was specified BuildErrorEventArgs errorEvent = new BuildErrorEventArgs( warningEvent.Subcategory, warningEvent.Code, diff --git a/src/XMakeBuildEngine/BackEnd/Components/Logging/ILoggingService.cs b/src/XMakeBuildEngine/BackEnd/Components/Logging/ILoggingService.cs index 9e4f0c1e068..7a6caf13b81 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/Logging/ILoggingService.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/Logging/ILoggingService.cs @@ -162,6 +162,15 @@ ISet WarningsAsErrors get; set; } + + /// + /// A list of warnings to treat as low importance messages. + /// + ISet WarningsAsMessages + { + get; + set; + } #endregion /// @@ -472,6 +481,15 @@ ISet WarningsAsErrors set; } + /// + /// A list of warnings to treat as low importance messages. + /// + ISet WarningsAsMessages + { + get; + set; + } + /// /// A list of build submissions that have logged errors. /// diff --git a/src/XMakeBuildEngine/BackEnd/Components/Logging/LoggingService.cs b/src/XMakeBuildEngine/BackEnd/Components/Logging/LoggingService.cs index 0d0c55e08fd..fc3ac97b501 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/Logging/LoggingService.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/Logging/LoggingService.cs @@ -224,6 +224,11 @@ internal partial class LoggingService : ILoggingService, INodePacketHandler, IBu /// private ISet _warningsAsErrors = null; + /// + /// A list of warnings to treat as low importance messages. + /// + private ISet _warningsAsMessages = null; + #endregion #endregion @@ -459,6 +464,15 @@ public ISet WarningsAsErrors set { _warningsAsErrors = value; } } + /// + /// A list of warnings to treat as low importance messages. + /// + public ISet WarningsAsMessages + { + get { return _warningsAsMessages; } + set { _warningsAsMessages = value; } + } + /// /// Determines if the specified submission has logged an errors. /// @@ -819,7 +833,8 @@ public bool RegisterDistributedLogger(ILogger centralLogger, LoggerDescription f // create an eventSourceSink which the central logger will register with to receive the events from the forwarding logger EventSourceSink eventSourceSink = new EventSourceSink { - WarningsAsErrors = WarningsAsErrors == null ? null : new HashSet(WarningsAsErrors, StringComparer.OrdinalIgnoreCase) + WarningsAsErrors = WarningsAsErrors == null ? null : new HashSet(WarningsAsErrors, StringComparer.OrdinalIgnoreCase), + WarningsAsMessages = WarningsAsMessages == null ? null : new HashSet(WarningsAsMessages, StringComparer.OrdinalIgnoreCase), }; // If the logger is already in the list it should not be registered again. @@ -1135,7 +1150,8 @@ private void CreateFilterEventSource() _filterEventSource = new EventSourceSink { Name = "Sink for Distributed/Filter loggers", - WarningsAsErrors = WarningsAsErrors == null ? null : new HashSet(WarningsAsErrors, StringComparer.OrdinalIgnoreCase) + WarningsAsErrors = WarningsAsErrors == null ? null : new HashSet(WarningsAsErrors, StringComparer.OrdinalIgnoreCase), + WarningsAsMessages = WarningsAsMessages == null ? null : new HashSet(WarningsAsMessages, StringComparer.OrdinalIgnoreCase), }; } } diff --git a/src/XMakeBuildEngine/UnitTests/BackEnd/MockLoggingService.cs b/src/XMakeBuildEngine/UnitTests/BackEnd/MockLoggingService.cs index c3559fac92b..6b8269d6eae 100644 --- a/src/XMakeBuildEngine/UnitTests/BackEnd/MockLoggingService.cs +++ b/src/XMakeBuildEngine/UnitTests/BackEnd/MockLoggingService.cs @@ -156,6 +156,14 @@ public ISet WarningsAsErrors set; } + /// + /// List of warnings to treat as low importance messages. + /// + public ISet WarningsAsMessages + { + get; + set; + } /// /// Is the logging service on a remote node, this is used to determine if properties need to be serialized diff --git a/src/XMakeCommandLine/CommandLineSwitches.cs b/src/XMakeCommandLine/CommandLineSwitches.cs index be2786a7d77..d37b937dbb1 100644 --- a/src/XMakeCommandLine/CommandLineSwitches.cs +++ b/src/XMakeCommandLine/CommandLineSwitches.cs @@ -103,6 +103,7 @@ internal enum ParameterizedSwitch ServerToClientPipeHandle, #endif WarningsAsErrors, + WarningsAsMessages, NumberOfParameterizedSwitches } @@ -281,6 +282,7 @@ bool emptyParametersAllowed new ParameterizedSwitchInfo( new string[] { "serverToClientPipeHandle", "s2c" }, ParameterizedSwitch.ServerToClientPipeHandle, null, false, null, true, false ), #endif new ParameterizedSwitchInfo( new string[] { "warnaserror", "err" }, ParameterizedSwitch.WarningsAsErrors, null, true, null, true, true ), + new ParameterizedSwitchInfo( new string[] { "warnasmessage", "nowarn" }, ParameterizedSwitch.WarningsAsMessages, null, true, "MissingWarnAsMessageParameterError", true, false ), }; /// diff --git a/src/XMakeCommandLine/Resources/Strings.resx b/src/XMakeCommandLine/Resources/Strings.resx index f5075e4711d..7786ca89dbb 100644 --- a/src/XMakeCommandLine/Resources/Strings.resx +++ b/src/XMakeCommandLine/Resources/Strings.resx @@ -589,7 +589,22 @@ Copyright (C) Microsoft Corporation. All rights reserved. build will fail. - LOCALIZATION: "warnaserror" should not be localized. + LOCALIZATION: "/warnaserror" and "/err" should not be localized. + LOCALIZATION: None of the lines should be longer than a standard width console window, eg 80 chars. + + + + /warnasmessage[:code[;code2]] + List of warning codes to treats as low importance + messages. Use a semicolon or a comma to separate + multiple warning codes. + (Short form: /nowarn[:c;[c2]]) + + Example: + /warnasmessage:MSB3026 + + + LOCALIZATION: "/warnasmessage" and "/nowarn" should not be localized. LOCALIZATION: None of the lines should be longer than a standard width console window, eg 80 chars. @@ -963,11 +978,19 @@ Copyright (C) Microsoft Corporation. All rights reserved. {0} ({1},{2}) A file location to be embedded in a string. + + MSBUILD : error MSB1050: Specify one or more warning codes to treat as low importance messages when using the /warnasmessage switch. + + {StrBegin="MSBUILD : error MSB1050: "} + UE: This happens if the user does something like "msbuild.exe /warnasmessage:" without any codes. + LOCALIZATION: The prefix "MSBUILD : error MSBxxxx:" should not be localized. + + diff --git a/src/XMakeCommandLine/UnitTests/CommandLineSwitches_Tests.cs b/src/XMakeCommandLine/UnitTests/CommandLineSwitches_Tests.cs index 60bc3af5ee2..05712bf3aa3 100644 --- a/src/XMakeCommandLine/UnitTests/CommandLineSwitches_Tests.cs +++ b/src/XMakeCommandLine/UnitTests/CommandLineSwitches_Tests.cs @@ -1123,7 +1123,8 @@ public void InvalidToolsVersionErrors() new StringWriter(), false, false, - warningsAsErrors: null); + warningsAsErrors: null, + warningsAsMessages: null); } finally { diff --git a/src/XMakeCommandLine/XMake.cs b/src/XMakeCommandLine/XMake.cs index 66d1ea04532..1847d36d252 100644 --- a/src/XMakeCommandLine/XMake.cs +++ b/src/XMakeCommandLine/XMake.cs @@ -547,6 +547,7 @@ string [] commandLine bool debugger = false; bool detailedSummary = false; ISet warningsAsErrors = null; + ISet warningsAsMessages = null; CommandLineSwitches switchesFromAutoResponseFile; CommandLineSwitches switchesNotFromAutoResponseFile; @@ -574,6 +575,7 @@ string [] commandLine ref debugger, ref detailedSummary, ref warningsAsErrors, + ref warningsAsMessages, recursing: false )) { @@ -602,7 +604,7 @@ string [] commandLine #if FEATURE_XML_SCHEMA_VALIDATION needToValidateProject, schemaFile, #endif - cpuCount, enableNodeReuse, preprocessWriter, debugger, detailedSummary, warningsAsErrors)) + cpuCount, enableNodeReuse, preprocessWriter, debugger, detailedSummary, warningsAsErrors, warningsAsMessages)) { exitType = ExitType.BuildError; } @@ -894,7 +896,8 @@ internal static bool BuildProject TextWriter preprocessWriter, bool debugger, bool detailedSummary, - ISet warningsAsErrors + ISet warningsAsErrors, + ISet warningsAsMessages ) { if (String.Equals(Path.GetExtension(projectFile), ".vcproj", StringComparison.OrdinalIgnoreCase) || @@ -1059,6 +1062,7 @@ ISet warningsAsErrors parameters.DetailedSummary = detailedSummary; parameters.LogTaskInputs = logTaskInputs; parameters.WarningsAsErrors = warningsAsErrors; + parameters.WarningsAsMessages = warningsAsMessages; if (!String.IsNullOrEmpty(toolsVersion)) { @@ -1793,6 +1797,7 @@ private static bool ProcessCommandLineSwitches ref bool debugger, ref bool detailedSummary, ref ISet warningsAsErrors, + ref ISet warningsAsMessages, bool recursing ) { @@ -1897,6 +1902,7 @@ bool recursing ref debugger, ref detailedSummary, ref warningsAsErrors, + ref warningsAsMessages, recursing: true ); } @@ -1933,6 +1939,8 @@ bool recursing warningsAsErrors = ProcessWarnAsErrorSwitch(commandLineSwitches); + warningsAsMessages = ProcessWarnAsMessageSwitch(commandLineSwitches); + // figure out which loggers are going to listen to build events string[][] groupedFileLoggerParameters = commandLineSwitches.GetFileLoggerParameters(); @@ -2071,6 +2079,28 @@ internal static ISet ProcessWarnAsErrorSwitch(CommandLineSwitches comman return warningsAsErrors; } + internal static ISet ProcessWarnAsMessageSwitch(CommandLineSwitches commandLineSwitches) + { + if (!commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.WarningsAsMessages)) + { + return null; + } + + string[] parameters = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.WarningsAsMessages]; + + ISet warningsAsMessages = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (string code in parameters + .SelectMany(parameter => parameter?.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) + .Where(i => !String.IsNullOrWhiteSpace(i)) + .Select(i => i.Trim())) + { + warningsAsMessages.Add(code); + } + + return warningsAsMessages; + } + /// /// Uses the input from thinNodeMode switch to start a local node server /// @@ -3164,6 +3194,7 @@ private static void ShowHelpMessage() Console.WriteLine(AssemblyResources.GetString("HelpMessage_21_DistributedFileLoggerSwitch")); Console.WriteLine(AssemblyResources.GetString("HelpMessage_11_LoggerSwitch")); Console.WriteLine(AssemblyResources.GetString("HelpMessage_28_WarnAsErrorSwitch")); + Console.WriteLine(AssemblyResources.GetString("HelpMessage_29_WarnAsMessageSwitch")); #if FEATURE_XML_SCHEMA_VALIDATION Console.WriteLine(AssemblyResources.GetString("HelpMessage_15_ValidateSwitch")); #endif