diff options
author | Andy Gocke <angocke@microsoft.com> | 2021-11-18 09:01:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-18 09:01:20 +0300 |
commit | fba858e92cc8ace3527f76e87fd6f7530bae1783 (patch) | |
tree | ce1145cc87612b6a047b444473e415fb2e684dc8 /test | |
parent | 8e8c6c75ac6be2cef115941fc0b38d15a21f0109 (diff) |
Cleanup analyzer testing (#2380)
This implementation doesn't skip members without attributes, so it found some
bugs as well.
Diffstat (limited to 'test')
6 files changed, 169 insertions, 169 deletions
diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs deleted file mode 100644 index 0f35b908a..000000000 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace ILLink.RoslynAnalyzer.Tests -{ - public class TestCase - { - public readonly MemberDeclarationSyntax MemberSyntax; - - private readonly IEnumerable<AttributeSyntax> Attributes; - - public string? Name { get; set; } - - public TestCase (MemberDeclarationSyntax memberSyntax, IEnumerable<AttributeSyntax> attributes) - { - MemberSyntax = memberSyntax; - Attributes = attributes; - } - - public void Run ((CompilationWithAnalyzers, SemanticModel) compAndModel) - { - var testSyntaxTree = MemberSyntax.SyntaxTree; - var testDependenciesSource = GetTestDependencies (testSyntaxTree) - .Select (testDependency => CSharpSyntaxTree.ParseText (File.ReadAllText (testDependency))); - - var test = new TestChecker (MemberSyntax, compAndModel); - test.ValidateAttributes (Attributes); - } - - public static IEnumerable<string> GetTestDependencies (SyntaxTree testSyntaxTree) - { - LinkerTestBase.GetDirectoryPaths (out var rootSourceDir, out _); - foreach (var attribute in testSyntaxTree.GetRoot ().DescendantNodes ().OfType<AttributeSyntax> ()) { - if (attribute.Name.ToString () != "SetupCompileBefore") - continue; - - var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType<NamespaceDeclarationSyntax> ().Single ().Name.ToString (); - var testSuiteName = testNamespace.Substring (testNamespace.LastIndexOf ('.') + 1); - var args = LinkerTestBase.GetAttributeArguments (attribute); - foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType<LiteralExpressionSyntax> ()) - yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); - } - } - } -} diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 44881437d..3cae7cdb7 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -50,44 +50,29 @@ namespace ILLink.RoslynAnalyzer.Tests SourceText.From (File.OpenRead (testPath), Encoding.UTF8), path: testPath); - var testDependenciesSource = TestCase.GetTestDependencies (tree) + var testDependenciesSource = GetTestDependencies (rootSourceDir, tree) .Select (f => SyntaxFactory.ParseSyntaxTree (SourceText.From (File.OpenRead (f)))); - var comp = await TestCaseCompilation.CreateCompilation ( + var (comp, model) = await TestCaseCompilation.CreateCompilation ( tree, msbuildProperties, additionalSources: testDependenciesSource); - foreach (var testCase in BuildTestCasesForTree (tree)) { - testCase.Run (comp); - } + + var diags = await comp.GetAnalyzerDiagnosticsAsync (); + var testChecker = new TestChecker ((CSharpSyntaxTree) tree, model, diags); + testChecker.Check (); } - /// <summary> - /// Builds a <see cref="TestCase" /> for each member in the tree. - /// </summary> - private static IEnumerable<TestCase> BuildTestCasesForTree (SyntaxTree tree) + private static IEnumerable<string> GetTestDependencies (string rootSourceDir, SyntaxTree testSyntaxTree) { - var root = tree.GetRoot (); - foreach (var node in root.DescendantNodes ()) { - if (node is MemberDeclarationSyntax m) { - var attrs = m.AttributeLists.SelectMany (al => al.Attributes.Where (IsWellKnown)).ToList (); - if (attrs.Count > 0) { - yield return new TestCase (m, attrs); - } - } - } - - static bool IsWellKnown (AttributeSyntax attr) - { - switch (attr.Name.ToString ()) { - // Currently, the analyzer's test infra only understands these attributes when placed on methods. - case "ExpectedWarning": - case "LogContains": - case "LogDoesNotContain": - case "UnrecognizedReflectionAccessPattern": - return true; - } - - return false; + foreach (var attribute in testSyntaxTree.GetRoot ().DescendantNodes ().OfType<AttributeSyntax> ()) { + if (attribute.Name.ToString () != "SetupCompileBefore") + continue; + + var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType<NamespaceDeclarationSyntax> ().Single ().Name.ToString (); + var testSuiteName = testNamespace.Substring (testNamespace.LastIndexOf ('.') + 1); + var args = LinkerTestBase.GetAttributeArguments (attribute); + foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType<LiteralExpressionSyntax> ()) + yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 5da895fce..e7af1b930 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; @@ -16,51 +17,146 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests { - internal class TestChecker + internal class TestChecker : CSharpSyntaxWalker { - private readonly CompilationWithAnalyzers Compilation; + private readonly CSharpSyntaxTree _tree; + private readonly SemanticModel _semanticModel; + private readonly IReadOnlyList<Diagnostic> _diagnostics; + private readonly List<Diagnostic> _unmatched; + private readonly List<(AttributeSyntax Attribute, string Message)> _missing; + + public TestChecker ( + CSharpSyntaxTree tree, + SemanticModel semanticModel, + ImmutableArray<Diagnostic> diagnostics) + { + _tree = tree; + _semanticModel = semanticModel; + _diagnostics = diagnostics + // Filter down to diagnostics which originate from this tree + .Where (d => d.Location.SourceTree == tree).ToList (); + + // Filled in later + _unmatched = new List<Diagnostic> (); + _missing = new List<(AttributeSyntax Attribute, string Message)> (); + } + + public void Check () + { + _unmatched.Clear (); + _unmatched.AddRange (_diagnostics); + _missing.Clear (); + + Visit (_tree.GetRoot ()); + + string message = ""; + if (_missing.Any ()) { + var missingLines = string.Join ( + Environment.NewLine, + _missing.Select (md => $"({md.Attribute.GetLocation ().GetLineSpan ()}) {md.Message}")); + message += $@"Expected warnings were not generated:{Environment.NewLine}{missingLines}{Environment.NewLine}"; + } + if (_unmatched.Any ()) { - private readonly SemanticModel SemanticModel; + message += $"Unexpected warnings were generated:{Environment.NewLine}{string.Join (Environment.NewLine, _unmatched)}"; + } - private readonly List<Diagnostic> DiagnosticMessages; + if (message.Length > 0) { + Assert.True (false, message); + } + } - private readonly SyntaxNode MemberSyntax; + public override void VisitClassDeclaration (ClassDeclarationSyntax node) + { + base.VisitClassDeclaration (node); + CheckMember (node); + } - public TestChecker (MemberDeclarationSyntax memberSyntax, (CompilationWithAnalyzers Compilation, SemanticModel SemanticModel) compilationResult) + public override void VisitInterfaceDeclaration (InterfaceDeclarationSyntax node) { - Compilation = compilationResult.Compilation; - SemanticModel = compilationResult.SemanticModel; - DiagnosticMessages = Compilation.GetAnalyzerDiagnosticsAsync ().Result - .Where (d => { - // Filter down to diagnostics which originate from this member. - - // Test data may include diagnostics originating from a testcase or testcase dependencies. - if (memberSyntax.SyntaxTree != d.Location.SourceTree) - return false; + base.VisitInterfaceDeclaration (node); + CheckMember (node); + } + + public override void VisitMethodDeclaration (MethodDeclarationSyntax node) + { + base.VisitMethodDeclaration (node); + CheckMember (node); + } + + public override void VisitPropertyDeclaration (PropertyDeclarationSyntax node) + { + base.VisitPropertyDeclaration (node); + CheckMember (node); + } + + public override void VisitFieldDeclaration (FieldDeclarationSyntax node) + { + base.VisitFieldDeclaration (node); + CheckMember (node); + } + + private void CheckMember (MemberDeclarationSyntax node) + { + ValidateDiagnostics (node, node.AttributeLists); + } - // Filter down to diagnostics which originate from this member - if (memberSyntax is ClassDeclarationSyntax classSyntax) { - if (SemanticModel.GetDeclaredSymbol (classSyntax) is not ITypeSymbol typeSymbol) - throw new NotImplementedException ("Unable to get type symbol for class declaration syntax."); + public override void VisitLocalFunctionStatement (LocalFunctionStatementSyntax node) + { + base.VisitLocalFunctionStatement (node); + ValidateDiagnostics (node, node.AttributeLists); + } + + public override void VisitAccessorDeclaration (AccessorDeclarationSyntax node) + { + base.VisitAccessorDeclaration (node); + ValidateDiagnostics (node, node.AttributeLists); + } + + private void ValidateDiagnostics (CSharpSyntaxNode memberSyntax, SyntaxList<AttributeListSyntax> attrLists) + { + var memberDiagnostics = _unmatched.Where (d => { + // Filter down to diagnostics which originate from this member + if (memberSyntax is ClassDeclarationSyntax classSyntax) { + if (_semanticModel.GetDeclaredSymbol (classSyntax) is not ITypeSymbol typeSymbol) + throw new NotImplementedException ("Unable to get type symbol for class declaration syntax."); + + if (typeSymbol.Locations.Length != 1) + throw new NotImplementedException ("Type defined in multiple source locations."); + + // For classes, only consider diagnostics which originate from the type (not its members). + // Approximate this by getting the location from the start of the type's syntax (which includes + // attributes declared on the type) to the opening brace. + var classSpan = TextSpan.FromBounds ( + classSyntax.GetLocation ().SourceSpan.Start, + classSyntax.OpenBraceToken.GetLocation ().SourceSpan.Start + ); + + return d.Location.SourceSpan.IntersectsWith (classSpan); + } + + return d.Location.SourceSpan.IntersectsWith (memberSyntax.Span); + }).ToList (); - if (typeSymbol.Locations.Length != 1) - throw new NotImplementedException ("Type defined in multiple source locations."); + foreach (var attrList in attrLists) { + foreach (var attribute in attrList.Attributes) { + if (attribute.Name.ToString () == "LogDoesNotContain") + ValidateLogDoesNotContainAttribute (attribute, memberDiagnostics); - // For classes, only consider diagnostics which originate from the type (not its members). - // Approximate this by getting the location from the start of the type's syntax (which includes - // attributes declared on the type) to the opening brace. - var classSpan = TextSpan.FromBounds ( - classSyntax.GetLocation ().SourceSpan.Start, - classSyntax.OpenBraceToken.GetLocation ().SourceSpan.Start - ); + if (!IsExpectedDiagnostic (attribute)) + continue; - return d.Location.SourceSpan.IntersectsWith (classSpan); + if (!TryValidateExpectedDiagnostic (attribute, memberDiagnostics, out int? matchIndexResult, out string? missingDiagnosticMessage)) { + _missing.Add ((attribute, missingDiagnosticMessage)); + continue; } - return d.Location.SourceSpan.IntersectsWith (memberSyntax.Span); - }) - .ToList (); - MemberSyntax = memberSyntax; + int matchIndex = matchIndexResult.GetValueOrDefault (); + var diagnostic = memberDiagnostics[matchIndex]; + memberDiagnostics.RemoveAt (matchIndex); + Assert.True (_unmatched.Remove (diagnostic)); + } + } } bool IsExpectedDiagnostic (AttributeSyntax attribute) @@ -118,38 +214,6 @@ namespace ILLink.RoslynAnalyzer.Tests } } - public void ValidateAttributes (IEnumerable<AttributeSyntax> attributes) - { - var unmatchedDiagnostics = DiagnosticMessages.ToList (); - - var missingDiagnostics = new List<(AttributeSyntax Attribute, string Message)> (); - foreach (var attribute in attributes) { - if (attribute.Name.ToString () == "LogDoesNotContain") - ValidateLogDoesNotContainAttribute (attribute, DiagnosticMessages); - - if (!IsExpectedDiagnostic (attribute)) - continue; - - if (!TryValidateExpectedDiagnostic (attribute, unmatchedDiagnostics, out int? matchIndex, out string? missingDiagnosticMessage)) { - missingDiagnostics.Add ((attribute, missingDiagnosticMessage)); - continue; - } - - unmatchedDiagnostics.RemoveAt (matchIndex.Value); - } - - var missingDiagnosticsMessage = missingDiagnostics.Any () - ? $"Missing diagnostics:{Environment.NewLine}{string.Join (Environment.NewLine, missingDiagnostics.Select (md => md.Message))}" - : String.Empty; - - var unmatchedDiagnosticsMessage = unmatchedDiagnostics.Any () - ? $"Found unmatched diagnostics:{Environment.NewLine}{string.Join (Environment.NewLine, unmatchedDiagnostics)}" - : String.Empty; - - Assert.True (!missingDiagnostics.Any (), $"{missingDiagnosticsMessage}{Environment.NewLine}{unmatchedDiagnosticsMessage}"); - Assert.True (!unmatchedDiagnostics.Any (), unmatchedDiagnosticsMessage); - } - private bool TryValidateExpectedWarningAttribute (AttributeSyntax attribute, List<Diagnostic> diagnostics, out int? matchIndex, out string? missingDiagnosticMessage) { missingDiagnosticMessage = null; @@ -162,7 +226,7 @@ namespace ILLink.RoslynAnalyzer.Tests List<string> expectedMessages = args .Where (arg => arg.Key.StartsWith ("#") && arg.Key != "#0") - .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, SemanticModel)) + .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, _semanticModel)) .ToList (); for (int i = 0; i < diagnostics.Count; i++) { @@ -218,15 +282,15 @@ namespace ILLink.RoslynAnalyzer.Tests } } - missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{(string.Join (Environment.NewLine, DiagnosticMessages))}"; + missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{(string.Join (Environment.NewLine, _diagnostics))}"; return false; } - private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, List<Diagnostic> diagnosticMessages) + private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnosticMessages) { var arg = Assert.Single (LinkerTestBase.GetAttributeArguments (attribute)); var text = LinkerTestBase.GetStringFromExpression (arg.Value); - foreach (var diagnostic in DiagnosticMessages) + foreach (var diagnostic in _diagnostics) Assert.DoesNotContain (text, diagnostic.GetMessage ()); } @@ -237,18 +301,18 @@ namespace ILLink.RoslynAnalyzer.Tests var args = LinkerTestBase.GetAttributeArguments (attribute); MemberDeclarationSyntax sourceMember = attribute.Ancestors ().OfType<MemberDeclarationSyntax> ().First (); - if (SemanticModel.GetDeclaredSymbol (sourceMember) is not ISymbol memberSymbol) + if (_semanticModel.GetDeclaredSymbol (sourceMember) is not ISymbol memberSymbol) return false; string sourceMemberName = memberSymbol!.GetDisplayName (); - string expectedReflectionMemberMethodType = LinkerTestBase.GetStringFromExpression (args["#0"], SemanticModel); - string expectedReflectionMemberMethodName = LinkerTestBase.GetStringFromExpression (args["#1"], SemanticModel); + string expectedReflectionMemberMethodType = LinkerTestBase.GetStringFromExpression (args["#0"], _semanticModel); + string expectedReflectionMemberMethodName = LinkerTestBase.GetStringFromExpression (args["#1"], _semanticModel); var reflectionMethodParameters = new List<string> (); if (args.TryGetValue ("#2", out var reflectionMethodParametersExpr) || args.TryGetValue ("reflectionMethodParameters", out reflectionMethodParametersExpr)) { if (reflectionMethodParametersExpr is ArrayCreationExpressionSyntax arrayReflectionMethodParametersExpr) { foreach (var rmp in arrayReflectionMethodParametersExpr.Initializer!.Expressions) - reflectionMethodParameters.Add (LinkerTestBase.GetStringFromExpression (rmp, SemanticModel)); + reflectionMethodParameters.Add (LinkerTestBase.GetStringFromExpression (rmp, _semanticModel)); } } @@ -256,7 +320,7 @@ namespace ILLink.RoslynAnalyzer.Tests if (args.TryGetValue ("#3", out var messageExpr) || args.TryGetValue ("message", out messageExpr)) { if (messageExpr is ArrayCreationExpressionSyntax arrayMessageExpr) { foreach (var m in arrayMessageExpr.Initializer!.Expressions) - expectedStringsInMessage.Add (LinkerTestBase.GetStringFromExpression (m, SemanticModel)); + expectedStringsInMessage.Add (LinkerTestBase.GetStringFromExpression (m, _semanticModel)); } } diff --git a/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Warnings/ComPInvokeWarning.cs b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Warnings/ComPInvokeWarning.cs index d64847908..c652f26fd 100644 --- a/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Warnings/ComPInvokeWarning.cs +++ b/test/Mono.Linker.Tests.Cases/Interop/PInvoke/Warnings/ComPInvokeWarning.cs @@ -156,6 +156,8 @@ namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Warnings static extern IFoo CanSuppressWarningOnReturnType (); [RequiresUnreferencedCode ("test")] + // Bug https://github.com/dotnet/linker/issues/2378 + [ExpectedWarning ("IL2050", ProducedBy = ProducedBy.Analyzer)] static void Call_CanSuppressWithRequiresUnreferencedCode () { CanSuppressWithRequiresUnreferencedCode (null); @@ -165,6 +167,8 @@ namespace Mono.Linker.Tests.Cases.Interop.PInvoke.Warnings static extern void CanSuppressWithRequiresUnreferencedCode (IFoo foo); [RequiresUnreferencedCode ("test")] + // Bug https://github.com/dotnet/linker/issues/2378 + [ExpectedWarning ("IL2050", ProducedBy = ProducedBy.Analyzer)] static void Call_CanSuppressPInvokeWithRequiresUnreferencedCode () { CanSuppressPInvokeWithRequiresUnreferencedCode (null); diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs index 40814d2e6..12f0004e0 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs @@ -1415,6 +1415,8 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [RequiresUnreferencedCode ("RUC")] class DerivedWithRequiresOnType : BaseWithoutRequiresOnType { + // Bug https://github.com/dotnet/linker/issues/2379 + [ExpectedWarning ("IL2046", ProducedBy = ProducedBy.Analyzer)] public override void Method () { } } @@ -1450,6 +1452,8 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability return 1; } + // Bug https://github.com/dotnet/linker/issues/2379 + [ExpectedWarning ("IL2046", ProducedBy = ProducedBy.Analyzer)] public int Method (int a) { return a; diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs index e5f176d87..35340706f 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs @@ -639,8 +639,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction (); - [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer)] void LocalFunction () => typeof (RequiresInCompilerGeneratedCode) .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic) .Invoke (null, new object[] { }); @@ -680,8 +679,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction (); - [ExpectedWarning ("IL2026")] - [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer)] void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); } @@ -691,7 +689,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction (); - [ExpectedWarning ("IL2077")] + [ExpectedWarning ("IL2077", ProducedBy = ProducedBy.Trimmer)] void LocalFunction () => unknownType.RequiresNonPublicMethods (); } @@ -701,7 +699,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction (); - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = ProducedBy.Trimmer)] void LocalFunction () => MethodWithGenericWhichRequiresMethods<TUnknown> (); } @@ -711,7 +709,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction (); - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = ProducedBy.Trimmer)] void LocalFunction () => new TypeWithGenericWhichRequiresNonPublicFields<TUnknown> (); } @@ -733,7 +731,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { LocalFunction<TUnknown> (); - [ExpectedWarning ("IL2087")] + [ExpectedWarning ("IL2087", ProducedBy = ProducedBy.Trimmer)] void LocalFunction<TSecond> () { typeof (TUnknown).RequiresPublicMethods (); @@ -1249,6 +1247,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability return CreateAsync (); [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles] static async IAsyncEnumerable<TValue> CreateAsync () { await MethodAsync (); |