diff options
author | Andy Gocke <angocke@microsoft.com> | 2022-05-24 08:25:27 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-24 08:25:27 +0300 |
commit | 254361896325fa94b103187e35af99794efa2f57 (patch) | |
tree | 5db92d80f390df03f7eef1be95b80fd33a246f70 /test | |
parent | d794136809e207f9cfe02914af68b308106cc2c3 (diff) |
Track attributes through Roslyn-generated types (#2786)
Type parameters for Roslyn-generated types are all alpha renames, so
there should be a unique original type parameter to map back to, which
can be used to get the original user attributes applied to the type
parameter. This change tries to build a map back from types to
constructor calls, which should map to the original type parameter annotations.
Only handles async and iterator state machines fully right now. Full support for
lambdas and local functions is left as future work.
Diffstat (limited to 'test')
4 files changed, 252 insertions, 8 deletions
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index b581247d7..b92038a6a 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -59,6 +59,12 @@ namespace ILLink.RoslynAnalyzer.Tests } [Fact] + public Task CompilerGeneratedTypes () + { + return RunTest (); + } + + [Fact] public Task ComplexTypeHandling () { return RunTest (); diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 2c49d205c..0e32c51d8 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.RegularExpressions; +using ILLink.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -197,6 +198,15 @@ namespace ILLink.RoslynAnalyzer.Tests // Skip if this warning is not expected to be produced by any of the analyzers that we are currently testing. return GetProducedBy (producedBy).HasFlag (ProducedBy.Analyzer); } + if (args.TryGetValue ("#0", out var id) && + (id as LiteralExpressionSyntax)?.Token.ValueText != DiagnosticId.RequiresUnreferencedCode.AsString () && + args.TryGetValue ("CompilerGeneratedCode", out var compilerGeneratedExpr)) { + // https://github.com/dotnet/linker/issues/2587 + // We currently don't generate any data flow warnings in compiler generated code for the analyzer since + // the compiler-generated code support in the linker is inconsistent. Until the above issue is + // fixed, skip all warnings in compiler generated code + return compilerGeneratedExpr is not LiteralExpressionSyntax { Token: { RawKind: (int) SyntaxKind.TrueKeyword } }; + } return true; default: diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs new file mode 100644 index 000000000..547e899ff --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs @@ -0,0 +1,233 @@ +// 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 System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [ExpectedNoWarnings] + [SkipKeptItemsValidation] + class CompilerGeneratedTypes + { + public static void Main () + { + // Iterators + UseIterator (); + IteratorTypeMismatch (); + LocalIterator (); + IteratorCapture (); + NestedIterators (); + IteratorInsideClosure (); + IteratorInsideClosureMismatch (); + + // Async + Async (); + AsyncCapture (); + AsyncTypeMismatch (); + AsyncInsideClosure (); + AsyncInsideClosureMismatch (); + } + + private static void UseIterator () + { + foreach (var m in BasicIterator<string> ()) { + } + } + + private static IEnumerable<MethodInfo> BasicIterator<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () + { + foreach (var m in typeof (T).GetMethods ()) { + yield return m; + } + } + + private static void IteratorTypeMismatch () + { + _ = Local<string> (); + + [ExpectedWarning ("IL2090", nameof (DynamicallyAccessedMemberTypes.PublicProperties), CompilerGeneratedCode = true)] + static IEnumerable<object> Local<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () + { + foreach (var m in typeof (T).GetMethods ()) { + yield return m; + } + foreach (var p in typeof (T).GetProperties ()) { + yield return p; + } + } + } + + private static void LocalIterator () + { + foreach (var m in Local<string, string> ()) { } + + static IEnumerable<object> Local< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + foreach (var m in typeof (T1).GetMethods ()) { + yield return m; + } + foreach (var p in typeof (T2).GetProperties ()) { + yield return p; + } + } + } + + private static void IteratorCapture () + { + Local1<string> (); + void Local1<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1> () + { + _ = Local2<string> (); + IEnumerable<object> Local2<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + foreach (var m in typeof (T1).GetMethods ()) { + yield return m; + } + foreach (var p in typeof (T2).GetProperties ()) { + yield return p; + } + } + } + } + + private static void NestedIterators () + { + Local1<string> (); + IEnumerable<object> Local1<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1> () + { + foreach (var o in Local2<string> ()) { yield return o; } + IEnumerable<object> Local2<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + foreach (var m in typeof (T1).GetMethods ()) { + yield return m; + } + foreach (var p in typeof (T2).GetProperties ()) { + yield return p; + } + } + } + } + + private static void IteratorInsideClosure () + { + Outer<string> (); + IEnumerable<object> Outer<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1> () + { + int x = 0; + foreach (var o in Inner<string> ()) yield return o; + IEnumerable<object> Inner<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + x++; + foreach (var m in typeof (T1).GetMethods ()) yield return m; + foreach (var p in typeof (T2).GetProperties ()) yield return p; + } + } + } + + private static void IteratorInsideClosureMismatch () + { + Outer<string> (); + + IEnumerable<object> Outer<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T1> () + { + int x = 0; + foreach (var o in Inner<string> ()) yield return o; + + [ExpectedWarning ("IL2090", "T1", "PublicMethods", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2090", "T2", "PublicProperties", CompilerGeneratedCode = true)] + IEnumerable<object> Inner<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T2> () + { + x++; + foreach (var m in typeof (T1).GetMethods ()) yield return m; + foreach (var p in typeof (T2).GetProperties ()) yield return p; + } + } + + } + + private static void Async () + { + Local<string> ().Wait (); + async Task Local<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () + { + await Task.Delay (0); + _ = typeof (T).GetMethods (); + } + } + + private static void AsyncCapture () + { + Local1<string> (); + void Local1<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1> () + { + Local2<string> ().Wait (); + async Task Local2<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + await Task.Delay (0); + _ = typeof (T1).GetMethods (); + await Task.Delay (0); + _ = typeof (T2).GetProperties (); + } + } + } + + [ExpectedWarning ("IL2090", nameof (DynamicallyAccessedMemberTypes.PublicProperties), CompilerGeneratedCode = true)] + private static void AsyncTypeMismatch () + { + _ = Local<string> (); + + static async Task Local<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () + { + await Task.Delay (0); + _ = typeof (T).GetMethods (); + await Task.Delay (0); + _ = typeof (T).GetProperties (); + } + } + + private static void AsyncInsideClosure () + { + Outer<string> (); + void Outer<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T1> () + { + int x = 0; + Inner<string> ().Wait (); + async Task Inner<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T2> () + { + await Task.Delay (0); + x++; + _ = typeof (T1).GetMethods (); + _ = typeof (T2).GetProperties (); + } + } + } + + private static void AsyncInsideClosureMismatch () + { + Outer<string> (); + + void Outer<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] T1> () + { + int x = 0; + Inner<string> ().Wait (); + + [ExpectedWarning ("IL2090", "T1", "PublicMethods", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2090", "T2", "PublicProperties", CompilerGeneratedCode = true)] + async Task Inner<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T2> () + { + await Task.Delay (0); + x++; + _ = typeof (T1).GetMethods (); + _ = typeof (T2).GetProperties (); + } + } + } + } +}
\ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs b/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs index 5d345f1e5..5f418f9bb 100644 --- a/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs +++ b/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs @@ -10,9 +10,8 @@ namespace Mono.Linker.Tests.Cases.Logging [SetupCompileArgument ("/debug:full")] [ExpectedNoWarnings] [ExpectedWarning ("IL2074", FileName = "", SourceLine = 39, SourceColumn = 4)] - [ExpectedWarning ("IL2074", FileName = "", SourceLine = 40, SourceColumn = 4)] - [ExpectedWarning ("IL2091", FileName = "", SourceLine = 51, SourceColumn = 4)] - [ExpectedWarning ("IL2089", FileName = "", SourceLine = 55, SourceColumn = 36)] + [ExpectedWarning ("IL2074", FileName = "", SourceLine = 38, SourceColumn = 4)] + [ExpectedWarning ("IL2089", FileName = "", SourceLine = 50, SourceColumn = 36)] public class SourceLines { public static void Main () @@ -44,11 +43,7 @@ namespace Mono.Linker.Tests.Cases.Logging [ExpectedWarning ("IL2089", nameof (SourceLines) + "." + nameof (type), "TOuterMethod", ProducedBy = ProducedBy.Analyzer)] static IEnumerable<int> GenericMethodIteratorWithRequirement<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TOuterMethod> () { - // Since this is iterator it will turn into a subclass with generic T - // but this T doesn't inherit the DAM annotation. - // So calling the LocationFunction which requires the DAM on T will generate a warning - // but that warning comes from compiler generated code - there's no user code doing that. - LocalFunction (); // IL2091 - The issue with attributes not propagating to the iterator generics + LocalFunction (); yield return 1; // The generator code for LocalFunction inherits the DAM on the T |