提交 65e9f88a 编写于 作者: T Tomáš Matoušek

Merge pull request #2346 from tmat/Fix2284

Enc: Fixes lambda id mapping
......@@ -929,7 +929,7 @@ private DebugId GetClosureId(SyntaxNode syntax, ArrayBuilder<ClosureDebugInfo> c
}
int syntaxOffset = _topLevelMethod.CalculateLocalSyntaxOffset(syntax.SpanStart, syntax.SyntaxTree);
closureDebugInfo.Add(new ClosureDebugInfo(syntaxOffset, closureId.Generation));
closureDebugInfo.Add(new ClosureDebugInfo(syntaxOffset, closureId));
return closureId;
}
......@@ -977,7 +977,7 @@ private DebugId GetLambdaId(SyntaxNode syntax, ClosureKind closureKind, int clos
}
int syntaxOffset = _topLevelMethod.CalculateLocalSyntaxOffset(lambdaOrLambdaBodySyntax.SpanStart, lambdaOrLambdaBodySyntax.SyntaxTree);
_lambdaDebugInfoBuilder.Add(new LambdaDebugInfo(syntaxOffset, closureOrdinal, lambdaId.Generation));
_lambdaDebugInfoBuilder.Add(new LambdaDebugInfo(syntaxOffset, lambdaId, closureOrdinal));
return lambdaId;
}
......
......@@ -914,7 +914,7 @@ public void F()
}
[Fact]
public void LambdasMultipleGenerations()
public void LambdasMultipleGenerations1()
{
var source0 = MarkedSource(@"
using System;
......@@ -1134,6 +1134,148 @@ .locals init (int V_0)
");
}
[Fact, WorkItem(2284, "https://github.com/dotnet/roslyn/issues/2284")]
public void LambdasMultipleGenerations2()
{
var source0 = MarkedSource(@"
using System;
using System.Linq;
class C
{
private int[] _titles = new int[] { 1, 2 };
Action A;
private void F()
{
// edit 1
// var z = from title in _titles
// where title > 0
// select title;
A += <N:0>() =>
<N:1>{
Console.WriteLine(1);
// edit 2
// Console.WriteLine(2);
}</N:1></N:0>;
}
}");
var source1 = MarkedSource(@"
using System;
using System.Linq;
class C
{
private int[] _titles = new int[] { 1, 2 };
Action A;
private void F()
{
// edit 1
var <N:3>z = from title in _titles
<N:2>where title > 0</N:2>
select title</N:3>;
A += <N:0>() =>
<N:1>{
Console.WriteLine(1);
// edit 2
// Console.WriteLine(2);
}</N:1></N:0>;
}
}");
var source2 = MarkedSource(@"
using System;
using System.Linq;
class C
{
private int[] _titles = new int[] { 1, 2 };
Action A;
private void F()
{
// edit 1
var <N:3>z = from title in _titles
<N:2>where title > 0</N:2>
select title</N:3>;
A += <N:0>() =>
<N:1>{
Console.WriteLine(1);
// edit 2
Console.WriteLine(2);
}</N:1></N:0>;
}
}");
var compilation0 = CreateCompilationWithMscorlib(source0.Tree, new[] { SystemCoreRef }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All));
var compilation1 = compilation0.WithSource(source1.Tree);
var compilation2 = compilation1.WithSource(source2.Tree);
var v0 = CompileAndVerify(compilation0);
var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData);
var f0 = compilation0.GetMember<MethodSymbol>("C.F");
var f1 = compilation1.GetMember<MethodSymbol>("C.F");
var f2 = compilation2.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)));
var md1 = diff1.GetMetadata();
var reader1 = md1.Reader;
// new lambda "<F>b__2_0#1" has been added:
diff1.VerifySynthesizedMembers(
"C: {<>c}",
"C.<>c: {<>9__2_0#1, <>9__2_0, <F>b__2_0#1, <F>b__2_0}");
// lambda body unchanged:
diff1.VerifyIL("C.<>c.<F>b__2_0", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""void System.Console.WriteLine(int)""
IL_0007: nop
IL_0008: br.s IL_000a
IL_000a: ret
}");
var diff2 = compilation2.EmitDifference(
diff1.NextGeneration,
ImmutableArray.Create(new SemanticEdit(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true)));
// no new members:
diff2.VerifySynthesizedMembers(
"C: {<>c}",
"C.<>c: {<>9__2_0#1, <>9__2_0, <F>b__2_0#1, <F>b__2_0}");
// lambda body updated:
diff2.VerifyIL("C.<>c.<F>b__2_0", @"
{
// Code size 18 (0x12)
.maxstack 1
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""void System.Console.WriteLine(int)""
IL_0007: nop
IL_0008: ldc.i4.2
IL_0009: call ""void System.Console.WriteLine(int)""
IL_000e: nop
IL_000f: br.s IL_0011
IL_0011: ret
}");
}
[Fact]
public void UniqueSynthesizedNames1()
{
......
......@@ -214,14 +214,14 @@ public void EditAndContinueLambdaAndClosureMap_NegativeSyntaxOffsets()
var slots = ImmutableArray<LocalSlotDebugInfo>.Empty;
var closures = ImmutableArray.Create(
new ClosureDebugInfo(-100, 0),
new ClosureDebugInfo(10, 0),
new ClosureDebugInfo(-200, 0));
new ClosureDebugInfo(-100, new DebugId(0, 0)),
new ClosureDebugInfo(10, new DebugId(1, 0)),
new ClosureDebugInfo(-200, new DebugId(2, 0)));
var lambdas = ImmutableArray.Create(
new LambdaDebugInfo(20, 1, 0),
new LambdaDebugInfo(-50, 0, 0),
new LambdaDebugInfo(-180, LambdaDebugInfo.StaticClosureOrdinal, 0));
new LambdaDebugInfo(20, new DebugId(0, 0), 1),
new LambdaDebugInfo(-50, new DebugId(1, 0), 0),
new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal));
var customMetadata = new Cci.MemoryStream();
var cmw = new Cci.BinaryWriter(customMetadata);
......@@ -244,7 +244,7 @@ public void EditAndContinueLambdaAndClosureMap_NoClosures()
var slots = ImmutableArray<LocalSlotDebugInfo>.Empty;
var closures = ImmutableArray<ClosureDebugInfo>.Empty;
var lambdas = ImmutableArray.Create(new LambdaDebugInfo(20, LambdaDebugInfo.StaticClosureOrdinal, 0));
var lambdas = ImmutableArray.Create(new LambdaDebugInfo(20, new DebugId(0, 0), LambdaDebugInfo.StaticClosureOrdinal));
var customMetadata = new Cci.MemoryStream();
var cmw = new Cci.BinaryWriter(customMetadata);
......@@ -293,14 +293,14 @@ public void EncCdiAlignment()
new LocalSlotDebugInfo(SynthesizedLocalKind.TryAwaitPendingCaughtException, new LocalDebugId(-20000, 10)));
var closures = ImmutableArray.Create(
new ClosureDebugInfo(-100, 0),
new ClosureDebugInfo(10, 0),
new ClosureDebugInfo(-200, 0));
new ClosureDebugInfo(-100, new DebugId(0, 0)),
new ClosureDebugInfo(10, new DebugId(1, 0)),
new ClosureDebugInfo(-200, new DebugId(2, 0)));
var lambdas = ImmutableArray.Create(
new LambdaDebugInfo(20, 1, 0),
new LambdaDebugInfo(-50, 0, 0),
new LambdaDebugInfo(-180, LambdaDebugInfo.StaticClosureOrdinal, 0));
new LambdaDebugInfo(20, new DebugId(0, 0), 1),
new LambdaDebugInfo(-50, new DebugId(1, 0), 0),
new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal));
var debugInfo = new EditAndContinueMethodDebugInformation(1, slots, closures, lambdas);
var records = new ArrayBuilder<Cci.MemoryStream>();
......
// 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 Roslyn.Utilities;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeGen
{
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal struct ClosureDebugInfo : IEquatable<ClosureDebugInfo>
{
public readonly int SyntaxOffset;
public readonly int Generation;
public readonly DebugId ClosureId;
public ClosureDebugInfo(int syntaxOffset, int generation)
public ClosureDebugInfo(int syntaxOffset, DebugId closureId)
{
Debug.Assert(generation >= 0);
SyntaxOffset = syntaxOffset;
Generation = generation;
ClosureId = closureId;
}
public bool Equals(ClosureDebugInfo other)
{
return SyntaxOffset == other.SyntaxOffset &&
Generation == other.Generation;
ClosureId.Equals(other.ClosureId);
}
public override bool Equals(object obj)
......@@ -32,12 +31,12 @@ public override bool Equals(object obj)
public override int GetHashCode()
{
return Hash.Combine(SyntaxOffset, Generation);
return Hash.Combine(SyntaxOffset, ClosureId.GetHashCode());
}
public override string ToString()
internal string GetDebuggerDisplay()
{
return $"(#{Generation} @{SyntaxOffset})";
return $"({ClosureId.GetDebuggerDisplay()} @{SyntaxOffset})";
}
}
}
......@@ -13,6 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGen
/// When used for a synthesized method the ordinal and generation numbers are included its name.
/// For user defined methods the ordinal is included in Custom Debug Information record attached to the method.
/// </remarks>
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal struct DebugId : IEquatable<DebugId>
{
public const int UndefinedOrdinal = -1;
......@@ -51,5 +52,10 @@ public override int GetHashCode()
{
return Hash.Combine(this.Ordinal, this.Generation);
}
internal string GetDebuggerDisplay()
{
return (Generation > 0) ? $"{Ordinal}#{Generation}" : Ordinal.ToString();
}
}
}
......@@ -12,6 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeGen
/// <remarks>
/// The information is emitted to PDB in Custom Debug Information record for a method containing the lambda.
/// </remarks>
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal struct LambdaDebugInfo : IEquatable<LambdaDebugInfo>
{
/// <summary>
......@@ -26,27 +27,26 @@ internal struct LambdaDebugInfo : IEquatable<LambdaDebugInfo>
/// </summary>
public readonly int ClosureOrdinal;
public readonly int Generation;
public readonly DebugId LambdaId;
public const int StaticClosureOrdinal = -1;
public const int ThisOnlyClosureOrdinal = -2;
public const int MinClosureOrdinal = ThisOnlyClosureOrdinal;
public LambdaDebugInfo(int syntaxOffset, int closureOrdinal, int generation)
public LambdaDebugInfo(int syntaxOffset, DebugId lambdaId, int closureOrdinal)
{
Debug.Assert(closureOrdinal >= MinClosureOrdinal);
Debug.Assert(generation >= 0);
SyntaxOffset = syntaxOffset;
ClosureOrdinal = closureOrdinal;
Generation = generation;
LambdaId = lambdaId;
}
public bool Equals(LambdaDebugInfo other)
{
return SyntaxOffset == other.SyntaxOffset
&& ClosureOrdinal == other.ClosureOrdinal
&& Generation == other.Generation;
&& LambdaId.Equals(other.LambdaId);
}
public override bool Equals(object obj)
......@@ -57,15 +57,15 @@ public override bool Equals(object obj)
public override int GetHashCode()
{
return Hash.Combine(ClosureOrdinal,
Hash.Combine(SyntaxOffset, Generation));
Hash.Combine(SyntaxOffset, LambdaId.GetHashCode()));
}
public override string ToString()
internal string GetDebuggerDisplay()
{
return
ClosureOrdinal == StaticClosureOrdinal ? $"(#{Generation} @{SyntaxOffset}, static)" :
ClosureOrdinal == ThisOnlyClosureOrdinal ? $"(#{Generation} @{SyntaxOffset}, this)" :
$"(#{Generation} @{SyntaxOffset} in {ClosureOrdinal})";
ClosureOrdinal == StaticClosureOrdinal ? $"({LambdaId.GetDebuggerDisplay()} @{SyntaxOffset}, static)" :
ClosureOrdinal == ThisOnlyClosureOrdinal ? $"(#{LambdaId.GetDebuggerDisplay()} @{SyntaxOffset}, this)" :
$"({LambdaId.GetDebuggerDisplay()} @{SyntaxOffset} in {ClosureOrdinal})";
}
}
}
......@@ -287,13 +287,13 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel
for (int i = 0; i < lambdaDebugInfo.Length; i++)
{
var lambdaInfo = lambdaDebugInfo[i];
lambdas[lambdaInfo.SyntaxOffset] = KeyValuePair.Create(new DebugId(i, lambdaInfo.Generation), lambdaInfo.ClosureOrdinal);
lambdas[lambdaInfo.SyntaxOffset] = KeyValuePair.Create(lambdaInfo.LambdaId, lambdaInfo.ClosureOrdinal);
}
for (int i = 0; i < closureDebugInfo.Length; i++)
{
var closureInfo = closureDebugInfo[i];
closures[closureInfo.SyntaxOffset] = new DebugId(i, closureInfo.Generation);
closures[closureInfo.SyntaxOffset] = closureInfo.ClosureId;
}
lambdaMap = lambdas;
......
......@@ -209,7 +209,8 @@ internal void SerializeLocalSlots(Cci.BinaryWriter writer)
{
int syntaxOffset = blobReader.ReadCompressedInteger();
closuresBuilder.Add(new ClosureDebugInfo(syntaxOffset + syntaxOffsetBaseline, generation: 0));
var closureId = new DebugId(closuresBuilder.Count, generation: 0);
closuresBuilder.Add(new ClosureDebugInfo(syntaxOffset + syntaxOffsetBaseline, closureId));
}
while (blobReader.RemainingBytes > 0)
......@@ -222,7 +223,8 @@ internal void SerializeLocalSlots(Cci.BinaryWriter writer)
throw CreateInvalidDataException(compressedLambdaMap, blobReader.Offset);
}
lambdasBuilder.Add(new LambdaDebugInfo(syntaxOffset + syntaxOffsetBaseline, closureOrdinal, generation: 0));
var lambdaId = new DebugId(lambdasBuilder.Count, generation: 0);
lambdasBuilder.Add(new LambdaDebugInfo(syntaxOffset + syntaxOffsetBaseline, lambdaId, closureOrdinal));
}
}
catch (BadImageFormatException)
......@@ -268,7 +270,7 @@ internal void SerializeLambdaMap(Cci.BinaryWriter writer)
foreach (LambdaDebugInfo info in this.Lambdas)
{
Debug.Assert(info.ClosureOrdinal >= LambdaDebugInfo.MinClosureOrdinal);
Debug.Assert(info.Generation == 0);
Debug.Assert(info.LambdaId.Generation == 0);
writer.WriteCompressedUInt((uint)(info.SyntaxOffset - syntaxOffsetBaseline));
writer.WriteCompressedUInt((uint)(info.ClosureOrdinal - LambdaDebugInfo.MinClosureOrdinal));
......
......@@ -965,7 +965,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Dim syntaxOffset As Integer = _topLevelMethod.CalculateLocalSyntaxOffset(syntax.SpanStart, syntax.SyntaxTree)
closureDebugInfo.Add(New ClosureDebugInfo(syntaxOffset, closureId.Generation))
closureDebugInfo.Add(New ClosureDebugInfo(syntaxOffset, closureId))
Return closureId
End Function
......@@ -1006,7 +1006,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Dim syntaxOffset As Integer = _topLevelMethod.CalculateLocalSyntaxOffset(lambdaOrLambdaBodySyntax.SpanStart, lambdaOrLambdaBodySyntax.SyntaxTree)
_lambdaDebugInfoBuilder.Add(New LambdaDebugInfo(syntaxOffset, closureOrdinal, lambdaId.Generation))
_lambdaDebugInfoBuilder.Add(New LambdaDebugInfo(syntaxOffset, lambdaId, closureOrdinal))
Return lambdaId
End Function
......
......@@ -895,7 +895,7 @@ End Class
' TODO: port C# tests, add more VB specific tests
<Fact>
Public Sub LambdasMultipleGenerations()
Public Sub LambdasMultipleGenerations1()
Dim source0 = MarkedSource("
Imports System
Class C
......@@ -1116,5 +1116,138 @@ End Class
}
")
End Sub
<Fact, WorkItem(2284, "https://github.com/dotnet/roslyn/issues/2284")>
Public Sub LambdasMultipleGenerations2()
Dim source0 = MarkedSource("
Imports System
Imports System.Linq
Class C
Private _titles As Integer() = New Integer() {1, 2}
Dim A As Action
Private Sub F()
' edit 1
' Dim z = From title In _titles
' Where title > 0
' Select title
A = <N:0>Sub ()
Console.WriteLine(1)
' edit 2
' Console.WriteLine(2)
End Sub</N:0>
End Sub
End Class
")
Dim source1 = MarkedSource("
Imports System
Imports System.Linq
Class C
Private _titles As Integer() = New Integer() {1, 2}
Dim A As Action
Private Sub F()
' edit 1
Dim <N:3>z</N:3> = From title In _titles
<N:2>Where title > 0</N:2>
Select <N:1:ExpressionRangeVariable>title</N:1>
A = <N:0>Sub ()
Console.WriteLine(1)
' edit 2
' Console.WriteLine(2)
End Sub</N:0>
End Sub
End Class")
Dim source2 = MarkedSource("
Imports System
Imports System.Linq
Class C
Private _titles As Integer() = New Integer() {1, 2}
Dim A As Action
Private Sub F()
' edit 1
Dim <N:3>z</N:3> = From title In _titles
<N:2>Where title > 0</N:2>
Select <N:1:ExpressionRangeVariable>title</N:1>
A = <N:0>Sub ()
Console.WriteLine(1)
' edit 2
Console.WriteLine(2)
End Sub</N:0>
End Sub
End Class")
Dim compilation0 = CreateCompilationWithReferences(source0.Tree, {MscorlibRef, SystemCoreRef}, options:=ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All))
Dim compilation1 = compilation0.WithSource(source1.Tree)
Dim compilation2 = compilation1.WithSource(source2.Tree)
Dim v0 = CompileAndVerify(compilation0)
Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)
Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F")
Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F")
Dim f2 = compilation2.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)))
Dim md1 = diff1.GetMetadata()
Dim reader1 = md1.Reader
' new lambda "_Lambda$__3-0#1" has been added
diff1.VerifySynthesizedMembers(
"C: {_Closure$__}",
"C._Closure$__: {$I3-0#1, $I3-1#1, $I3-0, _Lambda$__3-0#1, _Lambda$__3-1#1, _Lambda$__3-0}")
' lambda body unchanged
diff1.VerifyIL("C._Closure$__._Lambda$__3-0", "
{
// Code size 9 (0x9)
.maxstack 1
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""Sub System.Console.WriteLine(Integer)""
IL_0007: nop
IL_0008: ret
}")
Dim diff2 = compilation2.EmitDifference(
diff1.NextGeneration,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables:=True)))
' no new members
diff2.VerifySynthesizedMembers(
"C: {_Closure$__}",
"C._Closure$__: {$I3-0#1, $I3-1#1, $I3-0, _Lambda$__3-0#1, _Lambda$__3-1#1, _Lambda$__3-0}")
' lambda body updated
diff2.VerifyIL("C._Closure$__._Lambda$__3-0", "
{
// Code size 16 (0x10)
.maxstack 1
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call ""Sub System.Console.WriteLine(Integer)""
IL_0007: nop
IL_0008: ldc.i4.2
IL_0009: call ""Sub System.Console.WriteLine(Integer)""
IL_000e: nop
IL_000f: ret
}")
End Sub
End Class
End Namespace
......@@ -104,12 +104,22 @@ private SyntaxNode GetNode(SyntaxNode root, ValueTuple<TextSpan, int, int> spanA
{
var map0 = source0.MapMarksToSyntaxNodes();
var map1 = source1.MapSyntaxNodesToMarks();
#if DUMP
Console.WriteLine("========");
#endif
return new Func<SyntaxNode, SyntaxNode>(node1 =>
{
int mark;
SyntaxNode result;
return map1.TryGetValue(node1, out mark) && map0.TryGetValue(mark, out result) ? result : null;
if (map1.TryGetValue(node1, out mark) && map0.TryGetValue(mark, out result))
{
return result;
}
#if DUMP
Console.WriteLine($"? {node1.RawKind} [[{node1}]]");
#endif
return null;
});
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册