diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs index 67668004433ce9..589b0e8130efdf 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs @@ -9,11 +9,6 @@ namespace ILLink.Shared.TrimAnalysis { internal partial record MethodParameterValue { - public MethodParameterValue (IParameterSymbol parameterSymbol) - : this (new ParameterProxy (parameterSymbol)) { } - public MethodParameterValue (IMethodSymbol methodSymbol, ParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) - : this (new (new (methodSymbol), parameterIndex), dynamicallyAccessedMemberTypes) { } - public MethodParameterValue (ParameterProxy parameter) : this (parameter, FlowAnnotations.GetMethodParameterAnnotation (parameter)) { } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs index f57de9138dbf88..baa21aca62c8a4 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ParameterProxy.cs @@ -9,10 +9,10 @@ namespace ILLink.Shared.TypeSystemProxy { internal partial struct ParameterProxy { - public ParameterProxy (IParameterSymbol parameter) + public ParameterProxy (IParameterSymbol parameter, IMethodSymbol method) { - Method = new ((IMethodSymbol) parameter.ContainingSymbol); - Index = (ParameterIndex) parameter.Ordinal + (Method.HasImplicitThis () ? 1 : 0); + Method = new (method); + Index = (ParameterIndex) parameter.Ordinal + (method.HasImplicitThis () ? 1 : 0); } public partial ReferenceKind GetReferenceKind () diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index b960e2a461f97d..3eea09e78d4348 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -113,7 +113,7 @@ public override MultiValue VisitInstanceReference (IInstanceReferenceOperation i // The instance reference operation represents a 'this' or 'base' reference to the containing type, // so we get the annotation from the containing method. if (instanceRef.Type != null && instanceRef.Type.IsTypeInterestingForDataflow ()) - return new MethodParameterValue (Method, (ParameterIndex) 0, Method.GetDynamicallyAccessedMemberTypes ()); + return new MethodParameterValue (new ParameterProxy (new (Method), (ParameterIndex) 0)); return TopValue; } @@ -187,7 +187,11 @@ public override MultiValue GetFieldTargetValue (IFieldSymbol field) public override MultiValue GetParameterTargetValue (IParameterSymbol parameter) { - return parameter.Type.IsTypeInterestingForDataflow () ? new MethodParameterValue (parameter) : TopValue; + // Skip analysis for extension members (we have no way to represent a parameter on an extension type). + if (parameter.ContainingSymbol is not IMethodSymbol method) + return TopValue; + + return parameter.Type.IsTypeInterestingForDataflow () ? new MethodParameterValue (new ParameterProxy (parameter, method)) : TopValue; } public override void HandleAssignment (MultiValue source, MultiValue target, IOperation operation) diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index 29622dc32365c3..9add1124769a19 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -131,6 +131,12 @@ public Task EventDataFlow () return RunTest (); } + [Fact] + public Task ExtensionsDataFlow () + { + return RunTest (); + } + [Fact] public Task FieldDataFlow () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExtensionsDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExtensionsDataFlow.cs new file mode 100644 index 00000000000000..1f7b8bcb63df4d --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ExtensionsDataFlow.cs @@ -0,0 +1,66 @@ +// 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 Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class ExtensionsDataFlow + { + public static void Main () + { + TestExtensionMethod (); + TestExtensionMethodMismatch (); + TestExtensionMethodRequires (); + } + + [ExpectedWarning ("IL2072", "GetWithMethods", nameof (Extensions.ExtensionMethod))] + static void TestExtensionMethod () + { + GetWithFields ().ExtensionMethod (); + GetWithMethods ().ExtensionMethod (); + } + + static void TestExtensionMethodMismatch () + { + GetWithFields ().ExtensionMethodMismatch (); + } + + [ExpectedWarning ("IL2026", nameof (Extensions.ExtensionMethodRequires))] + static void TestExtensionMethodRequires () + { + GetWithFields ().ExtensionMethodRequires (); + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + static Type GetWithFields () => null; + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static Type GetWithMethods () => null; + } + + [ExpectedNoWarnings] + public static class Extensions + { + public static void ExtensionMethod ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] this Type type) + { + type.RequiresPublicFields (); + } + + [ExpectedWarning ("IL2067", "RequiresPublicMethods")] + public static void ExtensionMethodMismatch ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] this Type type) + { + type.RequiresPublicMethods (); + } + + [RequiresUnreferencedCode (nameof (ExtensionMethodRequires))] + public static void ExtensionMethodRequires ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] this Type type) + { + } + } +}