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