Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -272,19 +272,24 @@ TValue ProcessSingleTargetAssignment (IOperation targetOperation, IAssignmentOpe
Debug.Assert (operation.Target is not IFlowCaptureReferenceOperation);
break;
case IInvalidOperation:
// This can happen for a field assignment in an attribute instance.
// TODO: validate against the field attributes.
// This can happen for a field assignment in an attribute instance.
// TODO: validate against the field attributes.
case IInstanceReferenceOperation:
// Assignment to 'this' is not tracked currently.
// Not relevant for trimming dataflow.
// Assignment to 'this' is not tracked currently.
// Not relevant for trimming dataflow.
case IInvocationOperation:
// This can happen for an assignment to a ref return. Skip for now.
// The analyzer doesn't handle refs yet. This should be fixed once the analyzer
// also produces warnings for ref params/locals/returns.
// https://github.com/dotnet/linker/issues/2632
// https://github.com/dotnet/linker/issues/2158
// This can happen for an assignment to a ref return. Skip for now.
// The analyzer doesn't handle refs yet. This should be fixed once the analyzer
// also produces warnings for ref params/locals/returns.
// https://github.com/dotnet/linker/issues/2632
// https://github.com/dotnet/linker/issues/2158
Visit (targetOperation, state);
break;
case IDynamicMemberReferenceOperation:
case IDynamicIndexerAccessOperation:
// Not yet implemented in analyzer:
// https://github.com/dotnet/runtime/issues/94057
break;

// Keep these cases in sync with those in CapturedReferenceValue, for any that
// can show up in a flow capture reference (for example, where the right-hand side
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ public Task DynamicDependencyDataflow ()
return RunTest (nameof (DynamicDependencyDataflow));
}

[Fact]
public Task DynamicObjects ()
{
return RunTest ();
}

[Fact]
public Task EmptyArrayIntrinsicsDataFlow ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,83 +372,6 @@ private int M2 {
return VerifyRequiresUnreferencedCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
}

[Fact]
public Task InvocationOnDynamicType ()
{
var source = $$"""
using System;
class C
{
static void M0 ()
{
dynamic dynamicField = "Some string";
Console.WriteLine (dynamicField);
}

static void M1 ()
{
MethodWithDynamicArgDoNothing (0);
MethodWithDynamicArgDoNothing ("Some string");
MethodWithDynamicArg(-1);
}

static void MethodWithDynamicArgDoNothing (dynamic arg)
{
}

static void MethodWithDynamicArg (dynamic arg)
{
arg.MethodWithDynamicArg (arg);
}
}
""";

return VerifyRequiresUnreferencedCodeAnalyzer (source,
// (8,3): warning IL2026: Invoking members on dynamic types is not trimming safe. Types or members might have been removed by the trimmer.
VerifyCS.Diagnostic (dynamicInvocationDiagnosticDescriptor).WithSpan (7, 3, 7, 35),
// (24,3): warning IL2026: Invoking members on dynamic types is not trimming safe. Types or members might have been removed by the trimmer.
VerifyCS.Diagnostic (dynamicInvocationDiagnosticDescriptor).WithSpan (23, 3, 23, 33));
}

[Fact]
public Task DynamicInRequiresUnreferencedCodeClass ()
{
var source = $$"""
using System.Diagnostics.CodeAnalysis;

[RequiresUnreferencedCode("message")]
class ClassWithRequires
{
public static void MethodWithDynamicArg (dynamic arg)
{
arg.DynamicInvocation ();
}
}
""";

return VerifyRequiresUnreferencedCodeAnalyzer (source);
}

[Fact]
public Task InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes ()
{
var source = $$"""
using System;
using System.Diagnostics.CodeAnalysis;
class C
{
[RequiresUnreferencedCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
static void M0 ()
{
dynamic dynamicField = "Some string";
Console.WriteLine (dynamicField);
}
}
""";

return VerifyRequiresUnreferencedCodeAnalyzer (source);
}

[Fact]
public Task TestMakeGenericMethodUsage ()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// 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.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Metadata;

namespace Mono.Linker.Tests.Cases.DataFlow
{
[SkipKeptItemsValidation]
[ExpectedNoWarnings]
[Reference ("Microsoft.CSharp.dll")]
public class DynamicObjects
{
public static void Main ()
{
InvocationOnDynamicType.Test ();
DynamicMemberReference.Test ();
DynamicIndexerAccess.Test ();
DynamicInRequiresUnreferencedCodeClass.Test ();
InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes.Test ();
}

class InvocationOnDynamicType
{
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Invoking members on dynamic types is not trimming-compatible.", ProducedBy = Tool.Analyzer)]
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void DynamicArgument ()
{
dynamic dynamicObject = "Some string";
Console.WriteLine (dynamicObject);
}

static void DynamicParameter ()
{
MethodWithDynamicParameterDoNothing (0);
MethodWithDynamicParameterDoNothing ("Some string");
MethodWithDynamicParameter(-1);
}

static void MethodWithDynamicParameterDoNothing (dynamic arg)
{
}

// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Invoking members on dynamic types is not trimming-compatible.", ProducedBy = Tool.Analyzer)]
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void MethodWithDynamicParameter (dynamic arg)
{
arg.MethodWithDynamicParameter (arg);
}

[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.InvokeConstructor", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
// TODO: analyzer hole!
static void ObjectCreationDynamicArgument ()
{
dynamic dynamicObject = "Some string";
var x = new ClassWithDynamicCtor (dynamicObject);
}

class ClassWithDynamicCtor
{
public ClassWithDynamicCtor (dynamic arg)
{
}
}

public static void Test ()
{
DynamicArgument ();
DynamicParameter ();
ObjectCreationDynamicArgument ();
}
}

class DynamicMemberReference
{
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void Read (dynamic d)
{
var x = d.Member;
}

// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetMember", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void Write (dynamic d)
{
d.Member = 0;
}

public static void Test ()
{
Read (null);
Write (null);
}
}

class DynamicIndexerAccess
{
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.GetIndex", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void Read (dynamic d)
{
var x = d[0];
}

// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL2026", "Microsoft.CSharp.RuntimeBinder.Binder.SetIndex", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
static void Write (dynamic d)
{
d[0] = 0;
}

public static void Test ()
{
Read (null);
Write (null);
}
}

class DynamicInRequiresUnreferencedCodeClass
{
[RequiresUnreferencedCode("message")]
class ClassWithRequires
{
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[ExpectedWarning ("IL3050", ProducedBy = Tool.NativeAot)]
public static void MethodWithDynamicArg (dynamic arg)
{
arg.DynamicInvocation ();
}
}

[ExpectedWarning ("IL2026", nameof (ClassWithRequires))]
public static void Test ()
{
ClassWithRequires.MethodWithDynamicArg (null);
}
}

class InvocationOnDynamicTypeInMethodWithRUCDoesNotWarnTwoTimes ()
{
// Analyzer hole: https://github.com/dotnet/runtime/issues/94057
[RequiresUnreferencedCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
[RequiresDynamicCode ("We should only see the warning related to this annotation, and none about the dynamic type.")]
static void MethodWithRequires ()
{
dynamic dynamicField = "Some string";
Console.WriteLine (dynamicField);
}

[ExpectedWarning ("IL2026", nameof (MethodWithRequires))]
[ExpectedWarning ("IL3050", nameof (MethodWithRequires), ProducedBy = Tool.Analyzer | Tool.NativeAot)]
public static void Test ()
{
MethodWithRequires ();
}
}
}
}