From b3611be66c766d95866f205907739378c86b6920 Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 16 Dec 2020 13:14:24 -0800 Subject: [PATCH] Fix bug where constructor cycle detection would throw IndexOutOfBoundsException The problem here was when we do cycle detection, we tried to look at the source of the candidate constructor that we are looking at delegating to. If we are in a cross-language case, the target might be from metadata via the skeleton reference and we don't have source. Rather than fixing the code that assumes it's a source method, I'm making a change that says if the constructor you're delegating to is in the base type, then we can't create a cycle and can skip the check entirely. --- .../GenerateConstructorTests.vb | 38 +++++++++++++++++++ .../AbstractGenerateConstructorService.cs | 4 ++ 2 files changed, 42 insertions(+) diff --git a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb index 348137d89c1..c211b02839a 100644 --- a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb @@ -1866,6 +1866,44 @@ End Class", End Class") End Function + + Public Async Function TestDelegateConstructorCrossLanguageCycleAvoidance() As Task + Await TestInRegularAndScriptAsync( + + + + public class BaseType + { + public BaseType(int x, int y) { } + } + + + + CSharpProject + +Public Class B + Inherits BaseType + + Public Sub New(a As Integer) + [|Me.New(a, 1)|] + End Sub +End Class + +.ToString(), +" +Public Class B + Inherits BaseType + + Public Sub New(a As Integer) + Me.New(a, 1) + End Sub + + Public Sub New(x As Integer, y As Integer) + MyBase.New(x, y) + End Sub +End Class") + End Function + Public Async Function TestDelegateConstructorCrossLanguage() As Task diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs index 95486db117a..391c93153d0 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs @@ -57,6 +57,10 @@ protected bool WillCauseConstructorCycle(State state, SemanticDocument document, if (currentConstructor.Equals(delegatedConstructor)) return true; + // Delegating to a constructor in the base type can't cause a cycle + if (!delegatedConstructor.ContainingType.Equals(currentConstructor.ContainingType)) + return false; + // We need ensure that delegating constructor won't cause circular dependency. // The chain of dependency can not exceed the number for constructors var constructorsCount = delegatedConstructor.ContainingType.InstanceConstructors.Length; -- GitLab