未验证 提交 32c9dc06 编写于 作者: C Chris Sienkiewicz 提交者: GitHub

Report nullability for attribute arguments: (#33816)

* Report nullability for attribute arguments:
- Add an entry point to nullable walker for attribute analysis
- Implement analyze attribute in the walker
- Update MethodThisParameter to not throw
- Add extra fields to BoundAttribute that are needed for nullable analysis
- Add tests



* PR Feedback:
- Analyse attributes even when we don't bind a constructor

- Add tests for when we don't bind constructor but still want to analyze what we have

* PR Feedback:
- fix typos
- make no matching constructors use implicit constructors

* Replace tabs with spaces

* Fix failing test
......@@ -147,22 +147,34 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
AnalyzedAttributeArguments analyzedArguments = attributeArgumentBinder.BindAttributeArguments(argumentListOpt, attributeTypeForBinding, diagnostics);
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
ImmutableArray<int> argsToParamsOpt = default;
bool expanded = false;
MethodSymbol attributeConstructor = null;
// Bind attributeType's constructor based on the bound constructor arguments
MethodSymbol attributeConstructor = attributeTypeForBinding.IsErrorType() ?
null :
BindAttributeConstructor(node, attributeTypeForBinding, analyzedArguments.ConstructorArguments, diagnostics, ref resultKind, suppressErrors: attributeType.IsErrorType(), useSiteDiagnostics: ref useSiteDiagnostics);
if (!attributeTypeForBinding.IsErrorType())
{
attributeConstructor = BindAttributeConstructor(node,
attributeTypeForBinding,
analyzedArguments.ConstructorArguments,
diagnostics,
ref resultKind,
suppressErrors: attributeType.IsErrorType(),
ref argsToParamsOpt,
ref expanded,
ref useSiteDiagnostics);
}
diagnostics.Add(node, useSiteDiagnostics);
if ((object)attributeConstructor != null)
if (!(attributeConstructor is null))
{
ReportDiagnosticsIfObsolete(diagnostics, attributeConstructor, node, hasBaseReceiver: false);
}
if (attributeConstructor?.Parameters.Any(p => p.RefKind == RefKind.In) == true)
if (attributeConstructor.Parameters.Any(p => p.RefKind == RefKind.In))
{
Error(diagnostics, ErrorCode.ERR_AttributeCtorInParameter, node, attributeConstructor.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
}
}
var constructorArguments = analyzedArguments.ConstructorArguments;
ImmutableArray<BoundExpression> boundConstructorArguments = constructorArguments.Arguments.ToImmutableAndFree();
......@@ -170,10 +182,9 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
ImmutableArray<BoundExpression> boundNamedArguments = analyzedArguments.NamedArguments;
constructorArguments.Free();
return new BoundAttribute(node, attributeConstructor, boundConstructorArguments, boundConstructorArgumentNamesOpt,
return new BoundAttribute(node, attributeConstructor, boundConstructorArguments, boundConstructorArgumentNamesOpt, argsToParamsOpt, expanded,
boundNamedArguments, resultKind, attributeType, hasErrors: resultKind != LookupResultKind.Viable);
}
private CSharpAttributeData GetAttribute(BoundAttribute boundAttribute, DiagnosticBag diagnostics)
{
var attributeType = (NamedTypeSymbol)boundAttribute.Type;
......@@ -181,6 +192,8 @@ private CSharpAttributeData GetAttribute(BoundAttribute boundAttribute, Diagnost
Debug.Assert((object)attributeType != null);
NullableWalker.AnalyzeIfNeeded(Compilation, boundAttribute, diagnostics);
bool hasErrors = boundAttribute.HasAnyErrors;
if (attributeType.IsErrorType() || attributeType.IsAbstract || (object)attributeConstructor == null)
......@@ -484,13 +497,15 @@ private TypeSymbol BindNamedAttributeArgumentType(AttributeArgumentSyntax namedA
return namedArgumentType;
}
protected virtual MethodSymbol BindAttributeConstructor(
protected MethodSymbol BindAttributeConstructor(
AttributeSyntax node,
NamedTypeSymbol attributeType,
AnalyzedArguments boundConstructorArguments,
DiagnosticBag diagnostics,
ref LookupResultKind resultKind,
bool suppressErrors,
ref ImmutableArray<int> argsToParamsOpt,
ref bool expanded,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
MemberResolutionResult<MethodSymbol> memberResolutionResult;
......@@ -511,7 +526,8 @@ private TypeSymbol BindNamedAttributeArgumentType(AttributeArgumentSyntax namedA
LookupResultKind.Inaccessible :
LookupResultKind.OverloadResolutionFailure);
}
argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
expanded = memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
return memberResolutionResult.Member;
}
......
......@@ -1438,6 +1438,8 @@
<Field Name="Constructor" Type="MethodSymbol" Null="allow"/>
<Field Name="ConstructorArguments" Type="ImmutableArray&lt;BoundExpression&gt;"/>
<Field Name="ConstructorArgumentNamesOpt" Type="ImmutableArray&lt;string&gt;" Null="allow"/>
<Field Name="ConstructorArgumentsToParamsOpt" Type="ImmutableArray&lt;int&gt;" Null="allow"/>
<Field Name="ConstructorExpanded" Type="bool" />
<Field Name="NamedArguments" Type ="ImmutableArray&lt;BoundExpression&gt;"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
</Node>
......
......@@ -423,8 +423,9 @@ protected ParameterSymbol MethodThisParameter
{
get
{
var method = _symbol as MethodSymbol;
return (object)method == null ? null : method.ThisParameter;
ParameterSymbol thisParameter = null;
(_symbol as MethodSymbol)?.TryGetThisParameter(out thisParameter);
return thisParameter;
}
}
......
......@@ -265,7 +265,7 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
this.State = TopState(); // entry point is reachable
this.regionPlace = RegionPlace.Before;
EnterParameters(); // with parameters assigned
if ((object)methodThisParameter != null)
if (!(methodThisParameter is null))
{
EnterParameter(methodThisParameter, methodThisParameter.Type);
}
......@@ -288,6 +288,19 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
Analyze(compilation, method, node, diagnostics, useMethodSignatureReturnType: false, useMethodSignatureParameterTypes: false, methodSignatureOpt: null, returnTypes: null, initialState: null, callbackOpt);
}
internal static void AnalyzeIfNeeded(
CSharpCompilation compilation,
BoundAttribute attribute,
DiagnosticBag diagnostics)
{
if (compilation.LanguageVersion < MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion())
{
return;
}
Analyze(compilation, null, attribute, diagnostics, useMethodSignatureReturnType: false, useMethodSignatureParameterTypes: false, methodSignatureOpt: null, returnTypes: null, initialState: null, callbackOpt: null);
}
internal static void Analyze(
CSharpCompilation compilation,
BoundLambda lambda,
......@@ -1097,7 +1110,13 @@ protected override LocalState ReachableBottomState()
private void EnterParameters()
{
var methodParameters = ((MethodSymbol)_symbol).Parameters;
var methodSymbol = _symbol as MethodSymbol;
if (methodSymbol is null)
{
return;
}
var methodParameters = methodSymbol.Parameters;
var signatureParameters = _useMethodSignatureParameterTypes ? _methodSignatureOpt.Parameters : methodParameters;
Debug.Assert(signatureParameters.Length == methodParameters.Length);
int n = methodParameters.Length;
......@@ -5726,6 +5745,18 @@ public override BoundNode VisitLockStatement(BoundLockStatement node)
return null;
}
public override BoundNode VisitAttribute(BoundAttribute node)
{
VisitArguments(node, node.ConstructorArguments, ImmutableArray<RefKind>.Empty, node.Constructor, argsToParamsOpt: node.ConstructorArgumentsToParamsOpt, expanded: node.ConstructorExpanded);
foreach (var assignment in node.NamedArguments)
{
Visit(assignment);
}
SetNotNullResult(node);
return null;
}
protected override string Dump(LocalState state)
{
if (!state.Reachable)
......
......@@ -6015,7 +6015,7 @@ protected override BoundExpression ShallowClone()
internal sealed partial class BoundAttribute : BoundExpression
{
public BoundAttribute(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray<BoundExpression> constructorArguments, ImmutableArray<string> constructorArgumentNamesOpt, ImmutableArray<BoundExpression> namedArguments, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false)
public BoundAttribute(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray<BoundExpression> constructorArguments, ImmutableArray<string> constructorArgumentNamesOpt, ImmutableArray<int> constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray<BoundExpression> namedArguments, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.Attribute, syntax, type, hasErrors || constructorArguments.HasErrors() || namedArguments.HasErrors())
{
......@@ -6026,6 +6026,8 @@ public BoundAttribute(SyntaxNode syntax, MethodSymbol constructor, ImmutableArra
this.Constructor = constructor;
this.ConstructorArguments = constructorArguments;
this.ConstructorArgumentNamesOpt = constructorArgumentNamesOpt;
this.ConstructorArgumentsToParamsOpt = constructorArgumentsToParamsOpt;
this.ConstructorExpanded = constructorExpanded;
this.NamedArguments = namedArguments;
this._ResultKind = resultKind;
}
......@@ -6037,6 +6039,10 @@ public BoundAttribute(SyntaxNode syntax, MethodSymbol constructor, ImmutableArra
public ImmutableArray<string> ConstructorArgumentNamesOpt { get; }
public ImmutableArray<int> ConstructorArgumentsToParamsOpt { get; }
public bool ConstructorExpanded { get; }
public ImmutableArray<BoundExpression> NamedArguments { get; }
private readonly LookupResultKind _ResultKind;
......@@ -6047,11 +6053,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor)
return visitor.VisitAttribute(this);
}
public BoundAttribute Update(MethodSymbol constructor, ImmutableArray<BoundExpression> constructorArguments, ImmutableArray<string> constructorArgumentNamesOpt, ImmutableArray<BoundExpression> namedArguments, LookupResultKind resultKind, TypeSymbol type)
public BoundAttribute Update(MethodSymbol constructor, ImmutableArray<BoundExpression> constructorArguments, ImmutableArray<string> constructorArgumentNamesOpt, ImmutableArray<int> constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray<BoundExpression> namedArguments, LookupResultKind resultKind, TypeSymbol type)
{
if (constructor != this.Constructor || constructorArguments != this.ConstructorArguments || constructorArgumentNamesOpt != this.ConstructorArgumentNamesOpt || namedArguments != this.NamedArguments || resultKind != this.ResultKind || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
if (constructor != this.Constructor || constructorArguments != this.ConstructorArguments || constructorArgumentNamesOpt != this.ConstructorArgumentNamesOpt || constructorArgumentsToParamsOpt != this.ConstructorArgumentsToParamsOpt || constructorExpanded != this.ConstructorExpanded || namedArguments != this.NamedArguments || resultKind != this.ResultKind || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
var result = new BoundAttribute(this.Syntax, constructor, constructorArguments, constructorArgumentNamesOpt, namedArguments, resultKind, type, this.HasErrors);
var result = new BoundAttribute(this.Syntax, constructor, constructorArguments, constructorArgumentNamesOpt, constructorArgumentsToParamsOpt, constructorExpanded, namedArguments, resultKind, type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
......@@ -6060,7 +6066,7 @@ public BoundAttribute Update(MethodSymbol constructor, ImmutableArray<BoundExpre
protected override BoundExpression ShallowClone()
{
var result = new BoundAttribute(this.Syntax, this.Constructor, this.ConstructorArguments, this.ConstructorArgumentNamesOpt, this.NamedArguments, this.ResultKind, this.Type, this.HasErrors);
var result = new BoundAttribute(this.Syntax, this.Constructor, this.ConstructorArguments, this.ConstructorArgumentNamesOpt, this.ConstructorArgumentsToParamsOpt, this.ConstructorExpanded, this.NamedArguments, this.ResultKind, this.Type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
......@@ -11801,7 +11807,7 @@ public override BoundNode VisitAttribute(BoundAttribute node)
ImmutableArray<BoundExpression> constructorArguments = (ImmutableArray<BoundExpression>)this.VisitList(node.ConstructorArguments);
ImmutableArray<BoundExpression> namedArguments = (ImmutableArray<BoundExpression>)this.VisitList(node.NamedArguments);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(node.Constructor, constructorArguments, node.ConstructorArgumentNamesOpt, namedArguments, node.ResultKind, type);
return node.Update(node.Constructor, constructorArguments, node.ConstructorArgumentNamesOpt, node.ConstructorArgumentsToParamsOpt, node.ConstructorExpanded, namedArguments, node.ResultKind, type);
}
public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node)
{
......@@ -13541,6 +13547,8 @@ public override TreeDumperNode VisitAttribute(BoundAttribute node, object arg)
new TreeDumperNode("constructor", node.Constructor, null),
new TreeDumperNode("constructorArguments", null, from x in node.ConstructorArguments select Visit(x, null)),
new TreeDumperNode("constructorArgumentNamesOpt", node.ConstructorArgumentNamesOpt, null),
new TreeDumperNode("constructorArgumentsToParamsOpt", node.ConstructorArgumentsToParamsOpt, null),
new TreeDumperNode("constructorExpanded", node.ConstructorExpanded, null),
new TreeDumperNode("namedArguments", null, from x in node.NamedArguments select Visit(x, null)),
new TreeDumperNode("resultKind", node.ResultKind, null),
new TreeDumperNode("type", node.Type, null),
......
......@@ -4578,8 +4578,11 @@ public class MyAttribute : System.Attribute
class C { }
";
var comp = CreateCompilation(source, options: TestOptions.DebugDll);
comp.VerifyDiagnostics();
// Expecting a warning. Issue tracked by https://github.com/dotnet/roslyn/issues/23697
comp.VerifyDiagnostics(
// (7,20): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [My(new string[] { null })]
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 20)
);
}
[Fact, WorkItem(31740, "https://github.com/dotnet/roslyn/issues/31740")]
......@@ -4626,6 +4629,893 @@ class C { }
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s) { }
}
[MyAttribute(null)] //1
class C { }
[MyAttribute(""str"")]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_Suppressed()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s) { }
}
[MyAttribute(null!)]
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_CSharp7_3()
{
var source =
@"
class MyAttribute : System.Attribute
{
public MyAttribute(string s) { }
}
[MyAttribute(null)]
class C { }
[MyAttribute(""str"")]
class D { }
";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3);
comp.VerifyDiagnostics();
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_WithDefaultArgument()
{
var source =
@"#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2 = ""str"") { }
}
[MyAttribute(null)] //1
class C { }
[MyAttribute(null, null)] // 2, 3
class D { }
[MyAttribute(null, ""str"")] // 4
class E { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 14),
// (10,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, null)] // 2, 3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 14),
// (10,20): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, null)] // 2, 3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 20),
// (13,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, "str")] // 4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_WithNullDefaultArgument()
{
var source =
@"#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2 = null) { } //1
}
[MyAttribute(""str"")]
class C { }
[MyAttribute(""str"", null)] // 2
class D { }
[MyAttribute(""str"", ""str"")]
class E { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,46): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// public MyAttribute(string s, string s2 = null) { } //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 46),
// (10,21): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("str", null)] // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 21)
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_WithNamedArguments()
{
var source =
@"#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2 = ""str"", string? s3 = ""str"") { }
}
[MyAttribute(""str"", s2: null, s3: null)] //1
class C { }
[MyAttribute(s3: null, s2: null, s: ""str"")] // 2
class D { }
[MyAttribute(s3: null, s2: ""str"", s: ""str"")]
class E { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,25): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("str", s2: null, s3: null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 25),
// (10,28): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(s3: null, s2: null, s: "str")] // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 28)
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_DisabledEnabled()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2) { }
}
[MyAttribute(null, //1
#nullable disable
null
#nullable enable
)]
class C { }
[MyAttribute(
#nullable disable
null,
#nullable enable
null //2
)]
class D { }
[MyAttribute(null, //3
s2:
#nullable disable
null
#nullable enable
)]
class E { }
[MyAttribute(
#nullable disable
null,
s2:
#nullable enable
null //4
)]
class F { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 14),
// (19,1): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// null //2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(19, 1),
// (23,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, //3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(23, 14),
// (36,1): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// null //4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(36, 1)
);
}
[Fact]
public void AttributeArgument_Constructor_NullLiteral_WarningDisabledEnabled()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2) { }
}
#nullable disable
#pragma warning enable nullable
[MyAttribute(null, //1
#pragma warning disable nullable
null
#pragma warning enable nullable
)]
class C { }
[MyAttribute(
#pragma warning disable nullable
null,
#pragma warning enable nullable
null //2
)]
class D { }
[MyAttribute(null, //3
s2:
#pragma warning disable nullable
null
#pragma warning enable nullable
)]
class E { }
[MyAttribute(
#pragma warning disable nullable
null,
s2:
#pragma warning enable nullable
null //4
)]
class F { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 14),
// (21,1): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// null //2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(21, 1),
// (25,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, //3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(25, 14),
// (38,1): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// null //4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(38, 1)
);
}
[Fact]
public void AttributeArgument_Constructor_Array_LiteralNull()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(null)] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_Array_LiteralNull_Suppressed()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(null!)]
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void AttributeArgument_Constructor_Array_ArrayOfNullable()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(new string?[]{ null })] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8620: Argument of type 'string?[]' cannot be used as an input of type 'string[]' for parameter 's' in 'MyAttribute.MyAttribute(string[] s)' due to differences in the nullability of reference types.
// [MyAttribute(new string?[]{ null })] //1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "new string?[]{ null }").WithArguments("string?[]", "string[]", "s", "MyAttribute.MyAttribute(string[] s)").WithLocation(8, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_Array_ArrayOfNullable_Suppressed()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(new string?[]{ null }!)]
class C { }
[MyAttribute(new string[]{ null! })]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}
[Fact]
public void AttributeArgument_Constructor_Array_ArrayOfNullable_ImplicitType()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(new []{ ""str"", null })] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8620: Argument of type 'string?[]' cannot be used as an input of type 'string[]' for parameter 's' in 'MyAttribute.MyAttribute(string[] s)' due to differences in the nullability of reference types.
// [MyAttribute(new []{ "str", null })] //1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, @"new []{ ""str"", null }").WithArguments("string?[]", "string[]", "s", "MyAttribute.MyAttribute(string[] s)").WithLocation(8, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_Array_NullValueInInitializer()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string[] s) { }
}
[MyAttribute(new string[]{ ""str"", null, ""str"" })] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,35): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(new string[]{ "str", null, "str" })] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 35)
);
}
[Fact]
public void AttributeArgument_Constructor_Array_NullValueInNestedInitializer()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(object[] s) { }
}
[MyAttribute(new object[]
{
new string[] { ""str"", null }, //1
new string[] { null }, //2
new string?[] { null }
})]
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,27): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// new string[] { "str", null }, //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 27),
// (11,20): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// new string[] { null }, //2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 20)
);
}
[Fact]
public void AttributeArgument_Constructor_ParamsArrayOfNullable_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(params object?[] s) { }
}
[MyAttribute(null)] //1
class C { }
[MyAttribute(null, null)]
class D { }
[MyAttribute((object?)null)]
class E { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 14)
);
}
[Fact]
public void AttributeArgument_Constructor_ParamsArray_NullItem()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute(string s1, params object[] s) { }
}
[MyAttribute(""str"", null, ""str"", ""str"")] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,21): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("str", null, "str", "str")] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 21)
);
}
[Fact]
public void AttributeArgument_PropertyAssignment_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string MyValue { get; set; } = ""str"";
}
[MyAttribute(MyValue = null)] //1
class C { }
[MyAttribute(MyValue = ""str"")]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,24): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(MyValue = null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24)
);
}
[Fact]
public void AttributeArgument_PropertyAssignment_Array_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string[] PropertyArray { get; set; } = new string[] { };
public string[]? NullablePropertyArray { get; set; } = null;
}
[MyAttribute(PropertyArray = null)] //1
class C { }
[MyAttribute(NullablePropertyArray = null)]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (13,30): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(PropertyArray = null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 30)
);
}
[Fact]
public void AttributeArgument_PropertyAssignment_Array_ArrayOfNullable()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string[] PropertyArray { get; set; } = new string[] { ""str"" };
public string[]? PropertyNullableArray { get; set; } = new string[] { ""str"" };
}
[MyAttribute(PropertyArray = new string?[]{ null })] //1
class C { }
[MyAttribute(PropertyNullableArray = null)]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,30): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// [MyAttribute(PropertyArray = new string?[]{ null })] //1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(12, 30)
);
}
[Fact]
public void AttributeArgument_FieldAssignment_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string myValue = ""str"";
}
[MyAttribute(myValue = null)] //1
class C { }
[MyAttribute(myValue = ""str"")]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,24): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(myValue = null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24)
);
}
[Fact]
public void AttributeArgument_FieldAssignment_Array_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string[] fieldArray = new string[] { };
public string[]? nullableFieldArray = null;
}
[MyAttribute(fieldArray = null)] //1
class C { }
[MyAttribute(nullableFieldArray = null)]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,27): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(fieldArray = null)] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 27)
);
}
[Fact]
public void AttributeArgument_FieldAssignment_Array_ArrayOfNullable()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public MyAttribute() { }
public string[] fieldArray = new string[] { };
public string?[] fieldArrayOfNullable = new string?[] { };
}
[MyAttribute(fieldArray = new string?[]{ null })] //1
class C { }
[MyAttribute(fieldArrayOfNullable = new string?[]{ null })]
class D { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (12,27): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// [MyAttribute(fieldArray = new string?[]{ null })] //1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(12, 27)
);
}
[Fact]
public void AttributeArgument_NoMatchingConstructor_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
}
[MyAttribute(null)] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,2): error CS1729: 'MyAttribute' does not contain a constructor that takes 1 arguments
// [MyAttribute(null)] //1
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "MyAttribute(null)").WithArguments("MyAttribute", "1").WithLocation(7, 2)
);
}
[Fact]
public void AttributeArgument_NoMatchingConstructor_Array_NullValueInInitializer()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
}
[MyAttribute(new string[] { null })] //1
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (7,2): error CS1729: 'MyAttribute' does not contain a constructor that takes 1 arguments
// [MyAttribute(new string[] { null })] //1
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "MyAttribute(new string[] { null })").WithArguments("MyAttribute", "1").WithLocation(7, 2),
// (7,29): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(new string[] { null })] //1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 29)
);
}
[Fact]
public void AttributeArgument_NoMatchingConstructor_PropertyAssignment_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public string[] PropertyArray { get; set; } = new string[] { ""str"" };
public string[]? PropertyNullableArray { get; set; } = new string[] { ""str"" };
}
[MyAttribute( // 1
new string[] { null }, // 2
PropertyArray = null, // 3
PropertyNullableArray = new string[] { null } // 4
)]
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,2): error CS1729: 'MyAttribute' does not contain a constructor that takes 1 arguments
// [MyAttribute( // 1
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"MyAttribute( // 1
new string[] { null }, // 2
PropertyArray = null, // 3
PropertyNullableArray = new string[] { null } // 4
)").WithArguments("MyAttribute", "1").WithLocation(10, 2),
// (11,20): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// new string[] { null }, // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 20),
// (12,21): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// PropertyArray = null, // 3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 21),
// (13,44): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// PropertyNullableArray = new string[] { null } // 4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 44)
);
}
[Fact]
public void AttributeArgument_NoMatchingConstructor_FieldAssignment_NullLiteral()
{
var source =
@"
#nullable enable
class MyAttribute : System.Attribute
{
public string[] fieldArray = new string[] { };
public string?[] fieldArrayOfNullable = new string?[] { };
}
[MyAttribute( // 1
new string[] { null }, // 2
fieldArray = null, // 3
fieldArrayOfNullable = new string[] { null } // 4
)]
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,2): error CS1729: 'MyAttribute' does not contain a constructor that takes 1 arguments
// [MyAttribute( // 1
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"MyAttribute( // 1
new string[] { null }, // 2
fieldArray = null, // 3
fieldArrayOfNullable = new string[] { null } // 4
)").WithArguments("MyAttribute", "1").WithLocation(10, 2),
// (11,20): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// new string[] { null }, // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 20),
// (12,18): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// fieldArray = null, // 3
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 18),
// (13,43): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// fieldArrayOfNullable = new string[] { null } // 4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 43)
);
}
[Fact]
public void AttributeArgument_ComplexAssignment()
{
var source =
@"
#nullable enable
[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true)]
class MyAttribute : System.Attribute
{
public MyAttribute(string s, string s2 = ""str"", string s3 = ""str"") { }
public string[] fieldArray = new string[] { };
public string?[] fieldArrayOfNullable = new string[] { };
public string[]? nullableFieldArray = null;
public string[] PropertyArray { get; set; } = new string[] { };
public string?[] PropertyArrayOfNullable { get; set; } = new string[] { };
public string[]? NullablePropertyArray { get; set; } = null;
}
[MyAttribute(""s1"")]
[MyAttribute(""s1"", s3: ""s3"", fieldArray = new string[]{})]
[MyAttribute(""s1"", s2: ""s2"", fieldArray = new string[]{}, PropertyArray = new string[]{})]
[MyAttribute(""s1"", fieldArrayOfNullable = new string?[]{ null }, NullablePropertyArray = null)]
[MyAttribute(null)] // 1
[MyAttribute(""s1"", s3: null, fieldArray = new string[]{})] // 2
[MyAttribute(""s1"", s2: ""s2"", fieldArray = new string?[]{ null }, PropertyArray = new string[]{})] // 3
[MyAttribute(""s1"", PropertyArrayOfNullable = null)] // 4
[MyAttribute(""s1"", NullablePropertyArray = new string?[]{ null })] // 5
[MyAttribute(""s1"", fieldArrayOfNullable = null)] // 6
[MyAttribute(""s1"", nullableFieldArray = new string[]{ null })] // 7
[MyAttribute(null, //8
s2: null, //9
fieldArrayOfNullable = null, //10
NullablePropertyArray = new string?[]{ null })] // 11
[MyAttribute(null, // 12
#nullable disable
s2: null,
#nullable enable
fieldArrayOfNullable = null, //13
#pragma warning disable nullable
NullablePropertyArray = new string?[]{ null },
#pragma warning enable nullable
nullableFieldArray = new string?[]{ null })] //14
class C { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (26,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null)] // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(26, 14),
// (27,24): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("s1", s3: null, fieldArray = new string[]{})] // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(27, 24),
// (28,43): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// [MyAttribute("s1", s2: "s2", fieldArray = new string?[]{ null }, PropertyArray = new string[]{})] // 3
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(28, 43),
// (29,46): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("s1", PropertyArrayOfNullable = null)] // 4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(29, 46),
// (30,44): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// [MyAttribute("s1", NullablePropertyArray = new string?[]{ null })] // 5
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(30, 44),
// (31,43): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("s1", fieldArrayOfNullable = null)] // 6
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(31, 43),
// (32,55): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute("s1", nullableFieldArray = new string[]{ null })] // 7
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(32, 55),
// (33,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, //8
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(33, 14),
// (34,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// s2: null, //9
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(34, 17),
// (35,36): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// fieldArrayOfNullable = null, //10
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(35, 36),
// (36,37): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// NullablePropertyArray = new string?[]{ null })] // 11
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(36, 37),
// (37,14): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// [MyAttribute(null, // 12
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(37, 14),
// (41,36): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// fieldArrayOfNullable = null, //13
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(41, 36),
// (45,34): warning CS8619: Nullability of reference types in value of type 'string?[]' doesn't match target type 'string[]'.
// nullableFieldArray = new string?[]{ null })] //14
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new string?[]{ null }").WithArguments("string?[]", "string[]").WithLocation(45, 34)
);
}
[Fact]
public void NullableAndConditionalOperators()
{
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册