提交 afec3b7f 编写于 作者: T Tomas Matousek

Report rude edit when editing async/iterator method and SM attribute is not available

上级 5f108382
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Emit
{
......@@ -36,6 +33,8 @@ internal sealed partial class CSharpDefinitionMap : DefinitionMap<CSharpSymbolMa
_metadataDecoder = metadataDecoder;
}
internal override CommonMessageProvider MessageProvider => CSharp.MessageProvider.Instance;
internal bool TryGetAnonymousTypeName(NamedTypeSymbol template, out string name, out int index)
{
return this.mapToPrevious.TryGetAnonymousTypeName(template, out name, out index);
......
......@@ -203,6 +203,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost
public override int ERR_EncReferenceToAddedMember { get { return (int)ErrorCode.ERR_EncReferenceToAddedMember; } }
public override int ERR_TooManyUserStrings { get { return (int)ErrorCode.ERR_TooManyUserStrings; } }
public override int ERR_PeWritingFailure { get { return (int)ErrorCode.ERR_PeWritingFailure; } }
public override int ERR_ModuleEmitFailure { get { return (int)ErrorCode.ERR_ModuleEmitFailure; } }
public override void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
......
......@@ -96,7 +96,7 @@ private FieldSymbol GetAwaiterField(TypeSymbol awaiterType)
if (!_awaiterFields.TryGetValue(awaiterType, out result))
{
int slotIndex;
if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousAwaiterSlotIndex(F.ModuleBuilderOpt.Translate(awaiterType, F.Syntax, F.Diagnostics), out slotIndex))
if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousAwaiterSlotIndex(F.ModuleBuilderOpt.Translate(awaiterType, F.Syntax, F.Diagnostics), F.Diagnostics, out slotIndex))
{
slotIndex = _nextAwaiterId++;
}
......
......@@ -550,7 +550,14 @@ private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssi
// Editing await expression is not allowed. Thus all spilled fields will be present in the previous state machine.
// However, it may happen that the type changes, in which case we need to allocate a new slot.
int slotIndex;
if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(awaitSyntaxOpt, F.ModuleBuilderOpt.Translate(fieldType, awaitSyntaxOpt, Diagnostics), kind, id, out slotIndex))
if (slotAllocatorOpt == null ||
!slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(
awaitSyntaxOpt,
F.ModuleBuilderOpt.Translate(fieldType, awaitSyntaxOpt, Diagnostics),
kind,
id,
Diagnostics,
out slotIndex))
{
slotIndex = _nextFreeHoistedLocalSlot++;
}
......
......@@ -172,7 +172,13 @@ protected BoundStatement Rewrite()
// map local id to the previous id, if available:
int previousSlotIndex;
if (mapToPreviousFields && slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(declaratorSyntax, F.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, diagnostics), synthesizedKind, id, out previousSlotIndex))
if (mapToPreviousFields && slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(
declaratorSyntax,
F.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, diagnostics),
synthesizedKind,
id,
diagnostics,
out previousSlotIndex))
{
slotIndex = previousSlotIndex;
}
......
......@@ -4702,5 +4702,119 @@ .maxstack 5
"<>f__AnonymousType5<<<>h__TransparentIdentifier0>j__TPar, <length>j__TPar>: {Equals, GetHashCode, ToString}",
"<>f__AnonymousType2<<<>h__TransparentIdentifier0>j__TPar, <y>j__TPar>: {Equals, GetHashCode, ToString}");
}
[Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")]
public void MissingIteratorStateMachineAttribute()
{
var source0 = MarkedSource(@"
using System;
using System.Collections.Generic;
class C
{
public IEnumerable<int> F()
{
int <N:0>a = 0</N:0>;
<N:1>yield return 0;</N:1>
Console.WriteLine(a);
}
}
");
var source1 = MarkedSource(@"
using System;
using System.Collections.Generic;
class C
{
public IEnumerable<int> F()
{
int <N:0>a = 1</N:0>;
<N:1>yield return 1;</N:1>
Console.WriteLine(a);
}
}
");
var compilation0 = CreateCompilationWithMscorlib(new[] { source0.Tree }, options: ComSafeDebugDll);
var compilation1 = compilation0.WithSource(source1.Tree);
// older versions of mscorlib don't contain IteratorStateMachineAttribute
Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor));
var v0 = CompileAndVerify(compilation0);
v0.VerifyDiagnostics();
var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData);
var f0 = compilation0.GetMember<MethodSymbol>("C.F");
var f1 = compilation1.GetMember<MethodSymbol>("C.F");
var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo);
var diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(
new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true)));
diff1.EmitResult.Diagnostics.Verify(
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name));
}
[Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")]
public void MissingAsyncStateMachineAttribute()
{
var source0 = MarkedSource(@"
using System.Threading.Tasks;
class C
{
public async Task<int> F()
{
int <N:0>a = 0</N:0>;
<N:1>await new Task();</N:1>
return a;
}
}
");
var source1 = MarkedSource(@"
using System.Threading.Tasks;
class C
{
public async Task<int> F()
{
int <N:0>a = 1</N:0>;
<N:1>await new Task();</N:1>
return a;
}
}
");
var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync }, options: ComSafeDebugDll);
var compilation1 = compilation0.WithSource(source1.Tree);
// older versions of mscorlib don't contain AsyncStateMachineAttribute, IteratorStateMachineAttribute
Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor));
Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor));
var v0 = CompileAndVerify(compilation0, verify: false);
var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData);
var f0 = compilation0.GetMember<MethodSymbol>("C.F");
var f1 = compilation1.GetMember<MethodSymbol>("C.F");
var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo);
var diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(
new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true)));
diff1.EmitResult.Diagnostics.Verify(
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name),
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name));
}
}
}
......@@ -30,6 +30,7 @@ internal abstract class VariableSlotAllocator
Cci.ITypeReference currentType,
SynthesizedLocalKind synthesizedKind,
LocalDebugId currentId,
DiagnosticBag diagnostics,
out int slotIndex);
/// <summary>
......@@ -44,7 +45,7 @@ internal abstract class VariableSlotAllocator
/// <summary>
/// Returns true and an index of a slot that stores an awaiter of a specified type in the previous generation, if any.
/// </summary>
public abstract bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, out int slotIndex);
public abstract bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, DiagnosticBag diagnostics, out int slotIndex);
/// <summary>
/// Number of slots reserved for awaiters.
......
......@@ -204,6 +204,7 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil
public abstract int ERR_EncReferenceToAddedMember { get; }
public abstract int ERR_TooManyUserStrings { get; }
public abstract int ERR_PeWritingFailure { get; }
public abstract int ERR_ModuleEmitFailure { get; }
public abstract void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute);
public abstract void ReportInvalidNamedArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName);
......
......@@ -85,6 +85,7 @@ internal bool DefinitionExists(Cci.IDefinition definition)
internal abstract bool TryGetFieldHandle(Cci.IFieldDefinition def, out FieldDefinitionHandle handle);
internal abstract bool TryGetMethodHandle(Cci.IMethodDefinition def, out MethodDefinitionHandle handle);
internal abstract bool TryGetPropertyHandle(Cci.IPropertyDefinition def, out PropertyDefinitionHandle handle);
internal abstract CommonMessageProvider MessageProvider { get; }
}
internal abstract class DefinitionMap<TSymbolMatcher> : DefinitionMap
......@@ -260,6 +261,7 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel
}
return new EncVariableSlotAllocator(
MessageProvider,
symbolMap,
mappedMethod.SyntaxMap,
mappedMethod.PreviousMethod,
......
......@@ -13,6 +13,8 @@ namespace Microsoft.CodeAnalysis.Emit
{
internal sealed class EncVariableSlotAllocator : VariableSlotAllocator
{
private readonly CommonMessageProvider _messageProvider;
// symbols:
private readonly SymbolMatcher _symbolMap;
......@@ -37,6 +39,7 @@ internal sealed class EncVariableSlotAllocator : VariableSlotAllocator
private readonly IReadOnlyDictionary<int, DebugId> _closureMapOpt; // SyntaxOffset -> Id
public EncVariableSlotAllocator(
CommonMessageProvider messageProvider,
SymbolMatcher symbolMap,
Func<SyntaxNode, SyntaxNode> syntaxMapOpt,
IMethodSymbolInternal previousTopLevelMethod,
......@@ -50,10 +53,12 @@ internal sealed class EncVariableSlotAllocator : VariableSlotAllocator
int awaiterCount,
IReadOnlyDictionary<Cci.ITypeReference, int> awaiterMapOpt)
{
Debug.Assert(messageProvider != null);
Debug.Assert(symbolMap != null);
Debug.Assert(previousTopLevelMethod != null);
Debug.Assert(!previousLocals.IsDefault);
_messageProvider = messageProvider;
_symbolMap = symbolMap;
_syntaxMapOpt = syntaxMapOpt;
_previousLocals = previousLocals;
......@@ -177,9 +182,23 @@ private bool TryGetPreviousLocalId(SyntaxNode currentDeclarator, LocalDebugId cu
public override string PreviousStateMachineTypeName => _stateMachineTypeNameOpt;
public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDeclarator, Cci.ITypeReference currentType, SynthesizedLocalKind synthesizedKind, LocalDebugId currentId, out int slotIndex)
public override bool TryGetPreviousHoistedLocalSlotIndex(
SyntaxNode currentDeclarator,
Cci.ITypeReference currentType,
SynthesizedLocalKind synthesizedKind,
LocalDebugId currentId,
DiagnosticBag diagnostics,
out int slotIndex)
{
Debug.Assert(_hoistedLocalSlotsOpt != null);
// Well-formed state machine attribute wasn't found in the baseline (the type is missing or bad).
// Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist.
if (_hoistedLocalSlotsOpt == null)
{
// TODO: better error message https://github.com/dotnet/roslyn/issues/9196
diagnostics.Add(_messageProvider.CreateDiagnostic(_messageProvider.ERR_ModuleEmitFailure, NoLocation.Singleton, _previousTopLevelMethod.ContainingModule.Name));
slotIndex = -1;
return false;
}
LocalDebugId previousId;
if (!TryGetPreviousLocalId(currentDeclarator, currentId, out previousId))
......@@ -205,9 +224,18 @@ public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDecla
public override int PreviousHoistedLocalSlotCount => _hoistedLocalSlotCount;
public override int PreviousAwaiterSlotCount => _awaiterCount;
public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, out int slotIndex)
public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, DiagnosticBag diagnostics, out int slotIndex)
{
Debug.Assert(_awaiterMapOpt != null);
// Well-formed state machine attribute wasn't found in the baseline (the type is missing or bad).
// Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist.
if (_awaiterMapOpt == null)
{
// TODO: better error message https://github.com/dotnet/roslyn/issues/9196
diagnostics.Add(_messageProvider.CreateDiagnostic(_messageProvider.ERR_ModuleEmitFailure, NoLocation.Singleton, _previousTopLevelMethod.ContainingModule.Name));
slotIndex = -1;
return false;
}
return _awaiterMapOpt.TryGetValue(_symbolMap.MapReference(currentType), out slotIndex);
}
......
......@@ -129,10 +129,15 @@
<EmbeddedResource Include="MetadataTests\NetModule01\ModuleVB01.mod" />
<Content Include="MetadataTests\NetModule01\ModuleVB01.vb.txt" />
<EmbeddedResource Include="NetFX\aacorlib\aacorlib.v15.0.3928.cs" />
<Content Include="NetFX\aacorlib\build.cmd" />
<Content Include="NetFX\aacorlib\Key.snk" />
<EmbeddedResource Include="NetFX\Minimal\minasync.dll" />
<EmbeddedResource Include="NetFX\Minimal\mincorlib.dll" />
<Content Include="NetFX\Minimal\build.cmd" />
<Content Include="NetFX\Minimal\Key.snk" />
<Content Include="NetFX\Minimal\minasync.cs" />
<Content Include="NetFX\Minimal\mincorlib.cs" />
<EmbeddedResource Include="NetFX\Minimal\mincorlib.dll" />
<Content Include="SymbolsTests\NoPia\ParametersWithoutNames.cs" />
<EmbeddedResource Include="PerfTests\CSPerfTest.cs" />
<Content Include="Resources\License.txt" />
<Content Include="Resources\nativeCOFFResources.obj" />
......@@ -413,7 +418,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ResourceLoader.cs" />
<None Include="SymbolsTests\NoPia\ParametersWithoutNames.cs" />
<Compile Include="TestKeys.cs" />
<Compile Include="TestResources.cs" />
</ItemGroup>
......
REM Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
@REM Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
csc /target:library /nostdlib /noconfig /keyfile:Key.snk /out:mincorlib.dll mincorlib.cs
csc /target:library /nostdlib /noconfig /keyfile:Key.snk /r:mincorlib.dll /out:minasync.dll minasync.cs
using System;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
namespace System
{
public delegate void Action();
}
namespace System.Threading.Tasks
{
public class Task : IAsyncResult, IDisposable
{
public Awaiter GetAwaiter() => null;
}
public class Task<T> : IAsyncResult, IDisposable
{
public Awaiter<T> GetAwaiter() => null;
}
public class Awaiter : INotifyCompletion
{
public void OnCompleted(Action continuation) { }
public bool IsCompleted => false;
public void GetResult() { }
}
public class Awaiter<T> : INotifyCompletion
{
public void OnCompleted(Action continuation) { }
public bool IsCompleted => false;
public T GetResult() => default(T);
}
}
namespace System.Runtime.CompilerServices
{
public interface INotifyCompletion
{
void OnCompleted(Action continuation);
}
public interface ICriticalNotifyCompletion : INotifyCompletion
{
void UnsafeOnCompleted(Action continuation);
}
public interface IAsyncStateMachine
{
void MoveNext();
void SetStateMachine(IAsyncStateMachine stateMachine);
}
public struct AsyncVoidMethodBuilder
{
public static AsyncVoidMethodBuilder Create() { throw null; }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public void SetResult() { }
public void SetException(Exception exception) { }
}
public struct AsyncTaskMethodBuilder
{
public static AsyncTaskMethodBuilder Create() { throw null; }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public Task Task => null;
public void SetResult() { }
public void SetException(Exception exception) { }
}
public struct AsyncTaskMethodBuilder<TResult>
{
public static AsyncTaskMethodBuilder<TResult> Create() => default(AsyncTaskMethodBuilder<TResult>);
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
}
public Task<TResult> Task => null;
public void SetResult(TResult result) { }
public void SetException(Exception exception) { }
}
}
......@@ -162,6 +162,9 @@ public static class Minimal
{
private static byte[] s_mincorlib;
public static byte[] mincorlib => ResourceLoader.GetOrCreateResource(ref s_mincorlib, "NetFX.Minimal.mincorlib.dll");
private static byte[] s_minasync;
public static byte[] minasync => ResourceLoader.GetOrCreateResource(ref s_minasync, "NetFX.Minimal.minasync.dll");
}
}
......
......@@ -15,6 +15,26 @@ Imports Xunit
Friend Module CompilationUtils
Public Function CreateCompilation(trees As IEnumerable(Of SyntaxTree),
Optional references As IEnumerable(Of MetadataReference) = Nothing,
Optional options As VisualBasicCompilationOptions = Nothing,
Optional assemblyName As String = Nothing) As VisualBasicCompilation
If options Is Nothing Then
options = TestOptions.ReleaseDll
End If
' Using single-threaded build if debugger attached, to simplify debugging.
If Debugger.IsAttached Then
options = options.WithConcurrentBuild(False)
End If
Return VisualBasicCompilation.Create(
If(assemblyName, GetUniqueName()),
trees,
references,
options)
End Function
Public Function CreateCompilationWithMscorlib(sourceTrees As IEnumerable(Of String),
Optional references As IEnumerable(Of MetadataReference) = Nothing,
Optional options As VisualBasicCompilationOptions = Nothing,
......
......@@ -32,6 +32,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Me._metadataDecoder = metadataDecoder
End Sub
Friend Overrides ReadOnly Property MessageProvider As CommonMessageProvider
Get
Return VisualBasic.MessageProvider.Instance
End Get
End Property
Friend Function TryGetAnonymousTypeName(template As NamedTypeSymbol, <Out> ByRef name As String, <Out> ByRef index As Integer) As Boolean
Return Me.mapToPrevious.TryGetAnonymousTypeName(template, name, index)
End Function
......
......@@ -486,6 +486,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ERRID.ERR_PeWritingFailure
End Get
End Property
Public Overrides ReadOnly Property ERR_ModuleEmitFailure As Integer
Get
Return ERRID.ERR_ModuleEmitFailure
End Get
End Property
End Class
End Namespace
......@@ -95,7 +95,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' to find the previous awaiter field.
If Not Me._awaiterFields.TryGetValue(awaiterType, result) Then
Dim slotIndex As Integer = -1
If Me.SlotAllocatorOpt Is Nothing OrElse Not Me.SlotAllocatorOpt.TryGetPreviousAwaiterSlotIndex(F.CompilationState.ModuleBuilderOpt.Translate(awaiterType, F.Syntax, F.Diagnostics), slotIndex) Then
If Me.SlotAllocatorOpt Is Nothing OrElse Not Me.SlotAllocatorOpt.TryGetPreviousAwaiterSlotIndex(F.CompilationState.ModuleBuilderOpt.Translate(awaiterType, F.Syntax, F.Diagnostics), F.Diagnostics, slotIndex) Then
slotIndex = _nextAwaiterId
_nextAwaiterId = _nextAwaiterId + 1
End If
......
......@@ -295,7 +295,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
id = New LocalDebugId(syntaxOffset, ordinal)
Dim previousSlotIndex = -1
If SlotAllocatorOpt IsNot Nothing AndAlso SlotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(declaratorSyntax, F.CompilationState.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, Diagnostics), local.SynthesizedKind, id, previousSlotIndex) Then
If SlotAllocatorOpt IsNot Nothing AndAlso SlotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(declaratorSyntax,
F.CompilationState.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, Diagnostics),
local.SynthesizedKind,
id,
Diagnostics,
previousSlotIndex) Then
slotIndex = previousSlotIndex
End If
End If
......
......@@ -4402,5 +4402,127 @@ End Class
"C._Closure$__: {$I1-0, _Lambda$__1-0}",
"C.VB$StateMachine_1_F: {$State, $Builder, $VB$ResumableLocal_x$0, $VB$ResumableLocal_y$3, $A0, MoveNext, System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine, $VB$ResumableLocal_y$2, $VB$ResumableLocal_y$1}")
End Sub
<Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")>
Public Sub MissingIteratorStateMachineAttribute()
Dim source0 = MarkedSource("
Imports System
Imports System.Collections.Generic
Class C
Public Iterator Function F() As IEnumerable(Of Integer)
Dim <N:0>a</N:0> As Integer = 0
<N:1>Yield 0</N:1>
Console.WriteLine(a)
End Function
End Class
")
Dim source1 = MarkedSource("
Imports System
Imports System.Collections.Generic
Class C
Public Iterator Function F() As IEnumerable(Of Integer)
Dim <N:0>a</N:0> As Integer = 1
<N:1>Yield 1</N:1>
Console.WriteLine(a)
End Function
End Class
")
Dim compilation0 = CreateCompilationWithMscorlib({source0.Tree}, options:=ComSafeDebugDll)
Dim compilation1 = compilation0.WithSource(source1.Tree)
' older versions of mscorlib don't contain IteratorStateMachineAttribute
Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor))
Dim v0 = CompileAndVerify(compilation0, verify:=False)
Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)
Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F")
Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F")
Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo)
Dim diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True)))
diff1.EmitResult.Diagnostics.Verify(
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name))
End Sub
<Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")>
Public Sub MissingAsyncStateMachineAttribute()
Dim common = "
Imports System
Imports System.Threading.Tasks
' TODO: the attribute shouldn't be needed (https://github.com/dotnet/roslyn/issues/9167)
Namespace System.Runtime.CompilerServices
<AttributeUsage(AttributeTargets.All)>
Public Class CompilerGeneratedAttribute
Inherits Attribute
Public Sub New()
End Sub
End Class
End Namespace
' TODO: the attribute shouldn't be needed (https://github.com/dotnet/roslyn/issues/9167)
Namespace System.Diagnostics
<AttributeUsage(AttributeTargets.All)>
Public Class DebuggerHiddenAttribute
Inherits Attribute
Public Sub New()
End Sub
End Class
End Namespace
Namespace Microsoft.VisualBasic.CompilerServices
Class ProjectData
Shared Sub SetProjectError(e As Exception)
End Sub
Shared Sub ClearProjectError()
End Sub
End Class
End Namespace"
Dim source0 = MarkedSource(common & "
Class C
Public Async Function F() As Task(Of Integer)
Dim <N:0>a</N:0> As Integer = 0
Await New Task()
Return a
End Function
End Class
")
Dim source1 = MarkedSource(common & "
Class C
Public Async Function F() As Task(Of Integer)
Dim <N:0>a</N:0> As Integer = 1
Await New Task()
Return a
End Function
End Class
")
Dim compilation0 = CompilationUtils.CreateCompilation({source0.Tree}, {TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync}, options:=ComSafeDebugDll)
Dim compilation1 = compilation0.WithSource(source1.Tree)
Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor))
Dim v0 = CompileAndVerify(compilation0, verify:=False)
Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)
Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F")
Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F")
Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo)
Dim diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True)))
diff1.EmitResult.Diagnostics.Verify(
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name),
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name))
End Sub
End Class
End Namespace
......@@ -17,14 +17,29 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditAndContinue
{
internal sealed class CSharpEditAndContinueTestHelpers : EditAndContinueTestHelpers
{
internal static readonly CSharpEditAndContinueTestHelpers Instance = new CSharpEditAndContinueTestHelpers();
private readonly ImmutableArray<PortableExecutableReference> _fxReferences;
internal static readonly CSharpEditAndContinueTestHelpers Instance = new CSharpEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.v4_0_30316_17626.mscorlib, TestReferences.NetFx.v4_0_30319.System_Core));
internal static CSharpEditAndContinueTestHelpers Instance40 => new CSharpEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.v4_0_30319.mscorlib, TestReferences.NetFx.v4_0_30319.System_Core));
internal static CSharpEditAndContinueTestHelpers InstanceMinAsync => new CSharpEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync));
private static readonly CSharpEditAndContinueAnalyzer s_analyzer = new CSharpEditAndContinueAnalyzer();
public CSharpEditAndContinueTestHelpers(ImmutableArray<PortableExecutableReference> fxReferences)
{
_fxReferences = fxReferences;
}
public override AbstractEditAndContinueAnalyzer Analyzer { get { return s_analyzer; } }
public override Compilation CreateLibraryCompilation(string name, IEnumerable<SyntaxTree> trees)
{
return CSharpCompilation.Create("New", trees, new[] { TestReferences.NetFx.v4_0_30319.mscorlib, TestReferences.NetFx.v4_0_30319.System_Core }, TestOptions.UnsafeReleaseDll);
return CSharpCompilation.Create("New", trees, _fxReferences, TestOptions.UnsafeReleaseDll);
}
public override SyntaxTree ParseText(string source)
......
......@@ -72,8 +72,10 @@ internal static Match<SyntaxNode> GetMethodMatch(string src1, string src2, Parse
var m2 = MakeMethodBody(src2, options, kind);
var diagnostics = new List<RudeEditDiagnostic>();
bool needsSyntaxMap;
var match = Analyzer.ComputeBodyMatch(m1, m2, Array.Empty<AbstractEditAndContinueAnalyzer.ActiveNode>(), diagnostics, out needsSyntaxMap);
bool oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint;
var match = Analyzer.ComputeBodyMatch(m1, m2, Array.Empty<AbstractEditAndContinueAnalyzer.ActiveNode>(), diagnostics, out oldHasStateMachineSuspensionPoint, out newHasStateMachineSuspensionPoint);
bool needsSyntaxMap = oldHasStateMachineSuspensionPoint && newHasStateMachineSuspensionPoint;
Assert.Equal(kind != MethodKind.Regular && kind != MethodKind.ConstructorWithParameters, needsSyntaxMap);
......@@ -162,12 +164,14 @@ internal static void VerifyPreserveLocalVariables(EditScript<SyntaxNode> edits,
var body2 = ((MethodDeclarationSyntax)SyntaxFactory.SyntaxTree(decl2).GetRoot()).Body;
var diagnostics = new List<RudeEditDiagnostic>();
bool isActiveMethod;
var match = Analyzer.ComputeBodyMatch(body1, body2, Array.Empty<AbstractEditAndContinueAnalyzer.ActiveNode>(), diagnostics, out isActiveMethod);
bool oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint;
var match = Analyzer.ComputeBodyMatch(body1, body2, Array.Empty<AbstractEditAndContinueAnalyzer.ActiveNode>(), diagnostics, out oldHasStateMachineSuspensionPoint, out newHasStateMachineSuspensionPoint);
bool needsSyntaxMap = oldHasStateMachineSuspensionPoint && newHasStateMachineSuspensionPoint;
// Active methods are detected to preserve local variables for variable mapping and
// edited async/iterator methods are considered active.
Assert.Equal(preserveLocalVariables, isActiveMethod);
Assert.Equal(preserveLocalVariables, needsSyntaxMap);
}
}
}
......@@ -4,6 +4,7 @@
using System.IO;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.EditAndContinue.UnitTests;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditAndContinue;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -6425,6 +6426,81 @@ static IEnumerable<int> F()
Diagnostic(RudeEditKind.Insert, "yield return 2;", CSharpFeaturesResources.YieldStatement));
}
[Fact]
public void MissingIteratorStateMachineAttribute()
{
var src1 = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> F()
{
yield return 1;
}
}
";
var src2 = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> F()
{
yield return 2;
}
}
";
var edits = GetTopEdits(src1, src2);
CSharpEditAndContinueTestHelpers.Instance40.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
null,
null,
null,
new[]
{
Diagnostic(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "static IEnumerable<int> F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute")
});
}
[Fact]
public void MissingIteratorStateMachineAttribute2()
{
var src1 = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> F()
{
return null;
}
}
";
var src2 = @"
using System.Collections.Generic;
class C
{
static IEnumerable<int> F()
{
yield return 2;
}
}
";
var edits = GetTopEdits(src1, src2);
CSharpEditAndContinueTestHelpers.Instance40.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
null,
null,
null,
null);
}
#endregion
#region Await
......@@ -6810,6 +6886,84 @@ class C
edits.VerifyRudeDiagnostics();
}
[Fact]
public void MissingAsyncStateMachineAttribute1()
{
var src1 = @"
using System.Threading.Tasks;
class C
{
static async Task<int> F()
{
await new Task();
return 1;
}
}
";
var src2 = @"
using System.Threading.Tasks;
class C
{
static async Task<int> F()
{
await new Task();
return 2;
}
}
";
var edits = GetTopEdits(src1, src2);
CSharpEditAndContinueTestHelpers.InstanceMinAsync.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
null,
null,
null,
new[]
{
Diagnostic(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "static async Task<int> F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute")
});
}
[Fact]
public void MissingAsyncStateMachineAttribute2()
{
var src1 = @"
using System.Threading.Tasks;
class C
{
static Task<int> F()
{
return null;
}
}
";
var src2 = @"
using System.Threading.Tasks;
class C
{
static async Task<int> F()
{
await new Task();
return 2;
}
}
";
var edits = GetTopEdits(src1, src2);
CSharpEditAndContinueTestHelpers.InstanceMinAsync.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
null,
null,
null,
null);
}
#endregion
}
}
......@@ -12,6 +12,7 @@ internal static class Extensions
{
public static void Verify(this IEnumerable<RudeEditDiagnostic> diagnostics, string newSource, params RudeEditDiagnosticDescription[] expectedDiagnostics)
{
expectedDiagnostics = expectedDiagnostics ?? Array.Empty<RudeEditDiagnosticDescription>();
var actualDiagnostics = diagnostics.ToDescription(newSource, expectedDiagnostics.Any(d => d.FirstLine != null)).ToArray();
AssertEx.SetEqual(expectedDiagnostics, actualDiagnostics, itemSeparator: ",\r\n");
}
......
......@@ -59,8 +59,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests
Dim m2 = MakeMethodBody(src2, options, stateMachine)
Dim diagnostics = New List(Of RudeEditDiagnostic)()
Dim needsSyntaxMap As Boolean
Dim match = Analyzer.ComputeBodyMatch(m1, m2, Array.Empty(Of AbstractEditAndContinueAnalyzer.ActiveNode)(), diagnostics, needsSyntaxMap)
Dim oldHasStateMachineSuspensionPoint = False, newHasStateMachineSuspensionPoint = False
Dim match = Analyzer.ComputeBodyMatch(m1, m2, Array.Empty(Of AbstractEditAndContinueAnalyzer.ActiveNode)(), diagnostics, oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint)
Dim needsSyntaxMap = oldHasStateMachineSuspensionPoint AndAlso newHasStateMachineSuspensionPoint
Assert.Equal(stateMachine <> StateMachineKind.None, needsSyntaxMap)
......
......@@ -13,10 +13,23 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EditAndContinue
Friend NotInheritable Class VisualBasicEditAndContinueTestHelpers
Inherits EditAndContinueTestHelpers
Friend Shared ReadOnly Instance As VisualBasicEditAndContinueTestHelpers = New VisualBasicEditAndContinueTestHelpers()
Private ReadOnly _fxReferences As ImmutableArray(Of PortableExecutableReference)
Friend Shared ReadOnly Instance As VisualBasicEditAndContinueTestHelpers = New VisualBasicEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.v4_0_30316_17626.mscorlib, TestReferences.NetFx.v4_0_30319.System, TestReferences.NetFx.v4_0_30319.System_Core))
Friend Shared ReadOnly Instance40 As VisualBasicEditAndContinueTestHelpers = New VisualBasicEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.v4_0_30319.mscorlib, TestReferences.NetFx.v4_0_30319.System_Core))
Friend Shared ReadOnly InstanceMinAsync As VisualBasicEditAndContinueTestHelpers = New VisualBasicEditAndContinueTestHelpers(
ImmutableArray.Create(TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync))
Private Shared ReadOnly s_analyzer As VisualBasicEditAndContinueAnalyzer = New VisualBasicEditAndContinueAnalyzer()
Sub New(fxReferences As ImmutableArray(Of PortableExecutableReference))
_fxReferences = fxReferences
End Sub
Public Overrides ReadOnly Property Analyzer As AbstractEditAndContinueAnalyzer
Get
Return s_analyzer
......@@ -26,7 +39,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EditAndContinue
Public Overrides Function CreateLibraryCompilation(name As String, trees As IEnumerable(Of SyntaxTree)) As Compilation
Return VisualBasicCompilation.Create("New",
trees,
{TestReferences.NetFx.v4_0_30319.mscorlib, TestReferences.NetFx.v4_0_30319.System, TestReferences.NetFx.v4_0_30319.System_Core},
_fxReferences,
TestOptions.ReleaseDll.WithEmbedVbCoreRuntime(True))
End Function
......
......@@ -2,6 +2,7 @@
Imports Microsoft.CodeAnalysis.EditAndContinue
Imports Microsoft.CodeAnalysis.EditAndContinue.UnitTests
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EditAndContinue
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests
......@@ -5586,6 +5587,67 @@ Yield 2
edits.VerifyEdits(
"Delete [Yield 3]@66")
End Sub
<Fact>
Public Sub MissingIteratorStateMachineAttribute()
Dim src1 = "
Imports System.Collections.Generic
Class C
Shared Iterator Function F() As IEnumerable(Of Integer)
Yield 1
End Function
End Class
"
Dim src2 = "
Imports System.Collections.Generic
Class C
Shared Iterator Function F() As IEnumerable(Of Integer)
Yield 2
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
VisualBasicEditAndContinueTestHelpers.Instance40.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
Nothing,
Nothing,
Nothing,
{Diagnostic(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "Shared Iterator Function F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute")})
End Sub
<Fact>
Public Sub MissingIteratorStateMachineAttribute2()
Dim src1 = "
Imports System.Collections.Generic
Class C
Shared Function F() As IEnumerable(Of Integer)
Return Nothing
End Function
End Class
"
Dim src2 = "
Imports System.Collections.Generic
Class C
Shared Iterator Function F() As IEnumerable(Of Integer)
Yield 2
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
VisualBasicEditAndContinueTestHelpers.Instance40.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
Nothing,
Nothing,
Nothing,
Nothing)
End Sub
#End Region
#Region "Await"
......@@ -5639,6 +5701,69 @@ Await F(3)
edits.VerifyEdits(
"Delete [Await F(2)]@51")
End Sub
<Fact>
Public Sub MissingAsyncStateMachineAttribute1()
Dim src1 = "
Imports System.Threading.Tasks
Class C
Shared Async Function F() As Task(Of Integer)
Await New Task()
Return 1
End Function
End Class
"
Dim src2 = "
Imports System.Threading.Tasks
Class C
Shared Async Function F() As Task(Of Integer)
Await New Task()
Return 2
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
VisualBasicEditAndContinueTestHelpers.InstanceMinAsync.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
Nothing,
Nothing,
Nothing,
{Diagnostic(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "Shared Async Function F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute")})
End Sub
<Fact>
Public Sub MissingAsyncStateMachineAttribute2()
Dim src1 = "
Imports System.Threading.Tasks
Class C
Shared Function F() As Task(Of Integer)
Return Nothing
End Function
End Class
"
Dim src2 = "
Imports System.Threading.Tasks
Class C
Shared Async Function F() As Task(Of Integer)
Await New Task()
Return 2
End Function
End Class
"
Dim edits = GetTopEdits(src1, src2)
VisualBasicEditAndContinueTestHelpers.InstanceMinAsync.VerifySemantics(
edits,
ActiveStatementsDescription.Empty,
Nothing,
Nothing,
Nothing,
Nothing)
End Sub
#End Region
End Class
End Namespace
......@@ -167,7 +167,7 @@ public override string PreviousStateMachineTypeName
get { return null; }
}
public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDeclarator, Cci.ITypeReference currentType, SynthesizedLocalKind synthesizedKind, LocalDebugId currentId, out int slotIndex)
public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDeclarator, Cci.ITypeReference currentType, SynthesizedLocalKind synthesizedKind, LocalDebugId currentId, DiagnosticBag diagnostics, out int slotIndex)
{
slotIndex = -1;
return false;
......@@ -178,7 +178,7 @@ public override int PreviousHoistedLocalSlotCount
get { return 0; }
}
public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, out int slotIndex)
public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, DiagnosticBag diagnostics, out int slotIndex)
{
slotIndex = -1;
return false;
......
......@@ -162,12 +162,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
End Get
End Property
Public Overrides Function TryGetPreviousHoistedLocalSlotIndex(currentDeclarator As SyntaxNode, currentType As ITypeReference, synthesizedKind As SynthesizedLocalKind, currentId As LocalDebugId, <Out> ByRef slotIndex As Integer) As Boolean
Public Overrides Function TryGetPreviousHoistedLocalSlotIndex(currentDeclarator As SyntaxNode, currentType As ITypeReference, synthesizedKind As SynthesizedLocalKind, currentId As LocalDebugId, diagnostics As DiagnosticBag, <Out> ByRef slotIndex As Integer) As Boolean
slotIndex = -1
Return False
End Function
Public Overrides Function TryGetPreviousAwaiterSlotIndex(currentType As ITypeReference, <Out> ByRef slotIndex As Integer) As Boolean
Public Overrides Function TryGetPreviousAwaiterSlotIndex(currentType As ITypeReference, diagnostics As DiagnosticBag, <Out> ByRef slotIndex As Integer) As Boolean
slotIndex = -1
Return False
End Function
......
......@@ -222,8 +222,11 @@ private SyntaxNode FindStatement(SyntaxNode declarationBody, int position, out i
/// </summary>
protected abstract IEnumerable<SyntaxNode> GetVariableUseSites(IEnumerable<SyntaxNode> roots, ISymbol localOrParameter, SemanticModel model, CancellationToken cancellationToken);
// diagnostic spans:
protected abstract TextSpan GetDiagnosticSpan(SyntaxNode node, EditKind editKind);
internal abstract TextSpan GetLambdaParameterDiagnosticSpan(SyntaxNode lambda, int ordinal);
private TextSpan GetBodyDiagnosticSpan(SyntaxNode body, EditKind editKind) => GetDiagnosticSpan(IsMethod(body) ? body : body.Parent, EditKind.Update);
protected abstract string GetTopLevelDisplayName(SyntaxNode node, EditKind editKind);
protected abstract string GetStatementDisplayName(SyntaxNode node, EditKind editKind);
protected abstract string GetLambdaDisplayName(SyntaxNode lambda);
......@@ -805,9 +808,13 @@ internal struct UpdatedMemberInfo
// the method has an active statement (the statement might be in the body itself or in a lambda)
public readonly bool HasActiveStatement;
// The method body has a suspension point (await/yield);
// The old method body has a suspension point (await/yield);
// only true if the body itself has the suspension point, not if it contains async/iterator lambda
public readonly bool OldHasStateMachineSuspensionPoint;
// The new method body has a suspension point (await/yield);
// only true if the body itself has the suspension point, not if it contains async/iterator lambda
public readonly bool HasStateMachineSuspensionPoint;
public readonly bool NewHasStateMachineSuspensionPoint;
public UpdatedMemberInfo(
int editOrdinal,
......@@ -816,7 +823,8 @@ internal struct UpdatedMemberInfo
BidirectionalMap<SyntaxNode> map,
IReadOnlyDictionary<SyntaxNode, LambdaInfo> activeOrMatchedLambdasOpt,
bool hasActiveStatement,
bool hasStateMachineSuspensionPoint)
bool oldHasStateMachineSuspensionPoint,
bool newHasStateMachineSuspensionPoint)
{
Debug.Assert(editOrdinal >= 0);
Debug.Assert(!map.IsDefaultOrEmpty);
......@@ -829,7 +837,8 @@ internal struct UpdatedMemberInfo
Map = map;
ActiveOrMatchedLambdasOpt = activeOrMatchedLambdasOpt;
HasActiveStatement = hasActiveStatement;
HasStateMachineSuspensionPoint = hasStateMachineSuspensionPoint;
OldHasStateMachineSuspensionPoint = oldHasStateMachineSuspensionPoint;
NewHasStateMachineSuspensionPoint = newHasStateMachineSuspensionPoint;
}
}
......@@ -981,14 +990,14 @@ internal struct UpdatedMemberInfo
activeNodes[i] = new ActiveNode(oldStatementSyntax, oldEnclosingLambdaBody, statementPart, isTracked ? trackedSpan : (TextSpan?)null, trackedNode);
}
bool hasStateMachineSuspensionPoint;
var bodyMatch = ComputeBodyMatch(oldBody, newBody, activeNodes.Where(n => n.EnclosingLambdaBodyOpt == null).ToArray(), diagnostics, out hasStateMachineSuspensionPoint);
bool oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint;
var bodyMatch = ComputeBodyMatch(oldBody, newBody, activeNodes.Where(n => n.EnclosingLambdaBodyOpt == null).ToArray(), diagnostics, out oldHasStateMachineSuspensionPoint, out newHasStateMachineSuspensionPoint);
var map = ComputeMap(bodyMatch, activeNodes, ref lazyActiveOrMatchedLambdas, diagnostics);
// Save the body match for local variable mapping.
// We'll use it to tell the compiler what local variables to preserve in an active method.
// An edited async/iterator method is considered active.
updatedMembers.Add(new UpdatedMemberInfo(editOrdinal, oldBody, newBody, map, lazyActiveOrMatchedLambdas, hasActiveStatement, hasStateMachineSuspensionPoint));
updatedMembers.Add(new UpdatedMemberInfo(editOrdinal, oldBody, newBody, map, lazyActiveOrMatchedLambdas, hasActiveStatement, oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint));
for (int i = 0; i < activeNodes.Length; i++)
{
......@@ -1257,8 +1266,8 @@ internal struct UpdatedMemberInfo
info = new LambdaInfo();
}
bool needsSyntaxMap;
var lambdaBodyMatch = ComputeBodyMatch(oldLambdaBody, newLambdaBody, activeNodesInLambda ?? SpecializedCollections.EmptyArray<ActiveNode>(), diagnostics, out needsSyntaxMap);
bool _;
var lambdaBodyMatch = ComputeBodyMatch(oldLambdaBody, newLambdaBody, activeNodesInLambda ?? SpecializedCollections.EmptyArray<ActiveNode>(), diagnostics, out _, out _);
activeOrMatchedLambdas[oldLambdaBody] = info.WithMatch(lambdaBodyMatch, newLambdaBody);
......@@ -1271,7 +1280,8 @@ internal struct UpdatedMemberInfo
SyntaxNode newBody,
ActiveNode[] activeNodes,
List<RudeEditDiagnostic> diagnostics,
out bool hasStateMachineSuspensionPoint)
out bool oldHasStateMachineSuspensionPoint,
out bool newHasStateMachineSuspensionPoint)
{
Debug.Assert(oldBody != null);
Debug.Assert(newBody != null);
......@@ -1302,7 +1312,8 @@ internal struct UpdatedMemberInfo
// Note that iterators in VB don't need to contain yield, so this case is not covered by change in number of yields.
bool creatingStateMachineAroundActiveStatement = oldStateMachineSuspensionPoints.Length == 0 && newStateMachineSuspensionPoints.Length > 0 && activeNodes.Length > 0;
hasStateMachineSuspensionPoint = oldStateMachineSuspensionPoints.Length > 0 && newStateMachineSuspensionPoints.Length > 0;
oldHasStateMachineSuspensionPoint = oldStateMachineSuspensionPoints.Length > 0;
newHasStateMachineSuspensionPoint = newStateMachineSuspensionPoints.Length > 0;
if (oldStateMachineSuspensionPoints.Length > 0 || creatingStateMachineAroundActiveStatement)
{
......@@ -1357,7 +1368,7 @@ internal struct UpdatedMemberInfo
{
diagnostics.Add(new RudeEditDiagnostic(
RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement,
GetDiagnosticSpan(IsMethod(newBody) ? newBody : newBody.Parent, EditKind.Update)));
GetBodyDiagnosticSpan(newBody, EditKind.Update)));
}
}
......@@ -2301,6 +2312,8 @@ public ConstructorEdit(INamedTypeSymbol oldType)
{
var updatedMember = updatedMembers[updatedMemberIndex];
ReportStateMachineRudeEdits(updatedMember, oldSymbol, diagnostics);
bool newBodyHasLambdas;
ReportLambdaAndClosureRudeEdits(
oldModel,
......@@ -2323,7 +2336,7 @@ public ConstructorEdit(INamedTypeSymbol oldType)
// 3) The new member contains lambdas
// We need to map new lambdas in the method to the matching old ones.
// If the old method has lambdas but the new one doesn't there is nothing to preserve.
if (updatedMember.HasActiveStatement || updatedMember.HasStateMachineSuspensionPoint || newBodyHasLambdas)
if (updatedMember.HasActiveStatement || updatedMember.NewHasStateMachineSuspensionPoint || newBodyHasLambdas)
{
syntaxMapOpt = CreateSyntaxMap(updatedMember.Map.Reverse);
}
......@@ -3687,6 +3700,37 @@ private bool AreEquivalentClosureScopes(SyntaxNode oldScopeOpt, SyntaxNode newSc
#endregion
#region State Machines
private void ReportStateMachineRudeEdits(
UpdatedMemberInfo updatedInfo,
ISymbol oldMember,
List<RudeEditDiagnostic> diagnostics)
{
if (!updatedInfo.OldHasStateMachineSuspensionPoint)
{
return;
}
// only methods and anonymous functions may be async/iterators machines:
var stateMachineAttributeQualifiedName = ((IMethodSymbol)oldMember).IsAsync ?
"System.Runtime.CompilerServices.AsyncStateMachineAttribute" :
"System.Runtime.CompilerServices.IteratorStateMachineAttribute";
// We assume that the attributes, if exist, are well formed.
// If not an error will be reported during EnC delta emit.
if (oldMember.ContainingAssembly.GetTypeByMetadataName(stateMachineAttributeQualifiedName) == null)
{
diagnostics.Add(new RudeEditDiagnostic(
RudeEditKind.UpdatingStateMachineMethodMissingAttribute,
GetBodyDiagnosticSpan(updatedInfo.NewBody, EditKind.Update),
updatedInfo.NewBody,
new[] { stateMachineAttributeQualifiedName }));
}
}
#endregion
#endregion
#region Helpers
......
......@@ -80,6 +80,8 @@ internal static class RudeEditDiagnosticDescriptors
{ GetDescriptorPair(RudeEditKind.PartiallyExecutedActiveStatementDelete, FeaturesResources.AnActiveStatementHasBeenRemoved) },
{ GetDescriptorPair(RudeEditKind.InsertFile, FeaturesResources.AddingANewFile) },
{ GetDescriptorPair(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, FeaturesResources.UpdatingStateMachineMethodAroundActive) },
// TODO: move message to resources https://github.com/dotnet/roslyn/issues/9196
{ GetDescriptorPair(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "Attribute '{0}' is missing. Updating an async method or an iterator will prevent the debug session from continuing.") },
{ GetDescriptorPair(RudeEditKind.RUDE_EDIT_COMPLEX_QUERY_EXPRESSION, FeaturesResources.ModifyingAWhichContainsComplexQuery) },
......
......@@ -90,6 +90,7 @@ internal enum RudeEditKind : ushort
PartiallyExecutedActiveStatementUpdate = 72,
PartiallyExecutedActiveStatementDelete = 73,
UpdatingStateMachineMethodAroundActiveStatement = 74,
UpdatingStateMachineMethodMissingAttribute = 75,
// TODO: remove values below
RUDE_EDIT_COMPLEX_QUERY_EXPRESSION = 0x103,
......
......@@ -363,7 +363,15 @@ public override int ERR_TooManyUserStrings
}
}
public override int ERR_PeWritingFailure
public override int ERR_PeWritingFailure
{
get
{
throw new NotImplementedException();
}
}
public override int ERR_ModuleEmitFailure
{
get
{
......
......@@ -141,6 +141,37 @@ public static PortableExecutableReference VBInterfaces01
public static class NetFx
{
public static class Minimal
{
private static PortableExecutableReference s_mincorlib;
public static PortableExecutableReference mincorlib
{
get
{
if (s_mincorlib == null)
{
s_mincorlib = AssemblyMetadata.CreateFromImage(TestResources.NetFX.Minimal.mincorlib).GetReference(display: "mincorlib.dll");
}
return s_mincorlib;
}
}
private static PortableExecutableReference s_minasync;
public static PortableExecutableReference minasync
{
get
{
if (s_minasync == null)
{
s_minasync = AssemblyMetadata.CreateFromImage(TestResources.NetFX.Minimal.minasync).GetReference(display: "minasync.dll");
}
return s_minasync;
}
}
}
public static class silverlight_v5_0_5_0
{
private static PortableExecutableReference s_system;
......@@ -453,6 +484,23 @@ public static PortableExecutableReference System_Runtime_Serialization
}
}
}
public static class v4_0_30316_17626
{
private static PortableExecutableReference s_mscorlib;
public static PortableExecutableReference mscorlib
{
get
{
if (s_mscorlib == null)
{
s_mscorlib = AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30316_17626.mscorlib).GetReference(display: @"mscorlib.v4_0_30319_17626.dll", filePath: @"Z:\FxReferenceAssembliesUri");
}
return s_mscorlib;
}
}
}
}
public static class DiagnosticTests
......
......@@ -290,19 +290,7 @@ public static MetadataReference MscorlibRef_v20
}
}
private static MetadataReference s_mscorlibRef_v4_0_30316_17626;
public static MetadataReference MscorlibRef_v4_0_30316_17626
{
get
{
if (s_mscorlibRef_v4_0_30316_17626 == null)
{
s_mscorlibRef_v4_0_30316_17626 = AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30316_17626.mscorlib).GetReference(display: "mscorlib.v4_0_30319_17626.dll", filePath: @"Z:\FxReferenceAssembliesUri");
}
return s_mscorlibRef_v4_0_30316_17626;
}
}
public static MetadataReference MscorlibRef_v4_0_30316_17626 => TestReferences.NetFx.v4_0_30316_17626.mscorlib;
private static MetadataReference s_mscorlibRef_v46;
public static MetadataReference MscorlibRef_v46
......@@ -335,19 +323,7 @@ public static MetadataReference MscorlibRefSilverlight
}
}
private static MetadataReference s_minCorlibRef;
public static MetadataReference MinCorlibRef
{
get
{
if (s_minCorlibRef == null)
{
s_minCorlibRef = AssemblyMetadata.CreateFromImage(TestResources.NetFX.Minimal.mincorlib).GetReference(display: "minCorLib.dll");
}
return s_minCorlibRef;
}
}
public static MetadataReference MinCorlibRef => TestReferences.NetFx.Minimal.mincorlib;
private static MetadataReference s_msvbRef;
public static MetadataReference MsvbRef
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册