diff options
-rw-r--r-- | docs/error-codes.md | 4 | ||||
-rw-r--r-- | src/linker/Linker/Driver.cs | 20 | ||||
-rw-r--r-- | src/linker/Linker/LinkContext.cs | 57 | ||||
-rw-r--r-- | src/linker/Linker/MessageCategory.cs | 4 | ||||
-rw-r--r-- | src/linker/Linker/MessageContainer.cs | 47 | ||||
-rw-r--r-- | src/linker/ref/Linker/MessageContainer.cs | 4 | ||||
-rw-r--r-- | test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs | 28 | ||||
-rw-r--r-- | test/Mono.Linker.Tests.Cases/Warnings/NoWarnRegardlessOfWarnAsError.cs | 29 | ||||
-rw-r--r-- | test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/CanGenerateWarningSuppressionFileXml.cs | 3 | ||||
-rw-r--r-- | test/Mono.Linker.Tests/Tests/MessageContainerTests.cs | 2 |
10 files changed, 108 insertions, 90 deletions
diff --git a/docs/error-codes.md b/docs/error-codes.md index 8fb7833b8..d654257a4 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -113,6 +113,10 @@ the error code. For example: #### `IL1030`: Invalid argument for '{token}' option +#### `IL1031`: "Invalid value 'value' was used as warning code + +- All warning codes must start with `IL` prefix followed by numeric code. + ---- ## Warning Codes diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs index b2e402fbd..78da74298 100644 --- a/src/linker/Linker/Driver.cs +++ b/src/linker/Linker/Driver.cs @@ -444,14 +444,14 @@ namespace Mono.Linker if (!GetStringParam (token, l => noWarnArgument = l)) return -1; - context.NoWarn.UnionWith (ParseWarnings (noWarnArgument)); + context.NoWarn.UnionWith (ProcessWarningCodes (noWarnArgument)); continue; case "--warnaserror": case "--warnaserror+": var warningList = GetNextStringValue (); if (!string.IsNullOrEmpty (warningList)) { - foreach (var warning in ParseWarnings (warningList)) + foreach (var warning in ProcessWarningCodes (warningList)) context.WarnAsError[warning] = true; } else { @@ -464,7 +464,7 @@ namespace Mono.Linker case "--warnaserror-": warningList = GetNextStringValue (); if (!string.IsNullOrEmpty (warningList)) { - foreach (var warning in ParseWarnings (warningList)) + foreach (var warning in ProcessWarningCodes (warningList)) context.WarnAsError[warning] = false; } else { @@ -775,7 +775,7 @@ namespace Mono.Linker partial void PreProcessPipeline (Pipeline pipeline); - private static HashSet<uint> ParseWarnings (string value) + private IEnumerable<int> ProcessWarningCodes (string value) { string Unquote (string arg) { @@ -787,18 +787,14 @@ namespace Mono.Linker value = Unquote (value); string[] values = value.Split (new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); - HashSet<uint> warningCodes = new HashSet<uint> (); foreach (string id in values) { - if (!id.StartsWith ("IL", StringComparison.Ordinal)) + if (!id.StartsWith ("IL", StringComparison.Ordinal) || !ushort.TryParse (id.Substring (2), out ushort code)) { + context.LogError ($"Invalid value '{id}' was used as warning code", 1031); continue; + } - var warningCode = id.Substring (2); - if (ushort.TryParse (warningCode, out ushort code) - && code > 2000 && code <= 6000) - warningCodes.Add (code); + yield return code; } - - return warningCodes; } Assembly GetCustomAssembly (string arg) diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs index 331f51ba9..55f2e901a 100644 --- a/src/linker/Linker/LinkContext.cs +++ b/src/linker/Linker/LinkContext.cs @@ -174,9 +174,9 @@ namespace Mono.Linker public WarningSuppressionWriter WarningSuppressionWriter { get; private set; } - public HashSet<uint> NoWarn { get; set; } + public HashSet<int> NoWarn { get; set; } - public Dictionary<uint, bool> WarnAsError { get; set; } + public Dictionary<int, bool> WarnAsError { get; set; } public bool GeneralWarnAsError { get; set; } @@ -236,9 +236,9 @@ namespace Mono.Linker StripLinkAttributes = true; PInvokes = new List<PInvokeInfo> (); Suppressions = new UnconditionalSuppressMessageAttributeState (this); - NoWarn = new HashSet<uint> (); + NoWarn = new HashSet<int> (); GeneralWarnAsError = false; - WarnAsError = new Dictionary<uint, bool> (); + WarnAsError = new Dictionary<int, bool> (); WarnVersion = WarnVersion.Latest; // See https://github.com/mono/linker/issues/612 @@ -502,22 +502,9 @@ namespace Mono.Linker message.Category == MessageCategory.Info) && !LogMessages) return; - if (message.Category == MessageCategory.Warning && - NoWarn.Contains ((uint) message.Code)) { - // This warning was turned off by --nowarn. - return; - } - - // Note: message.Version is nullable. The comparison is false if it is null. - // Unversioned warnings are not controlled by WarnVersion. - // Error messages are guaranteed to only have a version if they were created for a warning due to warnaserror. - if ((message.Category == MessageCategory.Warning || message.Category == MessageCategory.Error) && - message.Version > WarnVersion) { - // This warning was turned off by --warn. - return; - } - - if (OutputWarningSuppressions && message.Category == MessageCategory.Warning && message.Origin?.MemberDefinition != null) + if (OutputWarningSuppressions && + (message.Category == MessageCategory.Warning || message.Category == MessageCategory.WarningAsError) && + message.Origin?.MemberDefinition != null) WarningSuppressionWriter.AddWarning (message.Code.Value, message.Origin?.MemberDefinition); Logger?.LogMessage (message); @@ -552,15 +539,8 @@ namespace Mono.Linker /// <returns>New MessageContainer of 'Warning' category</returns> public void LogWarning (string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None) { - var version = GetWarningVersion (code); - - if ((GeneralWarnAsError && (!WarnAsError.TryGetValue ((uint) code, out var warnAsError) || warnAsError)) || - (!GeneralWarnAsError && (WarnAsError.TryGetValue ((uint) code, out warnAsError) && warnAsError))) { - LogError (text, code, subcategory, origin, isWarnAsError: true, version: version); - return; - } - - var warning = MessageContainer.CreateWarningMessage (this, text, code, origin, subcategory, version); + WarnVersion version = GetWarningVersion (code); + MessageContainer warning = MessageContainer.CreateWarningMessage (this, text, code, origin, version, subcategory); LogMessage (warning); } @@ -604,21 +584,34 @@ namespace Mono.Linker /// <param name="subcategory">Optionally, further categorize this error</param> /// <param name="origin">Filename, line, and column where the error was found</param> /// <returns>New MessageContainer of 'Error' category</returns> - public void LogError (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null, bool isWarnAsError = false, WarnVersion? version = null) + public void LogError (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null) { - var error = MessageContainer.CreateErrorMessage (text, code, subcategory, origin, isWarnAsError, version); + var error = MessageContainer.CreateErrorMessage (text, code, subcategory, origin); LogMessage (error); } public bool IsWarningSuppressed (int warningCode, MessageOrigin origin) { + // This warning was turned off by --nowarn. + if (NoWarn.Contains (warningCode)) + return true; + if (Suppressions == null) return false; return Suppressions.IsSuppressed (warningCode, origin, out _); } - public static WarnVersion GetWarningVersion (int code) + public bool IsWarningAsError (int warningCode) + { + bool value; + if (GeneralWarnAsError) + return !WarnAsError.TryGetValue (warningCode, out value) || value; + + return WarnAsError.TryGetValue (warningCode, out value) && value; + } + + static WarnVersion GetWarningVersion (int code) { // This should return an increasing WarnVersion for new warning waves. return WarnVersion.ILLink5; diff --git a/src/linker/Linker/MessageCategory.cs b/src/linker/Linker/MessageCategory.cs index f0cf092f8..1ca1a1085 100644 --- a/src/linker/Linker/MessageCategory.cs +++ b/src/linker/Linker/MessageCategory.cs @@ -9,6 +9,8 @@ namespace Mono.Linker Error = 0, Warning, Info, - Diagnostic + Diagnostic, + + WarningAsError = 0xFF } } diff --git a/src/linker/Linker/MessageContainer.cs b/src/linker/Linker/MessageContainer.cs index f0149546a..fd81f732a 100644 --- a/src/linker/Linker/MessageContainer.cs +++ b/src/linker/Linker/MessageContainer.cs @@ -31,10 +31,6 @@ namespace Mono.Linker public int? Code { get; } /// <summary> - /// Version number for this warning. - public WarnVersion? Version { get; } - - /// <summary> /// User friendly text describing the error or warning. /// </summary> public string Text { get; } @@ -48,18 +44,12 @@ namespace Mono.Linker /// <param name="subcategory">Optionally, further categorize this error</param> /// <param name="origin">Filename, line, and column where the error was found</param> /// <returns>New MessageContainer of 'Error' category</returns> - public static MessageContainer CreateErrorMessage (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null, bool isWarnAsError = false, WarnVersion? version = null) + public static MessageContainer CreateErrorMessage (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null) { - if (isWarnAsError) { - ValidateWarning (code, version); - } else { - if (!(code >= 1000 && code <= 2000)) - throw new ArgumentException ($"The provided code '{code}' does not fall into the error category, which is in the range of 1000 to 2000 (inclusive)."); - if (version != null) - throw new ArgumentException ($"An error message may not have a version."); - } + if (!(code >= 1000 && code <= 2000)) + throw new ArgumentException ($"The provided code '{code}' does not fall into the error category, which is in the range of 1000 to 2000 (inclusive)."); - return new MessageContainer (MessageCategory.Error, text, code, subcategory, origin, version); + return new MessageContainer (MessageCategory.Error, text, code, subcategory, origin); } /// <summary> @@ -74,14 +64,24 @@ namespace Mono.Linker /// <param name="version">Optional warning version number. Versioned warnings can be controlled with the /// warning wave option --warn VERSION. Unversioned warnings are unaffected by this option. </param> /// <returns>New MessageContainer of 'Warning' category</returns> - public static MessageContainer CreateWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None, WarnVersion? version = null) + public static MessageContainer CreateWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, WarnVersion version, string subcategory = MessageSubCategory.None) { - ValidateWarning (code, version); + if (!(code > 2000 && code <= 6000)) + throw new ArgumentException ($"The provided code '{code}' does not fall into the warning category, which is in the range of 2001 to 6000 (inclusive)."); + + if (!(version >= WarnVersion.ILLink0 && version <= WarnVersion.Latest)) + throw new ArgumentException ($"The provided warning version '{version}' is invalid."); if (context.IsWarningSuppressed (code, origin)) return Empty; - return new MessageContainer (MessageCategory.Warning, text, code, subcategory, origin, version); + if (version > context.WarnVersion) + return Empty; + + if (context.IsWarningAsError (code)) + return new MessageContainer (MessageCategory.WarningAsError, text, code, subcategory, origin); + + return new MessageContainer (MessageCategory.Warning, text, code, subcategory, origin); } /// <summary> @@ -104,23 +104,13 @@ namespace Mono.Linker return new MessageContainer (MessageCategory.Diagnostic, text, null); } - private MessageContainer (MessageCategory category, string text, int? code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null, WarnVersion? version = null) + private MessageContainer (MessageCategory category, string text, int? code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null) { Code = code; Category = category; Origin = origin; SubCategory = subcategory; Text = text; - Version = version; - } - - static void ValidateWarning (int code, WarnVersion? version) - { - if (!(code > 2000 && code <= 6000)) - throw new ArgumentException ($"The provided code '{code}' does not fall into the warning category, which is in the range of 2001 to 6000 (inclusive)."); - - if (version != null && !(version >= WarnVersion.ILLink0 && version <= WarnVersion.Latest)) - throw new ArgumentException ($"The provided warning version '{version}' is invalid."); } public override string ToString () => ToMSBuildString (); @@ -139,6 +129,7 @@ namespace Mono.Linker string cat; switch (Category) { case MessageCategory.Error: + case MessageCategory.WarningAsError: cat = "error"; break; case MessageCategory.Warning: diff --git a/src/linker/ref/Linker/MessageContainer.cs b/src/linker/ref/Linker/MessageContainer.cs index e9b6ad9f4..11427d317 100644 --- a/src/linker/ref/Linker/MessageContainer.cs +++ b/src/linker/ref/Linker/MessageContainer.cs @@ -6,8 +6,8 @@ namespace Mono.Linker { public readonly struct MessageContainer { - public static MessageContainer CreateErrorMessage (string text, int code, string subcategory = "", MessageOrigin? origin = null, bool isWarnAsError = false, WarnVersion? version = null) { throw null; } - public static MessageContainer CreateWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, string subcategory = "", WarnVersion? version = null) { throw null; } + public static MessageContainer CreateErrorMessage (string text, int code, string subcategory = "", MessageOrigin? origin = null) { throw null; } + public static MessageContainer CreateWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, WarnVersion version, string subcategory = "") { throw null; } public static MessageContainer CreateInfoMessage (string text) { throw null; } public static MessageContainer CreateDiagnosticMessage (string text) { throw null; } } diff --git a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs index 77162f574..3223ab5ae 100644 --- a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs +++ b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs @@ -273,9 +273,9 @@ namespace ILLink.Tasks.Tests [InlineData ("IL2001;IL2002;IL2003;IL2004", 4)] [InlineData ("IL2001 IL2002 IL2003 IL2004", 4)] [InlineData ("IL2001,IL2002,IL2003,IL2004", 4)] - [InlineData ("IL2001,IL2002; IL2003 IL2004", 4)] - [InlineData ("IL2001,CS4550,CA2123,IL2002,2000,IL8000,IL1003", 2)] - [InlineData ("SomeText,IL20000,IL02000", 0)] + [InlineData ("IL2001,IL2002;IL2003 IL2004", 4)] + [InlineData ("IL2001,IL2002,IL8000,IL1003", 4)] + [InlineData ("IL20000,IL02000", 2)] public void TestValidNoWarn (string noWarn, int validNoWarns) { var task = new MockTask () { @@ -304,16 +304,16 @@ namespace ILLink.Tasks.Tests #nullable enable [Theory] - [InlineData (true, null, null, new uint[] { }, new uint[] { })] - [InlineData (false, "IL1001,IL####,IL2000,IL2054,IL2022", null, - new uint[] { 2054, 2022 }, new uint[] { })] + [InlineData (true, null, null, new int[] { }, new int[] { })] + [InlineData (false, "IL1001,IL2000,IL2054,IL2022", null, + new int[] { 1001, 2000, 2054, 2022 }, new int[] { })] [InlineData (false, "IL2023,IL6000;IL5042 IL2040", "IL4000,IL4001;IL4002 IL4003", - new uint[] { 2023, 2040, 5042, 6000 }, new uint[] { 4000, 4001, 4002, 4003 })] - [InlineData (false, "IL3000;IL3000;ABCD", "IL2005 il3000 IL2005", - new uint[] { 3000 }, new uint[] { 2005 })] - [InlineData (true, null, "IL2067", new uint[] { }, new uint[] { 2067 })] - [InlineData (true, "IL2001", "IL2001", new uint[] { }, new uint[] { 2001 })] - public void TestWarningsAsErrors (bool treatWarningsAsErrors, string? warningsAsErrors, string? warningsNotAsErrors, uint[] warnAsError, uint[] warnNotAsError) + new int[] { 2023, 2040, 5042, 6000 }, new int[] { 4000, 4001, 4002, 4003 })] + [InlineData (false, "IL3000;IL3000;ABCD", "IL2005 IL3005 IL2005", + new int[] { 3000 }, new int[] { 2005, 3005 })] + [InlineData (true, null, "IL2067", new int[] { }, new int[] { 2067 })] + [InlineData (true, "IL2001", "IL2001", new int[] { }, new int[] { 2001 })] + public void TestWarningsAsErrors (bool treatWarningsAsErrors, string? warningsAsErrors, string? warningsNotAsErrors, int[] warnAsError, int[] warnNotAsError) { var task = new MockTask () { TreatWarningsAsErrors = treatWarningsAsErrors, @@ -324,8 +324,8 @@ namespace ILLink.Tasks.Tests using (var driver = task.CreateDriver ()) { var actualWarnAsError = driver.Context.WarnAsError; var actualGeneralWarnAsError = driver.Context.GeneralWarnAsError; - Assert.Equal (actualWarnAsError.Count, warnAsError.Distinct ().Count () + warnNotAsError.Distinct ().Count ()); - Assert.Equal (actualGeneralWarnAsError, treatWarningsAsErrors); + Assert.Equal (warnAsError.Count () + warnNotAsError.Count (), actualWarnAsError.Count); + Assert.Equal (treatWarningsAsErrors, actualGeneralWarnAsError); if (warnAsError.Length > 0) { foreach (var warningCode in warnAsError) Assert.True (actualWarnAsError.ContainsKey (warningCode) && actualWarnAsError[warningCode] == true); diff --git a/test/Mono.Linker.Tests.Cases/Warnings/NoWarnRegardlessOfWarnAsError.cs b/test/Mono.Linker.Tests.Cases/Warnings/NoWarnRegardlessOfWarnAsError.cs new file mode 100644 index 000000000..dc49c24a6 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Warnings/NoWarnRegardlessOfWarnAsError.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Warnings +{ + [SkipKeptItemsValidation] + [SetupLinkerArgument ("--warnaserror")] + [SetupLinkerArgument ("--nowarn", "IL2006")] + [LogDoesNotContain ("IL2006")] + public class NoWarnRegardlessOfWarnAsError + { + public static void Main () + { + GetMethod (); + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + static string type; + + static void GetMethod () + { + _ = Type.GetType (type).GetMethod ("Foo"); + } + } +}
\ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/CanGenerateWarningSuppressionFileXml.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/CanGenerateWarningSuppressionFileXml.cs index b0bb6f72e..55bf0418f 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/CanGenerateWarningSuppressionFileXml.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/CanGenerateWarningSuppressionFileXml.cs @@ -14,6 +14,9 @@ namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression [SetupLinkerAction ("link", "library.dll")] [SetupLinkerArgument ("--verbose")] [SetupLinkerArgument ("--generate-warning-suppressions", "xml")] + + // Test that --warnaserror has no effect on --generate-warning-suppressions + [SetupLinkerArgument ("--warnaserror")] public class CanGenerateWarningSuppressionFileXml { public static void Main () diff --git a/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs b/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs index a6969b245..63765312b 100644 --- a/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs +++ b/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs @@ -13,7 +13,7 @@ namespace Mono.Linker.Tests var msg = MessageContainer.CreateErrorMessage ("text", 1000); Assert.AreEqual ("ILLink: error IL1000: text", msg.ToMSBuildString ()); - msg = MessageContainer.CreateWarningMessage (context, "message", 2001, new MessageOrigin ("logtest", 1, 1)); + msg = MessageContainer.CreateWarningMessage (context, "message", 2001, new MessageOrigin ("logtest", 1, 1), WarnVersion.Latest); Assert.AreEqual ("logtest(1,1): warning IL2001: message", msg.ToMSBuildString ()); msg = MessageContainer.CreateInfoMessage ("log test"); |