diff options
author | Sven Boemer <sbomer@gmail.com> | 2021-11-30 22:09:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-30 22:09:28 +0300 |
commit | d8170a8f95a52267f0fc87d76eb97e724f13b3f7 (patch) | |
tree | 2c53bfed4a284c630b0806b51b00fb672bf3eb39 | |
parent | 888fed7b56fbef827be1cdedb018153643613459 (diff) |
[DAM analyzer] Add support for properties and enable more tests (#2390)
The IOperation tree represents properties as
IPropertyReferenceOperation, so we need to handle
properties specially (whereas the linker sees calls
to the getter/setter directly).
14 files changed, 328 insertions, 96 deletions
diff --git a/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs b/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs index 959884fba..2769ff588 100644 --- a/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs +++ b/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using ILLink.RoslynAnalyzer.TrimAnalysis; using ILLink.Shared.DataFlow; using Microsoft.CodeAnalysis; @@ -76,11 +77,15 @@ namespace ILLink.RoslynAnalyzer.DataFlow public abstract void HandleAssignment (TValue source, TValue target, IOperation operation); // This is called to handle instance method invocations, where "receiver" is the - // analyzed value for the object on which the instance method is called. - public abstract void HandleReceiverArgument (TValue receiver, IInvocationOperation operation); + // analyzed value for the object on which the instance method is called, and similarly + // for property references. + public abstract void HandleReceiverArgument (TValue receiver, IMethodSymbol targetMethod, IOperation operation); public abstract void HandleArgument (TValue argument, IArgumentOperation operation); + // Called for property setters which are essentially like arguments passed to a method. + public abstract void HandlePropertySetterArgument (TValue value, IMethodSymbol setMethod, ISimpleAssignmentOperation operation); + // This takes an IOperation rather than an IReturnOperation because the return value // may (must?) come from BranchValue of an operation whose FallThroughSuccessor is the exit block. public abstract void HandleReturnValue (TValue returnValue, IOperation operation); @@ -115,12 +120,19 @@ namespace ILLink.RoslynAnalyzer.DataFlow // Doesn't get called for assignments to locals, which are handled above. HandleAssignment (value, targetValue, operation); break; - case IPropertyReferenceOperation: + case IPropertyReferenceOperation propertyRef: + // A property assignment is really a call to the property setter. + var setMethod = propertyRef.Property.SetMethod; + Debug.Assert (setMethod != null); + HandlePropertySetterArgument (value, setMethod!, operation); + break; // TODO: when setting a property in an attribute, target is an IPropertyReference. case IArrayElementReferenceOperation: // TODO break; - // TODO: DiscardOperation + case IDiscardOperation: + // Assignments like "_ = SomeMethod();" don't need dataflow tracking. + break; default: throw new NotImplementedException (operation.Target.GetType ().ToString ()); } @@ -153,7 +165,7 @@ namespace ILLink.RoslynAnalyzer.DataFlow { if (operation.Instance != null) { var instanceValue = Visit (operation.Instance, state); - HandleReceiverArgument (instanceValue, operation); + HandleReceiverArgument (instanceValue, operation.TargetMethod, operation); } foreach (var argument in operation.Arguments) @@ -162,6 +174,37 @@ namespace ILLink.RoslynAnalyzer.DataFlow return TopValue; } + public static IMethodSymbol GetPropertyMethod (IPropertyReferenceOperation operation) + { + // The IPropertyReferenceOperation doesn't tell us whether this reference is to the getter or setter. + // For this we need to look at the containing operation. + var parent = operation.Parent; + Debug.Assert (parent != null); + if (parent!.Kind == OperationKind.SimpleAssignment) { + var assignment = (ISimpleAssignmentOperation) parent; + if (assignment.Target == operation) { + var setMethod = operation.Property.SetMethod; + Debug.Assert (setMethod != null); + return setMethod!; + } + Debug.Assert (assignment.Value == operation); + } + + var getMethod = operation.Property.GetMethod; + Debug.Assert (getMethod != null); + return getMethod!; + } + + public override TValue VisitPropertyReference (IPropertyReferenceOperation operation, LocalState<TValue> state) + { + if (operation.Instance != null) { + var instanceValue = Visit (operation.Instance, state); + HandleReceiverArgument (instanceValue, GetPropertyMethod (operation), operation); + } + + return TopValue; + } + public override TValue VisitArgument (IArgumentOperation operation, LocalState<TValue> state) { var value = Visit (operation.Value, state); diff --git a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs index 71bb46141..fd22e7640 100644 --- a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs +++ b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs @@ -82,7 +82,9 @@ namespace ILLink.RoslynAnalyzer memberOptions: SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeExplicitInterface, - parameterOptions: SymbolDisplayParameterOptions.IncludeType + parameterOptions: + SymbolDisplayParameterOptions.IncludeType | + SymbolDisplayParameterOptions.IncludeParamsRefOut ); public static string GetDisplayName (this ISymbol symbol) diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/SymbolValue.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/SymbolValue.cs index 037ed00a5..9eefd7f9c 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/SymbolValue.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/SymbolValue.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; using ILLink.Shared; @@ -30,10 +31,41 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis public SymbolValue (ITypeParameterSymbol typeParameter) => Source = typeParameter; - public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes => - IsMethodReturn - ? ((IMethodSymbol) Source).GetDynamicallyAccessedMemberTypesOnReturnType () - : Source.GetDynamicallyAccessedMemberTypes (); + public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { + get { + if (IsMethodReturn) { + var method = (IMethodSymbol) Source; + var returnDamt = method.GetDynamicallyAccessedMemberTypesOnReturnType (); + // Is this a property getter? + // If there are conflicts between the getter and the property annotation, + // the getter annotation wins. (But DAMT.None is ignored) + if (method.MethodKind is MethodKind.PropertyGet && returnDamt == DynamicallyAccessedMemberTypes.None) { + var property = (IPropertySymbol) method.AssociatedSymbol!; + Debug.Assert (property != null); + returnDamt = property!.GetDynamicallyAccessedMemberTypes (); + } + + return returnDamt; + } + + var damt = Source.GetDynamicallyAccessedMemberTypes (); + + // Is this a property setter parameter? + if (Source.Kind == SymbolKind.Parameter) { + var parameterMethod = (IMethodSymbol) Source.ContainingSymbol; + Debug.Assert (parameterMethod != null); + // If there are conflicts between the setter and the property annotation, + // the setter annotation wins. (But DAMT.None is ignored) + if (parameterMethod!.MethodKind == MethodKind.PropertySet && damt == DynamicallyAccessedMemberTypes.None) { + var property = (IPropertySymbol) parameterMethod.AssociatedSymbol!; + Debug.Assert (property != null); + damt = property!.GetDynamicallyAccessedMemberTypes (); + } + } + + return damt; + } + } public override string ToString () { diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index e00bf7ff6..1f9ebe300 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -15,7 +15,6 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis { public readonly TrimAnalysisPatternStore TrimAnalysisPatterns; - public TrimAnalysisVisitor ( LocalStateLattice<MultiValue, ValueSetLattice<SingleValue>> lattice, OperationBlockAnalysisContext context @@ -42,6 +41,21 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis return new MultiValue (new SymbolValue (operation.TargetMethod, isMethodReturn: true)); } + // Just like VisitInvocation for a method call, we need to visit a property method invocation + // in case it has an annotated return value. + public override MultiValue VisitPropertyReference (IPropertyReferenceOperation operation, StateValue state) + { + // Base logic visits the receiver + base.VisitPropertyReference (operation, state); + + var propertyMethod = GetPropertyMethod (operation); + // Only the getter has a return value that may be annotated. + if (propertyMethod.MethodKind == MethodKind.PropertyGet) + return new MultiValue (new SymbolValue (propertyMethod, isMethodReturn: true)); + + return TopValue; + } + public override MultiValue VisitConversion (IConversionOperation operation, StateValue state) { var value = base.VisitConversion (operation, state); @@ -86,7 +100,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis // Override handlers for situations where annotated locations may be involved in reflection access: // - assignments - // - arguments passed to method parameters + // - arguments passed to method parameters (or implicitly passed to property setters) // this also needs to create the annotated value for parameters, because they are not represented // as 'IParameterReferenceOperation' when passing arguments // - instance passed as explicit or implicit receiver to a method invocation @@ -118,16 +132,23 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis )); } - public override void HandleReceiverArgument (MultiValue receieverValue, IInvocationOperation operation) + // Similar to HandleArgument, for an assignment operation that is really passing an argument to a property setter. + public override void HandlePropertySetterArgument (MultiValue value, IMethodSymbol setMethod, ISimpleAssignmentOperation operation) { - if (operation.Instance == null) - return; + var parameter = new MultiValue (new SymbolValue (setMethod.Parameters[0])); - MultiValue implicitReceiverParameter = new MultiValue (new SymbolValue (operation.TargetMethod, isMethodReturn: false)); + TrimAnalysisPatterns.Add (new TrimAnalysisPattern (value, parameter, operation)); + } + + // Can be called for an invocation or a propertyreference + // where the receiver is not null (so an instance method/property). + public override void HandleReceiverArgument (MultiValue receiverValue, IMethodSymbol targetMethod, IOperation operation) + { + MultiValue thisParameter = new MultiValue (new SymbolValue (targetMethod!, isMethodReturn: false)); TrimAnalysisPatterns.Add (new TrimAnalysisPattern ( - receieverValue, - implicitReceiverParameter, + receiverValue, + thisParameter, operation )); } diff --git a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index ebe9145d7..54f69ab98 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -13,7 +13,7 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (AnnotatedMembersAccessedViaReflection)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task ApplyTypeAnnotations () { return RunTest (nameof (ApplyTypeAnnotations)); @@ -25,37 +25,37 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (AssemblyQualifiedNameDataflow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task AttributeConstructorDataflow () { return RunTest (nameof (AttributeConstructorDataflow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task AttributeFieldDataflow () { return RunTest (nameof (AttributeFieldDataflow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task AttributePropertyDataflow () { return RunTest (nameof (AttributePropertyDataflow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task ByRefDataflow () { return RunTest (nameof (ByRefDataflow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task ComplexTypeHandling () { return RunTest (nameof (ComplexTypeHandling)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task DynamicDependencyDataflow () { return RunTest (nameof (DynamicDependencyDataflow)); @@ -67,7 +67,7 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (EmptyArrayIntrinsicsDataFlow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task FieldDataFlow () { return RunTest (nameof (FieldDataFlow)); @@ -97,7 +97,7 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (GetTypeDataFlow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task IReflectDataflow () { return RunTest (nameof (IReflectDataflow)); @@ -109,19 +109,19 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (LocalDataFlow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task LocalDataFlowKeptMembers () { return RunTest (nameof (LocalDataFlowKeptMembers)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task MemberTypes () { return RunTest (nameof (MemberTypes)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task MemberTypesAllOnCopyAssembly () { return RunTest (nameof (MemberTypesAllOnCopyAssembly)); @@ -145,13 +145,13 @@ namespace ILLink.RoslynAnalyzer.Tests return RunTest (nameof (MethodReturnParameterDataFlow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task MethodThisDataFlow () { return RunTest (nameof (MethodThisDataFlow)); } - [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")] + [Fact] public Task PropertyDataFlow () { return RunTest (nameof (PropertyDataFlow)); diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 7d23f9713..481f3c7a4 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -65,14 +65,30 @@ namespace ILLink.RoslynAnalyzer.Tests private static IEnumerable<string> GetTestDependencies (string rootSourceDir, SyntaxTree testSyntaxTree) { foreach (var attribute in testSyntaxTree.GetRoot ().DescendantNodes ().OfType<AttributeSyntax> ()) { - if (attribute.Name.ToString () != "SetupCompileBefore") + var attributeName = attribute.Name.ToString (); + if (attributeName != "SetupCompileBefore" && attributeName != "SandboxDependency") continue; - var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType<NamespaceDeclarationSyntax> ().Single ().Name.ToString (); + var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType<NamespaceDeclarationSyntax> ().First ().Name.ToString (); var testSuiteName = testNamespace.Substring (testNamespace.LastIndexOf ('.') + 1); var args = LinkerTestBase.GetAttributeArguments (attribute); - foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType<LiteralExpressionSyntax> ()) - yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); + + switch (attributeName) { + case "SetupCompileBefore": { + foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType<LiteralExpressionSyntax> ()) + yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); + break; + } + case "SandboxDependency": { + var sourceFile = LinkerTestBase.GetStringFromExpression (args["#0"]); + if (!sourceFile.EndsWith (".cs")) + throw new NotSupportedException (); + yield return Path.Combine (rootSourceDir, testSuiteName, sourceFile); + break; + } + default: + throw new InvalidOperationException (); + } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index cd55b716f..deaafb950 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -11,7 +11,6 @@ using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Xunit; @@ -116,7 +115,7 @@ namespace ILLink.RoslynAnalyzer.Tests public override void VisitConstructorDeclaration (ConstructorDeclarationSyntax node) { base.VisitConstructorDeclaration (node); - ValidateDiagnostics(node, node.AttributeLists); + ValidateDiagnostics (node, node.AttributeLists); } private void ValidateDiagnostics (CSharpSyntaxNode memberSyntax, SyntaxList<AttributeListSyntax> attrLists) @@ -288,11 +287,11 @@ namespace ILLink.RoslynAnalyzer.Tests } } - missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{(string.Join (Environment.NewLine, _diagnostics))}"; + missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{string.Join (Environment.NewLine, _diagnostics)}"; return false; } - private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnosticMessages) + private static void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnosticMessages) { var arg = Assert.Single (LinkerTestBase.GetAttributeArguments (attribute)); var text = LinkerTestBase.GetStringFromExpression (arg.Value); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs index 5863cf4a4..f02ea1cba 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs @@ -50,6 +50,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow } [Kept] + // Analyzer doesn't support intrinsics: https://github.com/dotnet/linker/issues/2374 + [ExpectedWarning ("IL2026", "System.Type.GetType(String)", + ProducedBy = ProducedBy.Analyzer)] + // Analyzer doesn't track known types: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2072", "'type'", nameof (ApplyTypeAnnotations) + "." + nameof (RequireCombination) + "(Type)", "System.Type.GetType(String)", + ProducedBy = ProducedBy.Analyzer)] static void TestFromTypeGetTypeOverConstant () { RequireCombination (Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromTypeGetTypeOverConstantTestType")); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs index 6cb0409cf..69d4e7959 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs @@ -40,14 +40,18 @@ namespace Mono.Linker.Tests.Cases.DataFlow static Type s_typeWithPublicParameterlessConstructor; [Kept] - [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "Type&" }, messageCode: "IL2077")] + // Trimmer and analyzer use different formats for ref parameters: https://github.com/dotnet/linker/issues/2406 + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2077", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", ProducedBy = ProducedBy.Analyzer)] public static void PassRefToField () { MethodWithRefParameter (ref s_typeWithPublicParameterlessConstructor); } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "Type&" }, messageCode: "IL2067")] + // Trimmer and analyzer use different formats for ref parameters: https://github.com/dotnet/linker/issues/2406 + [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(Type&)", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2067", nameof (ByRefDataflow) + "." + nameof (MethodWithRefParameter) + "(ref Type)", ProducedBy = ProducedBy.Analyzer)] public static void PassRefToParameter (Type parameter) { MethodWithRefParameter (ref parameter); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs index 7bcfbc70c..858d40088 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs @@ -99,6 +99,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow } [Kept] + // Analyzer doesn't support intrinsics: https://github.com/dotnet/linker/issues/2374 + [ExpectedWarning ("IL2072", "'type'", nameof (ComplexTypeHandling) + "." + nameof (RequirePublicMethods) + "(Type)", "System.Object.GetType()", + ProducedBy = ProducedBy.Analyzer)] static void TestArrayGetTypeFromMethodParamHelper (ArrayGetTypeFromMethodParamElement[] p) { RequirePublicMethods (p.GetType ()); @@ -121,6 +124,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow static ArrayGetTypeFromFieldElement[] _arrayGetTypeFromField; [Kept] + // Analyzer doesn't support intrinsics: https://github.com/dotnet/linker/issues/2374 + [ExpectedWarning ("IL2072", "'type'", nameof (ComplexTypeHandling) + "." + nameof (RequirePublicMethods) + "(Type)", "System.Object.GetType()", + ProducedBy = ProducedBy.Analyzer)] static void TestArrayGetTypeFromField () { RequirePublicMethods (_arrayGetTypeFromField.GetType ()); @@ -134,6 +140,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow } [Kept] + // Analyzer doesn't support intrinsics: https://github.com/dotnet/linker/issues/2374 + [ExpectedWarning ("IL2026", "System.Type.GetType(String)", + ProducedBy = ProducedBy.Analyzer)] + // Analyzer doesn't track known types: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2072", "'type'", nameof (ComplexTypeHandling) + "." + nameof (RequirePublicMethods) + "(Type)", "System.Type.GetType(String)", + ProducedBy = ProducedBy.Analyzer)] static void TestArrayTypeGetType () { RequirePublicMethods (Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.ComplexTypeHandling+ArrayTypeGetTypeElement[]")); @@ -148,6 +160,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow } [Kept] + // Analyzer doesn't support intrinsics: https://github.com/dotnet/linker/issues/2374 + [ExpectedWarning ("IL2026", "Activator.CreateInstance(String, String)", + ProducedBy = ProducedBy.Analyzer)] static void TestArrayCreateInstanceByName () { Activator.CreateInstance ("test", "Mono.Linker.Tests.Cases.DataFlow.ComplexTypeHandling+ArrayCreateInstanceByNameElement[]"); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index cb36d87a3..30b520ff7 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -43,7 +43,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow static Type _staticTypeWithoutRequirements; - [ExpectedWarning ("IL2097", nameof (_annotationOnWrongType))] + // TODO: warn about annotation on wrong type in analyzer: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2097", nameof (_annotationOnWrongType), + ProducedBy = ProducedBy.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] static object _annotationOnWrongType; @@ -58,18 +60,14 @@ namespace Mono.Linker.Tests.Cases.DataFlow RequireNothing (_typeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor), - messageCode: "IL2074", message: new string[] { - nameof (GetUnkownType), - nameof (_typeWithPublicParameterlessConstructor) - })] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [ExpectedWarning ("IL2074", nameof (FieldDataFlow) + "." + nameof (_typeWithPublicParameterlessConstructor), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (FieldDataFlow) + "." + nameof (_typeWithPublicParameterlessConstructor), nameof (GetTypeWithNonPublicConstructors))] private void WriteToInstanceField () { _typeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); _typeWithPublicParameterlessConstructor = GetTypeWithPublicConstructors (); _typeWithPublicParameterlessConstructor = GetTypeWithNonPublicConstructors (); - _typeWithPublicParameterlessConstructor = GetUnkownType (); + _typeWithPublicParameterlessConstructor = GetUnknownType (); } [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] @@ -84,8 +82,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow RequireNothing (store._typeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor), messageCode: "IL2074")] - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [ExpectedWarning ("IL2074", nameof (TypeStore) + "." + nameof (TypeStore._typeWithPublicParameterlessConstructor), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (TypeStore) + "." + nameof (TypeStore._typeWithPublicParameterlessConstructor), nameof (GetTypeWithNonPublicConstructors))] private void WriteToInstanceFieldOnADifferentClass () { var store = new TypeStore (); @@ -93,7 +91,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow store._typeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); store._typeWithPublicParameterlessConstructor = GetTypeWithPublicConstructors (); store._typeWithPublicParameterlessConstructor = GetTypeWithNonPublicConstructors (); - store._typeWithPublicParameterlessConstructor = GetUnkownType (); + store._typeWithPublicParameterlessConstructor = GetUnknownType (); } [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] @@ -106,19 +104,15 @@ namespace Mono.Linker.Tests.Cases.DataFlow RequireNothing (_staticTypeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), - messageCode: "IL2079", message: new string[] { - nameof(_staticTypeWithoutRequirements), - nameof(_staticTypeWithPublicParameterlessConstructor) - })] + [ExpectedWarning ("IL2074", nameof (FieldDataFlow) + "." + nameof (_staticTypeWithPublicParameterlessConstructor), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (FieldDataFlow) + "." + nameof (_staticTypeWithPublicParameterlessConstructor), nameof (GetTypeWithNonPublicConstructors))] + [ExpectedWarning ("IL2079", nameof (FieldDataFlow) + "." + nameof (_staticTypeWithPublicParameterlessConstructor), nameof (_staticTypeWithoutRequirements))] private void WriteToStaticField () { _staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); _staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicConstructors (); _staticTypeWithPublicParameterlessConstructor = GetTypeWithNonPublicConstructors (); - _staticTypeWithPublicParameterlessConstructor = GetUnkownType (); + _staticTypeWithPublicParameterlessConstructor = GetUnknownType (); _staticTypeWithPublicParameterlessConstructor = _staticTypeWithoutRequirements; } @@ -132,17 +126,19 @@ namespace Mono.Linker.Tests.Cases.DataFlow RequireNothing (TypeStore._staticTypeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [ExpectedWarning ("IL2074", nameof (TypeStore) + "." + nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (TypeStore) + "." + nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), nameof (GetTypeWithNonPublicConstructors))] private void WriteToStaticFieldOnADifferentClass () { TypeStore._staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); TypeStore._staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicConstructors (); TypeStore._staticTypeWithPublicParameterlessConstructor = GetTypeWithNonPublicConstructors (); - TypeStore._staticTypeWithPublicParameterlessConstructor = GetUnkownType (); + TypeStore._staticTypeWithPublicParameterlessConstructor = GetUnknownType (); } - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2064", message: new string[] { nameof (TypeStore._staticTypeWithPublicParameterlessConstructor) })] + // TODO: warn about unknown types in analyzer: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2064", nameof (TypeStore) + "." + nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), + ProducedBy = ProducedBy.Trimmer)] private void WriteUnknownValue () { var array = new object[1]; @@ -191,7 +187,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow return null; } - private static Type GetUnkownType () + private static Type GetUnknownType () { return null; } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs index 5ca8b3181..56c0844d4 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -92,9 +92,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow t.GetMethod ("foo"); NonTypeType.StaticMethod (); } - - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods), new Type[] { }, - messageCode: "IL2065", message: new string[] { nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods) })] + // Analyer doesn't warn about unknown values flowing into annotated locations + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2065", nameof (MethodThisDataFlowTypeTest) + "." + nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods), "'this'", + ProducedBy = ProducedBy.Trimmer)] static void TestUnknownThis () { var array = new object[1]; @@ -143,14 +144,18 @@ namespace Mono.Linker.Tests.Cases.DataFlow class NonTypeType { - [ExpectedWarning ("IL2041")] + // Analyzer doesn't warn about annotations on unsupported types: + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2041", ProducedBy = ProducedBy.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public MethodInfo GetMethod (string name) { return null; } - [ExpectedWarning ("IL2041")] + // Analyzer doesn't warn about annotations on unsupported types: + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2041", ProducedBy = ProducedBy.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public static void StaticMethod () { @@ -164,10 +169,9 @@ namespace System class MethodThisDataFlowTypeTest : TestSystemTypeBase { [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequireNonPublicMethods), new Type[] { typeof (Type) }, - messageCode: "IL2082", message: new string[] { - "'type' argument ", "in call to 'System.MethodThisDataFlowTypeTest.RequireNonPublicMethods(Type)'", - "implicit 'this' argument of method 'System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()'" })] + [ExpectedWarning ("IL2082", nameof (MethodThisDataFlowTypeTest) + "." + nameof (RequireNonPublicMethods) + "(Type)", + "'type' argument ", "in call to 'System.MethodThisDataFlowTypeTest.RequireNonPublicMethods(Type)'", + "implicit 'this' argument of method 'System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()'")] public void RequireThisPublicMethods () { RequirePublicMethods (this); @@ -175,8 +179,7 @@ namespace System } [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequirePublicMethods), new Type[] { typeof (Type) }, - messageCode: "IL2082")] + [ExpectedWarning ("IL2082", nameof (MethodThisDataFlowTypeTest) + "." + nameof (RequirePublicMethods) + "(Type)")] public void RequireThisNonPublicMethods () { RequirePublicMethods (this); @@ -198,11 +201,8 @@ namespace System [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type _requiresPublicConstructors; - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (_requiresPublicConstructors), - messageCode: "IL2084", message: new string[] { - nameof (PropagateToField), - nameof (_requiresPublicConstructors) - })] + [ExpectedWarning ("IL2084", nameof (MethodThisDataFlowTypeTest) + "." + nameof (_requiresPublicConstructors), + nameof (PropagateToField))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public void PropagateToField () { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index d1f6d57eb..685b6a296 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -42,7 +42,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] static Type StaticPropertyWithPublicConstructor { get; set; } - [ExpectedWarning ("IL2099", nameof (PropertyWithUnsupportedType))] + // Analyzer doesn't warn about annotations on unsupported types + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2099", nameof (PropertyWithUnsupportedType), ProducedBy = ProducedBy.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] static object PropertyWithUnsupportedType { get; set; } @@ -110,8 +112,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow return _fieldWithPublicConstructors; } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors), - messageCode: "IL2069", message: new string[] { "value", nameof (PropertyPublicParameterlessConstructorWithExplicitAccessors) + ".set", nameof (_fieldWithPublicConstructors) })] + [ExpectedWarning ("IL2069", nameof (PropertyDataFlow) + "." + nameof (_fieldWithPublicConstructors), + "'value'", + nameof (PropertyPublicParameterlessConstructorWithExplicitAccessors) + ".set")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] set { _fieldWithPublicConstructors = value; @@ -129,7 +132,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow return _fieldWithPublicConstructors; } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors), messageCode: "IL2069")] + [ExpectedWarning ("IL2069", nameof (PropertyDataFlow) + "." + nameof (_fieldWithPublicConstructors), + "'value'", + nameof (PropertyNonPublicConstructorsWithExplicitAccessors) + ".set")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] set { _fieldWithPublicConstructors = value; @@ -145,6 +150,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow instance.TestInstancePropertyWithStaticField (); instance.TestPropertyWithDifferentBackingFields (); instance.TestPropertyWithExistingAttributes (); + instance.TestPropertyWithConflictingAttributes (); + instance.TestPropertyWithConflictingNoneAttributes (); instance.TestPropertyWithIndexerWithMatchingAnnotations (null); instance.TestPropertyWithIndexerWithoutMatchingAnnotations (null); } @@ -185,6 +192,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow } [RecognizedReflectionAccessPattern] + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresPublicConstructors) + "(Type)", + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), + ProducedBy = ProducedBy.Analyzer)] public void TestPropertyWhichLooksLikeCompilerGenerated () { // If the property was correctly recognized both the property getter and the backing field should get the annotation. @@ -197,6 +208,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] static Type PropertyWhichLooksLikeCompilerGenerated { + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2078", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated) + ".get", + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWhichLooksLikeCompilerGenerated_Field), + ProducedBy = ProducedBy.Analyzer)] get { return PropertyWhichLooksLikeCompilerGenerated_Field; } @@ -235,8 +250,14 @@ namespace Mono.Linker.Tests.Cases.DataFlow [CompilerGenerated] private Type PropertyWithDifferentBackingFields_SetterField; + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2042", - "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields")] + "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields", + ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2078", + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithDifferentBackingFields) + ".get", + "Type", + ProducedBy = ProducedBy.Analyzer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithDifferentBackingFields { get { @@ -254,22 +275,95 @@ namespace Mono.Linker.Tests.Cases.DataFlow PropertyWithExistingAttributes = null; } - [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field")] + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field", + ProducedBy = ProducedBy.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] Type PropertyWithExistingAttributes_Field; [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithExistingAttributes { - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get")] + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", + ProducedBy = ProducedBy.Trimmer)] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] get { return PropertyWithExistingAttributes_Field; } - [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set")] + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", + ProducedBy = ProducedBy.Trimmer)] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] set { PropertyWithExistingAttributes_Field = value; } } + // When the property annotation conflicts with the getter/setter annotation, + // we issue a warning (IL2043 below) but respect the getter/setter annotations. + [ExpectedWarning ("IL2072", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingAttributes) + ".get", + nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresPublicConstructors) + "(Type)")] + [ExpectedWarning ("IL2072", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingAttributes) + ".set", + nameof (PropertyDataFlow) + "." + nameof (GetTypeWithPublicConstructors) + "()")] + public void TestPropertyWithConflictingAttributes () + { + PropertyWithConflictingAttributes.RequiresPublicConstructors (); + PropertyWithConflictingAttributes.RequiresNonPublicConstructors (); + PropertyWithConflictingAttributes = GetTypeWithPublicConstructors (); + PropertyWithConflictingAttributes = GetTypeWithNonPublicConstructors (); + } + + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2056", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes_Field", + ProducedBy = ProducedBy.Trimmer)] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] + [CompilerGenerated] + Type PropertyWithConflictingAttributes_Field; + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + Type PropertyWithConflictingAttributes { + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get", + ProducedBy = ProducedBy.Trimmer)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] + get { return PropertyWithConflictingAttributes_Field; } + + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set", + ProducedBy = ProducedBy.Trimmer)] + [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] + set { PropertyWithConflictingAttributes_Field = value; } + } + + // When the property annotation is DAMT.None and this conflicts with the getter/setter annotations, + // we don't produce a warning about the conflict, and just respect the property annotations. + [ExpectedWarning ("IL2072", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes) + ".get", + nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors) + "(Type)")] + [ExpectedWarning ("IL2072", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes) + ".set", + nameof (PropertyDataFlow) + "." + nameof (GetTypeWithNonPublicConstructors) + "()")] + public void TestPropertyWithConflictingNoneAttributes () + { + PropertyWithConflictingNoneAttributes.RequiresPublicConstructors (); + PropertyWithConflictingNoneAttributes.RequiresNonPublicConstructors (); + PropertyWithConflictingNoneAttributes = GetTypeWithPublicConstructors (); + PropertyWithConflictingNoneAttributes = GetTypeWithNonPublicConstructors (); + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.None)] + [CompilerGenerated] + Type PropertyWithConflictingNoneAttributes_Field; + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + Type PropertyWithConflictingNoneAttributes { + // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2078", nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes) + ".get", + nameof (TestAutomaticPropagationType) + "." + nameof (PropertyWithConflictingNoneAttributes_Field), + ProducedBy = ProducedBy.Analyzer)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.None)] + get { return PropertyWithConflictingNoneAttributes_Field; } + + [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.None)] + set { PropertyWithConflictingNoneAttributes_Field = value; } + } + [RecognizedReflectionAccessPattern] public void TestPropertyWithIndexerWithMatchingAnnotations ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type myType) { @@ -278,8 +372,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow propclass[1].RequiresPublicConstructors (); } - [UnrecognizedReflectionAccessPattern (typeof (PropertyWithIndexer), "Item.set", new Type[] { typeof (Type) }, messageCode: "IL2067")] - [UnrecognizedReflectionAccessPattern (typeof (DataFlowTypeExtensions), "RequiresNonPublicConstructors", new Type[] { typeof (Type) }, messageCode: "IL2072")] + // Trimmer and analyzer handle formatting of indexers differently. + [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".Item.set", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2067", nameof (PropertyWithIndexer) + ".this[Int32].set", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors) + "(Type)")] [LogDoesNotContain ("'Value passed to parameter 'index' of method 'Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithIndexer.Item.set'")] public void TestPropertyWithIndexerWithoutMatchingAnnotations (Type myType) { @@ -295,7 +391,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] public Type this[int index] { - [ExpectedWarning ("IL2063", "PropertyWithIndexer.Item.get")] + // TODO: warn about unknown types in analyzer: https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2063", "PropertyWithIndexer.Item.get", + ProducedBy = ProducedBy.Trimmer)] get => Property_Field[index]; set => Property_Field[index] = value; } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs index 15cebd41b..832461a3f 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs @@ -1205,7 +1205,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // RequiresUnfereferencedCode on the type will suppress IL2072 // https://github.com/dotnet/linker/issues/2379 - [ExpectedWarning("IL2072", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", ProducedBy = ProducedBy.Analyzer)] static ClassWithRequires () { Instance = Activator.CreateInstance (Type.GetType ("SomeText")); |