From f6d61adf5a3680d5c7b4b36ba080d4d17dc59afa Mon Sep 17 00:00:00 2001 From: nmgafter Date: Fri, 1 Aug 2014 14:56:06 -0700 Subject: [PATCH] 667579-DebuggerHidden iterator methods should hide MoveNext (changeset 1310286) --- .../Lowering/AsyncRewriter/AsyncRewriter.cs | 6 +- .../IteratorRewriter/IteratorRewriter.cs | 10 +-- .../StateMachineRewriter.cs | 16 ++++- .../SynthesizedStateMachineMethod.cs | 3 +- .../SynthesizedStateMachineProperty.cs | 1 + .../SynthesizedImplementationMethod.cs | 5 +- .../CSharp/Test/Emit/PDB/PDBIteratorTests.cs | 48 ++++++++++++++ .../Lowering/AsyncRewriter/AsyncRewriter.vb | 17 +++-- .../IteratorRewriter/IteratorRewriter.vb | 5 +- .../StateMachineRewriter.vb | 8 +++ .../Test/Emit/PDB/PDBIteratorTests.vb | 64 +++++++++++++++++++ 11 files changed, 163 insertions(+), 20 deletions(-) diff --git a/Src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs b/Src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs index fa856de0fd0..229daf6bd43 100644 --- a/Src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs +++ b/Src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs @@ -90,13 +90,13 @@ protected override void GenerateMethodImplementations() var IAsyncStateMachine_SetStateMachine = F.WellKnownMethod(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_SetStateMachine); // Add IAsyncStateMachine.MoveNext() - - var moveNextMethod = OpenMethodImplementation(IAsyncStateMachine_MoveNext, "MoveNext", asyncKickoffMethod: this.method, hasMethodBodyDependency: true); + + var moveNextMethod = OpenMethodImplementation(IAsyncStateMachine_MoveNext, "MoveNext", asyncKickoffMethod: this.method, hasMethodBodyDependency: true, debuggerHidden: IsDebuggerHidden(this.method), generateDebugInfo: true); GenerateMoveNext(moveNextMethod); // Add IAsyncStateMachine.SetStateMachine() - OpenMethodImplementation(IAsyncStateMachine_SetStateMachine, "SetStateMachine", debuggerHidden: true, hasMethodBodyDependency: false); + OpenMethodImplementation(IAsyncStateMachine_SetStateMachine, "SetStateMachine", debuggerHidden: true, generateDebugInfo: false, hasMethodBodyDependency: false); // SetStateMachine is used to initialize the underlying AsyncMethodBuilder's reference to the boxed copy of the state machine. // If the state machine is a class there is no copy made and thus the initialization is not necessary. diff --git a/Src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs b/Src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs index ec4243f3154..8e370dbe585 100644 --- a/Src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs +++ b/Src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs @@ -134,8 +134,8 @@ private void GenerateEnumeratorImplementation() // Add bool IEnumerator.MoveNext() and void IDisposable.Dispose() { - var disposeMethod = OpenMethodImplementation(IDisposable_Dispose, debuggerHidden: true, hasMethodBodyDependency: true); - var moveNextMethod = OpenMethodImplementation(IEnumerator_MoveNext, methodName: WellKnownMemberNames.MoveNextMethodName, hasMethodBodyDependency: true); + var disposeMethod = OpenMethodImplementation(IDisposable_Dispose, debuggerHidden: true, generateDebugInfo: false, hasMethodBodyDependency: true); + var moveNextMethod = OpenMethodImplementation(IEnumerator_MoveNext, methodName: WellKnownMemberNames.MoveNextMethodName, hasMethodBodyDependency: true, debuggerHidden: IsDebuggerHidden(this.method)); GenerateMoveNextAndDispose(moveNextMethod, disposeMethod); } @@ -147,7 +147,7 @@ private void GenerateEnumeratorImplementation() // Add void IEnumerator.Reset() { - OpenMethodImplementation(IEnumerator_Reset, debuggerHidden: true, hasMethodBodyDependency: false); + OpenMethodImplementation(IEnumerator_Reset, debuggerHidden: true, generateDebugInfo: false, hasMethodBodyDependency: false); F.CloseMethod(F.Throw(F.New(F.WellKnownType(WellKnownType.System_NotSupportedException)))); } @@ -184,7 +184,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI // The implementation doesn't depend on the method body of the iterator method. // Only on it's parameters and staticness. - var getEnumeratorGeneric = OpenMethodImplementation(IEnumerableOfElementType_GetEnumerator, debuggerHidden: true, hasMethodBodyDependency: false); + var getEnumeratorGeneric = OpenMethodImplementation(IEnumerableOfElementType_GetEnumerator, debuggerHidden: true, generateDebugInfo: false, hasMethodBodyDependency: false); var bodyBuilder = ArrayBuilder.GetInstance(); var resultVariable = F.SynthesizedLocal(stateMachineClass, null); // iteratorClass result; @@ -263,7 +263,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), bodyBuilder.ToImmutableAndFree())); // Generate IEnumerable.GetEnumerator - var getEnumerator = OpenMethodImplementation(IEnumerable_GetEnumerator, debuggerHidden: true); + var getEnumerator = OpenMethodImplementation(IEnumerable_GetEnumerator, debuggerHidden: true, generateDebugInfo: false); F.CloseMethod(F.Return(F.Call(F.This(), getEnumeratorGeneric))); } diff --git a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs index 8a9d71ee463..96650c4a454 100644 --- a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs +++ b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs @@ -247,11 +247,12 @@ private BoundStatement ReplaceOriginalMethod() protected SynthesizedImplementationMethod OpenMethodImplementation( MethodSymbol methodToImplement, string methodName = null, - bool debuggerHidden = false, + bool debuggerHidden = false, + bool generateDebugInfo = true, bool hasMethodBodyDependency = false, MethodSymbol asyncKickoffMethod = null) { - var result = new SynthesizedStateMachineMethod(methodName, methodToImplement, F.CurrentClass, asyncKickoffMethod, null, debuggerHidden, hasMethodBodyDependency); + var result = new SynthesizedStateMachineMethod(methodName, methodToImplement, F.CurrentClass, asyncKickoffMethod, null, debuggerHidden, generateDebugInfo, hasMethodBodyDependency); F.ModuleBuilderOpt.AddSynthesizedDefinition(F.CurrentClass, result); F.CurrentMethod = result; return result; @@ -271,5 +272,16 @@ private BoundStatement ReplaceOriginalMethod() F.CurrentMethod = getter; return getter; } + + protected bool IsDebuggerHidden(MethodSymbol method) + { + var debuggerHiddenAttribute = this.compilationState.Compilation.GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerHiddenAttribute); + foreach (var a in this.method.GetAttributes()) + { + if (a.AttributeClass == debuggerHiddenAttribute) return true; + } + + return false; + } } } \ No newline at end of file diff --git a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs index b9205d77f91..0c5c24d7ccb 100644 --- a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs +++ b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineMethod.cs @@ -19,8 +19,9 @@ internal sealed class SynthesizedStateMachineMethod : SynthesizedImplementationM MethodSymbol asyncKickoffMethod, PropertySymbol associatedProperty, bool debuggerHidden, + bool generateDebugInfo, bool hasMethodBodyDependency) - : base(interfaceMethod, implementingType, name, debuggerHidden, associatedProperty, asyncKickoffMethod) + : base(interfaceMethod, implementingType, name, debuggerHidden, generateDebugInfo, associatedProperty, asyncKickoffMethod) { this.hasMethodBodyDependency = hasMethodBodyDependency; } diff --git a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs index 2c2daaebbee..9cacf513687 100644 --- a/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs +++ b/Src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs @@ -29,6 +29,7 @@ internal class SynthesizedStateMachineProperty : PropertySymbol, ISynthesizedMet asyncKickoffMethod: null, associatedProperty: this, debuggerHidden: debuggerHidden, + generateDebugInfo: !debuggerHidden, hasMethodBodyDependency: hasMethodBodyDependency); } diff --git a/Src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs b/Src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs index 4fd8399b0e1..d64f6afc506 100644 --- a/Src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs +++ b/Src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs @@ -14,6 +14,7 @@ internal class SynthesizedImplementationMethod : SynthesizedInstanceMethodSymbol private readonly MethodSymbol interfaceMethod; private readonly NamedTypeSymbol implementingType; private readonly bool debuggerHidden; + private readonly bool generateDebugInfo; private readonly PropertySymbol associatedProperty; private readonly MethodSymbol asyncKickoffMethod; @@ -29,6 +30,7 @@ internal class SynthesizedImplementationMethod : SynthesizedInstanceMethodSymbol NamedTypeSymbol implementingType, string name = null, bool debuggerHidden = false, + bool generateDebugInfo = true, PropertySymbol associatedProperty = null, MethodSymbol asyncKickoffMethod = null) { @@ -39,6 +41,7 @@ internal class SynthesizedImplementationMethod : SynthesizedInstanceMethodSymbol this.interfaceMethod = interfaceMethod; this.implementingType = implementingType; this.debuggerHidden = debuggerHidden; + this.generateDebugInfo = generateDebugInfo; this.associatedProperty = associatedProperty; this.explicitInterfaceImplementations = ImmutableArray.Create(interfaceMethod); this.asyncKickoffMethod = asyncKickoffMethod; @@ -100,7 +103,7 @@ internal sealed override void AddSynthesizedAttributes(ModuleCompilationState co internal override bool GenerateDebugInfo { - get { return !debuggerHidden; } + get { return generateDebugInfo; } } public sealed override ImmutableArray TypeParameters diff --git a/Src/Compilers/CSharp/Test/Emit/PDB/PDBIteratorTests.cs b/Src/Compilers/CSharp/Test/Emit/PDB/PDBIteratorTests.cs index b95adca97fa..930307347e5 100644 --- a/Src/Compilers/CSharp/Test/Emit/PDB/PDBIteratorTests.cs +++ b/Src/Compilers/CSharp/Test/Emit/PDB/PDBIteratorTests.cs @@ -1009,6 +1009,54 @@ static IEnumerable M() +"; + AssertXmlEqual(expected, actual); + } + + [Fact, WorkItem(667579, "DevDiv")] + public void DebuggerHiddenIterator() + { + var text = @" +using System; +using System.Collections.Generic; +using System.Diagnostics; + +class C +{ + static void Main(string[] args) + { + foreach (var x in F()) ; + } + + [DebuggerHidden] + static IEnumerable F() + { + throw new Exception(); + yield break; + } +}"; + string actual = GetPdbXml(text, TestOptions.DebugDll, "C+d__0.MoveNext"); + string expected = +@" + + + + + + + + + + + + + + + + "; AssertXmlEqual(expected, actual); } diff --git a/Src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb b/Src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb index a5b6d991248..eed86773fd9 100644 --- a/Src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb +++ b/Src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic asyncKind As AsyncMethodKind, compilationState As TypeCompilationState, diagnostics As DiagnosticBag, - generateDebugInfo As boolean) + generateDebugInfo As Boolean) MyBase.New(body, method, compilationState, diagnostics, generateDebugInfo) @@ -62,10 +62,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Friend Shared Function CreateAsyncStateMachine(method As MethodSymbol, - typeIndex As Integer, + typeIndex As Integer, typeKind As TypeKind, - valueTypeSymbol As NamedTypeSymbol, - iAsyncStateMachine As NamedTypeSymbol) As NamedTypeSymbol + valueTypeSymbol As NamedTypeSymbol, + iAsyncStateMachine As NamedTypeSymbol) As NamedTypeSymbol Return New AsyncStateMachine(method, typeIndex, typeKind, valueTypeSymbol, iAsyncStateMachine) End Function @@ -133,14 +133,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic method As MethodSymbol, compilationState As TypeCompilationState, diagnostics As DiagnosticBag, - generateDebugInfo As boolean) As BoundBlock + generateDebugInfo As Boolean) As BoundBlock If body.HasErrors Then Return body End If Dim asyncMethodKind As AsyncMethodKind = GetAsyncMethodKind(method) - If asyncMethodKind = asyncMethodKind.None Then + If asyncMethodKind = AsyncMethodKind.None Then Return body End If @@ -156,10 +156,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected Overrides Sub GenerateMethodImplementations() ' Add IAsyncStateMachine.MoveNext() + Dim debuggerHidden = IsDebuggerHidden(Me.Method) + Dim moveNextAttrs As DebugAttributes = DebugAttributes.CompilerGeneratedAttribute + If debuggerHidden Then moveNextAttrs = moveNextAttrs Or DebugAttributes.DebuggerHiddenAttribute GenerateMoveNext(Me.StartMethodImplementation( WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext, "MoveNext", - DebugAttributes.CompilerGeneratedAttribute, Accessibility.Friend, True, asyncKickoffMethod:=Me.Method)) + moveNextAttrs, Accessibility.Friend, True, asyncKickoffMethod:=Me.Method)) 'Add IAsyncStateMachine.SetStateMachine() Me.StartMethodImplementation( diff --git a/Src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb b/Src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb index 4876ea7bf8c..9143682892d 100644 --- a/Src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb +++ b/Src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb @@ -144,9 +144,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Accessibility.Private, False) + Dim debuggerHidden = IsDebuggerHidden(Me.Method) + Dim moveNextAttrs As DebugAttributes = DebugAttributes.CompilerGeneratedAttribute + If debuggerHidden Then moveNextAttrs = moveNextAttrs Or DebugAttributes.DebuggerHiddenAttribute Dim moveNextMethod = Me.StartMethodImplementation(SpecialMember.System_Collections_IEnumerator__MoveNext, "MoveNext", - DebugAttributes.CompilerGeneratedAttribute, + moveNextAttrs, Accessibility.Private, True) diff --git a/Src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb b/Src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb index 63767dd3cce..69baf26bc21 100644 --- a/Src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb +++ b/Src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb @@ -435,6 +435,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return body End Function + Protected Function IsDebuggerHidden(method As MethodSymbol) As Boolean + Dim debuggerHiddenAttribute = Me.CompilationState.Compilation.GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerHiddenAttribute) + For Each a In Me.Method.GetAttributes() + If a.AttributeClass = debuggerHiddenAttribute Then Return True + Next + + Return False + End Function End Class End Namespace diff --git a/Src/Compilers/VisualBasic/Test/Emit/PDB/PDBIteratorTests.vb b/Src/Compilers/VisualBasic/Test/Emit/PDB/PDBIteratorTests.vb index 1c6b2c2de0d..c168c003a31 100644 --- a/Src/Compilers/VisualBasic/Test/Emit/PDB/PDBIteratorTests.vb +++ b/Src/Compilers/VisualBasic/Test/Emit/PDB/PDBIteratorTests.vb @@ -410,5 +410,69 @@ End Class PDBTests.AssertXmlEqual(expected, actual) End Sub + + Public Sub DebuggerHiddenIterator() + Dim source = + + +Imports System +Imports System.Collections.Generic +Imports System.Diagnostics +Module Module1 + + Sub Main() + For Each i In Foo + Console.Write(i) + Next + End Sub + + <DebuggerHidden> + Iterator Function Foo() As IEnumerable(Of Integer) + Yield 1 + Yield 2 + End Function + +End Module + + + + Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime( + source, + OptionsExe.WithOptimizations(False)) + + Dim actual = PDBTests.GetPdbXml(compilation, "Module1+VB$StateMachine_1_Foo.MoveNext") + + Dim expected = + + + + + + + + + + + + + + + + + + + + + + + PDBTests.AssertXmlEqual(expected, actual) + End Sub + End Class End Namespace -- GitLab