diff --git a/src/ILLink.RoslynAnalyzer/DiagnosticDescriptors.cs b/src/ILLink.RoslynAnalyzer/DiagnosticDescriptors.cs index 533435031f6a..30cf74e15267 100644 --- a/src/ILLink.RoslynAnalyzer/DiagnosticDescriptors.cs +++ b/src/ILLink.RoslynAnalyzer/DiagnosticDescriptors.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using ILLink.Shared; using Microsoft.CodeAnalysis; @@ -15,7 +14,7 @@ public static DiagnosticDescriptor GetDiagnosticDescriptor (DiagnosticId diagnos return new DiagnosticDescriptor (diagnosticId.AsString (), diagnosticString.GetTitleFormat (), diagnosticString.GetMessageFormat (), - GetDiagnosticCategory (diagnosticId), + diagnosticId.GetDiagnosticCategory (), DiagnosticSeverity.Warning, true); } @@ -24,7 +23,7 @@ public static DiagnosticDescriptor GetDiagnosticDescriptor (DiagnosticId diagnos => new DiagnosticDescriptor (diagnosticId.AsString (), diagnosticString.GetTitle (), diagnosticString.GetMessage (), - GetDiagnosticCategory (diagnosticId), + diagnosticId.GetDiagnosticCategory (), DiagnosticSeverity.Warning, true); @@ -41,7 +40,7 @@ public static DiagnosticDescriptor GetDiagnosticDescriptor (DiagnosticId diagnos return new DiagnosticDescriptor (diagnosticId.AsString (), diagnosticString.GetTitleFormat (), diagnosticString.GetMessageFormat (), - diagnosticCategory ?? GetDiagnosticCategory (diagnosticId), + diagnosticCategory ?? diagnosticId.GetDiagnosticCategory (), diagnosticSeverity, isEnabledByDefault, helpLinkUri); @@ -50,29 +49,10 @@ public static DiagnosticDescriptor GetDiagnosticDescriptor (DiagnosticId diagnos return new DiagnosticDescriptor (diagnosticId.AsString (), lrsTitle!, lrsMessage!, - diagnosticCategory ?? GetDiagnosticCategory (diagnosticId), + diagnosticCategory ?? diagnosticId.GetDiagnosticCategory (), diagnosticSeverity, isEnabledByDefault, helpLinkUri); } - - static string GetDiagnosticCategory (DiagnosticId diagnosticId) - { - switch ((int) diagnosticId) { - case > 2000 and < 3000: - return DiagnosticCategory.Trimming; - - case >= 3000 and < 3050: - return DiagnosticCategory.SingleFile; - - case >= 3050 and <= 6000: - return DiagnosticCategory.AOT; - - default: - break; - } - - throw new ArgumentException ($"The provided diagnostic id '{diagnosticId}' does not fall into the range of supported warning codes 2001 to 6000 (inclusive)."); - } } } diff --git a/src/ILLink.Shared/DiagnosticId.cs b/src/ILLink.Shared/DiagnosticId.cs index cb82b9e0ce0f..c7f5028f2d9d 100644 --- a/src/ILLink.Shared/DiagnosticId.cs +++ b/src/ILLink.Shared/DiagnosticId.cs @@ -4,6 +4,8 @@ // This is needed due to NativeAOT which doesn't enable nullable globally yet #nullable enable +using System; + namespace ILLink.Shared { public enum DiagnosticId @@ -224,5 +226,13 @@ public static string GetDiagnosticSubcategory (this DiagnosticId diagnosticId) = >= 3054 and <= 3055 => MessageSubCategory.AotAnalysis, _ => MessageSubCategory.None, }; + + public static string GetDiagnosticCategory (this DiagnosticId diagnosticId) => + (int) diagnosticId switch { + > 2000 and < 3000 => DiagnosticCategory.Trimming, + >= 3000 and < 3050 => DiagnosticCategory.SingleFile, + >= 3050 and <= 6000 => DiagnosticCategory.AOT, + _ => throw new ArgumentException ($"The provided diagnostic id '{diagnosticId}' does not fall into the range of supported warning codes 2001 to 6000 (inclusive).") + }; } } diff --git a/src/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs b/src/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs index 06353c222852..95c984d7fda5 100644 --- a/src/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs +++ b/src/ILLink.Shared/TrimAnalysis/DiagnosticContext.cs @@ -8,6 +8,17 @@ namespace ILLink.Shared.TrimAnalysis { readonly partial struct DiagnosticContext { + /// + /// The diagnostic context may be entirely disabled or some kinds of warnings may be suppressed. + /// The suppressions are determined based on the . + /// Typically the suppressions will be based on diagnostic category : + /// - Trimmer warnings (suppressed by RequiresUnreferencedCodeAttribute) + /// - AOT warnings (suppressed by RequiresDynamicCodeAttribute) + /// - Single-file warnings (suppressed by RequiresAssemblyFilesAttribute) + /// Note that not all categories are used/supported by all tools, for example the ILLink only handles trimmer warnings and ignores the rest. + /// + /// The diagnostic ID, this will be used to determine the category of diagnostic (trimmer, AOT, single-file) + /// The arguments for diagnostic message. public partial void AddDiagnostic (DiagnosticId id, params string[] args); } } diff --git a/src/linker/Linker/CompilerGeneratedState.cs b/src/linker/Linker/CompilerGeneratedState.cs index c019d73fec07..b4116e3ba752 100644 --- a/src/linker/Linker/CompilerGeneratedState.cs +++ b/src/linker/Linker/CompilerGeneratedState.cs @@ -104,8 +104,6 @@ public static bool TryGetStateMachineType (MethodDefinition method, [NotNullWhen /// TypeDefinition? PopulateCacheForType (TypeDefinition type) { - var originalType = type; - // Look in the declaring type if this is a compiler-generated type (state machine or display class). // State machines can be emitted into display classes, so we may also need to go one more level up. // To avoid depending on implementation details, we go up until we see a non-compiler-generated type. diff --git a/src/linker/Linker/MessageOrigin.cs b/src/linker/Linker/MessageOrigin.cs index 8919e8e4539a..24d18c065df2 100644 --- a/src/linker/Linker/MessageOrigin.cs +++ b/src/linker/Linker/MessageOrigin.cs @@ -120,7 +120,7 @@ public bool Equals (MessageOrigin other) => (FileName, Provider, SourceLine, SourceColumn, ILOffset) == (other.FileName, other.Provider, other.SourceLine, other.SourceColumn, other.ILOffset); public override bool Equals (object? obj) => obj is MessageOrigin messageOrigin && Equals (messageOrigin); - public override int GetHashCode () => (FileName, Provider, SourceLine, SourceColumn).GetHashCode (); + public override int GetHashCode () => (FileName, Provider, SourceLine, SourceColumn, ILOffset).GetHashCode (); public static bool operator == (MessageOrigin lhs, MessageOrigin rhs) => lhs.Equals (rhs); public static bool operator != (MessageOrigin lhs, MessageOrigin rhs) => !lhs.Equals (rhs); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs index 7f73071d4386..46120679c31a 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs @@ -16,8 +16,10 @@ class AttributeConstructorDataflow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructor (typeof (ClassWithKeptPublicConstructor))] [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeConstructorDataflow+ClassWithKeptPublicMethods")] + [TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] public static void Main () @@ -109,5 +111,15 @@ public void Method () { } public int Field; } } + + [Kept] + [KeptBaseType (typeof (Attribute))] + class TypeArrayAttribute : Attribute + { + [Kept] + public TypeArrayAttribute (Type[] types) // This should not trigger data flow analysis of the parameter + { + } + } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs index 44c857b74855..2cac037c5d80 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs @@ -16,8 +16,10 @@ class AttributeFieldDataflow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructors (Type = typeof (ClassWithKeptPublicConstructor))] - [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicMethods (Type = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods")] + [TypeArray (Types = new Type[] { typeof (AttributeFieldDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] public static void Main () @@ -46,12 +48,14 @@ public KeepsPublicConstructorsAttribute () class KeepsPublicMethodsAttribute : Attribute { [Kept] - public KeepsPublicMethodsAttribute ( - [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] - string type) + public KeepsPublicMethodsAttribute () { } + + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public string Type; } [Kept] @@ -74,5 +78,18 @@ class ClassWithKeptPublicMethods public static void KeptMethod () { } static void Method () { } } + + [Kept] + [KeptBaseType (typeof (Attribute))] + class TypeArrayAttribute : Attribute + { + [Kept] + public TypeArrayAttribute () + { + } + + [Kept] + public Type[] Types; + } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs index e6848fa5da9a..1b10390ea1cb 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs @@ -16,8 +16,10 @@ class AttributePropertyDataflow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructors (Type = typeof (ClassWithKeptPublicConstructor))] - [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicMethods (Type = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+ClassWithKeptPublicMethods")] + [TypeArray (Types = new Type[] { typeof (AttributePropertyDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] public static void Main () @@ -47,12 +49,15 @@ public KeepsPublicConstructorsAttribute () class KeepsPublicMethodsAttribute : Attribute { [Kept] - public KeepsPublicMethodsAttribute ( - [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] - string type) + public KeepsPublicMethodsAttribute () { } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public string Type { get; [Kept] set; } } [Kept] @@ -75,5 +80,19 @@ class ClassWithKeptPublicMethods public static void KeptMethod () { } static void Method () { } } + + [Kept] + [KeptBaseType (typeof (Attribute))] + class TypeArrayAttribute : Attribute + { + [Kept] + public TypeArrayAttribute () + { + } + + [field: Kept] + [Kept] + public Type[] Types { get; [Kept] set; } + } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs index 0b05ededcbc9..a16c455e8563 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs @@ -125,11 +125,29 @@ static unsafe void IntPtrDeref () [RequiresUnreferencedCode ("")] static IntPtr GetDangerous () { return IntPtr.Zero; } + [Kept] + [ExpectedWarning ("IL2070")] + static unsafe void LocalStackAllocDeref (Type t) + { + // Code pattern from CoreLib which caused problems in AOT port + // so making sure we handle this correctly (that is without failing) + int buffSize = 256; + byte* stackSpace = stackalloc byte[buffSize]; + byte* buffer = stackSpace; + + byte* toFree = buffer; + buffer = null; + + // IL2070 - this is to make sure that DataFlow ran on the method's body + t.GetProperties (); + } + [Kept] [ExpectedWarning ("IL2026")] public static void Test () { IntPtrDeref (); + LocalStackAllocDeref (null); } } }