diff --git a/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs b/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs
index 7a67734775b..5710084ae53 100644
--- a/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs
+++ b/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs
@@ -211,6 +211,10 @@ public partial interface IBuildEngine7 : Microsoft.Build.Framework.IBuildEngine,
{
bool AllowFailureWithoutError { get; set; }
}
+ public partial interface IBuildEngine8 : Microsoft.Build.Framework.IBuildEngine, Microsoft.Build.Framework.IBuildEngine2, Microsoft.Build.Framework.IBuildEngine3, Microsoft.Build.Framework.IBuildEngine4, Microsoft.Build.Framework.IBuildEngine5, Microsoft.Build.Framework.IBuildEngine6, Microsoft.Build.Framework.IBuildEngine7
+ {
+ bool ShouldTreatWarningAsError(string warningCode);
+ }
public partial interface ICancelableTask : Microsoft.Build.Framework.ITask
{
void Cancel();
diff --git a/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs b/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs
index 9e3004af4bb..3ce966850da 100644
--- a/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs
+++ b/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs
@@ -211,6 +211,10 @@ public partial interface IBuildEngine7 : Microsoft.Build.Framework.IBuildEngine,
{
bool AllowFailureWithoutError { get; set; }
}
+ public partial interface IBuildEngine8 : Microsoft.Build.Framework.IBuildEngine, Microsoft.Build.Framework.IBuildEngine2, Microsoft.Build.Framework.IBuildEngine3, Microsoft.Build.Framework.IBuildEngine4, Microsoft.Build.Framework.IBuildEngine5, Microsoft.Build.Framework.IBuildEngine6, Microsoft.Build.Framework.IBuildEngine7
+ {
+ bool ShouldTreatWarningAsError(string warningCode);
+ }
public partial interface ICancelableTask : Microsoft.Build.Framework.ITask
{
void Cancel();
diff --git a/ref/Microsoft.Build.Utilities.Core/net/Microsoft.Build.Utilities.Core.cs b/ref/Microsoft.Build.Utilities.Core/net/Microsoft.Build.Utilities.Core.cs
index 40abd53b294..56a49e69207 100644
--- a/ref/Microsoft.Build.Utilities.Core/net/Microsoft.Build.Utilities.Core.cs
+++ b/ref/Microsoft.Build.Utilities.Core/net/Microsoft.Build.Utilities.Core.cs
@@ -353,6 +353,7 @@ protected Task(System.Resources.ResourceManager taskResources, string helpKeywor
public Microsoft.Build.Framework.IBuildEngine5 BuildEngine5 { get { throw null; } }
public Microsoft.Build.Framework.IBuildEngine6 BuildEngine6 { get { throw null; } }
public Microsoft.Build.Framework.IBuildEngine7 BuildEngine7 { get { throw null; } }
+ public Microsoft.Build.Framework.IBuildEngine8 BuildEngine8 { get { throw null; } }
protected string HelpKeywordPrefix { get { throw null; } set { } }
public Microsoft.Build.Framework.ITaskHost HostObject { get { throw null; } set { } }
public Microsoft.Build.Utilities.TaskLoggingHelper Log { get { throw null; } }
diff --git a/ref/Microsoft.Build.Utilities.Core/netstandard/Microsoft.Build.Utilities.Core.cs b/ref/Microsoft.Build.Utilities.Core/netstandard/Microsoft.Build.Utilities.Core.cs
index e6cc6f3fa50..ae04054e92b 100644
--- a/ref/Microsoft.Build.Utilities.Core/netstandard/Microsoft.Build.Utilities.Core.cs
+++ b/ref/Microsoft.Build.Utilities.Core/netstandard/Microsoft.Build.Utilities.Core.cs
@@ -198,6 +198,7 @@ protected Task(System.Resources.ResourceManager taskResources, string helpKeywor
public Microsoft.Build.Framework.IBuildEngine5 BuildEngine5 { get { throw null; } }
public Microsoft.Build.Framework.IBuildEngine6 BuildEngine6 { get { throw null; } }
public Microsoft.Build.Framework.IBuildEngine7 BuildEngine7 { get { throw null; } }
+ public Microsoft.Build.Framework.IBuildEngine8 BuildEngine8 { get { throw null; } }
protected string HelpKeywordPrefix { get { throw null; } set { } }
public Microsoft.Build.Framework.ITaskHost HostObject { get { throw null; } set { } }
public Microsoft.Build.Utilities.TaskLoggingHelper Log { get { throw null; } }
diff --git a/src/Build.UnitTests/BackEnd/CustomLogAndReturnTask.cs b/src/Build.UnitTests/BackEnd/CustomLogAndReturnTask.cs
new file mode 100644
index 00000000000..e6f05dff154
--- /dev/null
+++ b/src/Build.UnitTests/BackEnd/CustomLogAndReturnTask.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+namespace Microsoft.Build.UnitTests
+{
+ public class CustomLogAndReturnTask : Task
+ {
+ public string WarningCode { get; set; }
+
+ public string ErrorCode { get; set; }
+
+ public bool ReturnHasLoggedErrors { get; set; }
+
+ [Required]
+ public bool Return { get; set; }
+
+ // Unused for now, created for task batching.
+ public ITaskItem[] Sources { get; set; }
+
+ ///
+ /// This task returns and logs what you want based on the running test.
+ ///
+ public override bool Execute()
+ {
+ if(!string.IsNullOrEmpty(WarningCode))
+ {
+ Log.LogWarning(null, WarningCode, null, null, 0, 0, 0, 0, "Warning Logged!", null);
+ }
+
+ if(!string.IsNullOrEmpty(ErrorCode))
+ {
+ Log.LogError(null, ErrorCode, null, null, 0, 0, 0, 0, "Error Logged!", null);
+ }
+ return ReturnHasLoggedErrors ? !Log.HasLoggedErrors : Return;
+ }
+ }
+}
diff --git a/src/Build.UnitTests/BackEnd/MockLoggingService.cs b/src/Build.UnitTests/BackEnd/MockLoggingService.cs
index 8c7c480a220..cfd53b89220 100644
--- a/src/Build.UnitTests/BackEnd/MockLoggingService.cs
+++ b/src/Build.UnitTests/BackEnd/MockLoggingService.cs
@@ -557,6 +557,11 @@ public bool HasBuildSubmissionLoggedErrors(int submissionId)
return false;
}
+ public ICollection GetWarningsToBeLoggedAsErrorsByProject(BuildEventContext context)
+ {
+ throw new NotImplementedException();
+ }
+
#endregion
}
}
diff --git a/src/Build.UnitTests/BackEnd/TaskHostConfiguration_Tests.cs b/src/Build.UnitTests/BackEnd/TaskHostConfiguration_Tests.cs
index 62a6e1a3d56..d892c47a917 100644
--- a/src/Build.UnitTests/BackEnd/TaskHostConfiguration_Tests.cs
+++ b/src/Build.UnitTests/BackEnd/TaskHostConfiguration_Tests.cs
@@ -5,6 +5,7 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Threading;
@@ -12,7 +13,7 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Utilities;
-
+using Shouldly;
using Xunit;
namespace Microsoft.Build.UnitTests.BackEnd
@@ -36,22 +37,27 @@ public void ConstructorWithNullName()
Assert.Throws(() =>
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- null,
- @"c:\my tasks\mytask.dll",
- null,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: null,
+ taskLocation: @"c:\my tasks\mytask.dll",
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: null);
}
);
}
@@ -64,22 +70,27 @@ public void ConstructorWithEmptyName()
Assert.Throws(() =>
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- String.Empty,
- @"c:\my tasks\mytask.dll",
- null,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: String.Empty,
+ taskLocation: @"c:\my tasks\mytask.dll",
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: null);
}
);
}
@@ -92,22 +103,27 @@ public void ConstructorWithNullLocation()
Assert.Throws(() =>
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- null,
- null,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: null,
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: null);
}
);
}
@@ -122,22 +138,27 @@ public void ConstructorWithEmptyLocation()
Assert.Throws(() =>
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- String.Empty,
- null,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: String.Empty,
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: null);
}
);
}
@@ -150,22 +171,27 @@ public void ConstructorWithEmptyLocation()
public void TestValidConstructors()
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- null,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: null);
TaskHostConfiguration config2 = new TaskHostConfiguration(
1,
@@ -183,26 +209,32 @@ public void TestValidConstructors()
"TaskName",
@"c:\MyTasks\MyTask.dll",
null,
+ null,
null);
IDictionary parameters = new Dictionary();
TaskHostConfiguration config3 = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- parameters,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters,
+ globalParameters: null,
+ warningsAsErrors: null);
IDictionary parameters2 = new Dictionary();
parameters2.Add("Text", "Hello!");
@@ -211,22 +243,56 @@ public void TestValidConstructors()
parameters2.Add("ItemArray", new ITaskItem[] { new TaskItem("DEF"), new TaskItem("GHI"), new TaskItem("JKL") });
TaskHostConfiguration config4 = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters2,
+ globalParameters: null,
+ warningsAsErrors: null);
+
+ HashSet WarningsAsErrors = new HashSet();
+ WarningsAsErrors.Add("MSB1234");
+ WarningsAsErrors.Add("MSB1235");
+ WarningsAsErrors.Add("MSB1236");
+ WarningsAsErrors.Add("MSB1237");
+
+ TaskHostConfiguration config5 = new TaskHostConfiguration(
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
+#if FEATURE_APPDOMAIN
+ null,
+#endif
+ lineNumberOfTask:
+#endif
1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- parameters2,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters2,
+ globalParameters: null,
+ warningsAsErrors: WarningsAsErrors);
}
///
@@ -242,22 +308,27 @@ public void TestTranslationWithNullDictionary()
};
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- null,
- expectedGlobalProperties);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: null,
+ globalParameters: expectedGlobalProperties,
+ warningsAsErrors: null);
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
@@ -280,22 +351,27 @@ public void TestTranslationWithNullDictionary()
public void TestTranslationWithEmptyDictionary()
{
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- new Dictionary(),
- new Dictionary());
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: new Dictionary(),
+ globalParameters: new Dictionary(),
+ warningsAsErrors: null);
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
@@ -323,22 +399,27 @@ public void TestTranslationWithValueTypesInDictionary()
parameters.Add("Text", "Foo");
parameters.Add("BoolValue", false);
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- parameters,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters,
+ globalParameters: null,
+ warningsAsErrors: null);
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
@@ -364,22 +445,27 @@ public void TestTranslationWithITaskItemInDictionary()
IDictionary parameters = new Dictionary();
parameters.Add("TaskItemValue", new TaskItem("Foo"));
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- parameters,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters,
+ globalParameters: null,
+ warningsAsErrors: null);
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
@@ -404,22 +490,27 @@ public void TestTranslationWithITaskItemArrayInDictionary()
IDictionary parameters = new Dictionary();
parameters.Add("TaskItemArrayValue", new ITaskItem[] { new TaskItem("Foo"), new TaskItem("Baz") });
TaskHostConfiguration config = new TaskHostConfiguration(
- 1,
- Directory.GetCurrentDirectory(),
- null,
- Thread.CurrentThread.CurrentCulture,
- Thread.CurrentThread.CurrentUICulture,
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
#if FEATURE_APPDOMAIN
null,
+#endif
+ lineNumberOfTask:
#endif
1,
- 1,
- @"c:\my project\myproj.proj",
- _continueOnErrorDefault,
- "TaskName",
- @"c:\MyTasks\MyTask.dll",
- parameters,
- null);
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: parameters,
+ globalParameters: null,
+ warningsAsErrors: null);
((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
@@ -439,6 +530,54 @@ public void TestTranslationWithITaskItemArrayInDictionary()
TaskHostPacketHelpers.AreEqual(itemArray, deserializedItemArray);
}
+ ///
+ /// Test serialization / deserialization when the parameter dictionary contains an ITaskItem array.
+ ///
+ [Fact]
+ public void TestTranslationWithWarningsAsErrors()
+ {
+ HashSet WarningsAsErrors = new HashSet();
+ WarningsAsErrors.Add("MSB1234");
+ WarningsAsErrors.Add("MSB1235");
+ WarningsAsErrors.Add("MSB1236");
+ WarningsAsErrors.Add("MSB1237");
+ TaskHostConfiguration config = new TaskHostConfiguration(
+ nodeId: 1,
+ startupDirectory: Directory.GetCurrentDirectory(),
+ buildProcessEnvironment: null,
+ culture: Thread.CurrentThread.CurrentCulture,
+ uiCulture: Thread.CurrentThread.CurrentUICulture,
+#if FEATURE_APPDOMAIN
+ appDomainSetup:
+#if FEATURE_APPDOMAIN
+ null,
+#endif
+ lineNumberOfTask:
+#endif
+ 1,
+ columnNumberOfTask: 1,
+ projectFileOfTask: @"c:\my project\myproj.proj",
+ continueOnError: _continueOnErrorDefault,
+ taskName: "TaskName",
+ taskLocation: @"c:\MyTasks\MyTask.dll",
+ taskParameters: null,
+ globalParameters: null,
+ warningsAsErrors: WarningsAsErrors);
+
+ ((ITranslatable)config).Translate(TranslationHelpers.GetWriteTranslator());
+ INodePacket packet = TaskHostConfiguration.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
+
+ TaskHostConfiguration deserializedConfig = packet as TaskHostConfiguration;
+
+ Assert.Equal(config.TaskName, deserializedConfig.TaskName);
+#if !FEATURE_ASSEMBLYLOADCONTEXT
+ Assert.Equal(config.TaskLocation, deserializedConfig.TaskLocation);
+#endif
+ Assert.NotNull(deserializedConfig.WarningsAsErrors);
+ config.WarningsAsErrors.SequenceEqual(deserializedConfig.WarningsAsErrors, StringComparer.Ordinal).ShouldBeTrue();
+
+ }
+
///
/// Helper methods for testing the task host-related packets.
///
diff --git a/src/Build.UnitTests/WarningsAsMessagesAndErrors_Tests.cs b/src/Build.UnitTests/WarningsAsMessagesAndErrors_Tests.cs
index eb56df3a007..e2973629106 100644
--- a/src/Build.UnitTests/WarningsAsMessagesAndErrors_Tests.cs
+++ b/src/Build.UnitTests/WarningsAsMessagesAndErrors_Tests.cs
@@ -272,6 +272,197 @@ private string GetTestProject(bool? treatAllWarningsAsErrors = null, string warn
";
}
+ ///
+ /// We have a unique task host per bucket. Show that in these scenarios the build will stop if one sees an error.
+ ///
+ [Fact]
+ public void TaskReturnsHasLoggedErrorAndLogsWarningAsError_BuildShouldStopAndFail_BatchedBuild()
+ {
+ using (TestEnvironment env = TestEnvironment.Create(_output))
+ {
+ TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles($@"
+
+
+
+
+ MSB1234
+
+
+
+ true
+ true
+ MSB1234
+
+
+ true
+ true
+ MSB1235
+
+
+
+
+
+
+ ");
+
+ MockLogger logger = proj.BuildProjectExpectFailure();
+
+ logger.WarningCount.ShouldBe(0);
+ logger.ErrorCount.ShouldBe(1);
+
+ // The build should STOP when a task logs an error, make sure ReturnFailureWithoutLoggingErrorTask doesn't run.
+ logger.AssertLogDoesntContain("MSB4181");
+ }
+ }
+
+ ///
+ /// Item1 and Item2 log warnings and continue, item 3 logs a warn-> error and prevents item 4 from running in the batched build.
+ ///
+ [Fact]
+ public void TaskReturnsHasLoggedErrorAndLogsWarningAsError_BuildShouldStopOnceItLogsWarningAsErrorAndFail_BatchedBuild()
+ {
+ using (TestEnvironment env = TestEnvironment.Create(_output))
+ {
+ TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles($@"
+
+
+
+
+ MSB1234
+
+
+
+ true
+ true
+ MSB1235
+
+
+ true
+ true
+ MSB1236
+
+
+ true
+ true
+ MSB1234
+
+
+ true
+ true
+ MSB1237
+
+
+
+
+
+
+ ");
+
+ MockLogger logger = proj.BuildProjectExpectFailure();
+
+ logger.WarningCount.ShouldBe(2);
+ logger.ErrorCount.ShouldBe(1);
+
+ // The build should STOP when a task logs an error, make sure ReturnFailureWithoutLoggingErrorTask doesn't run.
+ logger.AssertLogDoesntContain("MSB1237");
+ }
+ }
+
+ [Fact]
+ public void TaskReturnsHasLoggedErrorAndLogsWarningAsError_BuildShouldFinishAndFail()
+ {
+ using (TestEnvironment env = TestEnvironment.Create(_output))
+ {
+ TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles($@"
+
+
+
+
+ MSB1234
+
+
+
+
+
+ ");
+
+ MockLogger logger = proj.BuildProjectExpectFailure();
+
+ logger.WarningCount.ShouldBe(0);
+ logger.ErrorCount.ShouldBe(1);
+
+ // The build should STOP when a task logs an error, make sure ReturnFailureWithoutLoggingErrorTask doesn't run.
+ logger.AssertLogDoesntContain("MSB4181");
+ }
+ }
+
+ ///
+ /// MSBuild behavior as of 16.10: As long as a task returns true, the build will continue despite logging a warning as error.
+ /// This tests MSBuildWarningsAsErrors
+ ///
+ [Fact]
+ public void TaskReturnsTrueButLogsWarningAsError_BuildShouldFinishAndFail()
+ {
+ using (TestEnvironment env = TestEnvironment.Create(_output))
+ {
+ TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles($@"
+
+
+
+
+
+ MSB1234
+
+
+
+
+
+ ");
+
+ MockLogger logger = proj.BuildProjectExpectFailure();
+
+ logger.WarningCount.ShouldBe(1);
+ logger.ErrorCount.ShouldBe(1);
+
+ // The build will continue so we should see the warning MSB1235
+ logger.AssertLogContains("MSB1235");
+ }
+ }
+
+
+ ///
+ /// MSBuild behavior as of 16.10: As long as a task returns true, the build will continue despite logging warning as error.
+ /// This test specifically tests the MSBuildTreatWarningsAsErrors flag as opposed to MSBuildWarningsAsErrors
+ ///
+ [Fact]
+ public void TaskReturnsTrueButLogsWarning_TreatWarningsAsErrors_BuildShouldFinishAndFail()
+ {
+ using (TestEnvironment env = TestEnvironment.Create(_output))
+ {
+ TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles($@"
+
+
+
+
+
+ true
+
+
+
+
+
+ ");
+
+ MockLogger logger = proj.BuildProjectExpectFailure();
+
+ logger.WarningCount.ShouldBe(0);
+ logger.ErrorCount.ShouldBe(2);
+
+ // The build will continue so we should see the error MSB1235
+ logger.AssertLogContains("MSB1235");
+ }
+ }
+
[Fact]
public void TaskReturnsFailureButDoesNotLogError_ShouldCauseBuildFailure()
{
diff --git a/src/Build/BackEnd/Components/Logging/ILoggingService.cs b/src/Build/BackEnd/Components/Logging/ILoggingService.cs
index 42feb90220b..e8257651162 100644
--- a/src/Build/BackEnd/Components/Logging/ILoggingService.cs
+++ b/src/Build/BackEnd/Components/Logging/ILoggingService.cs
@@ -219,6 +219,14 @@ bool IncludeTaskInputs
/// true
if the build submission logged an errors, otherwise false
.
bool HasBuildSubmissionLoggedErrors(int submissionId);
+ ///
+ /// Returns a hashset of warnings to be logged as errors for the specified project instance ID.
+ /// Note that WarningsAsMessages takes priority over WarningsAsErrors and are excluded from the set.
+ ///
+ /// The build context through which warnings will be logged as errors.
+ /// A Hashset containing warning codes that should be treated as warnings that will not be treated as messages.
+ ICollection GetWarningsToBeLoggedAsErrorsByProject(BuildEventContext context);
+
#region Register
///
diff --git a/src/Build/BackEnd/Components/Logging/LoggingService.cs b/src/Build/BackEnd/Components/Logging/LoggingService.cs
index 85c95d728d1..cd2b92bb029 100644
--- a/src/Build/BackEnd/Components/Logging/LoggingService.cs
+++ b/src/Build/BackEnd/Components/Logging/LoggingService.cs
@@ -515,6 +515,44 @@ public bool HasBuildSubmissionLoggedErrors(int submissionId)
return _buildSubmissionIdsThatHaveLoggedErrors?.Contains(submissionId) == true;
}
+ ///
+ /// Returns a hashset of warnings to be logged as errors for the specified build context.
+ /// Note that WarningsAsMessages takes priority over WarningsAsErrors and are excluded from the set.
+ ///
+ /// If all warnings to be treated as errors should also be treated as messages, return null.
+ /// This is to avoid all warnings being treated as errors.
+ ///
+ /// The build context through which warnings will be logged as errors.
+ ///
+ /// An empty set if all warnings should be treated as errors.
+ /// A set containing warning codes to be logged as errors.
+ /// Null if no warnings should be treated as errors.
+ ///
+ public ICollection GetWarningsToBeLoggedAsErrorsByProject(BuildEventContext context)
+ {
+ if (_warningsAsErrorsByProject == null)
+ {
+ return null;
+ }
+
+ int key = GetWarningsAsErrorOrMessageKey(context);
+
+ HashSet warningsAsErrorsExcludingMessages = new HashSet(_warningsAsErrorsByProject[key]);
+
+ if (_warningsAsMessagesByProject != null)
+ {
+ warningsAsErrorsExcludingMessages.ExceptWith(_warningsAsMessagesByProject[key]);
+
+ // A non-null empty set means all warnings are errors. Avoid this.
+ if (warningsAsErrorsExcludingMessages.Count == 0)
+ {
+ warningsAsErrorsExcludingMessages = null;
+ }
+ }
+
+ return warningsAsErrorsExcludingMessages;
+ }
+
public void AddWarningsAsErrors(BuildEventContext buildEventContext, ISet codes)
{
lock (_lockObject)
diff --git a/src/Build/BackEnd/Components/Logging/TaskLoggingContext.cs b/src/Build/BackEnd/Components/Logging/TaskLoggingContext.cs
index c953ec6f226..2f4758b2196 100644
--- a/src/Build/BackEnd/Components/Logging/TaskLoggingContext.cs
+++ b/src/Build/BackEnd/Components/Logging/TaskLoggingContext.cs
@@ -1,10 +1,11 @@
// 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 Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Execution;
+using System;
+using System.Collections.Generic;
namespace Microsoft.Build.BackEnd.Logging
{
@@ -144,5 +145,10 @@ internal void LogTaskWarningFromException(Exception exception, BuildEventFileInf
ErrorUtilities.VerifyThrow(IsValid, "must be valid");
LoggingService.LogTaskWarningFromException(BuildEventContext, exception, file, taskName);
}
+
+ internal ICollection GetWarningsAsErrors()
+ {
+ return LoggingService.GetWarningsToBeLoggedAsErrorsByProject(BuildEventContext);
+ }
}
}
diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs
index 8d830c38a0b..3bc78d7159a 100644
--- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs
+++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs
@@ -33,7 +33,7 @@ internal class TaskHost :
#if FEATURE_APPDOMAIN
MarshalByRefObject,
#endif
- IBuildEngine7
+ IBuildEngine8
{
///
/// True if the "secret" environment variable MSBUILDNOINPROCNODE is set.
@@ -676,6 +676,44 @@ public IReadOnlyDictionary GetGlobalProperties()
public bool AllowFailureWithoutError { get; set; } = false;
#endregion
+ #region IBuildEngine8 Members
+ private ICollection _warningsAsErrors;
+
+ ///
+ /// Contains all warnings that should be logged as errors.
+ /// Non-null empty set when all warnings should be treated as errors.
+ ///
+ private ICollection WarningsAsErrors
+ {
+ get
+ {
+ // Test compatibility
+ if(_taskLoggingContext == null)
+ {
+ return null;
+ }
+
+ return _warningsAsErrors ??= _taskLoggingContext.GetWarningsAsErrors();
+ }
+ }
+
+ ///
+ /// Determines if the given warning should be treated as an error.
+ ///
+ ///
+ /// True if WarningsAsErrors is an empty set or contains the given warning code.
+ public bool ShouldTreatWarningAsError(string warningCode)
+ {
+ if (WarningsAsErrors == null)
+ {
+ return false;
+ }
+
+ // An empty set means all warnings are errors.
+ return WarningsAsErrors.Count == 0 || WarningsAsErrors.Contains(warningCode);
+ }
+ #endregion
+
///
/// Called by the internal MSBuild task.
/// Does not take the lock because it is called by another request builder thread.
diff --git a/src/Build/Instance/TaskFactories/TaskHostTask.cs b/src/Build/Instance/TaskFactories/TaskHostTask.cs
index 07f716a438f..4956e1383cd 100644
--- a/src/Build/Instance/TaskFactories/TaskHostTask.cs
+++ b/src/Build/Instance/TaskFactories/TaskHostTask.cs
@@ -271,7 +271,9 @@ public bool Execute()
_taskType.Type.FullName,
AssemblyUtilities.GetAssemblyLocation(_taskType.Type.GetTypeInfo().Assembly),
_setParameters,
- new Dictionary(_buildComponentHost.BuildParameters.GlobalProperties)
+ new Dictionary(_buildComponentHost.BuildParameters.GlobalProperties),
+ _taskLoggingContext.GetWarningsAsErrors()
+
);
try
diff --git a/src/Framework/IBuildEngine8.cs b/src/Framework/IBuildEngine8.cs
new file mode 100644
index 00000000000..bce28a4cfcf
--- /dev/null
+++ b/src/Framework/IBuildEngine8.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Generic;
+
+namespace Microsoft.Build.Framework
+{
+ ///
+ /// This interface extends to let tasks know if a warning
+ /// they are about to log will be converted into an error.
+ ///
+ public interface IBuildEngine8 : IBuildEngine7
+ {
+ ///
+ /// Determines whether the logging service will convert the specified
+ /// warning code into an error.
+ ///
+ /// The warning code to check.
+ /// A boolean to determine whether the warning should be treated as an error.
+ public bool ShouldTreatWarningAsError(string warningCode);
+ }
+}
diff --git a/src/MSBuild/OutOfProcTaskHostNode.cs b/src/MSBuild/OutOfProcTaskHostNode.cs
index e7604d0970b..7339ac36cd0 100644
--- a/src/MSBuild/OutOfProcTaskHostNode.cs
+++ b/src/MSBuild/OutOfProcTaskHostNode.cs
@@ -33,7 +33,7 @@ internal class OutOfProcTaskHostNode :
#if CLR2COMPATIBILITY
IBuildEngine3
#else
- IBuildEngine7
+ IBuildEngine8
#endif
{
///
@@ -267,6 +267,20 @@ public bool IsRunningMultipleNodes
public bool AllowFailureWithoutError { get; set; } = false;
#endregion
+ #region IBuildEngine8 Implementation
+
+ ///
+ /// Contains all warnings that should be logged as errors.
+ /// Non-null empty set when all warnings should be treated as errors.
+ ///
+ private ICollection WarningsAsErrors { get; set; }
+
+ public bool ShouldTreatWarningAsError(string warningCode)
+ {
+ return WarningsAsErrors != null && (WarningsAsErrors.Count == 0 || WarningsAsErrors.Contains(warningCode));
+ }
+ #endregion
+
#region IBuildEngine Implementation (Methods)
///
@@ -793,7 +807,7 @@ private void RunTask(object state)
_debugCommunications = taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBUILDDEBUGCOMM", "1", StringComparison.OrdinalIgnoreCase);
_updateEnvironment = !taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBuildTaskHostDoNotUpdateEnvironment", "1", StringComparison.OrdinalIgnoreCase);
_updateEnvironmentAndLog = taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBuildTaskHostUpdateEnvironmentAndLog", "1", StringComparison.OrdinalIgnoreCase);
-
+ WarningsAsErrors = taskConfiguration.WarningsAsErrors;
try
{
// Change to the startup directory
diff --git a/src/Shared/BinaryTranslator.cs b/src/Shared/BinaryTranslator.cs
index 1a6c9e3c39c..6c2b6337393 100644
--- a/src/Shared/BinaryTranslator.cs
+++ b/src/Shared/BinaryTranslator.cs
@@ -293,6 +293,32 @@ public void Translate(ref IList list, ObjectTranslator objectTransla
}
}
+ ///
+ /// Translates a collection of T into the specified type using an and
+ ///
+ /// The collection to be translated.
+ /// The translator to use for the values in the collection.
+ /// The factory to create the ICollection.
+ /// The type contained in the collection.
+ /// The type of collection to be created.
+ public void Translate(ref ICollection collection, ObjectTranslator objectTranslator, NodePacketCollectionCreator collectionFactory) where L : ICollection
+ {
+ if (!TranslateNullable(collection))
+ {
+ return;
+ }
+
+ int count = _reader.ReadInt32();
+ collection = collectionFactory(count);
+
+ for (int i = 0; i < count; i++)
+ {
+ T value = default(T);
+ objectTranslator(this, ref value);
+ collection.Add(value);
+ }
+ }
+
///
/// Translates a DateTime.
///
@@ -883,6 +909,30 @@ public void Translate(ref IList list, ObjectTranslator objectTransla
}
}
+ ///
+ /// Translates a collection of T into the specified type using an and
+ ///
+ /// The collection to be translated.
+ /// The translator to use for the values in the collection.
+ /// The factory to create the ICollection.
+ /// The type contained in the collection.
+ /// The type of collection to be created.
+ public void Translate(ref ICollection collection, ObjectTranslator objectTranslator, NodePacketCollectionCreator collectionFactory) where L : ICollection
+ {
+ if (!TranslateNullable(collection))
+ {
+ return;
+ }
+
+ _writer.Write(collection.Count);
+
+ foreach (T item in collection)
+ {
+ T value = item;
+ objectTranslator(this, ref value);
+ }
+ }
+
///
/// Translates a DateTime.
///
diff --git a/src/Shared/ITranslator.cs b/src/Shared/ITranslator.cs
index 6fec218805e..b1acb85ec2f 100644
--- a/src/Shared/ITranslator.cs
+++ b/src/Shared/ITranslator.cs
@@ -180,6 +180,16 @@ BinaryWriter Writer
/// factory to create a collection
void Translate(ref IList list, ObjectTranslator objectTranslator, NodePacketCollectionCreator collectionFactory) where L : IList;
+ ///
+ /// Translates a collection of T into the specified type using an and
+ ///
+ /// The collection to be translated.
+ /// The translator to use for the values in the collection.
+ /// The factory to create the ICollection.
+ /// The type contained in the collection.
+ /// The type of collection to be created.
+ void Translate(ref ICollection collection, ObjectTranslator objectTranslator, NodePacketCollectionCreator collectionFactory) where L : ICollection;
+
///
/// Translates a DateTime.
///
diff --git a/src/Shared/TaskHostConfiguration.cs b/src/Shared/TaskHostConfiguration.cs
index 45d007d25b3..367e2845823 100644
--- a/src/Shared/TaskHostConfiguration.cs
+++ b/src/Shared/TaskHostConfiguration.cs
@@ -85,6 +85,8 @@ internal class TaskHostConfiguration : INodePacket
private Dictionary _globalParameters;
+ private ICollection _warningsAsErrors;
+
#if FEATURE_APPDOMAIN
///
/// Constructor
@@ -103,6 +105,7 @@ internal class TaskHostConfiguration : INodePacket
/// Location of the assembly the task is to be loaded from.
/// Parameters to apply to the task.
/// global properties for the current project.
+ /// Warning codes to be thrown as errors for the current project.
#else
///
/// Constructor
@@ -120,6 +123,7 @@ internal class TaskHostConfiguration : INodePacket
/// Location of the assembly the task is to be loaded from.
/// Parameters to apply to the task.
/// global properties for the current project.
+ /// Warning codes to be logged as errors for the current project.
#endif
public TaskHostConfiguration
(
@@ -138,7 +142,8 @@ public TaskHostConfiguration
string taskName,
string taskLocation,
IDictionary taskParameters,
- Dictionary globalParameters
+ Dictionary globalParameters,
+ ICollection warningsAsErrors
)
{
ErrorUtilities.VerifyThrowInternalLength(taskName, nameof(taskName));
@@ -168,6 +173,7 @@ Dictionary globalParameters
_continueOnError = continueOnError;
_taskName = taskName;
_taskLocation = taskLocation;
+ _warningsAsErrors = warningsAsErrors;
if (taskParameters != null)
{
@@ -342,6 +348,15 @@ public NodePacketType Type
{ return NodePacketType.TaskHostConfiguration; }
}
+ public ICollection WarningsAsErrors
+ {
+ [DebuggerStepThrough]
+ get
+ {
+ return _warningsAsErrors;
+ }
+ }
+
///
/// Translates the packet to/from binary form.
///
@@ -364,6 +379,13 @@ public void Translate(ITranslator translator)
translator.TranslateDictionary(ref _taskParameters, StringComparer.OrdinalIgnoreCase, TaskParameter.FactoryForDeserialization);
translator.Translate(ref _continueOnError);
translator.TranslateDictionary(ref _globalParameters, StringComparer.OrdinalIgnoreCase);
+ translator.Translate(collection: ref _warningsAsErrors,
+ objectTranslator: (ITranslator t, ref string s) => t.Translate(ref s),
+#if CLR2COMPATIBILITY
+ collectionFactory: count => new HashSet());
+#else
+ collectionFactory: count => new HashSet(count, StringComparer.OrdinalIgnoreCase));
+#endif
}
///
diff --git a/src/Shared/TaskLoggingHelper.cs b/src/Shared/TaskLoggingHelper.cs
index 7592c784fc0..a4f4a164193 100644
--- a/src/Shared/TaskLoggingHelper.cs
+++ b/src/Shared/TaskLoggingHelper.cs
@@ -1016,6 +1016,28 @@ params object[] messageArgs
// that gives the user something.
bool fillInLocation = (String.IsNullOrEmpty(file) && (lineNumber == 0) && (columnNumber == 0));
+ // This warning will be converted to an error if:
+ // 1. Its code exists within WarningsAsErrors
+ // 2. If WarningsAsErrors is a non-null empty set (treat all warnings as errors)
+ if (BuildEngine is IBuildEngine8 be8 && be8.ShouldTreatWarningAsError(warningCode))
+ {
+ LogError
+ (
+ subcategory: subcategory,
+ errorCode: warningCode,
+ helpKeyword: helpKeyword,
+ helpLink: helpLink,
+ file: fillInLocation ? BuildEngine.ProjectFileOfTaskNode : file,
+ lineNumber: fillInLocation ? BuildEngine.LineNumberOfTaskNode : lineNumber,
+ columnNumber: fillInLocation ? BuildEngine.ColumnNumberOfTaskNode : columnNumber,
+ endLineNumber: endLineNumber,
+ endColumnNumber: endColumnNumber,
+ message: message,
+ messageArgs: messageArgs
+ );
+ return;
+ }
+
var e = new BuildWarningEventArgs
(
subcategory,
diff --git a/src/Utilities/Task.cs b/src/Utilities/Task.cs
index 39846721d3c..a9f3de6ff36 100644
--- a/src/Utilities/Task.cs
+++ b/src/Utilities/Task.cs
@@ -94,6 +94,11 @@ protected Task(ResourceManager taskResources, string helpKeywordPrefix)
///
public IBuildEngine7 BuildEngine7 => (IBuildEngine7)BuildEngine;
+ ///
+ /// Retrieves the version of the build engine interface provided by the host.
+ ///
+ public IBuildEngine8 BuildEngine8 => (IBuildEngine8)BuildEngine;
+
///
/// The build engine sets this property if the host IDE has associated a host object with this particular task.
///