Skip to content

Commit d69a792

Browse files
Merge branch 'main' into moreWait
2 parents aa8efc1 + 58e0ac1 commit d69a792

File tree

22 files changed

+980
-991
lines changed

22 files changed

+980
-991
lines changed

src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2541,6 +2541,7 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperator node)
25412541
do
25422542
{
25432543
stack.Push(binary);
2544+
EnterRegionIfNeeded(binary);
25442545
binary = binary.Left as BoundBinaryOperator;
25452546
}
25462547
while (binary != null && !binary.OperatorKind.IsLogical() && binary.InterpolatedStringHandlerData is null);
@@ -2550,6 +2551,7 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperator node)
25502551
}
25512552

25522553
#nullable enable
2554+
/// <param name="stack">Nested left-associative binary operators, pushed on from outermost to innermost.</param>
25532555
protected virtual void VisitBinaryOperatorChildren(ArrayBuilder<BoundBinaryOperator> stack)
25542556
{
25552557
var binary = stack.Pop();
@@ -2592,6 +2594,7 @@ protected virtual void VisitBinaryOperatorChildren(ArrayBuilder<BoundBinaryOpera
25922594
SetConditionalState(isNullConstant == isEquals(binary)
25932595
? (State, stateWhenNotNull)
25942596
: (stateWhenNotNull, State));
2597+
LeaveRegionIfNeeded(binary);
25952598

25962599
if (stack.Count == 0)
25972600
{
@@ -2609,6 +2612,7 @@ protected virtual void VisitBinaryOperatorChildren(ArrayBuilder<BoundBinaryOpera
26092612
Unsplit();
26102613
VisitRvalue(binary.Right);
26112614
}
2615+
LeaveRegionIfNeeded(binary);
26122616

26132617
if (stack.Count == 0)
26142618
{

src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ private NullableWalker(
462462
bool isSpeculative = false)
463463
: base(compilation, symbol, node, EmptyStructTypeCache.CreatePrecise(), trackUnassignments: true)
464464
{
465+
Debug.Assert(!TrackingRegions);
465466
Debug.Assert(!useDelegateInvokeParameterTypes || delegateInvokeMethodOpt is object);
466467
Debug.Assert(baseOrThisInitializer is null or { MethodKind: MethodKind.Constructor });
467468

src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9180,24 +9180,30 @@ private ForStatementSyntax ParseForStatement(SyntaxList<AttributeListSyntax> att
91809180
var openParen = this.EatToken(SyntaxKind.OpenParenToken);
91819181
var (variableDeclaration, initializers) = eatVariableDeclarationOrInitializers();
91829182

9183-
// Pulled out as we need to track this when parsing incrementors to place skipped tokens.
9184-
SyntaxToken secondSemicolonToken;
9183+
var firstSemicolonToken = eatCommaOrSemicolon();
9184+
var condition = this.CurrentToken.Kind is not SyntaxKind.SemicolonToken and not SyntaxKind.CommaToken
9185+
? this.ParseExpressionCore()
9186+
: null;
9187+
9188+
// Used to place skipped tokens we run into when parsing the incrementors list.
9189+
var secondSemicolonToken = eatCommaOrSemicolon();
9190+
9191+
// Do allow semicolons (with diagnostics) in the incrementors list. This allows us to consume
9192+
// accidental extra incrementors that should have been separated by commas.
9193+
var incrementors = this.CurrentToken.Kind != SyntaxKind.CloseParenToken
9194+
? parseForStatementExpressionList(ref secondSemicolonToken, allowSemicolonAsSeparator: true)
9195+
: default;
9196+
91859197
var forStatement = _syntaxFactory.ForStatement(
91869198
attributes,
91879199
forToken,
91889200
openParen,
91899201
variableDeclaration,
91909202
initializers,
9191-
firstSemicolonToken: eatCommaOrSemicolon(),
9192-
condition: this.CurrentToken.Kind is not SyntaxKind.SemicolonToken and not SyntaxKind.CommaToken
9193-
? this.ParseExpressionCore()
9194-
: null,
9195-
secondSemicolonToken = eatCommaOrSemicolon(),
9196-
// Do allow semicolons (with diagnostics) in the incrementors list. This allows us to consume
9197-
// accidental extra incrementors that should have been separated by commas.
9198-
incrementors: this.CurrentToken.Kind != SyntaxKind.CloseParenToken
9199-
? parseForStatementExpressionList(ref secondSemicolonToken, allowSemicolonAsSeparator: true)
9200-
: default,
9203+
firstSemicolonToken,
9204+
condition,
9205+
secondSemicolonToken,
9206+
incrementors,
92019207
eatUnexpectedTokensAndCloseParenToken(),
92029208
ParseEmbeddedStatement());
92039209

src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14147,5 +14147,128 @@ ref struct RS
1414714147
Assert.Null(GetSymbolNamesJoined(flowAnalysis.ReadInside));
1414814148
Assert.Equal("this", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
1414914149
}
14150+
14151+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")]
14152+
public void Repro_38087()
14153+
{
14154+
var comp = CreateCompilation("""
14155+
class Program
14156+
{
14157+
private static void Repro()
14158+
{
14159+
int i = 1, j = 2;
14160+
int k = i + j + 1;
14161+
}
14162+
}
14163+
""");
14164+
comp.VerifyEmitDiagnostics();
14165+
14166+
var tree = comp.CommonSyntaxTrees[0];
14167+
var model = comp.GetSemanticModel(tree);
14168+
14169+
var decls = tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().ToArray();
14170+
Assert.Equal(2, decls.Length);
14171+
var decl = decls[1];
14172+
Assert.Equal("int k = i + j + 1;", decl.ToString());
14173+
var flowAnalysis = model.AnalyzeDataFlow(decl);
14174+
Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14175+
14176+
var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray();
14177+
Assert.Equal(2, binOps.Length);
14178+
var add = binOps[0];
14179+
Assert.Equal("i + j + 1", add.ToString());
14180+
flowAnalysis = model.AnalyzeDataFlow(add);
14181+
Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14182+
14183+
add = binOps[1];
14184+
Assert.Equal("i + j", add.ToString());
14185+
flowAnalysis = model.AnalyzeDataFlow(add);
14186+
Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14187+
}
14188+
14189+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")]
14190+
public void FourBinaryOperands()
14191+
{
14192+
var comp = CreateCompilation("""
14193+
class Program
14194+
{
14195+
private static void Repro()
14196+
{
14197+
int i = 1, j = 2, k = 3, l = 4;
14198+
_ = i + j + k + l;
14199+
}
14200+
}
14201+
""");
14202+
comp.VerifyEmitDiagnostics();
14203+
14204+
var tree = comp.CommonSyntaxTrees[0];
14205+
var model = comp.GetSemanticModel(tree);
14206+
14207+
var decl = tree.GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().Single();
14208+
Assert.Equal("_ = i + j + k + l;", decl.ToString());
14209+
var flowAnalysis = model.AnalyzeDataFlow(decl);
14210+
Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14211+
14212+
var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray();
14213+
Assert.Equal(3, binOps.Length);
14214+
var add = binOps[0];
14215+
Assert.Equal("i + j + k + l", add.ToString());
14216+
flowAnalysis = model.AnalyzeDataFlow(add);
14217+
Assert.Equal("i, j, k, l", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14218+
14219+
add = binOps[1];
14220+
Assert.Equal("i + j + k", add.ToString());
14221+
flowAnalysis = model.AnalyzeDataFlow(add);
14222+
Assert.Equal("i, j, k", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14223+
14224+
add = binOps[2];
14225+
Assert.Equal("i + j", add.ToString());
14226+
flowAnalysis = model.AnalyzeDataFlow(add);
14227+
Assert.Equal("i, j", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14228+
}
14229+
14230+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")]
14231+
public void BinaryOpConditionalAccess()
14232+
{
14233+
var comp = CreateCompilation("""
14234+
class C
14235+
{
14236+
public bool M(out int x) { x = 0; return false; }
14237+
14238+
private static void Repro(C c)
14239+
{
14240+
const bool y = true;
14241+
const bool z = true;
14242+
int x;
14243+
_ = c?.M(out x) == y == z;
14244+
}
14245+
}
14246+
""");
14247+
comp.VerifyEmitDiagnostics();
14248+
14249+
var tree = comp.CommonSyntaxTrees[0];
14250+
var model = comp.GetSemanticModel(tree);
14251+
14252+
var decl = tree.GetRoot().DescendantNodes().OfType<ExpressionStatementSyntax>().Last();
14253+
Assert.Equal("_ = c?.M(out x) == y == z;", decl.ToString());
14254+
var flowAnalysis = model.AnalyzeDataFlow(decl);
14255+
Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14256+
Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
14257+
14258+
var binOps = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray();
14259+
Assert.Equal(2, binOps.Length);
14260+
14261+
var binOp = binOps[0];
14262+
Assert.Equal("c?.M(out x) == y == z", binOp.ToString());
14263+
flowAnalysis = model.AnalyzeDataFlow(binOp);
14264+
Assert.Equal("c, y, z", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14265+
Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
14266+
14267+
binOp = binOps[1];
14268+
Assert.Equal("c?.M(out x) == y", binOp.ToString());
14269+
flowAnalysis = model.AnalyzeDataFlow(binOp);
14270+
Assert.Equal("c, y", GetSymbolNamesJoined(flowAnalysis.ReadInside));
14271+
Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
14272+
}
1415014273
}
1415114274
}

src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3666,6 +3666,43 @@ enum VirtualKey
36663666
WalkTreeAndVerify(tree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot());
36673667
}
36683668

3669+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76439")]
3670+
public void InKeywordInsideAForBlock()
3671+
{
3672+
var source = """
3673+
void Main()
3674+
{
3675+
for (int i = 0; i < n; i++)
3676+
{
3677+
}
3678+
}
3679+
""";
3680+
var tree = SyntaxFactory.ParseSyntaxTree(source);
3681+
var text = tree.GetText();
3682+
3683+
// Update all the 'i's in the for-loop to be 'in' instead.
3684+
var position1 = source.IndexOf("i =") + 1;
3685+
var position2 = source.IndexOf("i <") + 1;
3686+
var position3 = source.IndexOf("i++") + 1;
3687+
text = text.WithChanges(
3688+
new TextChange(new TextSpan(position1, 0), "n"),
3689+
new TextChange(new TextSpan(position2, 0), "n"),
3690+
new TextChange(new TextSpan(position3, 0), "n"));
3691+
3692+
Assert.Equal("""
3693+
void Main()
3694+
{
3695+
for (int in = 0; in < n; in++)
3696+
{
3697+
}
3698+
}
3699+
""", text.ToString());
3700+
3701+
tree = tree.WithChangedText(text);
3702+
var fullTree = SyntaxFactory.ParseSyntaxTree(text.ToString());
3703+
WalkTreeAndVerify(tree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot());
3704+
}
3705+
36693706
#endregion
36703707

36713708
#region Helper functions

src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/RegionAnalysisTests.vb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9994,6 +9994,38 @@ End Module
99949994
capturedOutside)
99959995
End Sub
99969996

9997+
<WorkItem("https://github.com/dotnet/roslyn/issues/38087")>
9998+
<Fact()>
9999+
Public Sub NestedBinaryOperator()
10000+
Dim compilation = CreateCompilationWithMscorlib40AndVBRuntime(
10001+
<compilation>
10002+
<file name="a.vb">
10003+
Module Program
10004+
Sub M(i As Integer, j As Integer, k As Integer, l As Integer)
10005+
Dim x = i + j + k + l
10006+
End Sub
10007+
End Module
10008+
</file>
10009+
</compilation>)
10010+
10011+
Dim tree = compilation.SyntaxTrees.First()
10012+
Dim model = compilation.GetSemanticModel(tree)
10013+
Dim nodes = tree.GetRoot().DescendantNodes().OfType(Of BinaryExpressionSyntax)().ToArray()
10014+
Assert.Equal(3, nodes.Length)
10015+
10016+
Assert.Equal("i + j + k + l", nodes(0).ToString())
10017+
Dim dataFlowResults = model.AnalyzeDataFlow(nodes(0))
10018+
Assert.Equal("i, j, k, l", GetSymbolNamesJoined(dataFlowResults.ReadInside))
10019+
10020+
Assert.Equal("i + j + k", nodes(1).ToString())
10021+
dataFlowResults = model.AnalyzeDataFlow(nodes(1))
10022+
Assert.Equal("i, j, k", GetSymbolNamesJoined(dataFlowResults.ReadInside))
10023+
10024+
Assert.Equal("i + j", nodes(2).ToString())
10025+
dataFlowResults = model.AnalyzeDataFlow(nodes(2))
10026+
Assert.Equal("i, j", GetSymbolNamesJoined(dataFlowResults.ReadInside))
10027+
End Sub
10028+
999710029
#End Region
999810030

999910031
End Class

src/Features/CSharpTest/ExtractMethod/ExtractMethodCodeRefactoringTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6048,4 +6048,35 @@ struct S1
60486048
}
60496049
""");
60506050
}
6051+
6052+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38087")]
6053+
public async Task TestPartialSelectionOfArithmeticExpression()
6054+
{
6055+
await TestInRegularAndScript1Async(
6056+
"""
6057+
class C
6058+
{
6059+
private void Repro()
6060+
{
6061+
int i = 1, j = 2;
6062+
int k = [|i + j|] + 1;
6063+
}
6064+
}
6065+
""",
6066+
"""
6067+
class C
6068+
{
6069+
private void Repro()
6070+
{
6071+
int i = 1, j = 2;
6072+
int k = {|Rename:NewMethod|}(i, j) + 1;
6073+
}
6074+
6075+
private static int NewMethod(int i, int j)
6076+
{
6077+
return i + j;
6078+
}
6079+
}
6080+
""");
6081+
}
60516082
}

0 commit comments

Comments
 (0)