提交 5abfbeeb 编写于 作者: W Wonseok Chae

VS crash during EnC around active statements

It updates earlier C# implementation and ports to VB (#3894)
上级 3c027a4c
......@@ -78,6 +78,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax
Dim kind = CType(before.RawKind, SyntaxKind)
If Not AreModifiersEquivalent(before, after, kind) Then
Return False
End If
If topLevel Then
Select Case kind
Case SyntaxKind.SubBlock,
......@@ -173,5 +177,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax
Return True
End If
End Function
Private Function AreModifiersEquivalent(before As GreenNode, after As GreenNode, kind As SyntaxKind) As Boolean
Select Case kind
Case SyntaxKind.SubBlock,
SyntaxKind.FunctionBlock
Dim beforeModifiers = DirectCast(before, Green.MethodBlockBaseSyntax).Begin.Modifiers
Dim afterModifiers = DirectCast(after, Green.MethodBlockBaseSyntax).Begin.Modifiers
If beforeModifiers.Count <> afterModifiers.Count Then
Return False
End If
For i = 0 To beforeModifiers.Count - 1
If Not beforeModifiers.Any(afterModifiers(i).Kind) Then
Return False
End If
Next
End Select
Return True
End Function
End Module
End Namespace
......@@ -7437,8 +7437,7 @@ static async Task<int> F()
var active = GetActiveStatements(src1, src2);
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.InsertAroundActiveStatement, "await", CSharpFeaturesResources.AwaitExpression),
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async Task<int> F()"));
Diagnostic(RudeEditKind.InsertAroundActiveStatement, "await", CSharpFeaturesResources.AwaitExpression));
}
[Fact]
......@@ -7557,6 +7556,34 @@ static async void F()
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "static async void F()"));
}
[Fact]
public void MethodToAsyncMethod_WithActiveStatementInLambda_3()
{
string src1 = @"
class C
{
static void F()
{
var f = new Action(() => { <AS:0>Console.WriteLine(1);</AS:0> });
}
}
";
string src2 = @"
class C
{
static async void F()
{
var f = new Action(async () => { <AS:0>Console.WriteLine(1);</AS:0> });
}
}
";
var edits = GetTopEdits(src1, src2);
var active = GetActiveStatements(src1, src2);
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "()"));
}
[Fact]
public void MethodToAsyncMethod_WithLambda()
{
......
......@@ -4738,7 +4738,7 @@ End Class
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithActiveStatement()
Public Sub MethodToAsyncMethod_WithActiveStatement1()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
......@@ -4767,14 +4767,71 @@ End Class
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithActiveStatementInLambda()
Public Sub MethodToAsyncMethod_WithActiveStatement2()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
<AS:0>Function F() As Task(Of Integer)</AS:0>
Console.WriteLine(1)
Return Task.FromResult(1)
End Function
End Class
"
Dim src2 = "
Imports System
Imports System.Threading.Tasks
Class C
<AS:0>Async Function F() As Task(Of Integer)</AS:0>
Console.WriteLine(1)
Return 1
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
Dim active = GetActiveStatements(src1, src2)
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "Async Function F()"))
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithActiveStatement3()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
Function F() As Task(Of Integer)
<AS:0>Console.WriteLine(1)</AS:0>
Return Task.FromResult(1)
End Function
End Class
"
Dim src2 = "
Imports System
Imports System.Threading.Tasks
Class C
Async Function F() As Task(Of Integer)
<AS:0>Console.WriteLine(1)</AS:0>
Return 1
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
Dim active = GetActiveStatements(src1, src2)
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "Async Function F()"))
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithActiveStatementInLambda1()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
Function F() As Task(Of Integer)
Dim a = Sub() <AS:0>Console.WriteLine(1)</AS:0>
a()
Return Task.FromResult(1)
End Function
End Class
......@@ -4785,7 +4842,6 @@ Imports System.Threading.Tasks
Class C
Async Function F() As Task(Of Integer)
Dim a = Sub() <AS:0>Console.WriteLine(1)</AS:0>
a()
Return Await Task.FromResult(1)
End Function
End Class
......@@ -4797,7 +4853,69 @@ End Class
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithoutActiveStatement()
Public Sub MethodToAsyncMethod_WithActiveStatementInLambda2()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
Function F() As Task(Of Integer)
Dim a = Sub() <AS:1>Console.WriteLine(1)</AS:1>
<AS:0>a()</AS:0>
Return Task.FromResult(1)
End Function
End Class
"
Dim src2 = "
Imports System
Imports System.Threading.Tasks
Class C
Async Function F() As Task(Of Integer)
Dim a = Sub() <AS:1>Console.WriteLine(1)</AS:1>
<AS:0>a()</AS:0>
Return 1
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
Dim active = GetActiveStatements(src1, src2)
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "Async Function F()"))
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithActiveStatementInLambda3()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
Sub F()
Dim a = Sub() <AS:1>Console.WriteLine(1)</AS:1>
<AS:0>a()</AS:0>
Return
End Sub
End Class
"
Dim src2 = "
Imports System
Imports System.Threading.Tasks
Class C
Async Sub F()
Dim a = Sub() <AS:1>Console.WriteLine(1)</AS:1>
<AS:0>a()</AS:0>
Return
End Sub
End Class
"
Dim edits = GetTopEdits(src1, src2)
Dim active = GetActiveStatements(src1, src2)
edits.VerifyRudeDiagnostics(active,
Diagnostic(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, "Async Sub F()"))
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithoutActiveStatement1()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
......@@ -4823,6 +4941,34 @@ End Class
edits.VerifyRudeDiagnostics(active)
End Sub
<Fact>
Public Sub MethodToAsyncMethod_WithoutActiveStatement2()
Dim src1 = "
Imports System
Imports System.Threading.Tasks
Class C
Sub F()
Console.WriteLine(1)
Return
End Sub
End Class
"
Dim src2 = "
Imports System
Imports System.Threading.Tasks
Class C
Async Sub F()
Console.WriteLine(1)
Return
End Sub
End Class
"
Dim edits = GetTopEdits(src1, src2)
Dim active = GetActiveStatements(src1, src2)
edits.VerifyRudeDiagnostics(active)
End Sub
#End Region
#Region "On Error"
......
......@@ -60,7 +60,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests
Dim diagnostics = New List(Of RudeEditDiagnostic)()
Dim needsSyntaxMap As Boolean
Dim match = Analyzer.ComputeBodyMatch(m1, m2, {New AbstractEditAndContinueAnalyzer.ActiveNode}, diagnostics, needsSyntaxMap)
Dim match = Analyzer.ComputeBodyMatch(m1, m2, Array.Empty(Of AbstractEditAndContinueAnalyzer.ActiveNode)(), diagnostics, needsSyntaxMap)
Assert.Equal(stateMachine <> StateMachineKind.None, needsSyntaxMap)
......
......@@ -1898,16 +1898,32 @@ End Class
End Sub
<Fact>
Public Sub MethodUpdate_AsyncModifier()
Public Sub MethodUpdate_AsyncModifier1()
Dim src1 = "Class C : " & vbLf & "Function F() As Task(Of String) : End Function : End Class"
Dim src2 = "Class C : " & vbLf & "Async Function F() As Task(Of String) : End Function : End Class"
Dim edits = GetTopEdits(src1, src2)
edits.VerifyEdits(
"Update [Function F() As Task(Of String) : End Function]@11 -> [Async Function F() As Task(Of String) : End Function]@11",
"Update [Function F() As Task(Of String)]@11 -> [Async Function F() As Task(Of String)]@11")
edits.VerifyRudeDiagnostics()
End Sub
<Fact>
Public Sub MethodUpdate_AsyncModifier2()
Dim src1 = "Class C : " & vbLf & "Async Function F() As Task(Of String) : End Function : End Class"
Dim src2 = "Class C : " & vbLf & "Function F() As Task(Of String) : End Function : End Class"
Dim edits = GetTopEdits(src1, src2)
edits.VerifyEdits(
"Update [Async Function F() As Task(Of String) : End Function]@11 -> [Function F() As Task(Of String) : End Function]@11",
"Update [Async Function F() As Task(Of String)]@11 -> [Function F() As Task(Of String)]@11")
edits.VerifyRudeDiagnostics()
edits.VerifyRudeDiagnostics(
Diagnostic(RudeEditKind.ModifiersUpdate, "Function F()", FeaturesResources.Method))
End Sub
<Fact>
......
......@@ -3011,15 +3011,12 @@ private static bool IsSimpleAwaitAssignment(SyntaxNode node, SyntaxNode awaitExp
internal override void ReportOtherRudeEditsAroundActiveStatement(
List<RudeEditDiagnostic> diagnostics,
Match<SyntaxNode> match,
SyntaxNode oldBody,
SyntaxNode newBody,
SyntaxNode oldActiveStatement,
SyntaxNode newActiveStatement,
bool isLeaf)
{
ReportRudeEditsForAncestorsDeclaringInterStatementTemps(diagnostics, match, oldActiveStatement, newActiveStatement, isLeaf);
ReportRudeEditsForCheckedStatements(diagnostics, oldActiveStatement, newActiveStatement, isLeaf);
ReportRudeEditsForStateMachineMethod(diagnostics, oldBody, newBody, oldActiveStatement, newActiveStatement);
}
private void ReportRudeEditsForCheckedStatements(
......@@ -3132,19 +3129,11 @@ private static bool DeclareSameIdentifiers(SeparatedSyntaxList<VariableDeclarato
return true;
}
private void ReportRudeEditsForStateMachineMethod(
internal override void ReportRudeEditsForStateMachineMethod(
List<RudeEditDiagnostic> diagnostics,
SyntaxNode oldBody,
SyntaxNode newBody,
SyntaxNode oldActiveStatement,
SyntaxNode newActiveStatement)
SyntaxNode newBody)
{
var isInLambdaBody = FindEnclosingLambdaBody(oldBody, oldActiveStatement);
if (isInLambdaBody != null)
{
return;
}
// It is allow to update a regular method to an async method or an iterator.
// The only restriction is a presence of an active statement in the method body
// since the debugger does not support remapping active statements to a different method.
......
......@@ -234,7 +234,8 @@ private SyntaxNode FindStatement(SyntaxNode declarationBody, int position, out i
internal abstract void ReportSyntacticRudeEdits(List<RudeEditDiagnostic> diagnostics, Match<SyntaxNode> match, Edit<SyntaxNode> edit, Dictionary<SyntaxNode, EditKind> editMap);
internal abstract void ReportEnclosingExceptionHandlingRudeEdits(List<RudeEditDiagnostic> diagnostics, IEnumerable<Edit<SyntaxNode>> exceptionHandlingEdits, SyntaxNode oldStatement, SyntaxNode newStatement);
internal abstract void ReportOtherRudeEditsAroundActiveStatement(List<RudeEditDiagnostic> diagnostics, Match<SyntaxNode> match, SyntaxNode oldBody, SyntaxNode newBody, SyntaxNode oldStatement, SyntaxNode newStatement, bool isLeaf);
internal abstract void ReportOtherRudeEditsAroundActiveStatement(List<RudeEditDiagnostic> diagnostics, Match<SyntaxNode> match, SyntaxNode oldStatement, SyntaxNode newStatement, bool isLeaf);
internal abstract void ReportRudeEditsForStateMachineMethod(List<RudeEditDiagnostic> diagnostics, SyntaxNode oldBody, SyntaxNode newBody);
internal abstract void ReportMemberUpdateRudeEdits(List<RudeEditDiagnostic> diagnostics, SyntaxNode newMember, TextSpan? span);
internal abstract void ReportInsertedMemberSymbolRudeEdits(List<RudeEditDiagnostic> diagnostics, ISymbol newSymbol);
internal abstract void ReportStateMachineSuspensionPointRudeEdits(List<RudeEditDiagnostic> diagnostics, SyntaxNode oldNode, SyntaxNode newNode);
......@@ -1062,7 +1063,7 @@ internal struct UpdatedMemberInfo
}
// other statements around active statement:
ReportOtherRudeEditsAroundActiveStatement(diagnostics, match, oldBody, newBody, oldStatementSyntax, newStatementSyntax, isLeaf);
ReportOtherRudeEditsAroundActiveStatement(diagnostics, match, oldStatementSyntax, newStatementSyntax, isLeaf);
}
else if (match == null)
{
......@@ -1305,6 +1306,11 @@ internal struct UpdatedMemberInfo
ReportStateMachineSuspensionPointRudeEdits(diagnostics, oldStateMachineSuspensionPoints[i], newStateMachineSuspensionPoints[i]);
}
}
else if (activeNodes.Length > 0)
{
// other state machine related issue around active statement:
ReportRudeEditsForStateMachineMethod(diagnostics, oldBody, newBody);
}
return match;
}
......
......@@ -2594,6 +2594,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
newModifiers = newModifiers.RemoveAt(newAsyncIndex)
End If
' 'async' keyword is allowed to add, but not to remove
If oldAsyncIndex >= 0 AndAlso newAsyncIndex < 0 Then
Return False
End If
Dim oldIteratorIndex = oldModifiers.IndexOf(SyntaxKind.IteratorKeyword)
Dim newIteratorIndex = newModifiers.IndexOf(SyntaxKind.IteratorKeyword)
......@@ -2605,6 +2610,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
newModifiers = newModifiers.RemoveAt(newIteratorIndex)
End If
' 'iterator' keyword is allowed to add, but not to remove
If oldIteratorIndex >= 0 AndAlso newIteratorIndex < 0 Then
Return False
End If
Return SyntaxFactory.AreEquivalent(oldModifiers, newModifiers)
End Function
......@@ -3091,8 +3101,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
Friend Overrides Sub ReportOtherRudeEditsAroundActiveStatement(diagnostics As List(Of RudeEditDiagnostic),
match As Match(Of SyntaxNode),
oldBody As SyntaxNode,
newBody As SyntaxNode,
oldActiveStatement As SyntaxNode,
newActiveStatement As SyntaxNode,
isLeaf As Boolean)
......@@ -3154,6 +3162,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
areSimilar:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(DirectCast(n1.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable,
DirectCast(n2.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable))
End Sub
Friend Overrides Sub ReportRudeEditsForStateMachineMethod(diagnostics As List(Of RudeEditDiagnostic),
oldBody As SyntaxNode,
newBody As SyntaxNode)
' It Is allow to update a regular method to an async method Or an iterator.
' The only restriction Is a presence of an active statement in the method body
' since the debugger does Not support remapping active statements to a different method.
Dim IsAsyncAdded = Not SyntaxUtilities.IsAsyncMethodOrLambda(oldBody) AndAlso SyntaxUtilities.IsAsyncMethodOrLambda(newBody)
Dim IsIteratorAdded = Not SyntaxUtilities.IsIteratorMethodOrLambda(oldBody) AndAlso SyntaxUtilities.IsIteratorMethodOrLambda(newBody)
If IsAsyncAdded OrElse IsIteratorAdded Then
diagnostics.Add(New RudeEditDiagnostic(
RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement,
GetDiagnosticSpan(newBody, EditKind.Update)))
End If
End Sub
#End Region
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册