diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs index fd6873811eeb32..11505cb5c3cc61 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs @@ -257,16 +257,21 @@ bool merge { switch (targetOperation) { - case IFieldReferenceOperation: - case IParameterReferenceOperation: + case IFieldReferenceOperation fieldRef: { + // Visit the instance to ensure that method calls or other operations + // used as the instance are properly analyzed for diagnostics. + Visit(fieldRef.Instance, state); var current = state.Current; - TValue targetValue = targetOperation switch - { - IFieldReferenceOperation fieldRef => GetFieldTargetValue(fieldRef, in current.Context), - IParameterReferenceOperation parameterRef => GetParameterTargetValue(parameterRef.Parameter), - _ => throw new InvalidOperationException() - }; + TValue targetValue = GetFieldTargetValue(fieldRef, in current.Context); + TValue value = Visit(valueOperation, state); + HandleAssignment(value, targetValue, assignmentOperation, in current.Context); + return value; + } + case IParameterReferenceOperation parameterRef: + { + var current = state.Current; + TValue targetValue = GetParameterTargetValue(parameterRef.Parameter); TValue value = Visit(valueOperation, state); HandleAssignment(value, targetValue, assignmentOperation, in current.Context); return value; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index fdbbc1b47f3ba5..2510b4fde64876 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -161,6 +161,11 @@ public override MultiValue VisitInstanceReference(IInstanceReferenceOperation in public override MultiValue VisitFieldReference(IFieldReferenceOperation fieldRef, StateValue state) { + // Visit the instance to ensure that method calls or other operations + // used as the instance are properly analyzed for diagnostics. + // For example: someMethod().Field should analyze someMethod(). + Visit(fieldRef.Instance, state); + var field = fieldRef.Field; switch (field.Name) { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index 9a635d9a6acf78..d55c284549005c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -232,21 +232,21 @@ class AccessReturnedInstanceField static AccessReturnedInstanceField GetInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type unused) => null; - [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2832")] + [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance))] [ExpectedWarning("IL2077", nameof(field), nameof(DataFlowTypeExtensions.RequiresAll))] static void TestRead() { GetInstance(GetUnknownType()).field.RequiresAll(); } - [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2832")] + [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance))] [ExpectedWarning("IL2074", nameof(GetUnknownType), nameof(field))] static void TestWrite() { GetInstance(GetUnknownType()).field = GetUnknownType(); } - [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2832")] + [ExpectedWarning("IL2072", nameof(GetUnknownType), nameof(GetInstance))] [ExpectedWarning("IL2074", nameof(GetUnknownType), nameof(field))] static void TestNullCoalescingAssignment() { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs index f1c968ac870c4f..ee4c435b217b00 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs @@ -16,6 +16,7 @@ public static void Main() { GetInterface_Name.Test(); GetInterface_Name_IgnoreCase.Test(); + GetInterfaceMap_DataFlow.Test(); } class GetInterface_Name @@ -184,6 +185,44 @@ public static void Test() } } + class GetInterfaceMap_DataFlow + { + [ExpectedWarning("IL2072", nameof(Type.GetInterfaceMap))] + static void TestDirectCall() + { + var @interface = typeof(TestType).GetInterfaces()[0]; + _ = typeof(TestType).GetInterfaceMap(@interface); + } + + [ExpectedWarning("IL2072", nameof(Type.GetInterfaceMap))] + static void TestFieldAccess() + { + var @interface = typeof(TestType).GetInterfaces()[0]; + _ = typeof(TestType).GetInterfaceMap(@interface).TargetMethods; + } + + [ExpectedWarning("IL2072", nameof(Type.GetInterfaceMap))] + static void TestMultipleFieldAccess() + { + var @interface = typeof(TestType).GetInterfaces()[0]; + _ = typeof(TestType).GetInterfaceMap(@interface).TargetMethods.Length; + } + + static void TestWithAnnotation([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType) + { + _ = typeof(TestType).GetInterfaceMap(interfaceType); + _ = typeof(TestType).GetInterfaceMap(interfaceType).TargetMethods; + } + + public static void Test() + { + TestDirectCall(); + TestFieldAccess(); + TestMultipleFieldAccess(); + TestWithAnnotation(null); + } + } + interface ITestInterface { }