From 1f68b0e2a2bcf6c1fec0d852220b8ec6ff21731b Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 13 Aug 2022 08:25:44 +0200 Subject: [PATCH 1/5] Fix generate type dialog invoked on type argument in a base list --- .../GenerateType/GenerateTypeTests_Dialog.cs | 28 +++++++++++++++++++ ...ctUserDiagnosticTest_GenerateTypeDialog.cs | 6 ++-- .../GenerateType/CSharpGenerateTypeService.cs | 17 ++++------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index 2da0b9dcaf527..7651c444ad9dd 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -2271,6 +2271,34 @@ public struct Bar isNewFile: false, assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.Class | TypeKindOptions.Structure, false)); } + + [Fact, WorkItem(63280, "https://github.com/dotnet/roslyn/issues/63280")] + public async Task GenerateType_GenericBaseList() + { + await TestWithMockedGenerateTypeDialog( +initial: @" +using System.Collections.Generic; + +struct C : IEnumerable<[|$$NewType|]> +{ +}", +languageName: LanguageNames.CSharp, +typeName: "$$NewType", +expected: @" +using System.Collections.Generic; + +struct C : IEnumerable +{ +} + +public class $$NewType +{ +}", +accessibility: Accessibility.Public, +typeKind: TypeKind.Class, +isNewFile: false, +assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.AllOptions, false)); + } #endregion #region Delegates [Fact] diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs index 712b5060e3b07..45605d118ff13 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_GenerateTypeDialog.cs @@ -167,9 +167,9 @@ await TestOperationsAsync(testState.Workspace, expectedTextWithUsings, operation if (assertGenerateTypeDialogOptions != null) { - Assert.True(assertGenerateTypeDialogOptions.IsPublicOnlyAccessibility == generateTypeDialogOptions.IsPublicOnlyAccessibility); - Assert.True(assertGenerateTypeDialogOptions.TypeKindOptions == generateTypeDialogOptions.TypeKindOptions); - Assert.True(assertGenerateTypeDialogOptions.IsAttribute == generateTypeDialogOptions.IsAttribute); + Assert.Equal(assertGenerateTypeDialogOptions.IsPublicOnlyAccessibility, generateTypeDialogOptions.IsPublicOnlyAccessibility); + Assert.Equal(assertGenerateTypeDialogOptions.TypeKindOptions, generateTypeDialogOptions.TypeKindOptions); + Assert.Equal(assertGenerateTypeDialogOptions.IsAttribute, generateTypeDialogOptions.IsAttribute); } if (assertTypeKindPresent != null) diff --git a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs index 129b0945c52bf..303c511a413d0 100644 --- a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs +++ b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs @@ -664,23 +664,16 @@ internal override bool TryGetBaseList(ExpressionSyntax expression, out TypeKindO return false; } - var node = expression as SyntaxNode; - - while (node != null) + if (expression.Parent is BaseTypeSyntax { Parent: BaseListSyntax baseList }) { - if (node is BaseListSyntax) + if (baseList.Parent.IsKind(SyntaxKind.InterfaceDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordStructDeclaration)) { - if (node.Parent.Kind() is SyntaxKind.InterfaceDeclaration or SyntaxKind.StructDeclaration or SyntaxKind.RecordStructDeclaration) - { - typeKindValue = TypeKindOptions.Interface; - return true; - } - - typeKindValue = TypeKindOptions.BaseList; + typeKindValue = TypeKindOptions.Interface; return true; } - node = node.Parent; + typeKindValue = TypeKindOptions.BaseList; + return true; } return false; From e1a90899f7b7882fc8d4564b31a427b1e0076921 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 13 Aug 2022 08:52:40 +0200 Subject: [PATCH 2/5] Simplify code, add test --- .../GenerateType/GenerateTypeTests_Dialog.cs | 36 +++++++++++++++++++ .../AbstractGenerateTypeService.CodeAction.cs | 3 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index 7651c444ad9dd..a3f21bcf538a9 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -2299,6 +2299,42 @@ public class $$NewType isNewFile: false, assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.AllOptions, false)); } + + [Fact] + public async Task GenerateType_QualifiedBaseList() + { + await TestWithMockedGenerateTypeDialog( +initial: @" +using System.Collections.Generic; + +struct C : A.B.[|$$INewType|] +{ +} + +namespace A.B +{ +}", +languageName: LanguageNames.CSharp, +typeName: "$$INewType", +expected: @" +using System.Collections.Generic; + +struct C : A.B.INewType +{ +} + +namespace A.B +{ + public interface $$INewType + { + } +}", +accessibility: Accessibility.Public, +typeKind: TypeKind.Interface, +isNewFile: false, +assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.Interface, false)); + } + #endregion #region Delegates [Fact] diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs index 6c3ca86fd1c93..e7872f4dae9d6 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs @@ -140,8 +140,7 @@ private bool GetPredefinedTypeKindOption(State state, out TypeKindOptions typeKi return true; } - if (_service.TryGetBaseList(state.NameOrMemberAccessExpression, out var typeKindValue) || - _service.TryGetBaseList(state.SimpleName, out typeKindValue)) + if (_service.TryGetBaseList(state.NameOrMemberAccessExpression, out var typeKindValue)) { typeKindValueFinal = typeKindValue; return true; From 7bc4305a99d19d40bcc04f61f00255b6ff04f91d Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 13 Aug 2022 08:55:12 +0200 Subject: [PATCH 3/5] One more test case --- .../GenerateType/GenerateTypeTests_Dialog.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index a3f21bcf538a9..75a8c2c37e8b2 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -2335,6 +2335,40 @@ public interface $$INewType assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.Interface, false)); } + [Fact] + public async Task GenerateType_AliasQualifiedBaseList() + { + await TestWithMockedGenerateTypeDialog( +initial: @" +using System.Collections.Generic; + +struct C : global::A.B.[|$$INewType|] +{ +} + +namespace A.B +{ +}", +languageName: LanguageNames.CSharp, +typeName: "$$INewType", +expected: @" +using System.Collections.Generic; + +struct C : global::A.B.INewType +{ +} + +namespace A.B +{ + public interface $$INewType + { + } +}", +accessibility: Accessibility.Public, +typeKind: TypeKind.Interface, +isNewFile: false, +assertGenerateTypeDialogOptions: new GenerateTypeDialogOptions(false, TypeKindOptions.Interface, false)); + } #endregion #region Delegates [Fact] From c5173d1dbd61f087a7dd5f7e35b2b9f5fca318af Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 13 Aug 2022 11:20:58 +0200 Subject: [PATCH 4/5] Fix VB, fix tests --- .../GenerateType/GenerateTypeTests_Dialog.cs | 12 +++---- .../GenerateType/GenerateTypeTests_Dialog.vb | 31 +++++++++++++++++++ .../VisualBasicGenerateTypeService.vb | 21 +++++-------- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index 75a8c2c37e8b2..8a6acfa346e29 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -2283,7 +2283,7 @@ struct C : IEnumerable<[|$$NewType|]> { }", languageName: LanguageNames.CSharp, -typeName: "$$NewType", +typeName: "NewType", expected: @" using System.Collections.Generic; @@ -2291,7 +2291,7 @@ struct C : IEnumerable { } -public class $$NewType +public class NewType { }", accessibility: Accessibility.Public, @@ -2315,7 +2315,7 @@ namespace A.B { }", languageName: LanguageNames.CSharp, -typeName: "$$INewType", +typeName: "INewType", expected: @" using System.Collections.Generic; @@ -2325,7 +2325,7 @@ struct C : A.B.INewType namespace A.B { - public interface $$INewType + public interface INewType { } }", @@ -2350,7 +2350,7 @@ namespace A.B { }", languageName: LanguageNames.CSharp, -typeName: "$$INewType", +typeName: "INewType", expected: @" using System.Collections.Generic; @@ -2360,7 +2360,7 @@ struct C : global::A.B.INewType namespace A.B { - public interface $$INewType + public interface INewType { } }", diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.vb index 9d71a41dfd401..f7f5e9bd1e3c5 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.vb @@ -1626,6 +1626,37 @@ typeName:="Bar", isMissing:=True) End Function + + + Public Async Function GenerateType_GenericBaseList() As Task + Await TestWithMockedGenerateTypeDialog( +initial:= +Imports System.Collections.Generic + +Structure S + Implements IEnumerable(Of [|$$NewType|]) + +End Structure +.NormalizedValue, +languageName:=LanguageNames.VisualBasic, +typeName:="NewType", +expected:= +Imports System.Collections.Generic + +Structure S + Implements IEnumerable(Of NewType) + +End Structure + +Public Class NewType +End Class +.NormalizedValue, +isNewFile:=False, +accessibility:=Accessibility.Public, +typeKind:=TypeKind.Class, +assertGenerateTypeDialogOptions:=New GenerateTypeDialogOptions(False, TypeKindOptions.AllOptions, False)) + End Function + #End Region #Region "Delegates" diff --git a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb index ec54305a08db7..f0bf267e39a6f 100644 --- a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb +++ b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb @@ -539,23 +539,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateType Return False End If - Dim node As SyntaxNode = expression - While node IsNot Nothing - If TypeOf node Is InheritsStatementSyntax Then - If node.Parent IsNot Nothing AndAlso TypeOf node.Parent Is InterfaceBlockSyntax Then - typeKindValue = TypeKindOptions.Interface - Return True - End If - - typeKindValue = TypeKindOptions.Class - Return True - ElseIf TypeOf node Is ImplementsStatementSyntax Then + If TypeOf expression.Parent Is InheritsStatementSyntax Then + If expression.Parent.Parent IsNot Nothing AndAlso TypeOf expression.Parent.Parent Is InterfaceBlockSyntax Then typeKindValue = TypeKindOptions.Interface Return True End If - node = node.Parent - End While + typeKindValue = TypeKindOptions.Class + Return True + ElseIf TypeOf expression.Parent Is ImplementsStatementSyntax Then + typeKindValue = TypeKindOptions.Interface + Return True + End If Return False End Function From 574373044f5fee529b0a6a26a4ff1a4ac115890e Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Fri, 11 Nov 2022 00:11:54 +0200 Subject: [PATCH 5/5] Update CSharpGenerateTypeService.cs --- .../CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs index 303c511a413d0..468e73304c84f 100644 --- a/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs +++ b/src/Features/CSharp/Portable/GenerateType/CSharpGenerateTypeService.cs @@ -666,7 +666,7 @@ internal override bool TryGetBaseList(ExpressionSyntax expression, out TypeKindO if (expression.Parent is BaseTypeSyntax { Parent: BaseListSyntax baseList }) { - if (baseList.Parent.IsKind(SyntaxKind.InterfaceDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordStructDeclaration)) + if (baseList.Parent.Kind() is SyntaxKind.InterfaceDeclaration or SyntaxKind.StructDeclaration or SyntaxKind.RecordStructDeclaration) { typeKindValue = TypeKindOptions.Interface; return true;