未验证 提交 5bb48dbd 编写于 作者: C Charles Stoner 提交者: GitHub

Set null state on dereference (#30564)

上级 c20eae14
...@@ -1354,6 +1354,8 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node) ...@@ -1354,6 +1354,8 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node)
Debug.Assert(!IsConditionalState); Debug.Assert(!IsConditionalState);
Debug.Assert(!node.Expression.Type.IsValueType); Debug.Assert(!node.Expression.Type.IsValueType);
// https://github.com/dotnet/roslyn/issues/30598: Mark receiver as not null
// after indices have been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(node.Expression); CheckPossibleNullReceiver(node.Expression);
var type = _resultType.TypeSymbol as ArrayTypeSymbol; var type = _resultType.TypeSymbol as ArrayTypeSymbol;
...@@ -1943,6 +1945,8 @@ public override BoundNode VisitCall(BoundCall node) ...@@ -1943,6 +1945,8 @@ public override BoundNode VisitCall(BoundCall node)
if (receiverOpt != null && method.MethodKind != MethodKind.Constructor) if (receiverOpt != null && method.MethodKind != MethodKind.Constructor)
{ {
VisitRvalue(receiverOpt); VisitRvalue(receiverOpt);
// https://github.com/dotnet/roslyn/issues/30598: Mark receiver as not null
// after arguments have been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(receiverOpt); CheckPossibleNullReceiver(receiverOpt);
// Update method based on inferred receiver type: see https://github.com/dotnet/roslyn/issues/29605. // Update method based on inferred receiver type: see https://github.com/dotnet/roslyn/issues/29605.
} }
...@@ -3303,6 +3307,10 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node) ...@@ -3303,6 +3307,10 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node)
if (receiverOpt != null) if (receiverOpt != null)
{ {
VisitRvalue(receiverOpt); VisitRvalue(receiverOpt);
// https://github.com/dotnet/roslyn/issues/30563: Should not check receiver here.
// That check should be handled when applying the method group conversion,
// when we have a specific method, to avoid reporting null receiver warnings
// for extension method delegates.
CheckPossibleNullReceiver(receiverOpt); CheckPossibleNullReceiver(receiverOpt);
} }
...@@ -3672,6 +3680,8 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node) ...@@ -3672,6 +3680,8 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node)
{ {
var receiverOpt = node.ReceiverOpt; var receiverOpt = node.ReceiverOpt;
VisitRvalue(receiverOpt); VisitRvalue(receiverOpt);
// https://github.com/dotnet/roslyn/issues/30598: Mark receiver as not null
// after indices have been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(receiverOpt); CheckPossibleNullReceiver(receiverOpt);
// https://github.com/dotnet/roslyn/issues/29964 Update indexer based on inferred receiver type. // https://github.com/dotnet/roslyn/issues/29964 Update indexer based on inferred receiver type.
...@@ -3698,6 +3708,8 @@ private void VisitMemberAccess(BoundExpression receiverOpt, Symbol member, bool ...@@ -3698,6 +3708,8 @@ private void VisitMemberAccess(BoundExpression receiverOpt, Symbol member, bool
if (!member.IsStatic) if (!member.IsStatic)
{ {
member = AsMemberOfResultType(member); member = AsMemberOfResultType(member);
// https://github.com/dotnet/roslyn/issues/30598: For l-values, mark receiver as not null
// after RHS has been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(receiverOpt); CheckPossibleNullReceiver(receiverOpt);
} }
...@@ -4206,6 +4218,8 @@ public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOpera ...@@ -4206,6 +4218,8 @@ public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOpera
var receiverOpt = node.ReceiverOpt; var receiverOpt = node.ReceiverOpt;
if (!node.Event.IsStatic) if (!node.Event.IsStatic)
{ {
// https://github.com/dotnet/roslyn/issues/30598: Mark receiver as not null
// after arguments have been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(receiverOpt); CheckPossibleNullReceiver(receiverOpt);
} }
VisitRvalue(node.Argument); VisitRvalue(node.Argument);
...@@ -4294,6 +4308,8 @@ public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess no ...@@ -4294,6 +4308,8 @@ public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess no
{ {
var receiver = node.ReceiverOpt; var receiver = node.ReceiverOpt;
VisitRvalue(receiver); VisitRvalue(receiver);
// https://github.com/dotnet/roslyn/issues/30598: Mark receiver as not null
// after indices have been visited, and only if the receiver has not changed.
CheckPossibleNullReceiver(receiver); CheckPossibleNullReceiver(receiver);
VisitArgumentsEvaluate(node.Arguments, node.ArgumentRefKindsOpt); VisitArgumentsEvaluate(node.Arguments, node.ArgumentRefKindsOpt);
...@@ -4309,6 +4325,7 @@ public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess no ...@@ -4309,6 +4325,7 @@ public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess no
private void CheckPossibleNullReceiver(BoundExpression receiverOpt) private void CheckPossibleNullReceiver(BoundExpression receiverOpt)
{ {
Debug.Assert(!this.IsConditionalState);
if (receiverOpt != null && this.State.Reachable) if (receiverOpt != null && this.State.Reachable)
{ {
#if DEBUG #if DEBUG
...@@ -4320,6 +4337,11 @@ private void CheckPossibleNullReceiver(BoundExpression receiverOpt) ...@@ -4320,6 +4337,11 @@ private void CheckPossibleNullReceiver(BoundExpression receiverOpt)
!resultType.IsValueType) !resultType.IsValueType)
{ {
ReportDiagnostic(ErrorCode.WRN_NullReferenceReceiver, receiverOpt.Syntax); ReportDiagnostic(ErrorCode.WRN_NullReferenceReceiver, receiverOpt.Syntax);
int slot = MakeSlot(receiverOpt);
if (slot > 0)
{
this.State[slot] = true;
}
} }
} }
} }
......
...@@ -312,7 +312,7 @@ protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByS ...@@ -312,7 +312,7 @@ protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByS
/// <summary> /// <summary>
/// A pending branch. These are created for a return, break, continue, goto statement, /// A pending branch. These are created for a return, break, continue, goto statement,
/// yield return, yield break, await expression, await foreach/using, and if PreciseAbstractFlowPass.trackExceptions /// yield return, yield break, await expression, await foreach/using, and if PreciseAbstractFlowPass._trackExceptions
/// is true for other /// is true for other
/// constructs that can cause an exception to be raised such as a throw statement or method /// constructs that can cause an exception to be raised such as a throw statement or method
/// invocation. /// invocation.
......
...@@ -25,7 +25,7 @@ internal sealed class CSharpConvertForEachToForCodeRefactoringProvider : ...@@ -25,7 +25,7 @@ internal sealed class CSharpConvertForEachToForCodeRefactoringProvider :
protected override ForEachStatementSyntax GetForEachStatement(TextSpan selection, SyntaxToken token) protected override ForEachStatementSyntax GetForEachStatement(TextSpan selection, SyntaxToken token)
{ {
var foreachStatement = token.Parent.FirstAncestorOrSelf<ForEachStatementSyntax>(); var foreachStatement = token.Parent.FirstAncestorOrSelf<ForEachStatementSyntax>();
// PROTOTYPE(async-streams): Add tests for this scenario // https://github.com/dotnet/roslyn/issues/30584: Add tests for this scenario
if (foreachStatement == null || foreachStatement.AwaitKeyword != default) if (foreachStatement == null || foreachStatement.AwaitKeyword != default)
{ {
return null; return null;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册