From e0487a7310a8c967cb14c39e1569967a2989a272 Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Wed, 16 Dec 2020 12:41:20 -0800 Subject: [PATCH] Fix generate constructor throwing in a cross-language case We tried to locate a constructor to delegate to; in that case we would grab the types of the constructor and make sure the original call site actually can use those types. In the cross-language case, we'd mix up types from different languages. The correct behavior here is to map the candiate type back to the language of the call site, since it's the call site's language rules that matter. Fixes https://github.com/dotnet/roslyn/issues/49850 --- .../GenerateConstructorTests.vb | 39 +++++++++++++++++++ .../GenerateConstructorHelpers.cs | 13 ++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb index 4285cc767ca..348137d89c1 100644 --- a/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb +++ b/src/EditorFeatures/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb @@ -1866,6 +1866,45 @@ End Class", End Class") End Function + + + Public Async Function TestDelegateConstructorCrossLanguage() As Task + Await TestInRegularAndScriptAsync( + + + +public class BaseType +{ + public BaseType(string x) { } +} + + + CSharpProject + +Option Strict On + +Public Class B + Public Sub M() + Dim x = [|New BaseType(42)|] + End Sub +End Class + + +.ToString(), +" +public class BaseType +{ + private int v; + + public BaseType(string x) { } + + public BaseType(int v) + { + this.v = v; + } +}") + End Function + Public Async Function CreateFieldDefaultNamingStyle() As Task diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs index 46789490429..58e878efc63 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs @@ -9,6 +9,7 @@ using System.Linq; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor { @@ -77,9 +78,17 @@ private static bool IsSymbolAccessible(Compilation compilation, ISymbol symbol) { Debug.Assert(constructor.Parameters.Length == expressions.Length); - for (var i = 0; i < constructor.Parameters.Length; i++) + // Resolve the constructor into our semantic model's compilation; if the constructor we're looking at is from + // another project with a different language. + var constructorInCompilation = (IMethodSymbol?)SymbolKey.Create(constructor).Resolve(semanticModel.Compilation).Symbol; + Contract.ThrowIfNull(constructorInCompilation); + + for (var i = 0; i < constructorInCompilation.Parameters.Length; i++) { - var constructorParameter = constructor.Parameters[i]; + var constructorParameter = constructorInCompilation.Parameters[i]; + if (constructorParameter == null) + return false; + var conversion = semanticFacts.ClassifyConversion(semanticModel, expressions[i], constructorParameter.Type); if (!conversion.IsIdentity && !conversion.IsImplicit) return false; -- GitLab