Skip to content

Commit a4d66c5

Browse files
sbomerliveans
authored andcommitted
Fix analyzer assert and add dynamic object tests (dotnet#94058)
Fixes the assert from dotnet#94016. dotnet#94057 tracks adding full support for this in the analyzer. We had some existing tests that only covered IDynamicInvocationOperation. Those have been moved to a shared testcase (shared by ILLink/NativeAot), and some additional testcases have been added that include coverage for IDynamicMemberReference, which was causing the assert. This includes the same fix for IDynamicIndexerAccessOperation.
1 parent d5033fb commit a4d66c5

File tree

4 files changed

+191
-86
lines changed

4 files changed

+191
-86
lines changed

src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,19 +272,24 @@ TValue ProcessSingleTargetAssignment (IOperation targetOperation, IAssignmentOpe
272272
Debug.Assert (operation.Target is not IFlowCaptureReferenceOperation);
273273
break;
274274
case IInvalidOperation:
275-
// This can happen for a field assignment in an attribute instance.
276-
// TODO: validate against the field attributes.
275+
// This can happen for a field assignment in an attribute instance.
276+
// TODO: validate against the field attributes.
277277
case IInstanceReferenceOperation:
278-
// Assignment to 'this' is not tracked currently.
279-
// Not relevant for trimming dataflow.
278+
// Assignment to 'this' is not tracked currently.
279+
// Not relevant for trimming dataflow.
280280
case IInvocationOperation:
281-
// This can happen for an assignment to a ref return. Skip for now.
282-
// The analyzer doesn't handle refs yet. This should be fixed once the analyzer
283-
// also produces warnings for ref params/locals/returns.
284-
// https://github.com/dotnet/linker/issues/2632
285-
// https://github.com/dotnet/linker/issues/2158
281+
// This can happen for an assignment to a ref return. Skip for now.
282+
// The analyzer doesn't handle refs yet. This should be fixed once the analyzer
283+
// also produces warnings for ref params/locals/returns.
284+
// https://github.com/dotnet/linker/issues/2632
285+
// https://github.com/dotnet/linker/issues/2158
286286
Visit (targetOperation, state);
287287
break;
288+
case IDynamicMemberReferenceOperation:
289+
case IDynamicIndexerAccessOperation:
290+
// Not yet implemented in analyzer:
291+
// https://github.com/dotnet/runtime/issues/94057
292+
break;
288293

289294
// Keep these cases in sync with those in CapturedReferenceValue, for any that
290295
// can show up in a flow capture reference (for example, where the right-hand side

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ public Task DynamicDependencyDataflow ()
124124
return RunTest (nameof (DynamicDependencyDataflow));
125125
}
126126

127+
[Fact]
128+
public Task DynamicObjects ()
129+
{
130+
return RunTest ();
131+
}
132+
127133
[Fact]
128134
public Task EmptyArrayIntrinsicsDataFlow ()
129135
{

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -372,83 +372,6 @@ private int M2 {
372372
return VerifyRequiresUnreferencedCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
373373
}
374374

375-
[Fact]
376-
public Task InvocationOnDynamicType ()
377-
{
378-
var source = $$"""
379-
using System;
380-
class C
381-
{
382-
static void M0 ()
383-
{
384-
dynamic dynamicField = "Some string";
385-
Console.WriteLine (dynamicField);
386-
}
387-
388-
static void M1 ()
389-
{
390-
MethodWithDynamicArgDoNothing (0);
391-
MethodWithDynamicArgDoNothing ("Some string");
392-
MethodWithDynamicArg(-1);
393-
}
394-
395-
static void MethodWithDynamicArgDoNothing (dynamic arg)
396-
{
397-
}
398-
399-
static void MethodWithDynamicArg (dynamic arg)
400-
{
401-
arg.MethodWithDynamicArg (arg);
402-
}
403-
}
404-
""";
405-
406-
return VerifyRequiresUnreferencedCodeAnalyzer (source,
407-
// (8,3): warning IL2026: Invoking members on dynamic types is not trimming safe. Types or members might have been removed by the trimmer.
408-
VerifyCS.Diagnostic (dynamicInvocationDiagnosticDescriptor).WithSpan (7, 3, 7, 35),
409-
// (24,3): warning IL2026: Invoking members on dynamic types is not trimming safe. Types or members might have been removed by the trimmer.
410-
VerifyCS.Diagnostic (dynamicInvocationDiagnosticDescriptor).WithSpan (23, 3, 23, 33));
411-
}
412-
413-
[Fact]
414-
public Task DynamicInRequiresUnreferencedCodeClass ()
415-
{
416-
var source = $$"""
417-
using System.Diagnostics.CodeAnalysis;
418-
419-
[RequiresUnreferencedCode("message")]
420-
class ClassWithRequires
421-
{
422-
public static void MethodWithDynamicArg (dynamic arg)
423-
{
424-
arg.DynamicInvocation ();
425-
}
426-
}
427-
""";
428-
429-
return VerifyRequiresUnreferencedCodeAnalyzer (source);
430-
}
431-
432-
[Fact]
433-
public Task InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes ()
434-
{
435-
var source = $$"""
436-
using System;
437-
using System.Diagnostics.CodeAnalysis;
438-
class C
439-
{
440-
[RequiresUnreferencedCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
441-
static void M0 ()
442-
{
443-
dynamic dynamicField = "Some string";
444-
Console.WriteLine (dynamicField);
445-
}
446-
}
447-
""";
448-
449-
return VerifyRequiresUnreferencedCodeAnalyzer (source);
450-
}
451-
452375
[Fact]
453376
public Task TestMakeGenericMethodUsage ()
454377
{
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Runtime.CompilerServices;
7+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
8+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
9+
10+
namespace Mono.Linker.Tests.Cases.DataFlow
11+
{
12+
[SkipKeptItemsValidation]
13+
[ExpectedNoWarnings]
14+
[Reference ("Microsoft.CSharp.dll")]
15+
public class DynamicObjects
16+
{
17+
public static void Main ()
18+
{
19+
InvocationOnDynamicType.Test ();
20+
DynamicMemberReference.Test ();
21+
DynamicIndexerAccess.Test ();
22+
DynamicInRequiresUnreferencedCodeClass.Test ();
23+
InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes.Test ();
24+
}
25+
26+
class InvocationOnDynamicType
27+
{
28+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
29+
[ExpectedWarning ("IL2026", "Invoking members on dynamic types is not trimming-compatible.", ProducedBy = Tool.Analyzer)]
30+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
31+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
32+
static void DynamicArgument ()
33+
{
34+
dynamic dynamicObject = "Some string";
35+
Console.WriteLine (dynamicObject);
36+
}
37+
38+
static void DynamicParameter ()
39+
{
40+
MethodWithDynamicParameterDoNothing (0);
41+
MethodWithDynamicParameterDoNothing ("Some string");
42+
MethodWithDynamicParameter(-1);
43+
}
44+
45+
static void MethodWithDynamicParameterDoNothing (dynamic arg)
46+
{
47+
}
48+
49+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
50+
[ExpectedWarning ("IL2026", "Invoking members on dynamic types is not trimming-compatible.", ProducedBy = Tool.Analyzer)]
51+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
52+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
53+
static void MethodWithDynamicParameter (dynamic arg)
54+
{
55+
arg.MethodWithDynamicParameter (arg);
56+
}
57+
58+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeConstructor", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
59+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
60+
// TODO: analyzer hole!
61+
static void ObjectCreationDynamicArgument ()
62+
{
63+
dynamic dynamicObject = "Some string";
64+
var x = new ClassWithDynamicCtor (dynamicObject);
65+
}
66+
67+
class ClassWithDynamicCtor
68+
{
69+
public ClassWithDynamicCtor (dynamic arg)
70+
{
71+
}
72+
}
73+
74+
public static void Test ()
75+
{
76+
DynamicArgument ();
77+
DynamicParameter ();
78+
ObjectCreationDynamicArgument ();
79+
}
80+
}
81+
82+
class DynamicMemberReference
83+
{
84+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
85+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
86+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
87+
static void Read (dynamic d)
88+
{
89+
var x = d.Member;
90+
}
91+
92+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
93+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
94+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
95+
static void Write (dynamic d)
96+
{
97+
d.Member = 0;
98+
}
99+
100+
public static void Test ()
101+
{
102+
Read (null);
103+
Write (null);
104+
}
105+
}
106+
107+
class DynamicIndexerAccess
108+
{
109+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
110+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetIndex", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
111+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
112+
static void Read (dynamic d)
113+
{
114+
var x = d[0];
115+
}
116+
117+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
118+
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetIndex", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
119+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
120+
static void Write (dynamic d)
121+
{
122+
d[0] = 0;
123+
}
124+
125+
public static void Test ()
126+
{
127+
Read (null);
128+
Write (null);
129+
}
130+
}
131+
132+
class DynamicInRequiresUnreferencedCodeClass
133+
{
134+
[RequiresUnreferencedCode("message")]
135+
class ClassWithRequires
136+
{
137+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
138+
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
139+
public static void MethodWithDynamicArg (dynamic arg)
140+
{
141+
arg.DynamicInvocation ();
142+
}
143+
}
144+
145+
[ExpectedWarning ("IL2026", nameof (ClassWithRequires))]
146+
public static void Test ()
147+
{
148+
ClassWithRequires.MethodWithDynamicArg (null);
149+
}
150+
}
151+
152+
class InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes ()
153+
{
154+
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
155+
[RequiresUnreferencedCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
156+
[RequiresDynamicCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
157+
static void MethodWithRequires ()
158+
{
159+
dynamic dynamicField = "Some string";
160+
Console.WriteLine (dynamicField);
161+
}
162+
163+
[ExpectedWarning ("IL2026", nameof (MethodWithRequires))]
164+
[ExpectedWarning ("IL3050", nameof (MethodWithRequires), ProducedBy = Tool.Analyzer | Tool.NativeAot)]
165+
public static void Test ()
166+
{
167+
MethodWithRequires ();
168+
}
169+
}
170+
}
171+
}

0 commit comments

Comments
 (0)