提交 24b42d0d 编写于 作者: N Neal Gafter 提交者: GitHub

Fix DeclaredInside for expression variables and deconstruction (#15646)

Fixes #12940
Fixes #14110
Fixes #15640
上级 20926a8c
......@@ -794,7 +794,7 @@ private static void FlattenDeconstructVariables(ArrayBuilder<DeconstructionVaria
if ((object)declType != null)
{
CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, designation);
return new BoundLocal(designation, localSymbol, constantValueOpt: null, type: declType, hasErrors: hasErrors);
return new BoundLocal(designation, localSymbol, isDeclaration: true, constantValueOpt: null, type: declType, hasErrors: hasErrors);
}
return new DeconstructionVariablePendingInference(designation, localSymbol, receiverOpt: null);
......
......@@ -2232,7 +2232,7 @@ private BoundExpression BindOutVariableArgument(DeclarationExpressionSyntax decl
CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax);
return new BoundLocal(declarationExpression, localSymbol, constantValueOpt: null, type: declType);
return new BoundLocal(declarationExpression, localSymbol, isDeclaration:true, constantValueOpt: null, type: declType);
}
// Is this a field?
......
......@@ -110,6 +110,21 @@ public override Symbol ExpressionSymbol
{
get { return this.LocalSymbol; }
}
public BoundLocal(SyntaxNode syntax, LocalSymbol localSymbol, ConstantValue constantValueOpt, TypeSymbol type, bool hasErrors)
: this(syntax, localSymbol, false, constantValueOpt, type, hasErrors)
{
}
public BoundLocal(SyntaxNode syntax, LocalSymbol localSymbol, ConstantValue constantValueOpt, TypeSymbol type)
: this(syntax, localSymbol, false, constantValueOpt, type)
{
}
public BoundLocal Update(LocalSymbol localSymbol, ConstantValue constantValueOpt, TypeSymbol type)
{
return this.Update(localSymbol, this.IsDeclaration, constantValueOpt, type);
}
}
internal partial class BoundFieldAccess
......
......@@ -1007,8 +1007,8 @@
<Node Name="BoundLocal" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="LocalSymbol" Type="LocalSymbol"/>
<Field Name="IsDeclaration" Type="bool"/>
<Field Name="ConstantValueOpt" Type="ConstantValue" Null="allow"/>
</Node>
......
......@@ -35,7 +35,7 @@ public BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, Diagno
}
local.SetType(type);
return new BoundLocal(this.Syntax, local, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed);
return new BoundLocal(this.Syntax, local, isDeclaration: true, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed);
case SymbolKind.Field:
var field = (GlobalExpressionVariable)this.VariableSymbol;
......
......@@ -47,7 +47,7 @@ private BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, Diagn
}
localSymbol.SetType(type);
return new BoundLocal(this.Syntax, localSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed);
return new BoundLocal(this.Syntax, localSymbol, isDeclaration: true, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed);
case SymbolKind.Field:
var fieldSymbol = (GlobalExpressionVariable)this.VariableSymbol;
......
......@@ -122,17 +122,25 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen
return base.VisitLocalFunctionStatement(node);
}
public override BoundNode VisitForEachStatement(BoundForEachStatement node)
public override void VisitForEachIterationVariable(BoundForEachStatement node)
{
if (IsInside)
{
_variablesDeclared.Add(node.IterationVariableOpt);
}
if (node.IterationVariableOpt != null)
{
_variablesDeclared.Add(node.IterationVariableOpt);
}
return base.VisitForEachStatement(node);
var leftVariables =
(node.DeconstructionOpt?.DeconstructionAssignment?.LeftVariables)
.GetValueOrDefault().NullToEmpty();
foreach (var variable in leftVariables)
{
Visit(variable);
}
}
}
protected override void VisitCatchBlock(BoundCatchBlock catchBlock, ref LocalState finallyState)
{
if (IsInside)
......@@ -163,31 +171,17 @@ public override BoundNode VisitQueryClause(BoundQueryClause node)
protected override void VisitLvalue(BoundLocal node)
{
CheckOutVarDeclaration(node);
base.VisitLvalue(node);
VisitLocal(node);
}
private void CheckOutVarDeclaration(BoundLocal node)
public override BoundNode VisitLocal(BoundLocal node)
{
if (IsInside &&
!node.WasCompilerGenerated && node.Syntax.Kind() == SyntaxKind.DeclarationExpression)
if (IsInside && node.IsDeclaration)
{
var declaration = (DeclarationExpressionSyntax)node.Syntax;
if (declaration.Designation.Kind() == SyntaxKind.SingleVariableDesignation &&
((SingleVariableDesignationSyntax)declaration.Designation).Identifier == node.LocalSymbol.IdentifierToken &&
declaration.Parent != null &&
declaration.Parent.Kind() == SyntaxKind.Argument &&
((ArgumentSyntax)declaration.Parent).RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword)
{
_variablesDeclared.Add(node.LocalSymbol);
}
_variablesDeclared.Add(node.LocalSymbol);
}
}
public override BoundNode VisitLocal(BoundLocal node)
{
CheckOutVarDeclaration(node);
return base.VisitLocal(node);
return null;
}
}
}
......@@ -5040,6 +5040,65 @@ public void FieldBeforeAssignedInStructCtor()
Assert.Equal(null, GetSymbolNamesJoined(analysis.DataFlowsOut));
}
[Fact, WorkItem(14110, "https://github.com/dotnet/roslyn/issues/14110")]
public void Test14110()
{
var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@"
class Program
{
static void Main()
{
var (a0, b0) = (1, 2);
(var c0, int d0) = (3, 4);
bool e0 = a0 is int f0;
bool g0 = a0 is var h0;
M(out int i0);
M(out var j0);
/*<bind>*/
var (a, b) = (1, 2);
(var c, int d) = (3, 4);
bool e = a is int f;
bool g = a is var h;
M(out int i);
M(out var j);
/*</bind>*/
var (a1, b1) = (1, 2);
(var c1, int d1) = (3, 4);
bool e1 = a1 is int f1;
bool g1 = a1 is var h1;
M(out int i1);
M(out var j1);
}
static void M(out int z) => throw null;
}
");
Assert.Equal("a, b, c, d, e, f, g, h, i, j", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared));
}
[Fact, WorkItem(15640, "https://github.com/dotnet/roslyn/issues/15640")]
public void Test15640()
{
var dataFlowAnalysisResults = CompileAndAnalyzeDataFlowStatements(@"
using System;
class Programand
{
static void Main()
{
foreach (var (a0, b0) in new[] { (1, 2) }) {}
/*<bind>*/
foreach (var (a, b) in new[] { (1, 2) }) {}
/*</bind>*/
foreach (var (a1, b1) in new[] { (1, 2) }) {}
}
}
");
Assert.Equal("a, b", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared));
}
#endregion
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册