diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 234b0fced096..80251a28e7ec 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,5 +7,6 @@ /src/analyzer/ @radekdoulik /src/ILLink.Tasks/ @sbomer +/src/ILLink.RoslynAnalyzer/ @sbomer /src/linker/ @marek-safar @mrvoorhe /test/ @marek-safar @mrvoorhe diff --git a/.gitignore b/.gitignore index 414ad0275bcc..d7f81b2c86c8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.user *.userprefs .vs/ +.vscode/ .idea/ packages/ @@ -36,4 +37,7 @@ bin/ artifacts *.binlog +# Emacs backup files +*~ + test/Mono.Linker.Tests/TestResults.xml diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 035206c8f3cf..b4c07c7ccef5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,18 +3,18 @@ - + https://github.com/dotnet/arcade - 0cdef445272ad6a7374dfed71496c5affef90305 + a7c57abb74deaee6dac921dd68f9c3c58059ebfb - + https://github.com/dotnet/arcade - 0cdef445272ad6a7374dfed71496c5affef90305 + a7c57abb74deaee6dac921dd68f9c3c58059ebfb - + https://github.com/dotnet/runtime - 9e795c014b0be513c84f96427c544bae486bb101 + d40f560efbf4f85ec6d59892a6c4bafa39f66d19 - 7.0.0-alpha.1.21524.4 + 7.0.0-alpha.1.21556.5 $(MicrosoftNETSdkILPackageVersion) 5.0.0 17.0.0-preview-21267-01 17.0.0-preview-21267-01 - 7.0.0-beta.21524.1 + 7.0.0-beta.21555.2 6.0.0-beta.21271.1 3.10.0-2.final 3.10.0-2.final diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index a4a92efbedf9..cd2181bafa05 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -134,17 +134,17 @@ $CountMissingSymbols = { # Save the output and get diagnostic output $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String - if (Test-Path $PdbPath) { - return 'PDB' + if ((Test-Path $PdbPath) -and (Test-path $SymbolPath)) { + return 'Module and PDB for Module' } - elseif (Test-Path $NGenPdb) { - return 'NGen PDB' + elseif ((Test-Path $NGenPdb) -and (Test-Path $PdbPath) -and (Test-Path $SymbolPath)) { + return 'Dll, PDB and NGen PDB' } - elseif (Test-Path $SODbg) { - return 'DBG for SO' + elseif ((Test-Path $SODbg) -and (Test-Path $SymbolPath)) { + return 'So and DBG for SO' } - elseif (Test-Path $DylibDwarf) { - return 'Dwarf for Dylib' + elseif ((Test-Path $DylibDwarf) -and (Test-Path $SymbolPath)) { + return 'Dylib and Dwarf for Dylib' } elseif (Test-Path $SymbolPath) { return 'Module' diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 69eb67849d74..3aafc82e4171 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -60,11 +60,7 @@ jobs: - name: GuardianPackagesConfigFile value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config pool: - # To extract archives (.tar.gz, .zip), we need access to "tar", added in Windows 10/2019. - ${{ if eq(parameters.extractArchiveArtifacts, 'false') }}: - name: Hosted VS2017 - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: - vmImage: windows-2019 + vmImage: windows-2019 steps: - checkout: self clean: true diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index e8bc77d2ebbe..c4fc18b3ee77 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -4,7 +4,7 @@ parameters: # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex GithubPat: $(BotAccount-dotnet-bot-repo-PAT) @@ -12,6 +12,7 @@ parameters: SourcesDirectory: $(Build.SourcesDirectory) CreatePr: true AutoCompletePr: false + ReusePr: true UseLfLineEndings: true UseCheckedInLocProjectJson: false LanguageSet: VS_Main_Languages @@ -64,6 +65,8 @@ jobs: ${{ if eq(parameters.CreatePr, true) }}: isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + isShouldReusePrSelected: ${{ parameters.ReusePr }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml index 5023d36dcb3c..5cd5325d7b4e 100644 --- a/eng/common/templates/job/source-build.yml +++ b/eng/common/templates/job/source-build.yml @@ -31,11 +31,6 @@ parameters: # container and pool. platform: {} - # The default VM host AzDO pool. This should be capable of running Docker containers: almost all - # source-build builds run in Docker, including the default managed platform. - defaultContainerHostPool: - vmImage: ubuntu-20.04 - jobs: - job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} displayName: Source-Build (${{ parameters.platform.name }}) @@ -47,7 +42,15 @@ jobs: container: ${{ parameters.platform.container }} ${{ if eq(parameters.platform.pool, '') }}: - pool: ${{ parameters.defaultContainerHostPool }} + # The default VM host AzDO pool. This should be capable of running Docker containers: almost all + # source-build builds run in Docker, including the default managed platform. + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore1ESPool-Public + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 ${{ if ne(parameters.platform.pool, '') }}: pool: ${{ parameters.platform.pool }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index 1cc0c29e4fda..4af724eb1a9e 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -5,8 +5,6 @@ parameters: sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog - pool: - vmImage: vs2017-win2016 condition: '' dependsOn: '' @@ -24,7 +22,13 @@ jobs: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - group: source-dot-net stage1 variables - pool: ${{ parameters.pool }} + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore1ESPool-Public + demands: ImageOverride -equals Build.Server.Amd64.VS2019.Open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - ${{ each preStep in parameters.preSteps }}: - ${{ preStep }} diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index a1f8fce96ca8..8dd1fdbd144a 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -83,7 +83,7 @@ jobs: - ${{ if eq(parameters.enableSourceBuild, true) }}: - Source_Build_Complete pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' runAsPublic: ${{ parameters.runAsPublic }} publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} @@ -96,4 +96,4 @@ jobs: dependsOn: - Asset_Registry_Publish pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' diff --git a/global.json b/global.json index 8f219016596b..50f0cd7d7670 100644 --- a/global.json +++ b/global.json @@ -3,8 +3,8 @@ "dotnet": "6.0.100-rc.1.21430.12" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21524.1", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21555.2", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21524.4" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21556.5" } } diff --git a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs index e066d24de29e..b17114687048 100644 --- a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs +++ b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs @@ -49,14 +49,6 @@ public static string GetDisplayName (this ISymbol symbol) { var sb = new StringBuilder (); switch (symbol) { - case IFieldSymbol fieldSymbol: - sb.Append (fieldSymbol.Type); - sb.Append (" "); - sb.Append (fieldSymbol.ContainingSymbol.ToDisplayString ()); - sb.Append ("::"); - sb.Append (fieldSymbol.MetadataName); - break; - case IParameterSymbol parameterSymbol: sb.Append (parameterSymbol.Name); break; @@ -93,5 +85,11 @@ public static bool IsSubclassOf (this ISymbol symbol, string ns, string type) return false; } + + public static bool IsConstructor ([NotNullWhen (returnValue: true)] this ISymbol? symbol) + => (symbol as IMethodSymbol)?.MethodKind == MethodKind.Constructor; + + public static bool IsStaticConstructor ([NotNullWhen (returnValue: true)] this ISymbol? symbol) + => (symbol as IMethodSymbol)?.MethodKind == MethodKind.StaticConstructor; } } diff --git a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs index 52e56217c468..c57a8aecd281 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs @@ -8,6 +8,7 @@ using ILLink.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; @@ -94,6 +95,11 @@ public override void Initialize (AnalysisContext context) } }, OperationKind.ObjectCreation); + context.RegisterOperationAction (operationContext => { + var fieldReference = (IFieldReferenceOperation) operationContext.Operation; + CheckCalledMember (operationContext, fieldReference.Field, incompatibleMembers); + }, OperationKind.FieldReference); + context.RegisterOperationAction (operationContext => { var propAccess = (IPropertyReferenceOperation) operationContext.Operation; var prop = propAccess.Property; @@ -111,13 +117,19 @@ public override void Initialize (AnalysisContext context) context.RegisterOperationAction (operationContext => { var eventRef = (IEventReferenceOperation) operationContext.Operation; var eventSymbol = (IEventSymbol) eventRef.Member; - CheckCalledMember (operationContext, eventSymbol, incompatibleMembers); + var assignmentOperation = eventRef.Parent as IEventAssignmentOperation; - if (eventSymbol.AddMethod is IMethodSymbol eventAddMethod) + if (assignmentOperation != null && assignmentOperation.Adds && eventSymbol.AddMethod is IMethodSymbol eventAddMethod) CheckCalledMember (operationContext, eventAddMethod, incompatibleMembers); - if (eventSymbol.RemoveMethod is IMethodSymbol eventRemoveMethod) + if (assignmentOperation != null && !assignmentOperation.Adds && eventSymbol.RemoveMethod is IMethodSymbol eventRemoveMethod) CheckCalledMember (operationContext, eventRemoveMethod, incompatibleMembers); + + if (eventSymbol.RaiseMethod is IMethodSymbol eventRaiseMethod) + CheckCalledMember (operationContext, eventRaiseMethod, incompatibleMembers); + + if (AnalyzerDiagnosticTargets.HasFlag (DiagnosticTargets.Event)) + CheckCalledMember (operationContext, eventSymbol, incompatibleMembers); }, OperationKind.EventReference); context.RegisterOperationAction (operationContext => { @@ -133,6 +145,51 @@ public override void Initialize (AnalysisContext context) CheckCalledMember (operationContext, methodSymbol, incompatibleMembers); }, OperationKind.DelegateCreation); + context.RegisterSyntaxNodeAction (syntaxNodeAnalysisContext => { + var model = syntaxNodeAnalysisContext.SemanticModel; + if (syntaxNodeAnalysisContext.ContainingSymbol is not ISymbol containingSymbol || containingSymbol.HasAttribute (RequiresAttributeName)) + return; + + GenericNameSyntax genericNameSyntaxNode = (GenericNameSyntax) syntaxNodeAnalysisContext.Node; + var typeParams = ImmutableArray.Empty; + var typeArgs = ImmutableArray.Empty; + switch (model.GetSymbolInfo (genericNameSyntaxNode).Symbol) { + case INamedTypeSymbol typeSymbol: + typeParams = typeSymbol.TypeParameters; + typeArgs = typeSymbol.TypeArguments; + break; + + case IMethodSymbol methodSymbol: + typeParams = methodSymbol.TypeParameters; + typeArgs = methodSymbol.TypeArguments; + break; + + default: + return; + } + + for (int i = 0; i < typeParams.Length; i++) { + var typeParam = typeParams[i]; + var typeArg = typeArgs[i]; + if (!typeParam.HasConstructorConstraint) + continue; + + var typeArgCtors = ((INamedTypeSymbol) typeArg).InstanceConstructors; + foreach (var instanceCtor in typeArgCtors) { + if (instanceCtor.Arity > 0) + continue; + + if (instanceCtor.TryGetAttribute (RequiresAttributeName, out var requiresUnreferencedCodeAttribute)) { + syntaxNodeAnalysisContext.ReportDiagnostic (Diagnostic.Create (RequiresDiagnosticRule, + syntaxNodeAnalysisContext.Node.GetLocation (), + containingSymbol.GetDisplayName (), + (string) requiresUnreferencedCodeAttribute.ConstructorArguments[0].Value!, + GetUrlFromAttribute (requiresUnreferencedCodeAttribute))); + } + } + } + }, SyntaxKind.GenericName); + // Register any extra operation actions supported by the analyzer. foreach (var extraOperationAction in ExtraOperationActions) context.RegisterOperationAction (extraOperationAction.Action, extraOperationAction.OperationKind); @@ -163,34 +220,20 @@ void CheckCalledMember ( ISymbol containingSymbol = FindContainingSymbol (operationContext, AnalyzerDiagnosticTargets); // Do not emit any diagnostic if caller is annotated with the attribute too. - if (containingSymbol.HasAttribute (RequiresAttributeName)) - return; - - // Check also for RequiresAttribute in the associated symbol - if (containingSymbol is IMethodSymbol methodSymbol && methodSymbol.AssociatedSymbol is not null && methodSymbol.AssociatedSymbol!.HasAttribute (RequiresAttributeName)) + if (IsMemberInRequiresScope (containingSymbol)) return; if (ReportSpecialIncompatibleMembersDiagnostic (operationContext, incompatibleMembers, member)) return; - if (!member.HasAttribute (RequiresAttributeName)) - return; - // Warn on the most derived base method taking into account covariant returns while (member is IMethodSymbol method && method.OverriddenMethod != null && SymbolEqualityComparer.Default.Equals (method.ReturnType, method.OverriddenMethod.ReturnType)) member = method.OverriddenMethod; - if (TryGetRequiresAttribute (member, out var requiresAttribute)) { - if (member is IMethodSymbol eventAccessorMethod && eventAccessorMethod.AssociatedSymbol is IEventSymbol eventSymbol) { - // If the annotated member is an event accessor, we warn on the event to match the linker behavior. - member = eventAccessorMethod.ContainingSymbol; - operationContext.ReportDiagnostic (Diagnostic.Create (RequiresDiagnosticRule, - eventSymbol.Locations[0], member.Name, GetMessageFromAttribute (requiresAttribute), GetUrlFromAttribute (requiresAttribute))); - return; - } + if (!TargetHasRequiresAttribute (member, out var requiresAttribute)) + return; - ReportRequiresDiagnostic (operationContext, member, requiresAttribute); - } + ReportRequiresDiagnostic (operationContext, member, requiresAttribute); } void CheckMatchingAttributesInOverrides ( @@ -228,7 +271,8 @@ protected enum DiagnosticTargets Property = 0x0002, Field = 0x0004, Event = 0x0008, - All = MethodOrConstructor | Property | Field | Event + Class = 0x0010, + All = MethodOrConstructor | Property | Field | Event | Class } /// @@ -293,6 +337,46 @@ private void ReportMismatchInAttributesDiagnostic (SymbolAnalysisContext symbolA private bool HasMismatchingAttributes (ISymbol member1, ISymbol member2) => member1.HasAttribute (RequiresAttributeName) ^ member2.HasAttribute (RequiresAttributeName); + // TODO: Consider sharing with linker IsMethodInRequiresUnreferencedCodeScope method + /// + /// True if the source of a call is considered to be annotated with the Requires... attribute + /// + protected bool IsMemberInRequiresScope (ISymbol containingSymbol) + { + if (containingSymbol.HasAttribute (RequiresAttributeName) || + containingSymbol.ContainingType.HasAttribute (RequiresAttributeName)) { + return true; + } + + // Check also for RequiresAttribute in the associated symbol + if (containingSymbol is IMethodSymbol { AssociatedSymbol: { } associated } && associated.HasAttribute (RequiresAttributeName)) + return true; + + return false; + } + + // TODO: Consider sharing with linker DoesMethodRequireUnreferencedCode method + /// + /// True if the target of a call is considered to be annotated with the Requires... attribute + /// + protected bool TargetHasRequiresAttribute (ISymbol member, [NotNullWhen (returnValue: true)] out AttributeData? requiresAttribute) + { + requiresAttribute = null; + if (member.IsStaticConstructor ()) { + return false; + } + + if (TryGetRequiresAttribute (member, out requiresAttribute)) { + return true; + } + + // Also check the containing type + if (member.IsStatic || member.IsConstructor ()) { + return TryGetRequiresAttribute (member.ContainingType, out requiresAttribute); + } + return false; + } + protected abstract string GetMessageFromAttribute (AttributeData requiresAttribute); public static string GetUrlFromAttribute (AttributeData? requiresAttribute) diff --git a/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs index 146eef0642fc..f2e14ff60575 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs @@ -24,9 +24,9 @@ public sealed class RequiresAssemblyFilesAnalyzer : RequiresAnalyzerBase static readonly DiagnosticDescriptor s_requiresAssemblyFilesRule = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssemblyFiles, helpLinkUri: "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/il3002"); - static readonly DiagnosticDescriptor s_requiresAssembyFilesAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssembyFilesAttributeMismatch); + static readonly DiagnosticDescriptor s_requiresAssemblyFilesAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssemblyFilesAttributeMismatch); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_locationRule, s_getFilesRule, s_requiresAssemblyFilesRule, s_requiresAssembyFilesAttributeMismatch); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_locationRule, s_getFilesRule, s_requiresAssemblyFilesRule, s_requiresAssemblyFilesAttributeMismatch); private protected override string RequiresAttributeName => RequiresAssemblyFilesAttribute; @@ -36,7 +36,7 @@ public sealed class RequiresAssemblyFilesAnalyzer : RequiresAnalyzerBase private protected override DiagnosticDescriptor RequiresDiagnosticRule => s_requiresAssemblyFilesRule; - private protected override DiagnosticDescriptor RequiresAttributeMismatch => s_requiresAssembyFilesAttributeMismatch; + private protected override DiagnosticDescriptor RequiresAttributeMismatch => s_requiresAssemblyFilesAttributeMismatch; protected override bool IsAnalyzerEnabled (AnalyzerOptions options, Compilation compilation) { diff --git a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs index b9a3764589a8..7e4f7e5a291d 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs @@ -3,11 +3,8 @@ using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using ILLink.Shared; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace ILLink.RoslynAnalyzer @@ -35,56 +32,6 @@ public sealed class RequiresUnreferencedCodeAnalyzer : RequiresAnalyzerBase operationContext.Operation.Syntax.GetLocation ())); }; - [SuppressMessage ("MicrosoftCodeAnalysisPerformance", "RS1008", - Justification = "Storing per-compilation data inside a diagnostic analyzer might cause stale compilations to remain alive." + - "This action is registered through a compilation start action, so that instances that register this syntax" + - " node action will not outlive a compilation's lifetime, avoiding the possibility of the locals stored in" + - " this function to cause for any stale compilations to remain in memory.")] - static readonly Action s_constructorConstraint = syntaxNodeAnalysisContext => { - var model = syntaxNodeAnalysisContext.SemanticModel; - if (syntaxNodeAnalysisContext.ContainingSymbol is not ISymbol containingSymbol || containingSymbol.HasAttribute (RequiresUnreferencedCodeAttribute)) - return; - - GenericNameSyntax genericNameSyntaxNode = (GenericNameSyntax) syntaxNodeAnalysisContext.Node; - var typeParams = ImmutableArray.Empty; - var typeArgs = ImmutableArray.Empty; - switch (model.GetSymbolInfo (genericNameSyntaxNode).Symbol) { - case INamedTypeSymbol typeSymbol: - typeParams = typeSymbol.TypeParameters; - typeArgs = typeSymbol.TypeArguments; - break; - - case IMethodSymbol methodSymbol: - typeParams = methodSymbol.TypeParameters; - typeArgs = methodSymbol.TypeArguments; - break; - - default: - return; - } - - for (int i = 0; i < typeParams.Length; i++) { - var typeParam = typeParams[i]; - var typeArg = typeArgs[i]; - if (!typeParam.HasConstructorConstraint) - continue; - - var typeArgCtors = ((INamedTypeSymbol) typeArg).InstanceConstructors; - foreach (var instanceCtor in typeArgCtors) { - if (instanceCtor.Arity > 0) - continue; - - if (instanceCtor.TryGetAttribute (RequiresUnreferencedCodeAttribute, out var requiresUnreferencedCodeAttribute)) { - syntaxNodeAnalysisContext.ReportDiagnostic (Diagnostic.Create (s_requiresUnreferencedCodeRule, - syntaxNodeAnalysisContext.Node.GetLocation (), - containingSymbol.GetDisplayName (), - (string) requiresUnreferencedCodeAttribute.ConstructorArguments[0].Value!, - GetUrlFromAttribute (requiresUnreferencedCodeAttribute))); - } - } - } - }; - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_dynamicTypeInvocationRule, s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch); @@ -92,7 +39,7 @@ public sealed class RequiresUnreferencedCodeAnalyzer : RequiresAnalyzerBase private protected override string RequiresAttributeFullyQualifiedName => FullyQualifiedRequiresUnreferencedCodeAttribute; - private protected override DiagnosticTargets AnalyzerDiagnosticTargets => DiagnosticTargets.MethodOrConstructor; + private protected override DiagnosticTargets AnalyzerDiagnosticTargets => DiagnosticTargets.MethodOrConstructor | DiagnosticTargets.Class; private protected override DiagnosticDescriptor RequiresDiagnosticRule => s_requiresUnreferencedCodeRule; @@ -133,9 +80,6 @@ protected override bool ReportSpecialIncompatibleMembersDiagnostic (OperationAna private protected override ImmutableArray<(Action Action, OperationKind[] OperationKind)> ExtraOperationActions => ImmutableArray.Create ((s_dynamicTypeInvocation, new OperationKind[] { OperationKind.DynamicInvocation })); - private protected override ImmutableArray<(Action Action, SyntaxKind[] SyntaxKind)> ExtraSyntaxNodeActions => - ImmutableArray.Create ((s_constructorConstraint, new SyntaxKind[] { SyntaxKind.GenericName })); - protected override bool VerifyAttributeArguments (AttributeData attribute) => attribute.ConstructorArguments.Length >= 1 && attribute.ConstructorArguments[0] is { Type: { SpecialType: SpecialType.System_String } } ctorArg; diff --git a/src/ILLink.Shared/DiagnosticId.cs b/src/ILLink.Shared/DiagnosticId.cs index 6720edbc4054..8fe4fc2fe5ae 100644 --- a/src/ILLink.Shared/DiagnosticId.cs +++ b/src/ILLink.Shared/DiagnosticId.cs @@ -14,7 +14,7 @@ public enum DiagnosticId AvoidAssemblyLocationInSingleFile = 3000, AvoidAssemblyGetFilesInSingleFile = 3001, RequiresAssemblyFiles = 3002, - RequiresAssembyFilesAttributeMismatch = 3003 + RequiresAssemblyFilesAttributeMismatch = 3003 } public static class DiagnosticIdExtensions diff --git a/src/ILLink.Shared/SharedStrings.resx b/src/ILLink.Shared/SharedStrings.resx index 807f96a88f08..36ce24594b8a 100644 --- a/src/ILLink.Shared/SharedStrings.resx +++ b/src/ILLink.Shared/SharedStrings.resx @@ -147,6 +147,12 @@ 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + {0}. 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + + + 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + Base member '{2}' with '{0}' has a derived member '{1}' without '{0}' diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs index 2c52424d55b8..46db485f56bd 100644 --- a/src/linker/Linker/Driver.cs +++ b/src/linker/Linker/Driver.cs @@ -763,7 +763,7 @@ protected int SetupContext (ILogger? customLogger = null) // to the error code. // May propagate exceptions, which will result in the process getting an // exit code determined by dotnet. - public int Run (ILogger? customLogger = null) + public int Run (ILogger? customLogger = null, bool throwOnFatalLinkerException = false) { int setupStatus = SetupContext (customLogger); if (setupStatus > 0) @@ -782,6 +782,8 @@ public int Run (ILogger? customLogger = null) Debug.Assert (lex.MessageContainer.Category == MessageCategory.Error); Debug.Assert (lex.MessageContainer.Code != null); Debug.Assert (lex.MessageContainer.Code.Value != 0); + if (throwOnFatalLinkerException) + throw; return lex.MessageContainer.Code ?? 1; } catch (ResolutionException e) { Context.LogError ($"{e.Message}", 1040); diff --git a/src/linker/Linker/MethodReferenceExtensions.cs b/src/linker/Linker/MethodReferenceExtensions.cs index e9272fdb7b6d..569a9df5b3c5 100644 --- a/src/linker/Linker/MethodReferenceExtensions.cs +++ b/src/linker/Linker/MethodReferenceExtensions.cs @@ -23,6 +23,20 @@ public static string GetDisplayName (this MethodReference method) return sb.ToString (); } + if (methodDefinition != null && methodDefinition.IsEventMethod ()) { + // Append event name + string name = methodDefinition.SemanticsAttributes switch { + MethodSemanticsAttributes.AddOn => string.Concat (methodDefinition.Name.AsSpan (4), ".add"), + MethodSemanticsAttributes.RemoveOn => string.Concat (methodDefinition.Name.AsSpan (7), ".remove"), + MethodSemanticsAttributes.Fire => string.Concat (methodDefinition.Name.AsSpan (6), ".raise"), + _ => throw new NotSupportedException (), + }; + sb.Append (name); + // Insert declaring type name and namespace + sb.Insert (0, '.').Insert (0, method.DeclaringType.GetDisplayName ()); + return sb.ToString (); + } + // Append parameters sb.Append ("("); if (method.HasParameters) { diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs new file mode 100644 index 000000000000..7545840f04ee --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.InternalCalls +{ + public sealed class ComTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/InternalCalls/Com"; + + [Fact] + public Task DefaultConstructorOfParameterIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfParameterAreRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfReturnTypeAreRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfThisAreRemoved () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs new file mode 100644 index 000000000000..58e8ed443ea3 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs @@ -0,0 +1,47 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop +{ + public sealed class InternalCallsTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/InternalCalls"; + + [Fact] + public Task UnusedDefaultConstructorIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesWhenHasThisAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs new file mode 100644 index 000000000000..a07563ec983f --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public sealed class ComTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Com"; + + [Fact] + public Task DefaultConstructorOfParameterIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfParameterAreRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfReturnTypeAreRemoved () + { + return RunTest (); + } + + [Fact] + public Task FieldsOfThisAreRemoved () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs new file mode 100644 index 000000000000..04e393753919 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs @@ -0,0 +1,17 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public class IndividualTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Individual"; + + [Fact] + public Task CanOutputPInvokes () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs new file mode 100644 index 000000000000..7ee4ae899a91 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs @@ -0,0 +1,48 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop +{ + public sealed class PInvokeTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke"; + + + [Fact] + public Task UnusedDefaultConstructorIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedPInvoke () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs new file mode 100644 index 000000000000..a3a1a3f1d2ec --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs @@ -0,0 +1,17 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public sealed class WarningsTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Warnings"; + + [Fact] + public Task ComPInvokeWarning () + { + return RunTest (); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs new file mode 100644 index 000000000000..1a382693ea61 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs @@ -0,0 +1,20 @@ + +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public abstract class LinkerTestBase : TestCaseUtils + { + protected abstract string TestSuiteName { get; } + + private static readonly (string, string)[] MSBuildProperties = UseMSBuildProperties ( + MSBuildPropertyOptionNames.EnableTrimAnalyzer, + MSBuildPropertyOptionNames.EnableSingleFileAnalyzer); + + protected Task RunTest ([CallerMemberName] string testName = "") + { + return RunTestFile (TestSuiteName, testName, MSBuildProperties); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs deleted file mode 100644 index fed1cbfe6fb9..000000000000 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Xunit; - -namespace ILLink.RoslynAnalyzer.Tests -{ - /// - /// Test cases stored in files - /// - public class LinkerTestCases : TestCaseUtils - { - [Theory] - [MemberData (nameof (TestCaseUtils.GetTestData), parameters: nameof (RequiresCapability))] - public void RequiresCapability (string m) - { - RunTest (nameof (RequiresCapability), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer)); - } - - [Theory] - [MemberData (nameof (TestCaseUtils.GetTestData), parameters: nameof (Interop))] - public void Interop (string m) - { - RunTest (nameof (Interop), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer)); - } - } -} diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs index a4bdc5be5a82..7e27f278251e 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs @@ -77,29 +77,6 @@ void M() VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (12, 17, 12, 18).WithArguments ("C.E", "", "")); } - [Fact] - public Task SimpleDiagnosticOnMethod () - { - var TestRequiresAssemblyFilesOnMethod = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresAssemblyFiles] - void M1() - { - } - - void M2() - { - M1(); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesOnMethod, - // (13,3): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (13, 3, 13, 7).WithArguments ("C.M1()", "", "")); - } - [Fact] public Task SimpleDiagnosticOnProperty () { @@ -159,29 +136,6 @@ void M () VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (24, 3, 24, 4).WithArguments ("C.P", "", "")); } - [Fact] - public Task RequiresAssemblyFilesWithMessageAndUrl () - { - var TestRequiresAssemblyFilesWithMessageAndUrl = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresAssemblyFiles (""Message from attribute"", Url = ""https://helpurl"")] - void M1() - { - } - - void M2() - { - M1(); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesWithMessageAndUrl, - // (13,3): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. Message from attribute. https://helpurl - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (13, 3, 13, 7).WithArguments ("C.M1()", " Message from attribute.", " https://helpurl")); - } - [Fact] public Task RequiresAssemblyFilesWithUrlOnly () { @@ -394,53 +348,6 @@ public void M() return VerifyRequiresAssemblyFilesAnalyzer (src); } - [Fact] - public Task LazyDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - public static Lazy _default = new Lazy(InitC); - public static C Default => _default.Value; - - [RequiresAssemblyFiles] - public static C InitC() { - C cObject = new C(); - return cObject; - } -}"; - - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,50): warning IL3002: Using member 'C.InitC()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (6, 50, 6, 55).WithArguments ("C.InitC()", "", "")); - } - - [Fact] - public Task ActionDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresAssemblyFiles] - public static void M1() { } - public static void M2() - { - Action a = M1; - Action b = () => M1(); - } -}"; - - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (10,20): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (10, 20, 10, 22).WithArguments ("C.M1()", "", ""), - // (11,26): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (11, 26, 11, 30).WithArguments ("C.M1()", "", "")); - } - [Fact] public Task RequiresAssemblyFilesDiagnosticFix () { @@ -767,467 +674,5 @@ public event EventHandler E1 }, fixedExpected: Array.Empty ()); } - - [Fact] - public Task TestStaticCctorRequiresAssemblyFiles () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtor -{ - [RequiresAssemblyFiles (""Message for --TestStaticCtor--"")] - static StaticCtor () - { - } - - static void TestStaticCctorRequiresUnreferencedCode () - { - _ = new StaticCtor (); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src); - } - - [Fact] - public Task StaticCtorTriggeredByFieldAccess () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByFieldAccess -{ - public static int field; - - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByFieldAccess.Cctor--"")] - static StaticCtorTriggeredByFieldAccess () - { - field = 0; - } -} -class C -{ - static void TestStaticCtorMarkingIsTriggeredByFieldAccess () - { - var x = StaticCtorTriggeredByFieldAccess.field + 1; - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src); - } - - [Fact] - public Task TestStaticCtorTriggeredByMethodCall () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByMethodCall -{ - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByMethodCall.Cctor--"")] - static StaticCtorTriggeredByMethodCall () - { - } - - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--"")] - public void TriggerStaticCtorMarking () - { - } -} - -class C -{ - static void TestStaticCtorTriggeredByMethodCall () - { - new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (21,3): warning IL3002: Using member 'StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (21, 3, 21, 69).WithArguments ("StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()", " Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--.", "") - ); - } - - [Fact] - public Task OverrideHasAttributeButBaseDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - [RequiresAssemblyFiles] - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualPropertyWithAnnotationInAccesor - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - [RequiresAssemblyFiles] - public override string VirtualPropertyWithAnnotationInProperty { get; set; } -} - -class BaseClass -{ - public virtual void VirtualMethod () - { - } - - public virtual string VirtualPropertyWithAnnotationInAccesor { get; set; } - - public virtual string VirtualPropertyWithAnnotationInProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (7,23): warning IL3003: Member 'DerivedClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 23, 7, 36).WithArguments ("Member 'DerivedClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'"), - // (15,3): warning IL3003: Member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (15, 3, 15, 6).WithArguments ("Member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'"), - // (20,25): warning IL3003: Member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (20, 25, 20, 64).WithArguments ("Member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task VirtualHasAttributeButOverrideDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualPropertyWithAnnotationInAccesor - { - get { return name; } - set { name = value; } - } - - public override string VirtualPropertyWithAnnotationInProperty { get; set; } -} - -class BaseClass -{ - [RequiresAssemblyFiles] - public virtual void VirtualMethod () - { - } - - public virtual string VirtualPropertyWithAnnotationInAccesor {[RequiresAssemblyFiles] get; set; } - - [RequiresAssemblyFiles] - public virtual string VirtualPropertyWithAnnotationInProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,23): warning IL3003: Base member 'BaseClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (6, 23, 6, 36).WithArguments ("Base member 'BaseClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'"), - // (17,25): warning IL3003: Base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (17, 25, 17, 64).WithArguments ("Base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task ImplementationHasAttributeButInterfaceDoesnt () - { - // Once the interface has the attributes indicated in the warnings we would have warnings for AnotherImplementation. - // In the meantime AnotherImplementation doesn't generate a warning - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresAssemblyFiles] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class ExplicitImplementation : IRAF -{ - [RequiresAssemblyFiles] - void IRAF.Method() { } - - private string name; - string IRAF.StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - int IRAF.NumProperty - { - get { return num; } - set { num = value; } - } -} - -interface IRAF -{ - void Method(); - string StringProperty { get; set; } - int NumProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (7,14): warning IL3003: Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (19,13): warning IL3003: Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (19, 13, 19, 24).WithArguments ("Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (48,12): warning IL3003: Member 'ExplicitImplementation.IRAF.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (48, 12, 48, 18).WithArguments ("Member 'ExplicitImplementation.IRAF.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (54,3): warning IL3003: Member 'ExplicitImplementation.IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (54, 3, 54, 6).WithArguments ("Member 'ExplicitImplementation.IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (60,11): warning IL3003: Member 'ExplicitImplementation.IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (60, 11, 60, 22).WithArguments ("Member 'ExplicitImplementation.IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task InterfaceHasAttributeButImplementationDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -interface IRAF -{ - [RequiresAssemblyFiles] - void Method(); - string StringProperty { [RequiresAssemblyFiles] get; set; } - [RequiresAssemblyFiles] - int NumProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (6, 14, 6, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (11,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (11, 3, 11, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (16,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (16, 13, 16, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (25,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (25, 14, 25, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (30,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (30, 3, 30, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (35,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (35, 13, 35, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnSource () - { - var references = @" -using System.Diagnostics.CodeAnalysis; - -public interface IRAF -{ - [RequiresAssemblyFiles] - void Method(); - string StringProperty { [RequiresAssemblyFiles] get; set; } - [RequiresAssemblyFiles] - int NumProperty { get; set; } -}"; - - var src = @" -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresAssemblyFilesAnalyzer (src, additionalReferences: new[] { compilation }, - // (4,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (4, 14, 4, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (9,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (9, 3, 9, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (14,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (14, 13, 14, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (23,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (23, 14, 23, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (28,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (28, 3, 28, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (33,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (33, 13, 33, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnReference () - { - var references = @" -public interface IRAF -{ - void Method(); - string StringProperty { get; set; } - int NumProperty { get; set; } -}"; - - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresAssemblyFiles] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresAssemblyFilesAnalyzer (src, additionalReferences: new[] { compilation }, - // (7,14): warning IL3003: Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (19,13): warning IL3003: Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (19, 13, 19, 24).WithArguments ("Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs new file mode 100644 index 000000000000..6dba8bc956f3 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public sealed class RequiresCapabilityTests : LinkerTestBase + { + protected override string TestSuiteName => "RequiresCapability"; + + [Fact] + public Task RequiresCapability () + { + return RunTest (nameof (RequiresCapability)); + } + + [Fact] + public Task RequiresCapabilityFromCopiedAssembly () + { + return RunTest (nameof (RequiresCapabilityFromCopiedAssembly)); + } + + [Fact] + public Task RequiresCapabilityReflectionAnalysisEnabled () + { + return RunTest (nameof (RequiresCapabilityReflectionAnalysisEnabled)); + } + + [Fact] + public Task RequiresInCompilerGeneratedCode () + { + return RunTest (nameof (RequiresInCompilerGeneratedCode)); + } + + [Fact] + public Task RequiresOnAttributeCtor () + { + return RunTest (nameof (RequiresOnAttributeCtor)); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index 9cb7d89957ba..b54b65f8e90e 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -54,22 +54,7 @@ static Task VerifyRequiresUnreferencedCodeCodeFix ( return test.RunAsync (); } - [Fact] - public Task SimpleDiagnostic () - { - var TestRequiresWithMessageOnlyOnMethod = @" -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresUnreferencedCodeAttribute(""message"")] - int M1() => 0; - int M2() => M1(); -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (TestRequiresWithMessageOnlyOnMethod, - // (8,17): warning IL2026: Using member 'C.M1()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. message. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 17, 8, 21).WithArguments ("C.M1()", " message.", "")); - } [Fact] public async Task SimpleDiagnosticFix () @@ -321,541 +306,6 @@ public class C }); } - [Fact] - public Task TestRequiresWithMessageAndUrlOnMethod () - { - var MessageAndUrlOnMethod = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresWithMessageAndUrlOnMethod () - { - RequiresWithMessageAndUrl (); - } - [RequiresUnreferencedCode (""Message for --RequiresWithMessageAndUrl--"", Url = ""https://helpurl"")] - static void RequiresWithMessageAndUrl () - { - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (MessageAndUrlOnMethod, - // (8,3): warning IL2026: Using member 'C.RequiresWithMessageAndUrl()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --RequiresWithMessageAndUrl--. https://helpurl - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 3, 8, 31).WithArguments ("C.RequiresWithMessageAndUrl()", " Message for --RequiresWithMessageAndUrl--.", " https://helpurl") - ); - } - - [Fact] - public Task TestTrailingPeriodsOnWarningMessageAreNotDupplicated () - { - var source = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresUnreferencedCode (""Warning message"")] - static void MessageWithoutTrailingPeriod () - { - } - - [RequiresUnreferencedCode (""Warning message."")] - static void MessageWithTrailingPeriod () - { - } - - static void Test () - { - MessageWithoutTrailingPeriod (); - MessageWithTrailingPeriod (); - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (source, - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (18, 3, 18, 34).WithArguments ("C.MessageWithoutTrailingPeriod()", " Warning message.", string.Empty), - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (19, 3, 19, 31).WithArguments ("C.MessageWithTrailingPeriod()", " Warning message.", string.Empty)); - } - - [Fact] - public Task TestRequiresOnPropertyGetter () - { - var PropertyRequires = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresOnPropertyGetter () - { - _ = PropertyRequires; - } - - static int PropertyRequires { - [RequiresUnreferencedCode (""Message for --getter PropertyRequires--"")] - get { return 42; } - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,7): warning IL2026: Using member 'C.PropertyRequires.get' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --getter PropertyRequires--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 7, 8, 23).WithArguments ("C.PropertyRequires.get", " Message for --getter PropertyRequires--.", "") - ); - } - - [Fact] - public Task TestRequiresOnPropertySetter () - { - var PropertyRequires = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresOnPropertySetter () - { - PropertyRequires = 0; - } - - static int PropertyRequires { - [RequiresUnreferencedCode (""Message for --setter PropertyRequires--"")] - set { } - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,3): warning IL2026: Using member 'C.PropertyRequires.set' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --setter PropertyRequires--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 3, 8, 19).WithArguments ("C.PropertyRequires.set", " Message for --setter PropertyRequires--.", "") - ); - } - - [Fact] - public Task TestStaticCctorRequiresUnreferencedCode () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtor -{ - [RequiresUnreferencedCode (""Message for --TestStaticCtor--"")] - static StaticCtor () - { - } - - static void TestStaticCctorRequiresUnreferencedCode () - { - _ = new StaticCtor (); - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src); - } - - [Fact] - public Task StaticCtorTriggeredByFieldAccess () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByFieldAccess -{ - public static int field; - - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByFieldAccess.Cctor--"")] - static StaticCtorTriggeredByFieldAccess () - { - field = 0; - } -} -class C -{ - static void TestStaticCtorMarkingIsTriggeredByFieldAccess () - { - var x = StaticCtorTriggeredByFieldAccess.field + 1; - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src); - } - - [Fact] - public Task TestStaticCtorTriggeredByMethodCall () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByMethodCall -{ - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByMethodCall.Cctor--"")] - static StaticCtorTriggeredByMethodCall () - { - } - - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--"")] - public void TriggerStaticCtorMarking () - { - } -} - -class C -{ - static void TestStaticCtorTriggeredByMethodCall () - { - new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (21,3): warning IL2026: Using member 'StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (21, 3, 21, 69).WithArguments ("StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()", " Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--.", "") - ); - } - - [Fact] - public Task TypeIsBeforeFieldInit () - { - var TypeIsBeforeFieldInit = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - class TypeIsBeforeFieldInit - { - public static int field = AnnotatedMethod (); - - [RequiresUnreferencedCode (""Message from --TypeIsBeforeFieldInit.AnnotatedMethod--"")] - public static int AnnotatedMethod () => 42; - } - - static void TestTypeIsBeforeFieldInit () - { - var x = TypeIsBeforeFieldInit.field + 42; - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (TypeIsBeforeFieldInit, - // (8,29): warning IL2026: Using member 'C.TypeIsBeforeFieldInit.AnnotatedMethod()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --TypeIsBeforeFieldInit.AnnotatedMethod--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 29, 8, 47).WithArguments ("C.TypeIsBeforeFieldInit.AnnotatedMethod()", " Message from --TypeIsBeforeFieldInit.AnnotatedMethod--.", "") - ); - } - - [Fact] - public Task LazyDelegateWithRequiresUnreferencedCode () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - public static Lazy _default = new Lazy(InitC); - public static C Default => _default.Value; - - [RequiresUnreferencedCode (""Message from --C.InitC--"")] - public static C InitC() { - C cObject = new C(); - return cObject; - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (6,50): warning IL2026: Using member 'C.InitC()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.InitC--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (6, 50, 6, 55).WithArguments ("C.InitC()", " Message from --C.InitC--.", "")); - } - - [Fact] - public Task ActionDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresUnreferencedCode (""Message from --C.M1--"")] - public static void M1() { } - public static void M2() - { - Action a = M1; - Action b = () => M1(); - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (10,20): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.M1--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (10, 20, 10, 22).WithArguments ("C.M1()", " Message from --C.M1--.", ""), - // (11,26): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.M1--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (11, 26, 11, 30).WithArguments ("C.M1()", " Message from --C.M1--.", "")); - } - - [Fact] - public Task OverrideHasAttributeButBaseDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - [RequiresUnreferencedCode(""Message"")] - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualProperty - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -class BaseClass -{ - public virtual void VirtualMethod () - { - } - - public virtual string VirtualProperty { get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (7,23): warning IL2046: Member 'DerivedClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 23, 7, 36).WithArguments ("Member 'DerivedClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'"), - // (15,3): warning IL2046: Member 'DerivedClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (15, 3, 15, 6).WithArguments ("Member 'DerivedClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task VirtualHasAttributeButOverrideDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualProperty - { - get { return name; } - set { name = value; } - } -} - -class BaseClass -{ - [RequiresUnreferencedCode(""Message"")] - public virtual void VirtualMethod () - { - } - - public virtual string VirtualProperty {[RequiresUnreferencedCode(""Message"")] get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (13,3): warning IL2046: Base member 'BaseClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Base member 'BaseClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'"), - // (6,23): warning IL2046: Base member 'BaseClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (6, 23, 6, 36).WithArguments ("Base member 'BaseClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task ImplementationHasAttributeButInterfaceDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRUC -{ - [RequiresUnreferencedCode(""Message"")] - public void RUC () { } - - private string name; - public string Property - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -class ExplicitImplementation : IRUC -{ - [RequiresUnreferencedCode(""Message"")] - void IRUC.RUC() { } - - private string name; - string IRUC.Property - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -interface IRUC -{ - void RUC(); - string Property { get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (7,14): warning IL2046: Member 'Implementation.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 14, 7, 17).WithArguments ("Member 'Implementation.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (13,3): warning IL2046: Member 'Implementation.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'"), - // (33,12): warning IL2046: Member 'ExplicitImplementation.IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (33, 12, 33, 15).WithArguments ("Member 'ExplicitImplementation.IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (39,3): warning IL2046: Member 'ExplicitImplementation.IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (39, 3, 39, 6).WithArguments ("Member 'ExplicitImplementation.IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task InterfaceHasAttributeButImplementationDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -interface IRUC -{ - [RequiresUnreferencedCode(""Message"")] - void RUC(); - string Property {[RequiresUnreferencedCode(""Message"")] get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (6,14): warning IL2046: Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (6, 14, 6, 17).WithArguments ("Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (11,3): warning IL2046: Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (11, 3, 11, 6).WithArguments ("Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Property.get' without 'RequiresUnreferencedCodeAttribute'"), - // (18,14): warning IL2046: Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (18, 14, 18, 17).WithArguments ("Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (23,3): warning IL2046: Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (23, 3, 23, 6).WithArguments ("Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Property.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnSource () - { - var references = @" -using System.Diagnostics.CodeAnalysis; - -public interface IRAF -{ - [RequiresUnreferencedCode (""Message"")] - void Method(); - string StringProperty { [RequiresUnreferencedCode (""Message"")] get; set; } -}"; - - var src = @" -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresUnreferencedCodeAnalyzer (src, additionalReferences: new[] { compilation }, - // (4,14): warning IL2046: Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (4, 14, 4, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (16,14): warning IL2046: Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (16, 14, 16, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (9,3): warning IL2046: Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (9, 3, 9, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'"), - // (21,3): warning IL2046: Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (21, 3, 21, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnReference () - { - var references = @" -public interface IRAF -{ - void Method(); - string StringProperty { get; set; } -}"; - - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresUnreferencedCode (""Message"")] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresUnreferencedCode (""Message"")] - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresUnreferencedCodeAnalyzer (src, additionalReferences: new[] { compilation }, - // (7,14): warning IL2046: Member 'Implementation.Method()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (13,3): warning IL2046: Member 'Implementation.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - [Fact] public Task InvocationOnDynamicType () { diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs index f35bdbe21061..0f35b908a51c 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs @@ -28,34 +28,28 @@ public TestCase (MemberDeclarationSyntax memberSyntax, IEnumerable CSharpSyntaxTree.ParseText (File.ReadAllText (testDependency))); - var test = new TestChecker ( - MemberSyntax, - TestCaseCompilation.CreateCompilation ( - testSyntaxTree, - MSBuildProperties, - additionalSources: testDependenciesSource).Result); - + var test = new TestChecker (MemberSyntax, compAndModel); test.ValidateAttributes (Attributes); } - private static IEnumerable GetTestDependencies (SyntaxTree testSyntaxTree) + public static IEnumerable GetTestDependencies (SyntaxTree testSyntaxTree) { - TestCaseUtils.GetDirectoryPaths (out var rootSourceDir, out _); + LinkerTestBase.GetDirectoryPaths (out var rootSourceDir, out _); foreach (var attribute in testSyntaxTree.GetRoot ().DescendantNodes ().OfType ()) { if (attribute.Name.ToString () != "SetupCompileBefore") continue; var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType ().Single ().Name.ToString (); var testSuiteName = testNamespace.Substring (testNamespace.LastIndexOf ('.') + 1); - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType ()) - yield return Path.Combine (rootSourceDir, testSuiteName, TestCaseUtils.GetStringFromExpression (sourceFile)); + yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index d4d359a36bcb..44881437d341 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; @@ -13,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace ILLink.RoslynAnalyzer.Tests @@ -38,49 +40,33 @@ public async static ValueTask> GetNet6Referenc return s_net6Refs; } - public static IEnumerable GetTestData (string testSuiteName) - => s_testCases[testSuiteName].Keys.Select (testName => new object[] { testName }); - - public static void RunTest (string suiteName, string testName, params (string, string)[] MSBuildProperties) - { - s_testCases[suiteName][testName].Run (MSBuildProperties); - } - - private static readonly Dictionary> s_testCases = InitializeTestCases (); - - private static Dictionary> InitializeTestCases () + public static async Task RunTestFile (string suiteName, string testName, params (string, string)[] msbuildProperties) { - var testCases = new Dictionary> (); - foreach (var file in GetTestFiles ()) { - // Some tests are in nested directories. Walk up until we get the test suite directory. - string directory = Path.GetDirectoryName (file)!; - string parentDirectory; - while (Path.GetFileName (parentDirectory = Path.GetDirectoryName (directory)!) != MonoLinkerTestsCases) - directory = parentDirectory; - string suiteName = Path.GetFileName (directory); - - if (!testCases.TryGetValue (suiteName, out var suiteTestCases)) { - suiteTestCases = new (); - testCases.Add (suiteName, suiteTestCases); - } - - foreach (var testCase in BuildTestCasesForFile (file)) { - var canditateTestName = GetMemberSyntaxFullName (testCase.MemberSyntax); - string testName = canditateTestName; - int index = 0; - while (!suiteTestCases.TryAdd (testName, testCase)) { - testName = canditateTestName + "#" + (++index).ToString (); - } - - testCase.Name = testName; - } + GetDirectoryPaths (out string rootSourceDir, out string testAssemblyPath); + Debug.Assert (Path.GetFileName (rootSourceDir) == MonoLinkerTestsCases); + var testPath = Path.Combine (rootSourceDir, suiteName, $"{testName}.cs"); + Assert.True (File.Exists (testPath)); + var tree = SyntaxFactory.ParseSyntaxTree ( + SourceText.From (File.OpenRead (testPath), Encoding.UTF8), + path: testPath); + + var testDependenciesSource = TestCase.GetTestDependencies (tree) + .Select (f => SyntaxFactory.ParseSyntaxTree (SourceText.From (File.OpenRead (f)))); + var comp = await TestCaseCompilation.CreateCompilation ( + tree, + msbuildProperties, + additionalSources: testDependenciesSource); + foreach (var testCase in BuildTestCasesForTree (tree)) { + testCase.Run (comp); } - return testCases; } - private static IEnumerable BuildTestCasesForFile (string testFile) + /// + /// Builds a for each member in the tree. + /// + private static IEnumerable BuildTestCasesForTree (SyntaxTree tree) { - var root = CSharpSyntaxTree.ParseText (File.ReadAllText (testFile)).GetRoot (); + var root = tree.GetRoot (); foreach (var node in root.DescendantNodes ()) { if (node is MemberDeclarationSyntax m) { var attrs = m.AttributeLists.SelectMany (al => al.Attributes.Where (IsWellKnown)).ToList (); @@ -180,26 +166,6 @@ public static Dictionary GetAttributeArguments (Attrib return arguments; } - public static IEnumerable GetTestFiles () - { - GetDirectoryPaths (out var rootSourceDir, out _); - foreach (var subDir in Directory.EnumerateDirectories (rootSourceDir, "*", SearchOption.AllDirectories)) { - var subDirName = Path.GetFileName (subDir); - switch (subDirName) { - case "bin": - case "obj": - case "Properties": - case "Dependencies": - case "Individual": - continue; - } - - foreach (var file in Directory.EnumerateFiles (subDir, "*.cs")) { - yield return file; - } - } - } - public static (string, string)[] UseMSBuildProperties (params string[] MSBuildProperties) { return MSBuildProperties.Select (msbp => ($"build_property.{msbp}", "true")).ToArray (); @@ -211,30 +177,5 @@ public static string GetRepoRoot () string ThisFile ([CallerFilePath] string path = "") => path; } - - public static string GetMemberSyntaxFullName (MemberDeclarationSyntax member) - { - StringBuilder fullName = new (); - var parent = member.Parent; - while (parent is ClassDeclarationSyntax parentClass) { - fullName.Insert (0, "."); - fullName.Insert (0, parentClass.Identifier.ToString ()); - parent = parentClass.Parent; - } - - fullName.Append (GetMemberSyntaxName (member)); - return fullName.ToString (); - } - - public static string GetMemberSyntaxName (MemberDeclarationSyntax member) => - member switch { - MethodDeclarationSyntax method => method.Identifier.ToString (), - PropertyDeclarationSyntax property => property.Identifier.ToString (), - FieldDeclarationSyntax field => field.Declaration.Variables.Single ().Identifier.ToString (), - EventDeclarationSyntax @event => @event.Identifier.ToString (), - ClassDeclarationSyntax @class => @class.Identifier.ToString (), - ConstructorDeclarationSyntax ctor => ctor.Modifiers.Any (t => t.Text == "static") ? ".cctor" : ".ctor", - _ => "UnknownMember" - }; } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 995825152888..5da895fce8a9 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -68,7 +68,7 @@ bool IsExpectedDiagnostic (AttributeSyntax attribute) switch (attribute.Name.ToString ()) { case "ExpectedWarning": case "LogContains": - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); if (args.TryGetValue ("ProducedBy", out var producedBy)) { // Skip if this warning is not expected to be produced by any of the analyzers that we are currently testing. return GetProducedBy (producedBy).HasFlag (ProducedBy.Analyzer); @@ -154,15 +154,15 @@ private bool TryValidateExpectedWarningAttribute (AttributeSyntax attribute, Lis { missingDiagnosticMessage = null; matchIndex = null; - var args = TestCaseUtils.GetAttributeArguments (attribute); - string expectedWarningCode = TestCaseUtils.GetStringFromExpression (args["#0"]); + var args = LinkerTestBase.GetAttributeArguments (attribute); + string expectedWarningCode = LinkerTestBase.GetStringFromExpression (args["#0"]); if (!expectedWarningCode.StartsWith ("IL")) throw new InvalidOperationException ($"Expected warning code should start with \"IL\" prefix."); List expectedMessages = args .Where (arg => arg.Key.StartsWith ("#") && arg.Key != "#0") - .Select (arg => TestCaseUtils.GetStringFromExpression (arg.Value, SemanticModel)) + .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, SemanticModel)) .ToList (); for (int i = 0; i < diagnostics.Count; i++) { @@ -172,7 +172,7 @@ private bool TryValidateExpectedWarningAttribute (AttributeSyntax attribute, Lis } } - missingDiagnosticMessage = $"Expected to find warning containing:{string.Join (" ", expectedMessages.Select (m => "'" + m + "'"))}" + + missingDiagnosticMessage = $"Warning '{expectedWarningCode}'. Expected to find warning containing:{string.Join (" ", expectedMessages.Select (m => "'" + m + "'"))}" + $", but no such message was found.{ Environment.NewLine}"; return false; @@ -193,8 +193,8 @@ private bool TryValidateLogContainsAttribute (AttributeSyntax attribute, List: :' @@ -224,8 +224,8 @@ private bool TryValidateLogContainsAttribute (AttributeSyntax attribute, List diagnosticMessages) { - var arg = Assert.Single (TestCaseUtils.GetAttributeArguments (attribute)); - var text = TestCaseUtils.GetStringFromExpression (arg.Value); + var arg = Assert.Single (LinkerTestBase.GetAttributeArguments (attribute)); + var text = LinkerTestBase.GetStringFromExpression (arg.Value); foreach (var diagnostic in DiagnosticMessages) Assert.DoesNotContain (text, diagnostic.GetMessage ()); } @@ -234,21 +234,21 @@ private bool TryValidateUnrecognizedReflectionAccessPatternAttribute (AttributeS { missingDiagnosticMessage = null; matchIndex = null; - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); MemberDeclarationSyntax sourceMember = attribute.Ancestors ().OfType ().First (); if (SemanticModel.GetDeclaredSymbol (sourceMember) is not ISymbol memberSymbol) return false; string sourceMemberName = memberSymbol!.GetDisplayName (); - string expectedReflectionMemberMethodType = TestCaseUtils.GetStringFromExpression (args["#0"], SemanticModel); - string expectedReflectionMemberMethodName = TestCaseUtils.GetStringFromExpression (args["#1"], SemanticModel); + string expectedReflectionMemberMethodType = LinkerTestBase.GetStringFromExpression (args["#0"], SemanticModel); + string expectedReflectionMemberMethodName = LinkerTestBase.GetStringFromExpression (args["#1"], SemanticModel); var reflectionMethodParameters = new List (); if (args.TryGetValue ("#2", out var reflectionMethodParametersExpr) || args.TryGetValue ("reflectionMethodParameters", out reflectionMethodParametersExpr)) { if (reflectionMethodParametersExpr is ArrayCreationExpressionSyntax arrayReflectionMethodParametersExpr) { foreach (var rmp in arrayReflectionMethodParametersExpr.Initializer!.Expressions) - reflectionMethodParameters.Add (TestCaseUtils.GetStringFromExpression (rmp, SemanticModel)); + reflectionMethodParameters.Add (LinkerTestBase.GetStringFromExpression (rmp, SemanticModel)); } } @@ -256,13 +256,13 @@ private bool TryValidateUnrecognizedReflectionAccessPatternAttribute (AttributeS if (args.TryGetValue ("#3", out var messageExpr) || args.TryGetValue ("message", out messageExpr)) { if (messageExpr is ArrayCreationExpressionSyntax arrayMessageExpr) { foreach (var m in arrayMessageExpr.Initializer!.Expressions) - expectedStringsInMessage.Add (TestCaseUtils.GetStringFromExpression (m, SemanticModel)); + expectedStringsInMessage.Add (LinkerTestBase.GetStringFromExpression (m, SemanticModel)); } } string expectedWarningCode = string.Empty; if (args.TryGetValue ("#4", out var messageCodeExpr) || args.TryGetValue ("messageCode", out messageCodeExpr)) { - expectedWarningCode = TestCaseUtils.GetStringFromExpression (messageCodeExpr); + expectedWarningCode = LinkerTestBase.GetStringFromExpression (messageCodeExpr); Assert.True (expectedWarningCode.StartsWith ("IL"), $"The warning code specified in {messageCodeExpr.ToString ()} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'"); } diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs index fe054761b823..934512ce5881 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs @@ -14,6 +14,10 @@ public LogContainsAttribute (string message, bool regexMatch = false) throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAndAnalyzer; } } \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs index 599908cfb430..2cd8667ed22e 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs @@ -13,5 +13,11 @@ public LogDoesNotContainAttribute (string message, bool regexMatch = false) if (string.IsNullOrEmpty (message)) throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } + + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// + public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAndAnalyzer; } } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs new file mode 100644 index 000000000000..e30fd271c457 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies +{ + public class ReferenceInterfaces + { + public interface IBaseWithRequiresInReference + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public void Method (); + + public string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithoutRequiresInReference + { + public void Method (); + + public string PropertyAnnotationInAccesor { + get; + set; + } + + public string PropertyAnnotationInProperty { get; set; } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs index 74cdff268d28..c121ff4ef6ae 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs @@ -15,24 +15,29 @@ public RequiresInCopyAssembly () } [RequiresUnreferencedCode ("Message for --Method--")] + [RequiresAssemblyFiles ("Message for --Method--")] public void Method () { } [RequiresUnreferencedCode ("Message for --UncalledMethod--")] + [RequiresAssemblyFiles ("Message for --UncalledMethod--")] public void UncalledMethod () { } [RequiresUnreferencedCode ("Message for --MethodCalledThroughReflection--")] + [RequiresAssemblyFiles ("Message for --MethodCalledThroughReflection--")] static void MethodCalledThroughReflection () { } public int UnusedProperty { [RequiresUnreferencedCode ("Message for --getter UnusedProperty--")] + [RequiresAssemblyFiles ("Message for --getter UnusedProperty--")] get { return 42; } + [RequiresAssemblyFiles ("Message for --setter UnusedProperty--")] [RequiresUnreferencedCode ("Message for --setter UnusedProperty--")] set { } } @@ -40,16 +45,19 @@ public int UnusedProperty { class UnusedBaseType { [RequiresUnreferencedCode ("Message for --UnusedBaseTypeCctor--")] + [RequiresAssemblyFiles ("Message for --UnusedBaseTypeCctor--")] static UnusedBaseType () { } [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod1--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod1--")] public virtual void UnusedVirtualMethod1 () { } [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod2--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod2--")] public virtual void UnusedVirtualMethod2 () { } @@ -58,6 +66,7 @@ public virtual void UnusedVirtualMethod2 () class UnusedDerivedType : UnusedBaseType { [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod1--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod1--")] public override void UnusedVirtualMethod1 () { } @@ -71,12 +80,14 @@ public override void UnusedVirtualMethod2 () interface IUnusedInterface { [RequiresUnreferencedCode ("Message for --IUnusedInterface.UnusedMethod--")] + [RequiresAssemblyFiles ("Message for --IUnusedInterface.UnusedMethod--")] public void UnusedMethod (); } class UnusedImplementationClass : IUnusedInterface { [RequiresUnreferencedCode ("Message for --UnusedImplementationClass.UnusedMethod--")] + [RequiresAssemblyFiles ("Message for --UnusedImplementationClass.UnusedMethod--")] public void UnusedMethod () { } @@ -85,12 +96,14 @@ public void UnusedMethod () public interface IBaseInterface { [RequiresUnreferencedCode ("Message for --IBaseInterface.MethodInBaseInterface--")] + [RequiresAssemblyFiles ("Message for --IBaseInterface.MethodInBaseInterface--")] void MethodInBaseInterface (); } public interface IDerivedInterface : IBaseInterface { [RequiresUnreferencedCode ("Message for --IDerivedInterface.MethodInDerivedInterface--")] + [RequiresAssemblyFiles ("Message for --IDerivedInterface.MethodInDerivedInterface--")] void MethodInDerivedInterface (); } } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs index f6b21bca68db..40814d2e676f 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs @@ -19,6 +19,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [SetupLinkerAction ("copy", "lib")] [SetupCompileBefore ("lib.dll", new[] { "Dependencies/RequiresInCopyAssembly.cs" })] [KeptAllTypesAndMembersInAssembly ("lib.dll")] + [SetupLinkerAction ("copy", "lib2")] + [SetupCompileBefore ("lib2.dll", new[] { "Dependencies/ReferenceInterfaces.cs" })] + [KeptAllTypesAndMembersInAssembly ("lib2.dll")] [SetupLinkAttributesFile ("RequiresCapability.attributes.xml")] [SetupLinkerDescriptorFile ("RequiresCapability.descriptor.xml")] [SkipKeptItemsValidation] @@ -82,32 +85,38 @@ public static void Main () AccessThroughNewConstraint.TestNewConstraintOnTypeParameter (); AccessThroughNewConstraint.TestNewConstraintOnTypeParameterOfStaticType (); AccessThroughLdToken.Test (); + AttributeMismatch.Test (); RequiresOnClass.Test (); } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageOnly--.")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageOnly--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresWithMessageOnlyOnMethod () { RequiresWithMessageOnly (); } [RequiresUnreferencedCode ("Message for --RequiresWithMessageOnly--")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageOnly--")] static void RequiresWithMessageOnly () { } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresWithMessageAndUrlOnMethod () { RequiresWithMessageAndUrl (); } [RequiresUnreferencedCode ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] static void RequiresWithMessageAndUrl () { } [ExpectedWarning ("IL2026", "Message for --ConstructorRequires--.")] + [ExpectedWarning ("IL3002", "Message for --ConstructorRequires--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresOnConstructor () { new ConstructorRequires (); @@ -116,6 +125,7 @@ static void TestRequiresOnConstructor () class ConstructorRequires { [RequiresUnreferencedCode ("Message for --ConstructorRequires--")] + [RequiresAssemblyFiles ("Message for --ConstructorRequires--")] public ConstructorRequires () { } @@ -123,6 +133,8 @@ public ConstructorRequires () [ExpectedWarning ("IL2026", "Message for --getter PropertyRequires--.")] [ExpectedWarning ("IL2026", "Message for --setter PropertyRequires--.")] + [ExpectedWarning ("IL3002", "Message for --getter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3002", "Message for --setter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresOnPropertyGetterAndSetter () { _ = PropertyRequires; @@ -131,9 +143,11 @@ static void TestRequiresOnPropertyGetterAndSetter () static int PropertyRequires { [RequiresUnreferencedCode ("Message for --getter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --getter PropertyRequires--")] get { return 42; } [RequiresUnreferencedCode ("Message for --setter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --setter PropertyRequires--")] set { } } @@ -144,6 +158,7 @@ class SuppressMethodBodyReferences static Type GetUnknownType () => null; [RequiresUnreferencedCode ("Message for --MethodWithRequires--")] + [RequiresAssemblyFiles ("Message for --MethodWithRequires--")] static void MethodWithRequires () { } @@ -152,6 +167,7 @@ static void MethodWithRequires () static Type _requiresPublicConstructors; [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMethodWithRequires () { // Normally this would warn, but with the attribute on this method it should be auto-suppressed @@ -159,24 +175,28 @@ static void TestMethodWithRequires () } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestParameter () { _unknownType.RequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestReturnValue () { GetUnknownType ().RequiresPublicEvents (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestField () { _requiresPublicConstructors = _unknownType; } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestMethodWithRequires (); @@ -196,36 +216,42 @@ class SuppressGenericParameters { } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericMethod () { GenericMethodRequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericMethodMismatch () { GenericMethodRequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericType () { new GenericTypeRequiresPublicFields (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericTypeWithStaticTypes () { typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (typeof (TUnknown)); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericTypeWithDynamicTypes () { typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (_unknownType); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericMethod () { typeof (SuppressGenericParameters) @@ -234,6 +260,7 @@ static void TestMakeGenericMethod () } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestGenericMethod (); @@ -292,6 +319,7 @@ public static void Test () class BaseType { [RequiresUnreferencedCode ("Message for --BaseType.VirtualMethodRequires--")] + [RequiresAssemblyFiles ("Message for --BaseType.VirtualMethodRequires--")] public virtual void VirtualMethodRequires () { } @@ -300,12 +328,14 @@ public virtual void VirtualMethodRequires () class TypeWhichOverridesMethod : BaseType { [RequiresUnreferencedCode ("Message for --TypeWhichOverridesMethod.VirtualMethodRequires--")] + [RequiresAssemblyFiles ("Message for --TypeWhichOverridesMethod.VirtualMethodRequires--")] public override void VirtualMethodRequires () { } } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestBaseTypeVirtualMethodRequires () { var tmp = new BaseType (); @@ -314,6 +344,7 @@ static void TestBaseTypeVirtualMethodRequires () [LogDoesNotContain ("TypeWhichOverridesMethod.VirtualMethodRequires")] [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesMethodVirtualMethodRequires () { var tmp = new TypeWhichOverridesMethod (); @@ -322,6 +353,7 @@ static void TestTypeWhichOverridesMethodVirtualMethodRequires () [LogDoesNotContain ("TypeWhichOverridesMethod.VirtualMethodRequires")] [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesMethodVirtualMethodRequiresOnBase () { BaseType tmp = new TypeWhichOverridesMethod (); @@ -330,19 +362,25 @@ static void TestTypeWhichOverridesMethodVirtualMethodRequiresOnBase () class PropertyBaseType { - public virtual int VirtualPropertyRequires { [RequiresUnreferencedCode ("Message for --PropertyBaseType.VirtualPropertyRequires--")] get; } + public virtual int VirtualPropertyRequires { + [RequiresUnreferencedCode ("Message for --PropertyBaseType.VirtualPropertyRequires--")] + [RequiresAssemblyFiles ("Message for --PropertyBaseType.VirtualPropertyRequires--")] + get; + } } class TypeWhichOverridesProperty : PropertyBaseType { public override int VirtualPropertyRequires { [RequiresUnreferencedCode ("Message for --TypeWhichOverridesProperty.VirtualPropertyRequires--")] + [RequiresAssemblyFiles ("Message for --TypeWhichOverridesProperty.VirtualPropertyRequires--")] get { return 1; } } } [LogDoesNotContain ("TypeWhichOverridesProperty.VirtualPropertyRequires")] [ExpectedWarning ("IL2026", "--PropertyBaseType.VirtualPropertyRequires--")] + [ExpectedWarning ("IL3002", "--PropertyBaseType.VirtualPropertyRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesVirtualPropertyRequires () { var tmp = new TypeWhichOverridesProperty (); @@ -382,6 +420,8 @@ static void TestStaticCtorMarkingIsTriggeredByFieldAccess () struct StaticCCtorForFieldAccess { + // TODO: Analyzer still allows RUC/RAF on static constructor with no warning + // https://github.com/dotnet/linker/issues/2347 [ExpectedWarning ("IL2116", "StaticCCtorForFieldAccess..cctor()", ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Message for --StaticCCtorForFieldAccess.cctor--")] static StaticCCtorForFieldAccess () { } @@ -397,9 +437,11 @@ static void TestStaticCtorMarkingIsTriggeredByFieldAccessOnExplicitLayout () class TypeIsBeforeFieldInit { [ExpectedWarning ("IL2026", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3002", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = ProducedBy.Analyzer)] public static int field = AnnotatedMethod (); [RequiresUnreferencedCode ("Message from --TypeIsBeforeFieldInit.AnnotatedMethod--")] + [RequiresAssemblyFiles ("Message from --TypeIsBeforeFieldInit.AnnotatedMethod--")] public static int AnnotatedMethod () => 42; } @@ -416,19 +458,24 @@ static void TestTypeIsBeforeFieldInit () class StaticCtorTriggeredByMethodCall { + // TODO: Analyzer still allows RUC/RAF on static constructor with no warning + // https://github.com/dotnet/linker/issues/2347 [ExpectedWarning ("IL2116", "StaticCtorTriggeredByMethodCall..cctor()", ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] + [RequiresAssemblyFiles ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] static StaticCtorTriggeredByMethodCall () { } [RequiresUnreferencedCode ("Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] + [RequiresAssemblyFiles ("Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] public void TriggerStaticCtorMarking () { } } [ExpectedWarning ("IL2026", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] + [ExpectedWarning ("IL3002", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", ProducedBy = ProducedBy.Analyzer)] static void TestStaticCtorTriggeredByMethodCall () { new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); @@ -449,6 +496,7 @@ static void TestDynamicallyAccessedMembersWithRequires ( [LogDoesNotContain ("ImplementationClass.MethodWithRequires")] [ExpectedWarning ("IL2026", "--IRequires.MethodWithRequires--")] + [ExpectedWarning ("IL3002", "--IRequires.MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestInterfaceMethodWithRequires () { IRequires inst = new ImplementationClass (); @@ -461,12 +509,14 @@ class DerivedReturnType : BaseReturnType { } interface IRequires { [RequiresUnreferencedCode ("Message for --IRequires.MethodWithRequires--")] + [RequiresAssemblyFiles ("Message for --IRequires.MethodWithRequires--")] public void MethodWithRequires (); } class ImplementationClass : IRequires { [RequiresUnreferencedCode ("Message for --ImplementationClass.RequiresMethod--")] + [RequiresAssemblyFiles ("Message for --ImplementationClass.RequiresMethod--")] public void MethodWithRequires () { } @@ -475,12 +525,14 @@ public void MethodWithRequires () abstract class CovariantReturnBase { [RequiresUnreferencedCode ("Message for --CovariantReturnBase.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnBase.GetRequires--")] public abstract BaseReturnType GetRequires (); } class CovariantReturnDerived : CovariantReturnBase { [RequiresUnreferencedCode ("Message for --CovariantReturnDerived.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnDerived.GetRequires--")] public override DerivedReturnType GetRequires () { return null; @@ -489,6 +541,7 @@ public override DerivedReturnType GetRequires () [LogDoesNotContain ("--CovariantReturnBase.GetRequires--")] [ExpectedWarning ("IL2026", "--CovariantReturnDerived.GetRequires--")] + [ExpectedWarning ("IL3002", "--CovariantReturnDerived.GetRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCovariantReturnCallOnDerived () { var tmp = new CovariantReturnDerived (); @@ -496,6 +549,7 @@ static void TestCovariantReturnCallOnDerived () } [ExpectedWarning ("IL2026", "--Method--")] + [ExpectedWarning ("IL3002", "--Method--", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresInMethodFromCopiedAssembly () { var tmp = new RequiresInCopyAssembly (); @@ -516,11 +570,13 @@ static void TestRequiresInDynamicallyAccessedMethodFromCopiedAssembly ( } [RequiresUnreferencedCode ("Message for --RequiresInDynamicDependency--")] + [RequiresAssemblyFiles ("Message for --RequiresInDynamicDependency--")] static void RequiresInDynamicDependency () { } [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--")] + [ExpectedWarning ("IL3002", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Analyzer)] [DynamicDependency ("RequiresInDynamicDependency")] static void TestRequiresInDynamicDependency () { @@ -528,22 +584,27 @@ static void TestRequiresInDynamicDependency () } [RequiresUnreferencedCode ("Linker adds a trailing period to this message")] + [RequiresAssemblyFiles ("Linker adds a trailing period to this message")] static void WarningMessageWithoutEndingPeriod () { } [ExpectedWarning ("IL2026", "Linker adds a trailing period to this message.")] + [ExpectedWarning ("IL3002", "Linker adds a trailing period to this message.", ProducedBy = ProducedBy.Analyzer)] static void TestThatTrailingPeriodIsAddedToMessage () { WarningMessageWithoutEndingPeriod (); } [RequiresUnreferencedCode ("Linker does not add a period to this message.")] + [RequiresAssemblyFiles ("Linker does not add a period to this message.")] static void WarningMessageEndsWithPeriod () { } + [LogDoesNotContain ("Linker does not add a period to this message..")] [ExpectedWarning ("IL2026", "Linker does not add a period to this message.")] + [ExpectedWarning ("IL3002", "Linker does not add a period to this message.", ProducedBy = ProducedBy.Analyzer)] static void TestThatTrailingPeriodIsNotDuplicatedInWarningMessage () { WarningMessageEndsWithPeriod (); @@ -570,6 +631,7 @@ class RequiresOnAttribute class AttributeWhichRequiresAttribute : Attribute { [RequiresUnreferencedCode ("Message for --AttributeWhichRequiresAttribute.ctor--")] + [RequiresAssemblyFiles ("Message for --AttributeWhichRequiresAttribute.ctor--")] public AttributeWhichRequiresAttribute () { } @@ -585,17 +647,20 @@ public bool PropertyWhichRequires { get => false; [RequiresUnreferencedCode ("--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [RequiresAssemblyFiles ("--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] set { } } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] class GenericTypeWithAttributedParameter<[AttributeWhichRequires] T> { public static void TestMethod () { } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] static void GenericMethodWithAttributedParameter<[AttributeWhichRequires] T> () { } static void TestRequiresOnAttributeOnGenericParameter () @@ -605,7 +670,9 @@ static void TestRequiresOnAttributeOnGenericParameter () } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] class TypeWithAttributeWhichRequires @@ -613,19 +680,25 @@ class TypeWithAttributeWhichRequires } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static void MethodWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static int _fieldWithAttributeWhichRequires; [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static bool PropertyWithAttributeWhichRequires { get; set; } @@ -633,9 +706,11 @@ static void MethodWithAttributeWhichRequires () { } [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] [RequiresUnreferencedCode ("--MethodWhichRequiresWithAttributeWhichRequires--")] + [RequiresAssemblyFiles ("--MethodWhichRequiresWithAttributeWhichRequires--")] static void MethodWhichRequiresWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--MethodWhichRequiresWithAttributeWhichRequires--")] + [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestMethodWhichRequiresWithAttributeWhichRequires () { MethodWhichRequiresWithAttributeWhichRequires (); @@ -662,10 +737,12 @@ class RequiresOnGenerics class GenericWithStaticMethod { [RequiresUnreferencedCode ("Message for --GenericTypeWithStaticMethodWhichRequires--")] + [RequiresAssemblyFiles ("Message for --GenericTypeWithStaticMethodWhichRequires--")] public static void GenericTypeWithStaticMethodWhichRequires () { } } [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--")] + [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)] public static void GenericTypeWithStaticMethodViaLdftn () { var _ = new Action (GenericWithStaticMethod.GenericTypeWithStaticMethodWhichRequires); @@ -682,12 +759,14 @@ class CovariantReturnViaLdftn abstract class Base { [RequiresUnreferencedCode ("Message for --CovariantReturnViaLdftn.Base.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnViaLdftn.Base.GetRequires--")] public abstract BaseReturnType GetRequires (); } class Derived : Base { [RequiresUnreferencedCode ("Message for --CovariantReturnViaLdftn.Derived.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnViaLdftn.Derived.GetRequires--")] public override DerivedReturnType GetRequires () { return null; @@ -695,6 +774,7 @@ public override DerivedReturnType GetRequires () } [ExpectedWarning ("IL2026", "--CovariantReturnViaLdftn.Derived.GetRequires--")] + [ExpectedWarning ("IL3002", "--CovariantReturnViaLdftn.Derived.GetRequires--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { var tmp = new Derived (); @@ -744,24 +824,30 @@ public static void Test () class OnEventMethod { - [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--")] + [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Trimmer)] static event EventHandler EventToTestRemove { add { } [RequiresUnreferencedCode ("Message for --EventToTestRemove.remove--")] + [RequiresAssemblyFiles ("Message for --EventToTestRemove.remove--")] remove { } } - [ExpectedWarning ("IL2026", "--EventToTestAdd.add--")] + [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Trimmer)] static event EventHandler EventToTestAdd { [RequiresUnreferencedCode ("Message for --EventToTestAdd.add--")] + [RequiresAssemblyFiles ("Message for --EventToTestAdd.add--")] add { } remove { } } + [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--")] + [ExpectedWarning ("IL3002", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2026", "--EventToTestAdd.add--")] + [ExpectedWarning ("IL3002", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { - EventToTestRemove += (sender, e) => { }; - EventToTestAdd -= (sender, e) => { }; + EventToTestRemove -= (sender, e) => { }; + EventToTestAdd += (sender, e) => { }; } } @@ -770,12 +856,14 @@ class AccessThroughNewConstraint class NewConstraintTestType { [RequiresUnreferencedCode ("Message for --NewConstraintTestType.ctor--")] + [RequiresAssemblyFiles ("Message for --NewConstraintTestType.ctor--")] public NewConstraintTestType () { } } static void GenericMethod () where T : new() { } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { GenericMethod (); @@ -791,12 +879,14 @@ public static void DoNothing () { } } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void TestNewConstraintOnTypeParameter () { _ = new NewConstaintOnTypeParameter (); } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void TestNewConstraintOnTypeParameterOfStaticType () { NewConstraintOnTypeParameterOfStaticType.DoNothing (); @@ -807,18 +897,283 @@ class AccessThroughLdToken { static bool PropertyWithLdToken { [RequiresUnreferencedCode ("Message for --PropertyWithLdToken.get--")] + [RequiresAssemblyFiles ("Message for --PropertyWithLdToken.get--")] get { return false; } } [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--")] + [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { Expression> getter = () => PropertyWithLdToken; } } + class AttributeMismatch + { + static void RequirePublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + + class BaseClassWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + } + + class BaseClassWithoutRequires + { + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { get; set; } + + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithRequires : BaseClassWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithoutRequires : BaseClassWithRequires + { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + void Method (); + + string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + string PropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithoutRequires + { + void Method (); + + string PropertyAnnotationInAccesor { get; set; } + + string PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ExplicitImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithoutRequires.Method () + { + } + + private string name; + string IBaseWithoutRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithoutRequires.PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithoutRequires : IBaseWithRequires + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ExplicitImplementationClassWithoutRequires : IBaseWithRequires + { + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.Method()")] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithRequires.Method () + { + } + + private string name; + string IBaseWithRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithRequires.PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithoutRequiresInSource : ReferenceInterfaces.IBaseWithRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty", "IBaseWithRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithRequiresInSource : ReferenceInterfaces.IBaseWithoutRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Trimmer)] + public static void Test () + { + RequirePublicMethods (typeof (BaseClassWithRequires)); + RequirePublicMethods (typeof (BaseClassWithoutRequires)); + RequirePublicMethods (typeof (DerivedClassWithRequires)); + RequirePublicMethods (typeof (DerivedClassWithoutRequires)); + RequirePublicMethods (typeof (IBaseWithRequires)); + RequirePublicMethods (typeof (IBaseWithoutRequires)); + RequirePublicMethods (typeof (ImplementationClassWithRequires)); + RequirePublicMethods (typeof (ImplementationClassWithoutRequires)); + RequirePublicMethods (typeof (ExplicitImplementationClassWithRequires)); + RequirePublicMethods (typeof (ExplicitImplementationClassWithoutRequires)); + RequirePublicMethods (typeof (ImplementationClassWithoutRequiresInSource)); + RequirePublicMethods (typeof (ImplementationClassWithRequiresInSource)); + } + } + class RequiresOnClass { [RequiresUnreferencedCode ("Message for --ClassWithRequires--")] @@ -924,7 +1279,7 @@ static StaticCtor () } } - [ExpectedWarning ("IL2026", "RequiresOnClass.StaticCtor.StaticCtor()", "Message for --StaticCtor--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.StaticCtor.StaticCtor()", "Message for --StaticCtor--")] static void TestStaticCctorRequires () { _ = new StaticCtor (); @@ -941,13 +1296,13 @@ static StaticCtorTriggeredByFieldAccess () public static int field; } - [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--")] static void TestStaticCtorMarkingIsTriggeredByFieldAccessWrite () { StaticCtorTriggeredByFieldAccess.field = 1; } - [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--")] static void TestStaticCtorMarkingTriggeredOnSecondAccessWrite () { StaticCtorTriggeredByFieldAccess.field = 2; @@ -971,7 +1326,7 @@ class StaticCCtorTriggeredByFieldAccessRead public static int field = 42; } - [ExpectedWarning ("IL2026", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--")] static void TestStaticCtorMarkingIsTriggeredByFieldAccessRead () { var _ = StaticCCtorTriggeredByFieldAccessRead.field; @@ -989,7 +1344,7 @@ public void TriggerStaticCtorMarking () } } - [ExpectedWarning ("IL2026", "StaticCtorTriggeredByCtorCalls.StaticCtorTriggeredByCtorCalls()", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticCtorTriggeredByCtorCalls.StaticCtorTriggeredByCtorCalls()")] static void TestStaticCtorTriggeredByCtorCall () { new StaticCtorTriggeredByCtorCalls (); @@ -1001,7 +1356,7 @@ class ClassWithInstanceField public int field = 42; } - [ExpectedWarning ("IL2026", "ClassWithInstanceField.ClassWithInstanceField()", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "ClassWithInstanceField.ClassWithInstanceField()")] static void TestInstanceFieldCallDontWarn () { ClassWithInstanceField instance = new ClassWithInstanceField (); @@ -1101,13 +1456,13 @@ public int Method (int a) } } - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] static void TestRequiresInClassAccessedByStaticMethod () { ClassWithRequires.StaticMethod (); } - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires", "--ClassWithRequires--")] static void TestRequiresInClassAccessedByCctor () { var classObject = new ClassWithRequires (); @@ -1118,10 +1473,10 @@ static void TestRequiresInParentClassAccesedByStaticMethod () ClassWithRequires.NestedClass.NestedStaticMethod (); } - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] // Although we suppress the warning from RequiresOnMethod.MethodWithRequires () we still get a warning because we call CallRequiresMethod() which is an static method on a type with RUC - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.CallMethodWithRequires()", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "ClassWithRequires.Instance", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.CallMethodWithRequires()", "--ClassWithRequires--")] + [ExpectedWarning ("IL2026", "ClassWithRequires.Instance", "--ClassWithRequires--")] static void TestRequiresOnBaseButNotOnDerived () { DerivedWithoutRequires.StaticMethodInInheritedClass (); @@ -1135,7 +1490,7 @@ static void TestRequiresOnBaseButNotOnDerived () DerivedWithoutRequires2.StaticMethod (); } - [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires.StaticMethodInInheritedClass()", "--DerivedWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires.StaticMethodInInheritedClass()", "--DerivedWithRequires--")] static void TestRequiresOnDerivedButNotOnBase () { DerivedWithRequires.StaticMethodInInheritedClass (); @@ -1144,8 +1499,8 @@ static void TestRequiresOnDerivedButNotOnBase () DerivedWithRequires.NestedClass.NestedStaticMethod (); } - [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires2.StaticMethodInInheritedClass()", "--DerivedWithRequires2--", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "RequiresOnClass.DerivedWithRequires2.StaticMethodInInheritedClass()", "--DerivedWithRequires2--")] + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.StaticMethod()", "--ClassWithRequires--")] static void TestRequiresOnBaseAndDerived () { DerivedWithRequires2.StaticMethodInInheritedClass (); @@ -1154,7 +1509,8 @@ static void TestRequiresOnBaseAndDerived () DerivedWithRequires2.NestedClass.NestedStaticMethod (); } - [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.TestSuppressions(Type[])", ProducedBy = ProducedBy.Trimmer)] + // TODO: Parameter signature differs between linker and analyzer + [ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequires.TestSuppressions(", "Type[])")] static void TestSuppressionsOnClass () { ClassWithRequires.TestSuppressions (new[] { typeof (ClassWithRequires) }); @@ -1192,14 +1548,14 @@ class MemberTypesWithRequires public static int Property { get; set; } // These should not be reported https://github.com/mono/linker/issues/2218 - [ExpectedWarning ("IL2026", "add_Event", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "remove_Event", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.add", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.remove", ProducedBy = ProducedBy.Trimmer)] public static event EventHandler Event; } - [ExpectedWarning ("IL2026", "MemberTypesWithRequires.field", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Property.set", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "MemberTypesWithRequires.remove_Event", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "MemberTypesWithRequires.field")] + [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Property.set")] + [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.remove")] static void TestOtherMemberTypesWithRequires () { MemberTypesWithRequires.field = 1; @@ -1340,7 +1696,7 @@ class WithRequires [RequiresUnreferencedCode ("--WithRequiresOnlyInstanceFields--")] class WithRequiresOnlyInstanceFields { - public int InstnaceField; + public int InstanceField; } [ExpectedWarning ("IL2109", "ReflectionAccessOnField/DerivedWithoutRequires", "ReflectionAccessOnField.WithRequires", ProducedBy = ProducedBy.Trimmer)] @@ -1367,20 +1723,22 @@ static void TestDAMAccess () typeof (DerivedWithRequires).RequiresPublicFields (); } - [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "WithRequires.StaticField")] + // Analyzer does not recognize the binding flags [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticField", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField")] + [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField", ProducedBy = ProducedBy.Analyzer)] static void TestDirectReflectionAccess () { typeof (WithRequires).GetField (nameof (WithRequires.StaticField)); typeof (WithRequires).GetField (nameof (WithRequires.InstanceField)); // Doesn't warn typeof (WithRequires).GetField ("PrivateStaticField", BindingFlags.NonPublic); - typeof (WithRequiresOnlyInstanceFields).GetField (nameof (WithRequiresOnlyInstanceFields.InstnaceField)); // Doesn't warn + typeof (WithRequiresOnlyInstanceFields).GetField (nameof (WithRequiresOnlyInstanceFields.InstanceField)); // Doesn't warn typeof (DerivedWithoutRequires).GetField (nameof (DerivedWithRequires.DerivedStaticField)); // Doesn't warn typeof (DerivedWithRequires).GetField (nameof (DerivedWithRequires.DerivedStaticField)); } - [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "WithRequires.StaticField")] [DynamicDependency (nameof (WithRequires.StaticField), typeof (WithRequires))] [DynamicDependency (nameof (WithRequires.InstanceField), typeof (WithRequires))] // Doesn't warn [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (DerivedWithoutRequires))] // Doesn't warn @@ -1432,12 +1790,12 @@ class WithRequires { // These should be reported only in TestDirectReflectionAccess // https://github.com/mono/linker/issues/2218 - [ExpectedWarning ("IL2026", "add_StaticEvent", ProducedBy = ProducedBy.Trimmer)] - [ExpectedWarning ("IL2026", "remove_StaticEvent", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticEvent.remove", ProducedBy = ProducedBy.Trimmer)] public static event EventHandler StaticEvent; } - [ExpectedWarning ("IL2026", "add_StaticEvent", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = ProducedBy.Trimmer)] static void TestDirectReflectionAccess () { typeof (WithRequires).GetEvent (nameof (WithRequires.StaticEvent)); @@ -1567,7 +1925,7 @@ public class AttributeWithRequires : Attribute public static int field; // `field` cannot be used as named attribute argument because is static, and if accessed via - // a property the property will be the one generating the warning, but then the warning will + // a property the property will be the one generating the warning, but then the warning will // be suppresed by the Requires on the declaring type public int PropertyOnAttribute { get { return field; } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs index b30833564b89..6036d704423a 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs @@ -11,6 +11,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [SetupCompileBefore ("lib.dll", new[] { "Dependencies/RequiresInCopyAssembly.cs" })] [KeptAllTypesAndMembersInAssembly ("lib.dll")] [LogDoesNotContain ("IL2026")] + [LogDoesNotContain ("IL3002")] [LogDoesNotContain ("IL2027")] public class RequiresCapabilityFromCopiedAssembly { diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs index dbbb7fc181dd..e5f176d87026 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs @@ -44,6 +44,7 @@ public static void Main () class WarnInIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -51,6 +52,7 @@ static IEnumerable TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -68,6 +70,7 @@ static IEnumerable TestReflectionAccess () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestLdftn () { yield return 0; @@ -75,6 +78,18 @@ static IEnumerable TestLdftn () var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static IEnumerable TestLazyDelegate () + { + yield return 0; + yield return 1; + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static IEnumerable TestDynamicallyAccessedMethod () { @@ -89,6 +104,7 @@ public static void Test () TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -96,6 +112,7 @@ public static void Test () class SuppressInIteratorBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestCall () { MethodWithRequires (); @@ -105,6 +122,7 @@ static IEnumerable TestCall () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestReflectionAccess () { yield return 0; @@ -115,6 +133,7 @@ static IEnumerable TestReflectionAccess () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestLdftn () { yield return 0; @@ -122,7 +141,20 @@ static IEnumerable TestLdftn () var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static IEnumerable TestLazyDelegate () + { + yield return 0; + yield return 1; + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -131,6 +163,7 @@ static IEnumerable TestDynamicallyAccessedMethod () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -138,6 +171,7 @@ static IEnumerable TestMethodParameterWithRequirements (Type unknownType = } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestGenericMethodParameterRequirement () { MethodWithGenericWhichRequiresMethods (); @@ -145,6 +179,7 @@ static IEnumerable TestGenericMethodParameterRequirement () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -152,11 +187,13 @@ static IEnumerable TestGenericTypeParameterRequirement () } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -167,6 +204,7 @@ public static void Test () class WarnInAsyncBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -174,6 +212,7 @@ static async void TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestCallAfterYieldReturn () { await MethodAsync (); @@ -191,12 +230,23 @@ static async void TestReflectionAccess () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestLdftn () { await MethodAsync (); var action = new Action (MethodWithRequires); } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async void TestLazyDelegate () + { + await MethodAsync (); + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static async void TestDynamicallyAccessedMethod () { @@ -210,6 +260,7 @@ public static void Test () TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -217,6 +268,7 @@ public static void Test () class SuppressInAsyncBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestCall () { MethodWithRequires (); @@ -226,6 +278,7 @@ static async void TestCall () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestReflectionAccess () { await MethodAsync (); @@ -236,13 +289,26 @@ static async void TestReflectionAccess () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestLdftn () { await MethodAsync (); var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async void TestLazyDelegate () + { + await MethodAsync (); + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -250,6 +316,7 @@ static async void TestDynamicallyAccessedMethod () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -257,6 +324,7 @@ static async void TestMethodParameterWithRequirements (Type unknownType = null) } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestGenericMethodParameterRequirement () { MethodWithGenericWhichRequiresMethods (); @@ -264,6 +332,7 @@ static async void TestGenericMethodParameterRequirement () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -271,11 +340,13 @@ static async void TestGenericTypeParameterRequirement () } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -286,6 +357,7 @@ public static void Test () class WarnInAsyncIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestCallBeforeYieldReturn () { await MethodAsync (); @@ -294,6 +366,7 @@ static async IAsyncEnumerable TestCallBeforeYieldReturn () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -314,6 +387,7 @@ static async IAsyncEnumerable TestReflectionAccess () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestLdftn () { await MethodAsync (); @@ -321,6 +395,17 @@ static async IAsyncEnumerable TestLdftn () var action = new Action (MethodWithRequires); } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async IAsyncEnumerable TestLazyDelegate () + { + await MethodAsync (); + yield return 0; + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static async IAsyncEnumerable TestDynamicallyAccessedMethod () { @@ -335,6 +420,7 @@ public static void Test () TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -342,6 +428,7 @@ public static void Test () class SuppressInAsyncIteratorBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestCall () { MethodWithRequires (); @@ -352,6 +439,7 @@ static async IAsyncEnumerable TestCall () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestReflectionAccess () { await MethodAsync (); @@ -364,6 +452,7 @@ static async IAsyncEnumerable TestReflectionAccess () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestLdftn () { await MethodAsync (); @@ -371,7 +460,20 @@ static async IAsyncEnumerable TestLdftn () yield return 0; } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async IAsyncEnumerable TestLazyDelegate () + { + await MethodAsync (); + yield return 0; + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -380,6 +482,7 @@ static async IAsyncEnumerable TestDynamicallyAccessedMethod () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -388,6 +491,7 @@ static async IAsyncEnumerable TestMethodParameterWithRequirements (Type unk } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestGenericMethodParameterRequirement () { yield return 0; @@ -396,6 +500,7 @@ static async IAsyncEnumerable TestGenericMethodParameterRequirement TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -404,11 +509,13 @@ static async IAsyncEnumerable TestGenericTypeParameterRequirement } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -419,6 +526,7 @@ public static void Test () class WarnInLocalFunction { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCall () { LocalFunction (); @@ -427,6 +535,7 @@ static void TestCall () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCallWithClosure (int p = 0) { LocalFunction (); @@ -449,6 +558,7 @@ void LocalFunction () => typeof (RequiresInCompilerGeneratedCode) } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestLdftn () { LocalFunction (); @@ -459,6 +569,20 @@ void LocalFunction () } } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + LocalFunction (); + + void LocalFunction () + { + _ = _default.Value; + } + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static void TestDynamicallyAccessedMethod () { @@ -473,6 +597,7 @@ public static void Test () TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -483,20 +608,24 @@ class SuppressInLocalFunction // so its suppression effect also doesn't propagate [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCall () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithClosure (int p = 0) { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () { p++; @@ -505,38 +634,59 @@ void LocalFunction () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestReflectionAccess () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => typeof (RequiresInCompilerGeneratedCode) .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic) .Invoke (null, new object[] { }); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestLdftn () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () { var action = new Action (MethodWithRequires); } } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + LocalFunction (); + + void LocalFunction () + { + _ = _default.Value; + } + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestDynamicallyAccessedMethod () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { LocalFunction (); @@ -546,6 +696,7 @@ static async void TestMethodParameterWithRequirements (Type unknownType = null) } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericMethodParameterRequirement () { LocalFunction (); @@ -555,6 +706,7 @@ static void TestGenericMethodParameterRequirement () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericTypeParameterRequirement () { LocalFunction (); @@ -564,6 +716,7 @@ static void TestGenericTypeParameterRequirement () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericLocalFunction () { LocalFunction (); @@ -575,6 +728,7 @@ static void TestGenericLocalFunction () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericLocalFunctionInner () { LocalFunction (); @@ -611,32 +765,38 @@ void LocalFunction () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallMethodWithRequiresInLtftnLocalFunction () { var _ = new Action (LocalFunction); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } class DynamicallyAccessedLocalFunction { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction () { typeof (DynamicallyAccessedLocalFunction).RequiresNonPublicMethods (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } } [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static void TestSuppressionLocalFunction () { LocalFunction (); // This will produce a warning since the location function has Requires on it [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] void LocalFunction (Type unknownType = null) { MethodWithRequires (); @@ -645,11 +805,13 @@ void LocalFunction (Type unknownType = null) } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestSuppressionOnOuterAndLocalFunction () { LocalFunction (); [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] void LocalFunction (Type unknownType = null) { MethodWithRequires (); @@ -658,12 +820,14 @@ void LocalFunction (Type unknownType = null) } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestMethodParameterWithRequirements (); TestDynamicallyAccessedMethod (); TestGenericMethodParameterRequirement (); @@ -682,12 +846,14 @@ public static void Test () class WarnInLambda { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCall () { Action _ = () => MethodWithRequires (); } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCallWithClosure (int p = 0) { Action _ = () => { @@ -707,6 +873,7 @@ static void TestReflectionAccess () } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestLdftn () { Action _ = () => { @@ -714,6 +881,17 @@ static void TestLdftn () }; } + [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + Action _ = () => { + var action = _default.Value; + }; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static void TestDynamicallyAccessedMethod () { @@ -728,6 +906,7 @@ public static void Test () TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -741,7 +920,9 @@ class SuppressInLambda // - Would be useful for testing - have to use the CompilerGeneratedCode = true trick instead [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCall () { Action _ = () => MethodWithRequires (); @@ -750,6 +931,7 @@ static void TestCall () // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2067", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithReflectionAnalysisWarning () { // This should not produce warning because the Requires @@ -757,7 +939,9 @@ static void TestCallWithReflectionAnalysisWarning () } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithClosure (int p = 0) { Action _ = () => { @@ -769,6 +953,7 @@ static void TestCallWithClosure (int p = 0) // Analyzer doesn't recognize reflection access - so doesn't warn in this case [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestReflectionAccess () { Action _ = () => { @@ -779,7 +964,9 @@ static void TestReflectionAccess () } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestLdftn () { Action _ = () => { @@ -787,9 +974,21 @@ static void TestLdftn () }; } + [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + Action _ = () => { + var action = _default.Value; + }; + } + // Analyzer doesn't apply DAM - so won't see this warnings [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestDynamicallyAccessedMethod () { Action _ = () => { @@ -800,6 +999,7 @@ static void TestDynamicallyAccessedMethod () // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2077", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { Action _ = () => unknownType.RequiresNonPublicMethods (); @@ -808,6 +1008,7 @@ static async void TestMethodParameterWithRequirements (Type unknownType = null) // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericMethodParameterRequirement () { Action _ = () => { @@ -818,6 +1019,7 @@ static void TestGenericMethodParameterRequirement () // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericTypeParameterRequirement () { Action _ = () => { @@ -826,6 +1028,7 @@ static void TestGenericTypeParameterRequirement () } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); @@ -833,6 +1036,7 @@ public static void Test () TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -843,6 +1047,7 @@ public static void Test () class WarnInComplex { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestIteratorLocalFunctionInAsync () { await MethodAsync (); @@ -874,6 +1079,7 @@ public static void Test () class SuppressInComplex { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestIteratorLocalFunctionInAsync () { await MethodAsync (); @@ -881,6 +1087,7 @@ static async void TestIteratorLocalFunctionInAsync () await MethodAsync (); [RequiresUnreferencedCode ("Suppress in local function")] + [RequiresAssemblyFiles ("Suppress in local function")] IEnumerable LocalFunction () { yield return 0; @@ -890,6 +1097,7 @@ IEnumerable LocalFunction () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestIteratorLocalFunctionInAsyncWithoutInner () { await MethodAsync (); @@ -897,6 +1105,7 @@ static async void TestIteratorLocalFunctionInAsyncWithoutInner () await MethodAsync (); [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] IEnumerable LocalFunction () { yield return 0; @@ -906,6 +1115,7 @@ IEnumerable LocalFunction () } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator () { MethodWithGenericWhichRequiresMethods (); @@ -913,6 +1123,7 @@ static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterIn } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestIteratorLocalFunctionInAsync (); @@ -924,6 +1135,7 @@ public static void Test () class StateMachinesOnlyReferencedViaReflection { [RequiresUnreferencedCode ("Requires to suppress")] + [RequiresAssemblyFiles ("Requires to suppress")] static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress () { yield return 0; @@ -931,6 +1143,7 @@ static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldSuppre } [RequiresUnreferencedCode ("Requires to suppress")] + [RequiresAssemblyFiles ("Requires to suppress")] static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress () { await MethodAsync (); @@ -938,6 +1151,7 @@ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress () } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn () { yield return 0; @@ -945,6 +1159,7 @@ static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn ( } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn () { await MethodAsync (); @@ -966,12 +1181,14 @@ class ComplexCases public class AsyncBodyCallingMethodWithRequires { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static Task MethodWithRequiresAsync (Type type) { return Task.FromResult (new object ()); } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static async Task AsyncMethodCallingRequires (Type type) { using (var diposable = await GetDisposableAsync ()) { @@ -980,6 +1197,7 @@ static async Task AsyncMethodCallingRequires (Type type) } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncMethodCallingRequires (typeof (object)); @@ -989,12 +1207,14 @@ public static void Test () public class GenericAsyncBodyCallingMethodWithRequires { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static ValueTask MethodWithRequiresAsync () { return ValueTask.FromResult (default (TValue)); } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static async Task AsyncMethodCallingRequires () { using (var disposable = await GetDisposableAsync ()) { @@ -1003,6 +1223,7 @@ static async Task AsyncMethodCallingRequires () } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncMethodCallingRequires (); @@ -1014,12 +1235,14 @@ public class GenericAsyncEnumerableBodyCallingRequiresWithAnnotations class RequiresOnCtor { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] public RequiresOnCtor () { } } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static IAsyncEnumerable AsyncEnumMethodCallingRequires< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TValue> () { @@ -1035,6 +1258,7 @@ static async IAsyncEnumerable CreateAsync () } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncEnumMethodCallingRequires (); @@ -1052,6 +1276,7 @@ static async Task MethodAsync () } [RequiresUnreferencedCode ("--MethodWithRequires--")] + [RequiresAssemblyFiles ("--MethodWithRequires--")] static void MethodWithRequires () { } @@ -1059,11 +1284,19 @@ static void MethodWithRequires () class TypeWithMethodWithRequires { [RequiresUnreferencedCode ("--TypeWithMethodWithRequires.MethodWithRequires--")] + [RequiresAssemblyFiles ("--TypeWithMethodWithRequires.MethodWithRequires--")] static void MethodWithRequires () { } } + [RequiresUnreferencedCode ("Message from --MethodWithRequiresAndReturns--")] + [RequiresAssemblyFiles ("Message from --MethodWithRequiresAndReturns--")] + public static string MethodWithRequiresAndReturns () + { + return "string"; + } + static void MethodWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> () { } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs index 89dd43a081c1..01f57a3aae57 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs @@ -25,7 +25,7 @@ public virtual void Link (string[] args, LinkerCustomizations customizations, IL { Driver.ProcessResponseFile (args, out var queue); using (var driver = new TestDriver (queue, customizations)) { - driver.Run (logger); + driver.Run (logger, throwOnFatalLinkerException: true); } } } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index fe2b6bf8e367..949029edc66a 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -679,7 +679,7 @@ void VerifyLoggedMessages (AssemblyDefinition original, LinkerTestLogger logger, bool foundReflectionAccessPatternAttributesToVerify = false; foreach (var attr in attrProvider.CustomAttributes) { if (!IsProducedByLinker (attr)) - break; + continue; switch (attr.AttributeType.Name) { @@ -777,6 +777,9 @@ void VerifyLoggedMessages (AssemblyDefinition original, LinkerTestLogger logger, if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && actualName.Contains ("<" + expectedMember.Name + ">")) return true; + if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && + actualName.Contains (".cctor") && (expectedMember is FieldDefinition || expectedMember is PropertyDefinition)) + return true; if (methodDefinition.Name == ".ctor" && methodDefinition.DeclaringType.FullName == expectedMember.FullName) return true;