Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix generate type dialog invoked on type argument in a base list #63378

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,104 @@ 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<NewType>
{
}
public class NewType
{
}",
accessibility: Accessibility.Public,
typeKind: TypeKind.Class,
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));
}

[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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines +170 to +172
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This produces better assertion failures.

}

if (assertTypeKindPresent != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1626,6 +1626,37 @@ typeName:="Bar",
isMissing:=True)
End Function

<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)>
<WorkItem(63280, "https://github.com/dotnet/roslyn/issues/63280")>
Public Async Function GenerateType_GenericBaseList() As Task
Await TestWithMockedGenerateTypeDialog(
initial:=<Text>
Imports System.Collections.Generic

Structure S
Implements IEnumerable(Of [|$$NewType|])

End Structure
</Text>.NormalizedValue,
languageName:=LanguageNames.VisualBasic,
typeName:="NewType",
expected:=<Text>
Imports System.Collections.Generic

Structure S
Implements IEnumerable(Of NewType)

End Structure

Public Class NewType
End Class
</Text>.NormalizedValue,
isNewFile:=False,
accessibility:=Accessibility.Public,
typeKind:=TypeKind.Class,
assertGenerateTypeDialogOptions:=New GenerateTypeDialogOptions(False, TypeKindOptions.AllOptions, False))
End Function

#End Region
#Region "Delegates"
<Fact>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.Kind() is SyntaxKind.InterfaceDeclaration or SyntaxKind.StructDeclaration or 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading