diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 53533e252c5dfa..39c8f8e71dad32 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -64,6 +64,8 @@ void AddRange (DiagnosticId first, DiagnosticId last) public override ImmutableArray SupportedDiagnostics => GetSupportedDiagnostics (); + static Location GetPrimaryLocation (ImmutableArray locations) => locations.Length > 0 ? locations[0] : Location.None; + public override void Initialize (AnalysisContext context) { if (!System.Diagnostics.Debugger.IsAttached) @@ -87,6 +89,7 @@ public override void Initialize (AnalysisContext context) // Examine generic instantiations in base types and interface list context.RegisterSymbolAction (context => { var type = (INamedTypeSymbol) context.Symbol; + var location = GetPrimaryLocation (type.Locations); // RUC on type doesn't silence DAM warnings about generic base/interface types. // This knowledge lives in IsInRequiresUnreferencedCodeAttributeScope, // which we still call for consistency here, but it is expected to return false. @@ -94,12 +97,12 @@ public override void Initialize (AnalysisContext context) return; if (type.BaseType is INamedTypeSymbol baseType) { - foreach (var diagnostic in ProcessGenericParameters (baseType, type.Locations[0])) + foreach (var diagnostic in ProcessGenericParameters (baseType, location)) context.ReportDiagnostic (diagnostic); } foreach (var interfaceType in type.Interfaces) { - foreach (var diagnostic in ProcessGenericParameters (interfaceType, type.Locations[0])) + foreach (var diagnostic in ProcessGenericParameters (interfaceType, location)) context.ReportDiagnostic (diagnostic); } }, SymbolKind.NamedType); @@ -111,11 +114,11 @@ public override void Initialize (AnalysisContext context) return; var returnType = method.ReturnType; - foreach (var diagnostic in ProcessGenericParameters (returnType, method.Locations[0])) + foreach (var diagnostic in ProcessGenericParameters (returnType, GetPrimaryLocation (method.Locations))) context.ReportDiagnostic (diagnostic); foreach (var parameter in method.Parameters) { - foreach (var diagnostic in ProcessGenericParameters (parameter.Type, parameter.Locations[0])) + foreach (var diagnostic in ProcessGenericParameters (parameter.Type, GetPrimaryLocation (parameter.Locations))) context.ReportDiagnostic (diagnostic); } }, SymbolKind.Method); @@ -125,7 +128,7 @@ public override void Initialize (AnalysisContext context) if (field.IsInRequiresUnreferencedCodeAttributeScope (out _)) return; - foreach (var diagnostic in ProcessGenericParameters (field.Type, field.Locations[0])) + foreach (var diagnostic in ProcessGenericParameters (field.Type, GetPrimaryLocation (field.Locations))) context.ReportDiagnostic (diagnostic); }, SymbolKind.Field); // Examine generic instantiations in invocations of generically instantiated methods, @@ -244,19 +247,20 @@ static List GetDynamicallyAccessedMembersDiagnostics (SingleValue so static void VerifyMemberOnlyApplyToTypesOrStrings (SymbolAnalysisContext context, ISymbol member) { + var location = GetPrimaryLocation (member.Locations); if (member is IFieldSymbol field && field.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !field.Type.IsTypeInterestingForDataflow ()) - context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings), member.Locations[0], member.GetDisplayName ())); + context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); else if (member is IMethodSymbol method) { if (method.GetDynamicallyAccessedMemberTypesOnReturnType () != DynamicallyAccessedMemberTypes.None && !method.ReturnType.IsTypeInterestingForDataflow ()) - context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings), member.Locations[0], member.GetDisplayName ())); + context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); if (method.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !method.ContainingType.IsTypeInterestingForDataflow ()) - context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods), member.Locations[0])); + context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods), location)); foreach (var parameter in method.Parameters) { if (parameter.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !parameter.Type.IsTypeInterestingForDataflow ()) - context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings), member.Locations[0], parameter.GetDisplayName (), member.GetDisplayName ())); + context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings), location, parameter.GetDisplayName (), member.GetDisplayName ())); } } else if (member is IPropertySymbol property && property.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !property.Type.IsTypeInterestingForDataflow ()) { - context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings), member.Locations[0], member.GetDisplayName ())); + context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); } } @@ -277,7 +281,7 @@ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbo (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (overrideMethod, baseMethod, overrideMethodReturnAnnotation, baseMethodReturnAnnotation); - Location attributableSymbolLocation = attributableMethod.Locations[0]; + Location attributableSymbolLocation = GetPrimaryLocation (attributableMethod.Locations); // code fix does not support merging multiple attributes. If an attribute is present or the method is not in source, do not provide args for code fix. (Location[]? sourceLocation, Dictionary? DAMArgs) = (!attributableSymbolLocation.IsInSource @@ -287,7 +291,7 @@ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbo context.ReportDiagnostic (Diagnostic.Create ( DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides), - overrideMethod.Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (), overrideMethod.GetDisplayName (), baseMethod.GetDisplayName ())); + GetPrimaryLocation (overrideMethod.Locations), sourceLocation, DAMArgs?.ToImmutableDictionary (), overrideMethod.GetDisplayName (), baseMethod.GetDisplayName ())); } foreach (var overrideParam in overrideMethod.GetMetadataParameters ()) { @@ -320,7 +324,8 @@ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbo (IMethodSymbol attributableMethod, DynamicallyAccessedMemberTypes missingAttribute) = GetTargetAndRequirements (overrideMethod, baseMethod, methodTypeParameterAnnotation, overriddenMethodTypeParameterAnnotation); - Location attributableSymbolLocation = attributableMethod.TypeParameters[i].Locations[0]; + var attributableSymbol = attributableMethod.TypeParameters[i]; + Location attributableSymbolLocation = GetPrimaryLocation (attributableSymbol.Locations); // code fix does not support merging multiple attributes. If an attribute is present or the method is not in source, do not provide args for code fix. (Location[]? sourceLocation, Dictionary? DAMArgs) = (!attributableSymbolLocation.IsInSource @@ -330,7 +335,7 @@ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbo context.ReportDiagnostic (Diagnostic.Create ( DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides), - overrideMethod.TypeParameters[i].Locations[0], sourceLocation, DAMArgs?.ToImmutableDictionary (), + GetPrimaryLocation (overrideMethod.TypeParameters[i].Locations), sourceLocation, DAMArgs?.ToImmutableDictionary (), overrideMethod.TypeParameters[i].GetDisplayName (), overrideMethod.GetDisplayName (), baseMethod.TypeParameters[i].GetDisplayName (), baseMethod.GetDisplayName ())); } @@ -339,7 +344,7 @@ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbo if (!overrideMethod.IsStatic && overrideMethod.GetDynamicallyAccessedMemberTypes () != baseMethod.GetDynamicallyAccessedMemberTypes ()) context.ReportDiagnostic (Diagnostic.Create ( DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides), - overrideMethod.Locations[0], + GetPrimaryLocation (overrideMethod.Locations), overrideMethod.GetDisplayName (), baseMethod.GetDisplayName ())); } @@ -364,10 +369,11 @@ static void VerifyDamOnPropertyAndAccessorMatch (SymbolAnalysisContext context, // None on parameter of 'set' matches unannotated || methodSymbol.MethodKind == MethodKind.PropertySet && methodSymbol.Parameters[methodSymbol.Parameters.Length - 1].GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None) { + var associatedSymbol = methodSymbol.AssociatedSymbol!; context.ReportDiagnostic (Diagnostic.Create ( DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor), - methodSymbol.AssociatedSymbol!.Locations[0], - methodSymbol.AssociatedSymbol!.GetDisplayName (), + GetPrimaryLocation (associatedSymbol.Locations), + associatedSymbol.GetDisplayName (), methodSymbol.GetDisplayName () )); return; diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs index 2a1f1e713281f0..0b7f9e5d1c8ba7 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs @@ -13,9 +13,14 @@ namespace ILLink.RoslynAnalyzer.Tests { public class DynamicallyAccessedMembersAnalyzerTests { - static Task VerifyDynamicallyAccessedMembersAnalyzer (string source, params DiagnosticResult[] expected) - { - return VerifyCS.VerifyAnalyzerAsync (source, + static Task VerifyDynamicallyAccessedMembersAnalyzer ( + string source, + bool consoleApplication, + params DiagnosticResult[] expected) + { + return VerifyCS.VerifyAnalyzerAsync ( + source, + consoleApplication, TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer), expected: expected); } @@ -49,7 +54,7 @@ private static void M(Type type) } } """; - return VerifyCS.VerifyAnalyzerAsync (TargetParameterWithAnnotations); + return VerifyCS.VerifyAnalyzerAsync (TargetParameterWithAnnotations, consoleApplication: false); } #region SourceParameter @@ -84,7 +89,7 @@ private static void M(Type type) // (21,3): warning IL2067: 'parameter' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'. // The parameter 'type' of method 'C.M(Type)' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter) .WithSpan (21, 3, 21, 38) .WithSpan (19, 24, 19, 33) @@ -124,7 +129,7 @@ private static Type M(Type type) // (18,10): warning IL2068: 'C.M(Type)' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The parameter 'type' of method 'C.M(Type)' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType) .WithSpan (18, 10, 18, 14) .WithSpan (16, 24, 16, 33) @@ -165,7 +170,7 @@ private static void M(Type type) // (17,3): warning IL2069: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The parameter 'type' of method 'C.M(Type)' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField) .WithSpan (17, 3, 17, 11) .WithSpan (15, 24, 15, 33) @@ -203,7 +208,7 @@ private static void M(Type type) // (16,3): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. // The parameter 'type' of method 'C.M(Type)' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter) .WithSpan (16, 3, 16, 24) .WithSpan (14, 24, 14, 33) @@ -248,7 +253,7 @@ private static Type GetT() // (12,3): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'. // The return value of method 'C.GetT()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter) .WithSpan (12, 3, 12, 40) .WithSpan (20, 2, 23, 3) @@ -289,7 +294,7 @@ private static Type GetFoo() // (18,10): warning IL2073: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The return value of method 'C.GetT()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType) .WithSpan (18, 10, 18, 18) .WithSpan (21, 2, 24, 3) @@ -327,7 +332,7 @@ private static Type M() // (12,3): warning IL2074: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The return value of method 'C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField) .WithSpan (12, 3, 12, 10) .WithSpan (15, 2, 18, 3) @@ -365,7 +370,7 @@ private static Type GetFoo () // (11,3): warning IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. // The return value of method 'C.GetT()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter) .WithSpan (11, 3, 11, 28) .WithSpan (15, 2, 18, 3) @@ -404,7 +409,7 @@ private static void NeedsPublicMethods( // (14,3): warning IL2077: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethods(Type)'. // The field 'C.f' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter) .WithSpan (14, 3, 14, 24) .WithSpan (10, 22, 10, 37) @@ -445,7 +450,7 @@ private static Type M() // (20,10): warning IL2078: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The field 'C.f' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType) .WithSpan (20, 10, 20, 11) .WithSpan (10, 22, 10, 37) @@ -480,7 +485,7 @@ public static void Main() // (17,3): warning IL2079: value stored in field 'C.f2' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The field 'C.f1' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField) .WithSpan (17, 3, 17, 10) .WithSpan (10, 22, 10, 38) @@ -514,7 +519,7 @@ public static void Main() // (13,3): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. // The field 'C.f' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter) .WithSpan (13, 3, 13, 21) .WithSpan (9, 22, 9, 37) @@ -749,7 +754,7 @@ private static void M2( // (198,4): warning IL2082: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'. // The implicit 'this' argument of method 'System.C.M1()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetParameterWithAnnotations), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetParameterWithAnnotations), consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter) .WithSpan (198, 4, 198, 12) .WithSpan (196, 3, 199, 4) @@ -788,7 +793,7 @@ private static void M2( } """; - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), ConversionOperation), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), ConversionOperation), consoleApplication: false, // (203,4): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'. The return value of method 'System.ConvertsToType.implicit operator Type(ConvertsToType)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter) .WithSpan (203, 4, 203, 28) @@ -831,7 +836,7 @@ private static void M2( } """; - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation), consoleApplication: false, // (205,4): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'. The return value of method 'System.ConvertsToType.implicit operator Type(ConvertsToType)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter) .WithSpan (205, 4, 205, 28) @@ -872,7 +877,7 @@ private static void M2( } """; - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation)); + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation), consoleApplication: false); } @@ -902,7 +907,7 @@ private Type M() // (200,11): warning IL2083: 'System.C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The implicit 'this' argument of method 'System.C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodReturnTypeWithAnnotations), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodReturnTypeWithAnnotations), consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType) .WithSpan (200, 11, 200, 15) .WithSpan (196, 3, 201, 4) @@ -937,7 +942,7 @@ private void M() // (198,4): warning IL2084: value stored in field 'System.C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The implicit 'this' argument of method 'System.C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetFieldWithAnnotations), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetFieldWithAnnotations), consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField) .WithSpan (198, 4, 198, 12) .WithSpan (196, 3, 199, 4) @@ -970,7 +975,7 @@ private void M() // (198,4): warning IL2085: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'. // The implicit 'this' argument of method 'System.C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodWithAnnotations), + return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodWithAnnotations), consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter) .WithSpan (198, 4, 198, 21) .WithSpan (196, 3, 199, 4) @@ -1007,7 +1012,7 @@ private static void M2() // (18,3): warning IL2087: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.M1(Type)'. // The generic parameter 'T' of 'C.M2()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter) .WithSpan (18, 3, 18, 16) .WithSpan (16, 25, 16, 26) @@ -1039,7 +1044,7 @@ private static Type M() // (14,10): warning IL2088: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' requirements. // The generic parameter 'T' of 'C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType) .WithSpan (14, 10, 14, 19) .WithSpan (12, 24, 12, 25) @@ -1073,7 +1078,7 @@ private static void M() // (16,3): warning IL2089: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements. // The generic parameter 'T' of 'C.M()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField) .WithSpan (16, 3, 16, 16) .WithSpan (14, 24, 14, 25) @@ -1110,7 +1115,7 @@ private static void M2() // (16,3): warning IL2091: 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' // in 'C.M1()'. The generic parameter 'S' of 'C.M2()' does not have matching annotations. // The source value must declare at least the same requirements as those declared on the target location it is assigned to. - return VerifyDynamicallyAccessedMembersAnalyzer (TargetGenericParameterWithAnnotations, + return VerifyDynamicallyAccessedMembersAnalyzer (TargetGenericParameterWithAnnotations, consoleApplication: false, VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter) .WithSpan (16, 3, 16, 10) .WithSpan (14, 25, 14, 26) @@ -1140,7 +1145,7 @@ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes } } """; - return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations); + return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations, consoleApplication: false); } [Fact] @@ -1169,7 +1174,7 @@ private static Type M() } """; - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations); + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false); } [Fact] @@ -1198,7 +1203,7 @@ private static Type M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes } """; - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations); + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations, consoleApplication: false); } [Fact] @@ -1229,7 +1234,7 @@ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes } """; - return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations); + return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations, consoleApplication: false); } [Fact] @@ -1257,7 +1262,7 @@ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes } """; - return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations); + return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations, consoleApplication: false); } [Fact] @@ -1278,7 +1283,7 @@ static void RequireAll([DynamicallyAccessedMembers(DynamicallyAccessedMemberType } """; - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (8,14): error CS0103: The name 'type' does not exist in the current context DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 14, 8, 18).WithArguments ("type")); } @@ -1302,7 +1307,7 @@ public static void Main() } """; - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (12,34): error CS0103: The name 'type' does not exist in the current context DiagnosticResult.CompilerError ("CS0103").WithSpan (12, 34, 12, 38).WithArguments ("type")); } @@ -1326,7 +1331,7 @@ public static void Main() } """; - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (8,22): error CS0103: The name 'type' does not exist in the current context DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 22, 8, 26).WithArguments ("type")); } @@ -1350,7 +1355,7 @@ public static void Main() } """; - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (8,9): error CS0103: The name 'type' does not exist in the current context DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 3, 8, 7).WithArguments ("type")); } @@ -1374,7 +1379,7 @@ public static void Main() } """; - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (8,3): error CS0103: The name 'type' does not exist in the current context DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 3, 8, 7).WithArguments ("type")); } @@ -1400,9 +1405,22 @@ class CRequires<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Publi """; // The actual usage (return value) should warn, about missing annotation, but the cref should not. - return VerifyDynamicallyAccessedMembersAnalyzer (Source, + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, // (11,9): warning IL2091: 'TInner' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in 'CRequires'. The generic parameter 'TOuter' of 'C' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter).WithSpan (11, 36, 11, 57).WithSpan (4, 9, 4, 15).WithArguments ("TInner", "CRequires", "TOuter", "C", "'DynamicallyAccessedMemberTypes.PublicMethods'")); } + + [Fact] + public Task MethodParameterWithoutLocationAnalysis () + { + // The implicit main method has parameters + var Source = """ + using System; + foreach (var arg in args) + Console.WriteLine (arg); + """; + + return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: true); + } } } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs index ecea646eb5696c..7b5e1e923bb477 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs @@ -22,10 +22,15 @@ static Task VerifyRequiresAssemblyFilesAnalyzer (string source, params Diagnosti return VerifyRequiresAssemblyFilesAnalyzer (source, null, expected); } - static async Task VerifyRequiresAssemblyFilesAnalyzer (string source, IEnumerable? additionalReferences, params DiagnosticResult[] expected) + static async Task VerifyRequiresAssemblyFilesAnalyzer ( + string source, + IEnumerable? additionalReferences, + params DiagnosticResult[] expected) { - await VerifyCS.VerifyAnalyzerAsync (source, + await VerifyCS.VerifyAnalyzerAsync ( + source, + consoleApplication: false, TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.EnableSingleFileAnalyzer), additionalReferences ?? Array.Empty (), expected); @@ -338,7 +343,7 @@ public void M() """; // If 'PublishSingleFile' is not set to true, no diagnostics should be produced by the analyzer. This will // effectively verify that the number of produced diagnostics matches the number of expected ones (zero). - return VerifyCS.VerifyAnalyzerAsync (src); + return VerifyCS.VerifyAnalyzerAsync (src, consoleApplication: false); } [Fact] diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index 12f839003297d5..77497b9b398d5d 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -23,7 +23,9 @@ static Task VerifyRequiresUnreferencedCodeAnalyzer (string source, params Diagno VerifyRequiresUnreferencedCodeAnalyzer (source, null, expected); static async Task VerifyRequiresUnreferencedCodeAnalyzer (string source, IEnumerable? additionalReferences, params DiagnosticResult[] expected) => - await VerifyCS.VerifyAnalyzerAsync (source, + await VerifyCS.VerifyAnalyzerAsync ( + source, + consoleApplication: false, TestCaseUtils.UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer), additionalReferences ?? Array.Empty (), expected); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs index e45d10a010754d..8b4473d8be10fb 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs @@ -24,14 +24,16 @@ internal static class TestCaseCompilation public static Task<(CompilationWithAnalyzers Compilation, SemanticModel SemanticModel, List ExceptionDiagnostics)> CreateCompilation ( string src, + bool consoleApplication, (string, string)[]? globalAnalyzerOptions = null, IEnumerable? additionalReferences = null, IEnumerable? additionalSources = null, IEnumerable? additionalFiles = null) - => CreateCompilation (CSharpSyntaxTree.ParseText (src), globalAnalyzerOptions, additionalReferences, additionalSources, additionalFiles); + => CreateCompilation (CSharpSyntaxTree.ParseText (src), consoleApplication, globalAnalyzerOptions, additionalReferences, additionalSources, additionalFiles); public static async Task<(CompilationWithAnalyzers Compilation, SemanticModel SemanticModel, List ExceptionDiagnostics)> CreateCompilation ( SyntaxTree src, + bool consoleApplication, (string, string)[]? globalAnalyzerOptions = null, IEnumerable? additionalReferences = null, IEnumerable? additionalSources = null, @@ -45,7 +47,7 @@ internal static class TestCaseCompilation assemblyName: Guid.NewGuid ().ToString ("N"), syntaxTrees: sources, references: (await TestCaseUtils.GetNet6References ()).Add (mdRef).AddRange (additionalReferences), - new CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary)); + new CSharpCompilationOptions (consoleApplication ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary)); var analyzerOptions = new AnalyzerOptions ( additionalFiles: additionalFiles?.ToImmutableArray () ?? ImmutableArray.Empty, new SimpleAnalyzerOptions (globalAnalyzerOptions)); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 76da0406184c65..c36c8645457393 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -74,6 +74,7 @@ public static async Task RunTestFile (string suiteName, string testName, bool al var (comp, model, exceptionDiagnostics) = await TestCaseCompilation.CreateCompilation ( tree, + consoleApplication: false, msbuildProperties, additionalSources: testDependenciesSource, additionalFiles: additionalFiles); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs index 32f60660d3fd7b..3256e8da7fbd56 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs @@ -39,9 +39,14 @@ public static DiagnosticResult Diagnostic (DiagnosticId diagnosticId) => CSharpAnalyzerVerifier.Diagnostic (DiagnosticDescriptors.GetDiagnosticDescriptor (diagnosticId)); /// - public static async Task VerifyAnalyzerAsync (string src, (string, string)[]? analyzerOptions = null, IEnumerable? additionalReferences = null, params DiagnosticResult[] expected) + public static async Task VerifyAnalyzerAsync ( + string src, + bool consoleApplication, + (string, string)[]? analyzerOptions = null, + IEnumerable? additionalReferences = null, + params DiagnosticResult[] expected) { - var (comp, _, exceptionDiagnostics) = await TestCaseCompilation.CreateCompilation (src, analyzerOptions, additionalReferences); + var (comp, _, exceptionDiagnostics) = await TestCaseCompilation.CreateCompilation (src, consoleApplication, analyzerOptions, additionalReferences); var diags = (await comp.GetAllDiagnosticsAsync ()).AddRange (exceptionDiagnostics); var analyzers = ImmutableArray.Create (new TAnalyzer ()); VerifyDiagnosticResults (diags, analyzers, expected, DefaultVerifier); diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs index d163a30ae44df6..33c9d178c699d2 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs @@ -54,8 +54,13 @@ public static DiagnosticResult Diagnostic (DiagnosticDescriptor descriptor) => CSharpAnalyzerVerifier.Diagnostic (descriptor); /// - public static Task VerifyAnalyzerAsync (string source, (string, string)[]? analyzerOptions = null, IEnumerable? additionalReferences = null, params DiagnosticResult[] expected) - => CSharpAnalyzerVerifier.VerifyAnalyzerAsync (source, analyzerOptions, additionalReferences, expected); + public static Task VerifyAnalyzerAsync ( + string source, + bool consoleApplication, + (string, string)[]? analyzerOptions = null, + IEnumerable? additionalReferences = null, + params DiagnosticResult[] expected) + => CSharpAnalyzerVerifier.VerifyAnalyzerAsync (source, consoleApplication, analyzerOptions, additionalReferences, expected); /// /// Verifies the analyzer provides diagnostics which, in combination with the code fix, produce the expected