diff --git a/CLAUDE.md b/CLAUDE.md
index 0a3fa69..0d82574 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -21,7 +21,7 @@ dotnet build ReferenceAssemblyAnnotator.slnx -c Release
## Tests
-`ICSharpCode.ReferenceAssemblyAnnotator.Tests` (xUnit v3 on Microsoft Testing Platform, net10.0) unit-tests the comparers and `Program.Annotate`/`AnnotateType` on in-memory Cecil modules built with `CecilBuilder`; it sees the weaver's internals via `InternalsVisibleTo`. `global.json` selects the MTP runner for `dotnet test`. After building the solution:
+`ICSharpCode.ReferenceAssemblyAnnotator.Tests` (xUnit v3 on Microsoft Testing Platform, net10.0) unit-tests the comparers and `Program.Annotate`/`AnnotateType` on in-memory Cecil modules built with `CecilBuilder`, and `ProgramMainTests` runs `Program.Main` end to end on netstandard2.0's `netstandard.dll` (from a `NETStandard.Library` download) against the net10.0 one the test project compiles against. The project sees the weaver's internals via `InternalsVisibleTo`. `global.json` selects the MTP runner for `dotnet test`. After building the solution:
```
dotnet test --project ICSharpCode.ReferenceAssemblyAnnotator.Tests -c Release --no-build
@@ -42,7 +42,7 @@ dotnet msbuild -restore tests/SingleTFM -p:TestFramework=netstandard2.0 -warnase
```
- `tests/SingleTFM` is parameterized by `-p:TestFramework=` (net35 … net10.0); MultiTFM, RefVersion3.1.0, NoDisabledWarnings (uses `-p:TreatWarningsAsErrors=true`, since `-warnaserror` ignores `WarningsNotAsErrors`) and WPF cover the rest.
-- The test projects leave out the `Microsoft.NETCore.App.Ref` `PackageDownload` for .NET Core 3.0+ (netcoreapp3.x, net10.0). Those aren't annotated, and the SDK adds its own download whenever the targeting pack isn't installed, so a second one fails with NU1505. The `GetHashCode` line in the test sources is `#if !NETCOREAPP3_0_OR_GREATER` because only annotated TFMs get `[DisallowNull]` removed (`Program.IsExcludedAnnotation`).
+- The test projects leave out the `Microsoft.NETCore.App.Ref` `PackageDownload` for .NET Core 3.0+ (netcoreapp3.x, net10.0). Those aren't annotated, and the SDK adds its own download whenever the targeting pack isn't installed, so a second one fails with NU1505. The `GetHashCode` line in the test sources is `#if !NETCOREAPP3_0_OR_GREATER` because only annotated TFMs get `[DisallowNull]` removed (`Program.IsExcludedAnnotation`). The `Task.IsFaulted` line checks that `MemberNotNullWhen` is copied (CS8602 otherwise); it is left out of `RefVersion3.1.0` and excluded for net35 and netcoreapp3.x, whose references lack the attribute.
- Keep the local source path in `tests/NuGet.Config` with forward slashes: with backslashes, source mapping doesn't match it on Linux/macOS (NU1100).
CI: `.github/workflows/build.yml` runs the same build, the unit tests and the test script with both engines (Release only) and uploads the nupkg. On the runner, paths in the isolated cache exceed MAX_PATH under `msbuild.exe`. So the workflow passes `-PackagesPath` with a short path outside the checkout; that cache isn't wiped between cases, which is safe because a run only ever contains one annotator version. `test.ps1` also passes `core.longpaths=true` to `git clean`.
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ICSharpCode.ReferenceAssemblyAnnotator.Tests.csproj b/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ICSharpCode.ReferenceAssemblyAnnotator.Tests.csproj
index 1cff9b2..6f03d45 100644
--- a/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ICSharpCode.ReferenceAssemblyAnnotator.Tests.csproj
+++ b/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ICSharpCode.ReferenceAssemblyAnnotator.Tests.csproj
@@ -14,8 +14,25 @@
+
+
+
+
+
+ <_AnnotatedNetStandard Include="@(Reference)" Condition="'%(Filename)' == 'netstandard'" />
+
+ <_Parameter1>UnannotatedNetStandard
+ <_Parameter2>$([MSBuild]::EnsureTrailingSlash($(NuGetPackageRoot)))netstandard.library/2.0.3/build/netstandard2.0/ref/netstandard.dll
+
+
+ <_Parameter1>AnnotatedNetStandard
+ <_Parameter2>@(_AnnotatedNetStandard->'%(FullPath)')
+
+
+
+
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ProgramMainTests.cs b/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ProgramMainTests.cs
new file mode 100644
index 0000000..91b6bad
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator.Tests/ProgramMainTests.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator.Tests
+{
+ using System;
+ using System.Collections.Immutable;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using Mono.Cecil;
+ using Xunit;
+
+ ///
+ /// Runs end to end: annotates netstandard2.0's netstandard.dll and reads the output back.
+ ///
+ public class ProgramMainTests
+ {
+ private const string CodeAnalysis = "System.Diagnostics.CodeAnalysis";
+
+ private static readonly Lazy Annotated = new Lazy(AnnotateNetStandard);
+
+ [Fact]
+ public void CopiesMemberNotNullWhen()
+ {
+ var isFaulted = GetType("System.Threading.Tasks", "Task").Properties.Single(property => property.Name == "IsFaulted");
+
+ var attribute = GetAttribute(isFaulted, "MemberNotNullWhenAttribute");
+
+ Assert.Equal(new object[] { true, "Exception" }, attribute.ConstructorArguments.Select(argument => argument.Value));
+ }
+
+ [Fact]
+ public void CopiesDynamicallyAccessedMembersWithEnumArgument()
+ {
+ var getMethods = GetType("System", "Type").Methods.Single(method => method.Name == "GetMethods" && method.Parameters.Count == 1);
+
+ var attribute = GetAttribute(getMethods, "DynamicallyAccessedMembersAttribute");
+
+ // PublicMethods | NonPublicMethods
+ Assert.Equal(8 | 16, (int)attribute.ConstructorArguments.Single().Value);
+ }
+
+ [Theory]
+ [InlineData("System.Reflection", "Assembly", "GetTypes", "RequiresUnreferencedCodeAttribute")]
+ [InlineData("System", "Type", "MakeGenericType", "RequiresDynamicCodeAttribute")]
+ [InlineData("System.Reflection", "Assembly", "GetFiles", "RequiresAssemblyFilesAttribute")]
+ public void CopiesRequiresAttributes(string @namespace, string typeName, string methodName, string attributeName)
+ {
+ var method = GetType(@namespace, typeName).Methods.First(method => method.Name == methodName);
+
+ Assert.NotEmpty(GetAttribute(method, attributeName).ConstructorArguments);
+ }
+
+ [Fact]
+ public void AssemblyResolver_LoadsDependenciesWithItself()
+ {
+ string netStandard = GetMetadata("UnannotatedNetStandard");
+ using var resolver = new AssemblyResolver(ImmutableArray.Create(Path.GetDirectoryName(netStandard)!));
+
+ // The System.Runtime facade forwards Object to netstandard, which must not come from the test host's runtime.
+ var facade = resolver.Resolve(AssemblyNameReference.Parse("System.Runtime"))!;
+
+ Assert.Equal(Path.GetFullPath(netStandard), facade.MainModule.TypeSystem.Object.Resolve().Module.FileName, ignoreCase: true);
+ }
+
+ [Theory]
+ [InlineData("MemberNotNullAttribute")]
+ [InlineData("MemberNotNullWhenAttribute")]
+ [InlineData("RequiresUnreferencedCodeAttribute")]
+ [InlineData("RequiresDynamicCodeAttribute")]
+ [InlineData("RequiresAssemblyFilesAttribute")]
+ [InlineData("DynamicallyAccessedMembersAttribute")]
+ [InlineData("DynamicallyAccessedMemberTypes")]
+ public void SynthesizesInternalTypes(string typeName)
+ {
+ Assert.False(GetType(CodeAnalysis, typeName).IsPublic);
+ }
+
+ private static TypeDefinition GetType(string @namespace, string name)
+ => Annotated.Value.GetType(@namespace, name) ?? throw new InvalidOperationException($"{@namespace}.{name} not found");
+
+ private static CustomAttribute GetAttribute(Mono.Cecil.ICustomAttributeProvider provider, string name)
+ => provider.CustomAttributes.Single(attribute => attribute.AttributeType.FullName == $"{CodeAnalysis}.{name}");
+
+ private static string GetMetadata(string key)
+ => typeof(ProgramMainTests).Assembly.GetCustomAttributes().Single(attribute => attribute.Key == key).Value!;
+
+ private static ModuleDefinition AnnotateNetStandard()
+ {
+ string input = GetMetadata("UnannotatedNetStandard");
+ string output = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dll");
+ try
+ {
+ Program.Main(null, input, ImmutableArray.Create(Path.GetDirectoryName(input)!), GetMetadata("AnnotatedNetStandard"), output);
+ return ModuleDefinition.ReadModule(new MemoryStream(File.ReadAllBytes(output)));
+ }
+ finally
+ {
+ File.Delete(output);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/AssemblyResolver.cs b/ICSharpCode.ReferenceAssemblyAnnotator/AssemblyResolver.cs
index cab015a..621d1a9 100644
--- a/ICSharpCode.ReferenceAssemblyAnnotator/AssemblyResolver.cs
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/AssemblyResolver.cs
@@ -11,19 +11,21 @@ namespace ICSharpCode.ReferenceAssemblyAnnotator
internal sealed class AssemblyResolver : IAssemblyResolver
{
- private static readonly ReaderParameters DefaultReaderParameters = new ReaderParameters(ReadingMode.Deferred);
-
private readonly ImmutableArray _searchDirectories;
private readonly Dictionary _assembliesByFileName = new Dictionary();
+ // Dependencies must resolve through this resolver too; Cecil's default one would find the build host's runtime.
+ private readonly ReaderParameters _readerParameters;
+
public AssemblyResolver(ImmutableArray searchDirectories)
{
_searchDirectories = searchDirectories;
+ _readerParameters = new ReaderParameters(ReadingMode.Deferred) { AssemblyResolver = this };
}
public AssemblyDefinition? Resolve(AssemblyNameReference name)
{
- return Resolve(name, DefaultReaderParameters);
+ return Resolve(name, _readerParameters);
}
public AssemblyDefinition? Resolve(AssemblyNameReference name, ReaderParameters parameters)
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/Program.cs b/ICSharpCode.ReferenceAssemblyAnnotator/Program.cs
index 131dde8..9a650ba 100644
--- a/ICSharpCode.ReferenceAssemblyAnnotator/Program.cs
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/Program.cs
@@ -57,6 +57,12 @@ internal static void Main(SuppressibleLoggingHelper? log, string referenceAssemb
AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisNotNullAttribute);
AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisNotNullIfNotNullAttribute);
AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisNotNullWhenAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisMemberNotNullAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisRequiresUnreferencedCodeAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisRequiresDynamicCodeAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisRequiresAssemblyFilesAttribute);
+ AddAttributeOfInterest(attributesOfInterest, wellKnownTypes.SystemDiagnosticsCodeAnalysisDynamicallyAccessedMembersAttribute);
AnnotateAssembly(log, assemblyDefinition, annotatedAssemblyDefinition, attributesOfInterest);
@@ -216,7 +222,7 @@ internal static void Annotate(ModuleDefinition module, ICustomAttributeProvider
static bool IsMatchingConstructor(MethodDefinition constructor, CustomAttribute customAttribute)
{
- if (constructor.Parameters.Count != customAttribute.ConstructorArguments.Count)
+ if (!constructor.IsConstructor || constructor.Parameters.Count != customAttribute.ConstructorArguments.Count)
return false;
for (int i = 0; i < constructor.Parameters.Count; i++)
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMemberTypesProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMemberTypesProvidedType.cs
new file mode 100644
index 0000000..5d97af1
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMemberTypesProvidedType.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using Mono.Cecil;
+
+ internal partial class WellKnownTypes
+ {
+ // Only the underlying type matters: attribute blobs store the enum value as int32.
+ private sealed class DynamicallyAccessedMemberTypesProvidedType : ProvidedType
+ {
+ public DynamicallyAccessedMemberTypesProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "DynamicallyAccessedMemberTypes")
+ {
+ }
+
+ protected override TypeReference DefineType(ModuleDefinition module, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ var type = new TypeDefinition(
+ @namespace: NamespaceName,
+ name: TypeName,
+ TypeAttributes.NotPublic | TypeAttributes.Sealed,
+ module.ImportReference(wellKnownTypes.SystemEnum));
+
+ type.Fields.Add(new FieldDefinition(
+ name: "value__",
+ attributes: FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName,
+ fieldType: module.TypeSystem.Int32));
+
+ module.Types.Add(type);
+
+ return type;
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMembersAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMembersAttributeProvidedType.cs
new file mode 100644
index 0000000..d11b477
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+DynamicallyAccessedMembersAttributeProvidedType.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class DynamicallyAccessedMembersAttributeProvidedType : ProvidedAttributeType
+ {
+ public DynamicallyAccessedMembersAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "DynamicallyAccessedMembersAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, inherited: false));
+
+ var constructor = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor.Parameters.Add(new ParameterDefinition("memberTypes", ParameterAttributes.None, wellKnownTypes.SystemDiagnosticsCodeAnalysisDynamicallyAccessedMemberTypes.Value));
+ attribute.Methods.Add(constructor);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullAttributeProvidedType.cs
new file mode 100644
index 0000000..6f625b9
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullAttributeProvidedType.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+ using Mono.Cecil.Rocks;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class MemberNotNullAttributeProvidedType : ProvidedAttributeType
+ {
+ public MemberNotNullAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "MemberNotNullAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.NullableContext(1));
+ attribute.CustomAttributes.Add(attributeFactory.Nullable(0));
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, allowMultiple: true, inherited: false));
+
+ var constructor1 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor1.Parameters.Add(new ParameterDefinition("member", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
+ attribute.Methods.Add(constructor1);
+
+ var constructor2 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor2.Parameters.Add(new ParameterDefinition("members", ParameterAttributes.None, wellKnownTypes.TypeSystem.String.MakeArrayType()));
+ attribute.Methods.Add(constructor2);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullWhenAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullWhenAttributeProvidedType.cs
new file mode 100644
index 0000000..0c4abf2
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+MemberNotNullWhenAttributeProvidedType.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+ using Mono.Cecil.Rocks;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class MemberNotNullWhenAttributeProvidedType : ProvidedAttributeType
+ {
+ public MemberNotNullWhenAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "MemberNotNullWhenAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.NullableContext(1));
+ attribute.CustomAttributes.Add(attributeFactory.Nullable(0));
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, allowMultiple: true, inherited: false));
+
+ var constructor1 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor1.Parameters.Add(new ParameterDefinition("returnValue", ParameterAttributes.None, wellKnownTypes.TypeSystem.Boolean));
+ constructor1.Parameters.Add(new ParameterDefinition("member", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
+ attribute.Methods.Add(constructor1);
+
+ var constructor2 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor2.Parameters.Add(new ParameterDefinition("returnValue", ParameterAttributes.None, wellKnownTypes.TypeSystem.Boolean));
+ constructor2.Parameters.Add(new ParameterDefinition("members", ParameterAttributes.None, wellKnownTypes.TypeSystem.String.MakeArrayType()));
+ attribute.Methods.Add(constructor2);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresAssemblyFilesAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresAssemblyFilesAttributeProvidedType.cs
new file mode 100644
index 0000000..f5ef48e
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresAssemblyFilesAttributeProvidedType.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class RequiresAssemblyFilesAttributeProvidedType : ProvidedAttributeType
+ {
+ public RequiresAssemblyFilesAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "RequiresAssemblyFilesAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event, inherited: false));
+
+ attribute.AddDefaultConstructor(wellKnownTypes.TypeSystem);
+
+ var constructor = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor.Parameters.Add(new ParameterDefinition("message", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
+ attribute.Methods.Add(constructor);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresDynamicCodeAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresDynamicCodeAttributeProvidedType.cs
new file mode 100644
index 0000000..4420b3d
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresDynamicCodeAttributeProvidedType.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class RequiresDynamicCodeAttributeProvidedType : ProvidedAttributeType
+ {
+ public RequiresDynamicCodeAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "RequiresDynamicCodeAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Method, inherited: false));
+
+ var constructor = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor.Parameters.Add(new ParameterDefinition("message", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
+ attribute.Methods.Add(constructor);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresUnreferencedCodeAttributeProvidedType.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresUnreferencedCodeAttributeProvidedType.cs
new file mode 100644
index 0000000..e09402e
--- /dev/null
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes+RequiresUnreferencedCodeAttributeProvidedType.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+namespace ICSharpCode.ReferenceAssemblyAnnotator
+{
+ using System;
+ using Mono.Cecil;
+
+ internal partial class WellKnownTypes
+ {
+ private sealed class RequiresUnreferencedCodeAttributeProvidedType : ProvidedAttributeType
+ {
+ public RequiresUnreferencedCodeAttributeProvidedType()
+ : base("System.Diagnostics.CodeAnalysis", "RequiresUnreferencedCodeAttribute")
+ {
+ }
+
+ protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
+ {
+ attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Method, inherited: false));
+
+ var constructor = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
+ constructor.Parameters.Add(new ParameterDefinition("message", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
+ attribute.Methods.Add(constructor);
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes.cs b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes.cs
index 5993109..3120692 100644
--- a/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes.cs
+++ b/ICSharpCode.ReferenceAssemblyAnnotator/WellKnownTypes.cs
@@ -10,6 +10,7 @@ namespace ICSharpCode.ReferenceAssemblyAnnotator
internal partial class WellKnownTypes
{
+ private readonly WellKnownType _systemEnum = new PredefinedType(typeof(Enum));
private readonly WellKnownType _systemAttribute = new PredefinedType(typeof(Attribute));
private readonly WellKnownType _systemAttributeTargets = new PredefinedType(typeof(AttributeTargets));
private readonly WellKnownType _systemAttributeUsageAttribute = new PredefinedType(typeof(AttributeUsageAttribute));
@@ -30,6 +31,14 @@ internal partial class WellKnownTypes
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullAttribute = new NotNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullIfNotNullAttribute = new NotNullIfNotNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullWhenAttribute = new NotNullWhenAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisMemberNotNullAttribute = new MemberNotNullAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute = new MemberNotNullWhenAttributeProvidedType();
+
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisRequiresUnreferencedCodeAttribute = new RequiresUnreferencedCodeAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisRequiresDynamicCodeAttribute = new RequiresDynamicCodeAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisRequiresAssemblyFilesAttribute = new RequiresAssemblyFilesAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisDynamicallyAccessedMembersAttribute = new DynamicallyAccessedMembersAttributeProvidedType();
+ private readonly WellKnownType _systemDiagnosticsCodeAnalysisDynamicallyAccessedMemberTypes = new DynamicallyAccessedMemberTypesProvidedType();
public WellKnownTypes(AssemblyDefinition assemblyDefinition)
{
@@ -79,12 +88,36 @@ public WellKnownTypes(AssemblyDefinition assemblyDefinition)
SystemDiagnosticsCodeAnalysisNotNullWhenAttribute = new Lazy(
() => _systemDiagnosticsCodeAnalysisNotNullWhenAttribute.GetOrCreateTypeReference(Module, this),
LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisMemberNotNullAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisMemberNotNullAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+
+ SystemDiagnosticsCodeAnalysisRequiresUnreferencedCodeAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisRequiresUnreferencedCodeAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisRequiresDynamicCodeAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisRequiresDynamicCodeAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisRequiresAssemblyFilesAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisRequiresAssemblyFilesAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisDynamicallyAccessedMembersAttribute = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisDynamicallyAccessedMembersAttribute.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ SystemDiagnosticsCodeAnalysisDynamicallyAccessedMemberTypes = new Lazy(
+ () => _systemDiagnosticsCodeAnalysisDynamicallyAccessedMemberTypes.GetOrCreateTypeReference(Module, this),
+ LazyThreadSafetyMode.ExecutionAndPublication);
}
public ModuleDefinition Module { get; }
public TypeSystem TypeSystem => Module.TypeSystem;
+ public TypeReference SystemEnum => _systemEnum.GetOrCreateTypeReference(Module, this);
+
public TypeReference SystemAttribute => _systemAttribute.GetOrCreateTypeReference(Module, this);
public TypeReference SystemAttributeTargets => _systemAttributeTargets.GetOrCreateTypeReference(Module, this);
@@ -121,6 +154,20 @@ public WellKnownTypes(AssemblyDefinition assemblyDefinition)
public Lazy SystemDiagnosticsCodeAnalysisNotNullWhenAttribute { get; }
+ public Lazy SystemDiagnosticsCodeAnalysisMemberNotNullAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisRequiresUnreferencedCodeAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisRequiresDynamicCodeAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisRequiresAssemblyFilesAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisDynamicallyAccessedMembersAttribute { get; }
+
+ public Lazy SystemDiagnosticsCodeAnalysisDynamicallyAccessedMemberTypes { get; }
+
private static TypeDefinition ResolveRequiredWellKnownType(ModuleDefinition module, Type type)
{
return ResolveWellKnownType(module, type)
diff --git a/tests/MultiTFM/Class1.cs b/tests/MultiTFM/Class1.cs
index 09b33d8..d9002c5 100644
--- a/tests/MultiTFM/Class1.cs
+++ b/tests/MultiTFM/Class1.cs
@@ -19,5 +19,10 @@ public static void M(SqlConnection connection, [AllowNull] string? x)
_ = EqualityComparer.Default.GetHashCode(x);
#endif
}
+
+#if !NET35 && !NETCOREAPP3_0 && !NETCOREAPP3_1
+ // Task.IsFaulted carries [MemberNotNullWhen(true, nameof(Exception))]; without it this warns CS8602.
+ public static string F(System.Threading.Tasks.Task task) => task.IsFaulted ? task.Exception.Message : "";
+#endif
}
}
diff --git a/tests/NoDisabledWarnings/Class1.cs b/tests/NoDisabledWarnings/Class1.cs
index 09b33d8..d9002c5 100644
--- a/tests/NoDisabledWarnings/Class1.cs
+++ b/tests/NoDisabledWarnings/Class1.cs
@@ -19,5 +19,10 @@ public static void M(SqlConnection connection, [AllowNull] string? x)
_ = EqualityComparer.Default.GetHashCode(x);
#endif
}
+
+#if !NET35 && !NETCOREAPP3_0 && !NETCOREAPP3_1
+ // Task.IsFaulted carries [MemberNotNullWhen(true, nameof(Exception))]; without it this warns CS8602.
+ public static string F(System.Threading.Tasks.Task task) => task.IsFaulted ? task.Exception.Message : "";
+#endif
}
}
diff --git a/tests/SingleTFM/Class1.cs b/tests/SingleTFM/Class1.cs
index 09b33d8..d9002c5 100644
--- a/tests/SingleTFM/Class1.cs
+++ b/tests/SingleTFM/Class1.cs
@@ -19,5 +19,10 @@ public static void M(SqlConnection connection, [AllowNull] string? x)
_ = EqualityComparer.Default.GetHashCode(x);
#endif
}
+
+#if !NET35 && !NETCOREAPP3_0 && !NETCOREAPP3_1
+ // Task.IsFaulted carries [MemberNotNullWhen(true, nameof(Exception))]; without it this warns CS8602.
+ public static string F(System.Threading.Tasks.Task task) => task.IsFaulted ? task.Exception.Message : "";
+#endif
}
}
diff --git a/tests/WPF/UserControl1.xaml.cs b/tests/WPF/UserControl1.xaml.cs
index 4addbca..ea38b7d 100644
--- a/tests/WPF/UserControl1.xaml.cs
+++ b/tests/WPF/UserControl1.xaml.cs
@@ -25,5 +25,10 @@ public static void M(SqlConnection connection, [AllowNull] string? x)
_ = EqualityComparer.Default.GetHashCode(x);
#endif
}
+
+#if !NET35 && !NETCOREAPP3_0 && !NETCOREAPP3_1
+ // Task.IsFaulted carries [MemberNotNullWhen(true, nameof(Exception))]; without it this warns CS8602.
+ public static string F(System.Threading.Tasks.Task task) => task.IsFaulted ? task.Exception.Message : "";
+#endif
}
}