diff --git a/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs new file mode 100644 index 000000000000..bdccec06903a --- /dev/null +++ b/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis; + +namespace ILLink.RoslynAnalyzer +{ + static class INamedTypeSymbolExtensions + { + /// + /// Returns true if has the same name as + /// + internal static bool HasName (this INamedTypeSymbol type, string typeName) + { + var roSpan = typeName.AsSpan (); + INamespaceOrTypeSymbol? currentType = type; + while (roSpan.Length > 0) { + var dot = roSpan.LastIndexOf ('.'); + var currentName = dot < 0 ? roSpan : roSpan.Slice (dot + 1); + if (currentType is null || + !currentName.Equals (currentType.Name.AsSpan (), StringComparison.Ordinal)) { + return false; + } + currentType = (INamespaceOrTypeSymbol?) currentType.ContainingType ?? currentType.ContainingNamespace; + roSpan = roSpan.Slice (0, dot > 0 ? dot : 0); + } + + return true; + } + } +} diff --git a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs new file mode 100644 index 000000000000..f458cc1fecb0 --- /dev/null +++ b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis; + +namespace ILLink.RoslynAnalyzer +{ + static class ISymbolExtensions + { + /// + /// Returns true if symbol has an attribute with name . + /// + internal static bool HasAttribute (this ISymbol symbol, string attributeName) + { + foreach (var attr in symbol.GetAttributes ()) + if (attr.AttributeClass?.Name == attributeName) + return true; + + return false; + } + + internal static bool TryGetRequiresAssemblyFileAttribute (this ISymbol symbol, out AttributeData? attribute) + { + attribute = null; + foreach (var _attribute in symbol.GetAttributes ()) { + if (_attribute.AttributeClass is var attrClass && attrClass != null && + attrClass.HasName (RequiresAssemblyFilesAnalyzer.FullyQualifiedRequiresAssemblyFilesAttribute) && + _attribute.ConstructorArguments.Length == 0) { + attribute = _attribute; + return true; + } + } + + return false; + } + + internal static bool TryGetAttributeWithMessageOnCtor (this ISymbol symbol, string qualifiedAttributeName, out AttributeData? attribute) + { + attribute = null; + foreach (var _attribute in symbol.GetAttributes ()) { + if (_attribute.AttributeClass is var attrClass && attrClass != null && + attrClass.HasName (qualifiedAttributeName) && _attribute.ConstructorArguments.Length >= 1 && + _attribute.ConstructorArguments[0] is { Type: { SpecialType: SpecialType.System_String } } ctorArg) { + attribute = _attribute; + return true; + } + } + + return false; + } + } +} diff --git a/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs new file mode 100644 index 000000000000..65006691c3c9 --- /dev/null +++ b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace ILLink.RoslynAnalyzer +{ + [DiagnosticAnalyzer (LanguageNames.CSharp)] + public sealed class RequiresAssemblyFilesAnalyzer : DiagnosticAnalyzer + { + public const string IL3002 = nameof (IL3002); + internal const string RequiresAssemblyFilesAttribute = nameof (RequiresAssemblyFilesAttribute); + internal const string FullyQualifiedRequiresAssemblyFilesAttribute = "System.Diagnostics.CodeAnalysis." + RequiresAssemblyFilesAttribute; + + static readonly DiagnosticDescriptor s_requiresAssemblyFilesRule = new DiagnosticDescriptor ( + IL3002, + new LocalizableResourceString (nameof (Resources.RequiresAssemblyFilesTitle), + Resources.ResourceManager, typeof (Resources)), + new LocalizableResourceString (nameof (Resources.RequiresAssemblyFilesMessage), + Resources.ResourceManager, typeof (Resources)), + DiagnosticCategory.SingleFile, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_requiresAssemblyFilesRule); + + public override void Initialize (AnalysisContext context) + { + context.EnableConcurrentExecution (); + context.ConfigureGeneratedCodeAnalysis (GeneratedCodeAnalysisFlags.ReportDiagnostics); + + context.RegisterCompilationStartAction (context => { + var compilation = context.Compilation; + + var isSingleFilePublish = context.Options.GetMSBuildPropertyValue (MSBuildPropertyOptionNames.PublishSingleFile, compilation); + if (!string.Equals (isSingleFilePublish?.Trim (), "true", StringComparison.OrdinalIgnoreCase)) + return; + + var includesAllContent = context.Options.GetMSBuildPropertyValue (MSBuildPropertyOptionNames.IncludeAllContentForSelfExtract, compilation); + if (string.Equals (includesAllContent?.Trim (), "true", StringComparison.OrdinalIgnoreCase)) + return; + + context.RegisterOperationAction (operationContext => { + var methodInvocation = (IInvocationOperation) operationContext.Operation; + CheckCalledMember (operationContext, methodInvocation.TargetMethod); + }, OperationKind.Invocation); + + context.RegisterOperationAction (operationContext => { + var objectCreation = (IObjectCreationOperation) operationContext.Operation; + CheckCalledMember (operationContext, objectCreation.Constructor); + }, OperationKind.ObjectCreation); + + context.RegisterOperationAction (operationContext => { + var propAccess = (IPropertyReferenceOperation) operationContext.Operation; + var prop = propAccess.Property; + var usageInfo = propAccess.GetValueUsageInfo (prop); + if (usageInfo.HasFlag (ValueUsageInfo.Read) && prop.GetMethod != null) + CheckCalledMember (operationContext, prop.GetMethod); + + if (usageInfo.HasFlag (ValueUsageInfo.Write) && prop.SetMethod != null) + CheckCalledMember (operationContext, prop.SetMethod); + + CheckCalledMember (operationContext, prop); + }, OperationKind.PropertyReference); + + context.RegisterOperationAction (operationContext => { + var eventRef = (IEventReferenceOperation) operationContext.Operation; + CheckCalledMember (operationContext, eventRef.Member); + }, OperationKind.EventReference); + + static void CheckCalledMember ( + OperationAnalysisContext operationContext, + ISymbol member) + { + // Do not emit any diagnostic if caller is annotated with the attribute too. + if (operationContext.ContainingSymbol.HasAttribute (RequiresAssemblyFilesAttribute)) + return; + + if (member.TryGetRequiresAssemblyFileAttribute (out AttributeData? requiresAssemblyFilesAttribute)) { + operationContext.ReportDiagnostic (Diagnostic.Create ( + s_requiresAssemblyFilesRule, + operationContext.Operation.Syntax.GetLocation (), + member.OriginalDefinition.ToString (), + requiresAssemblyFilesAttribute?.NamedArguments.FirstOrDefault (na => na.Key == "Message").Value.Value?.ToString (), + requiresAssemblyFilesAttribute?.NamedArguments.FirstOrDefault (na => na.Key == "Url").Value.Value?.ToString ())); + } + } + }); + } + } +} diff --git a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs index 1b93e3cf3971..50744cbb7884 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs @@ -15,8 +15,10 @@ namespace ILLink.RoslynAnalyzer public class RequiresUnreferencedCodeAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "IL2026"; + const string RequiresUnreferencedCodeAttribute = nameof (RequiresUnreferencedCodeAttribute); + const string FullyQualifiedRequiresUnreferencedCodeAttribute = "System.Diagnostics.CodeAnalysis." + RequiresUnreferencedCodeAttribute; - private static readonly DiagnosticDescriptor s_rule = new DiagnosticDescriptor ( + static readonly DiagnosticDescriptor s_requiresUnreferencedCodeRule = new DiagnosticDescriptor ( DiagnosticId, new LocalizableResourceString (nameof (Resources.RequiresUnreferencedCodeAnalyzerTitle), Resources.ResourceManager, typeof (Resources)), @@ -26,7 +28,7 @@ public class RequiresUnreferencedCodeAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_rule); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_requiresUnreferencedCodeRule); public override void Initialize (AnalysisContext context) { @@ -46,46 +48,41 @@ public override void Initialize (AnalysisContext context) if (call.IsVirtual && call.TargetMethod.OverriddenMethod != null) return; - CheckMethodOrCtorCall (operationContext, call.TargetMethod, call.Syntax.GetLocation ()); + CheckMethodOrCtorCall (operationContext, call.TargetMethod); }, OperationKind.Invocation); context.RegisterOperationAction (operationContext => { var call = (IObjectCreationOperation) operationContext.Operation; - CheckMethodOrCtorCall (operationContext, call.Constructor, call.Syntax.GetLocation ()); + CheckMethodOrCtorCall (operationContext, call.Constructor); }, OperationKind.ObjectCreation); context.RegisterOperationAction (operationContext => { var propAccess = (IPropertyReferenceOperation) operationContext.Operation; var prop = propAccess.Property; var usageInfo = propAccess.GetValueUsageInfo (prop); - if (usageInfo.HasFlag (ValueUsageInfo.Read) && prop.GetMethod != null) { - CheckMethodOrCtorCall ( - operationContext, - prop.GetMethod, - propAccess.Syntax.GetLocation ()); - } - if (usageInfo.HasFlag (ValueUsageInfo.Write) && prop.SetMethod != null) { - CheckMethodOrCtorCall ( - operationContext, - prop.SetMethod, - propAccess.Syntax.GetLocation ()); - } + if (usageInfo.HasFlag (ValueUsageInfo.Read) && prop.GetMethod != null) + CheckMethodOrCtorCall (operationContext, prop.GetMethod); + + if (usageInfo.HasFlag (ValueUsageInfo.Write) && prop.SetMethod != null) + CheckMethodOrCtorCall (operationContext, prop.SetMethod); }, OperationKind.PropertyReference); - void CheckMethodOrCtorCall ( + static void CheckMethodOrCtorCall ( OperationAnalysisContext operationContext, - IMethodSymbol method, - Location location) + IMethodSymbol method) { - AttributeData? requiresUnreferencedCode; // If parent method contains RequiresUnreferencedCodeAttribute then we shouldn't report diagnostics for this method if (operationContext.ContainingSymbol is IMethodSymbol && - TryGetRequiresUnreferencedCodeAttribute (operationContext.ContainingSymbol.GetAttributes (), out requiresUnreferencedCode)) + operationContext.ContainingSymbol.HasAttribute (RequiresUnreferencedCodeAttribute)) + return; + + if (!method.HasAttribute (RequiresUnreferencedCodeAttribute)) return; - if (TryGetRequiresUnreferencedCodeAttribute (method.GetAttributes (), out requiresUnreferencedCode)) { + + if (method.TryGetAttributeWithMessageOnCtor (FullyQualifiedRequiresUnreferencedCodeAttribute, out AttributeData? requiresUnreferencedCode)) { operationContext.ReportDiagnostic (Diagnostic.Create ( - s_rule, - location, + s_requiresUnreferencedCodeRule, + operationContext.Operation.Syntax.GetLocation (), method.OriginalDefinition.ToString (), (string) requiresUnreferencedCode!.ConstructorArguments[0].Value!, requiresUnreferencedCode!.NamedArguments.FirstOrDefault (na => na.Key == "Url").Value.Value?.ToString ())); @@ -93,44 +90,5 @@ void CheckMethodOrCtorCall ( } }); } - - /// - /// Returns true if has the same name as - /// - internal static bool IsNamedType (INamedTypeSymbol type, string typeName) - { - var roSpan = typeName.AsSpan (); - INamespaceOrTypeSymbol? currentType = type; - while (roSpan.Length > 0) { - var dot = roSpan.LastIndexOf ('.'); - var currentName = dot < 0 ? roSpan : roSpan.Slice (dot + 1); - if (currentType is null || - !currentName.Equals (currentType.Name.AsSpan (), StringComparison.Ordinal)) { - return false; - } - currentType = (INamespaceOrTypeSymbol?) currentType.ContainingType ?? currentType.ContainingNamespace; - roSpan = roSpan.Slice (0, dot > 0 ? dot : 0); - } - - return true; - } - - /// - /// Returns a RequiresUnreferencedCodeAttribute if found - /// - static bool TryGetRequiresUnreferencedCodeAttribute (ImmutableArray attributes, out AttributeData? requiresUnreferencedCode) - { - requiresUnreferencedCode = null; - foreach (var attr in attributes) { - if (attr.AttributeClass is { } attrClass && - IsNamedType (attrClass, "System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute") && - attr.ConstructorArguments.Length == 1 && - attr.ConstructorArguments[0] is { Type: { SpecialType: SpecialType.System_String } } ctorArg) { - requiresUnreferencedCode = attr; - return true; - } - } - return false; - } } } diff --git a/src/ILLink.RoslynAnalyzer/Resources.resx b/src/ILLink.RoslynAnalyzer/Resources.resx index 202514e6dcc2..86ac84a05afd 100644 --- a/src/ILLink.RoslynAnalyzer/Resources.resx +++ b/src/ILLink.RoslynAnalyzer/Resources.resx @@ -135,4 +135,10 @@ '{0}' will throw for assemblies embedded in a single-file app + + + + + + \ No newline at end of file diff --git a/src/ILLink.RoslynAnalyzer/SingleFileAnalyzer.cs b/src/ILLink.RoslynAnalyzer/SingleFileAnalyzer.cs index 536cd82f266c..15f17caf3cac 100644 --- a/src/ILLink.RoslynAnalyzer/SingleFileAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/SingleFileAnalyzer.cs @@ -20,7 +20,7 @@ public sealed class AvoidAssemblyLocationInSingleFile : DiagnosticAnalyzer public const string IL3000 = nameof (IL3000); public const string IL3001 = nameof (IL3001); - private static readonly DiagnosticDescriptor LocationRule = new DiagnosticDescriptor ( + static readonly DiagnosticDescriptor s_locationRule = new DiagnosticDescriptor ( IL3000, new LocalizableResourceString (nameof (Resources.AvoidAssemblyLocationInSingleFileTitle), Resources.ResourceManager, typeof (Resources)), @@ -30,7 +30,7 @@ public sealed class AvoidAssemblyLocationInSingleFile : DiagnosticAnalyzer DiagnosticSeverity.Warning, isEnabledByDefault: true); - private static readonly DiagnosticDescriptor GetFilesRule = new DiagnosticDescriptor ( + static readonly DiagnosticDescriptor s_getFilesRule = new DiagnosticDescriptor ( IL3001, new LocalizableResourceString (nameof (Resources.AvoidAssemblyGetFilesInSingleFileTitle), Resources.ResourceManager, typeof (Resources)), @@ -40,7 +40,7 @@ public sealed class AvoidAssemblyLocationInSingleFile : DiagnosticAnalyzer DiagnosticSeverity.Warning, isEnabledByDefault: true); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (LocationRule, GetFilesRule); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_locationRule, s_getFilesRule); public override void Initialize (AnalysisContext context) { @@ -88,7 +88,7 @@ public override void Initialize (AnalysisContext context) return; } - operationContext.ReportDiagnostic (Diagnostic.Create (LocationRule, access.Syntax.GetLocation (), property)); + operationContext.ReportDiagnostic (Diagnostic.Create (s_locationRule, access.Syntax.GetLocation (), property)); }, OperationKind.PropertyReference); context.RegisterOperationAction (operationContext => { @@ -98,7 +98,7 @@ public override void Initialize (AnalysisContext context) return; } - operationContext.ReportDiagnostic (Diagnostic.Create (GetFilesRule, invocation.Syntax.GetLocation (), targetMethod)); + operationContext.ReportDiagnostic (Diagnostic.Create (s_getFilesRule, invocation.Syntax.GetLocation (), targetMethod)); }, OperationKind.Invocation); return; diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs new file mode 100644 index 000000000000..466f81db88be --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs @@ -0,0 +1,152 @@ +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Xunit; +using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier< + ILLink.RoslynAnalyzer.RequiresAssemblyFilesAnalyzer>; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public class RequiresAssemblyFilesAnalyzerTests + { + static Task VerifyRequiresAssemblyFilesAnalyzer (string source, params DiagnosticResult[] expected) + { + // TODO: Remove this once we have the new attribute in the runtime. + source = @"namespace System.Diagnostics.CodeAnalysis +{ +#nullable enable + [AttributeUsage(AttributeTargets.Constructor | + AttributeTargets.Event | + AttributeTargets.Method | + AttributeTargets.Property, + Inherited = false, + AllowMultiple = false)] + public sealed class RequiresAssemblyFilesAttribute : Attribute + { + public RequiresAssemblyFilesAttribute() { } + public string? Message { get; set; } + public string? Url { get; set; } + } +}" + Environment.NewLine + source; + return VerifyCS.VerifyAnalyzerAsync (source, + TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.PublishSingleFile), + expected); + } + + [Fact] + public Task SimpleDiagnosticOnEvent () + { + var TestRequiresAssemblyFieldsOnEvent = @" +class C +{ + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles] + event System.EventHandler? E; + + void M() + { + var handler = E; + } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFieldsOnEvent, + VerifyCS.Diagnostic ().WithSpan (25, 17, 25, 18).WithArguments ("C.E")); + } + + [Fact] + public Task SimpleDiagnosticOnMethod () + { + var TestRequiresAssemblyFilesOnMethod = @" +class C +{ + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles] + void M1() + { + } + + void M2() + { + M1(); + } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesOnMethod, + VerifyCS.Diagnostic ().WithSpan (27, 3, 27, 7).WithArguments ("C.M2()")); + } + + [Fact] + public Task SimpleDiagnosticOnProperty () + { + var TestRequiresAssemblyFilesOnProperty = @" +class C +{ + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles] + bool P { get; set; } + + void M() + { + P = false; + bool b = P; + } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesOnProperty, + VerifyCS.Diagnostic ().WithSpan (25, 3, 25, 4).WithArguments ("C.P"), + VerifyCS.Diagnostic ().WithSpan (26, 12, 26, 13).WithArguments ("C.P")); + } + + [Fact] + public Task RequiresAssemblyFilesWithMessageAndUrl () + { + var TestRequiresAssemblyFilesWithMessageAndUrl = @" +class C +{ + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles (Message = ""Message from attribute"", Url = ""https://helpurl"")] + void M1() + { + } + + void M2() + { + M1(); + } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesWithMessageAndUrl, + VerifyCS.Diagnostic ().WithSpan (27, 3, 27, 7).WithArguments ("C.M2()", "Message from attribute", "https://helpurl")); + } + + [Fact] + public Task NoDiagnosticIfMethodNotCalled () + { + var TestNoDiagnosticIfMethodNotCalled = @" +class C +{ + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles] + void M() { } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestNoDiagnosticIfMethodNotCalled); + } + + [Fact] + public Task NoDiagnosticIsProducedIfCallerIsAnnotated () + { + var TestNoDiagnosticIsProducedIfCallerIsAnnotated = @" +class C +{ + void M1() + { + M2(); + } + + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles (Message = ""Warn from M2"")] + void M2() + { + M3(); + } + + [System.Diagnostics.CodeAnalysis.RequiresAssemblyFiles (Message = ""Warn from M3"")] + void M3() + { + } +}"; + return VerifyRequiresAssemblyFilesAnalyzer (TestNoDiagnosticIsProducedIfCallerIsAnnotated, + VerifyCS.Diagnostic ().WithSpan (22, 3, 22, 7).WithArguments ("C.M2()", "Warn from M2")); + } + } +} diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index 81899e8906d0..25050d50721a 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -32,7 +32,6 @@ class C int M2() => M1(); }"; return VerifyRequiresUnreferencedCodeAnalyzer (TestRequiresWithMessageOnlyOnMethod, - // (8,17): warning IL2026: Calling 'System.Int32 C::M1()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. message. VerifyCS.Diagnostic ().WithSpan (8, 17, 8, 21).WithArguments ("C.M1()", "message", "")); } @@ -54,7 +53,6 @@ static void RequiresWithMessageAndUrl () } }"; return VerifyRequiresUnreferencedCodeAnalyzer (MessageAndUrlOnMethod, - // (8,3): warning IL2026: Calling 'C.RequiresWithMessageAndUrl()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --RequiresWithMessageAndUrl--. VerifyCS.Diagnostic ().WithSpan (8, 3, 8, 31).WithArguments ("C.RequiresWithMessageAndUrl()", "Message for --RequiresWithMessageAndUrl--", "https://helpurl") ); } @@ -78,7 +76,6 @@ static int PropertyRequires { } }"; return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,7): warning IL2026: Calling 'C.PropertyRequires.get' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --getter PropertyRequires--. VerifyCS.Diagnostic ().WithSpan (8, 7, 8, 23).WithArguments ("C.PropertyRequires.get", "Message for --getter PropertyRequires--", "") ); } @@ -102,7 +99,6 @@ static int PropertyRequires { } }"; return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,3): warning IL2026: Calling 'C.PropertyRequires.set' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --setter PropertyRequires--. VerifyCS.Diagnostic ().WithSpan (8, 3, 8, 19).WithArguments ("C.PropertyRequires.set", "Message for --setter PropertyRequires--", "") ); } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index c62c2d762004..458d0b34635b 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Mono.Linker.Tests.Cases.Expectations.Assertions; using Xunit; namespace ILLink.RoslynAnalyzer.Tests