Skip to content

Commit

Permalink
Remove AttributeTargets.Module from NullableContextAttribute (#37610)
Browse files Browse the repository at this point in the history
  • Loading branch information
cston authored Jul 31, 2019
1 parent 5f9dff6 commit 0a24561
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 7 deletions.
8 changes: 4 additions & 4 deletions docs/features/nullable-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Each type parameter definition may have an associated `NullableAttribute` with a
namespace System.Runtime.CompilerServices
{
[System.AttributeUsage(
AttributeTargets.Module |
AttributeTargets.Class |
AttributeTargets.Delegate |
AttributeTargets.Interface |
Expand All @@ -102,7 +101,7 @@ The type declaration is synthesized by the compiler if not already included in t

The `NullableContextAttribute` is optional - nullable annotations can be represented in metadata with full fidelity using `NullableAttribute` only.

`NullableContextAttribute` is valid in metadata at the module level and at type and method declarations.
`NullableContextAttribute` is valid in metadata on type and method declarations.
The `byte` value represents the implicit `NullableAttribute` value for type references within that scope
that do not have an explicit `NullableAttribute` and would not otherwise be represented by an empty `byte[]`.
The nearest `NullableContextAttribute` in the metadata hierarchy applies.
Expand All @@ -121,8 +120,9 @@ and any `NullableContextAttribute` attributes on immediate children.
If there are no single `byte` values, there are no changes.
Otherwise, a `NullableContext(value)` attribute is created at that level where `value` is most common
value (preferring `0` over `1` and preferring `1` over `2`), and all `NullableAttribute` and `NullableContextAttribute` attributes with that value are removed.
That iterative process continues up to the module level.
If the common value at the module level is a value other than `0` (the default), a module level `NullableContext(value)` attribute is emitted.
That iterative process continues up to, and including, the top-level containing type definition.
If the common value at the top-level type definition is a value other than `0` (the default),
a `NullableContext(value)` attribute is emitted.

Note that an assembly compiled with C#8 where all reference types are oblivious will have no
`NullableContextAttribute` and no `NullableAttribute` attributes emitted.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public SynthesizedEmbeddedNullableContextAttributeSymbol(
internal override AttributeUsageInfo GetAttributeUsageInfo()
{
return new AttributeUsageInfo(
AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct,
AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct,
allowMultiple: false,
inherited: false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,37 @@ System.IAsyncResult BeginInvoke(System.Object?[] o, System.AsyncCallback callbac
AssertNullableAttributes(comp, expected);
}

[Fact]
public void EmitAttribute_NestedEnum()
{
var source =
@"#nullable enable
public class Program
{
public enum E
{
A,
B
}
public object F1;
public object F2;
public object F3;
}";
var comp = CreateCompilation(source);
var expected =
@"[NullableContext(1)] [Nullable(0)] Program
System.Object! F1
System.Object! F2
System.Object! F3
Program()
[NullableContext(0)] Program.E
A
B
E()
";
AssertNullableAttributes(comp, expected);
}

[Fact]
public void EmitAttribute_LambdaReturnType()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public class Program
Assert.False(attributeUsage.Inherited);
Assert.False(attributeUsage.AllowMultiple);
Assert.True(attributeUsage.HasValidAttributeTargets);
var expectedTargets = AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct;
var expectedTargets = AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct;
Assert.Equal(expectedTargets, attributeUsage.ValidTargets);
});
}
Expand Down Expand Up @@ -241,6 +241,53 @@ public class Program
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "Inherited").WithLocation(1, 1));
}

/// <summary>
/// Module-level NullableContextAttribute is ignored.
/// </summary>
[Fact]
public void ExplicitAttribute_Module()
{
var source0 =
@"namespace System.Runtime.CompilerServices
{
public sealed class NullableContextAttribute : Attribute
{
public NullableContextAttribute(byte b) { }
}
}";
var comp0 = CreateCompilation(source0);
var ref0 = comp0.EmitToImageReference();

var source1 =
@"Imports System.Runtime.CompilerServices
<Module: NullableContext(2)>
Public Class A
Public Shared FA As Object
End Class
<NullableContext(2)>
Public Class B
Public Shared FB As Object
End Class";
var comp1 = CreateVisualBasicCompilation(source1, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard).Concat(ref0));
var ref1 = comp1.EmitToImageReference();

var source2 =
@"#nullable enable
class Program
{
static void Main()
{
A.FA.ToString();
B.FB.ToString(); // warning
}
}";
var comp2 = CreateCompilation(source2, references: new[] { ref1 });
comp2.VerifyDiagnostics(
// (7,9): warning CS8602: Dereference of a possibly null reference.
// B.FB.ToString(); // warning
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "B.FB").WithLocation(7, 9));
}

[Fact]
public void AttributeField()
{
Expand Down
1 change: 0 additions & 1 deletion src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ public NullableAttribute(byte[] transformFlags)
namespace System.Runtime.CompilerServices
{
[System.AttributeUsage(
AttributeTargets.Module |
AttributeTargets.Class |
AttributeTargets.Delegate |
AttributeTargets.Interface |
Expand Down

0 comments on commit 0a24561

Please sign in to comment.