Skip to content

Commit a405d25

Browse files
Merge pull request #59548 from CyrusNajmabadi/vbGenEquals
Fix Generate-Equals for VB when invoked on type header.
2 parents f767c70 + 3efcf4f commit a405d25

File tree

8 files changed

+43
-14
lines changed

8 files changed

+43
-14
lines changed

src/Analyzers/Core/CodeFixes/UseSystemHashCode/UseSystemHashCodeCodeFixProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ protected override async Task FixAllAsync(
7070

7171
var methodDecl = diagnostic.AdditionalLocations[1].FindNode(cancellationToken);
7272
var method = semanticModel.GetDeclaredSymbol(methodDecl, cancellationToken);
73+
if (method == null)
74+
continue;
75+
7376
var methodBlock = declarationService.GetDeclarations(method)[0].GetSyntax(cancellationToken);
7477

7578
var (accessesBase, members, _) = analyzer.GetHashedMembers(method, operation);

src/EditorFeatures/VisualBasicTest/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.vb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,5 +818,27 @@ End Class
818818
",
819819
index:=1)
820820
End Function
821+
822+
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
823+
<WorkItem(45919, "https://github.com/dotnet/roslyn/issues/45919")>
824+
Public Async Function TestWithDialogOnClassHeader() As Task
825+
Await TestWithPickMembersDialogAsync(
826+
"
827+
Class [||]Program
828+
Public Property F() As Integer
829+
830+
End Class",
831+
"
832+
Class Program
833+
Public Property F() As Integer
834+
835+
Public Overrides Function Equals(obj As Object) As Boolean
836+
Dim program = TryCast(obj, Program)
837+
Return program IsNot Nothing AndAlso
838+
F = program.F
839+
End Function
840+
End Class",
841+
chosenSymbols:=Nothing)
842+
End Function
821843
End Class
822844
End Namespace

src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections.Immutable;
77
using System.Composition;
88
using Microsoft.CodeAnalysis.CodeFixes;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
910
using Microsoft.CodeAnalysis.GenerateDefaultConstructors;
1011
using Microsoft.CodeAnalysis.Host.Mef;
1112

@@ -26,5 +27,8 @@ public CSharpGenerateDefaultConstructorsCodeFixProvider()
2627

2728
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
2829
ImmutableArray.Create(CS1729, CS7036, CS8983);
30+
31+
protected override SyntaxToken? TryGetTypeName(SyntaxNode typeDeclaration)
32+
=> (typeDeclaration as BaseTypeDeclarationSyntax)?.Identifier;
2933
}
3034
}

src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ internal abstract class AbstractGenerateDefaultConstructorCodeFixProvider : Code
1515
{
1616
public override FixAllProvider? GetFixAllProvider() => null;
1717

18+
protected abstract SyntaxToken? TryGetTypeName(SyntaxNode typeDeclaration);
19+
1820
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
1921
{
2022
var cancellationToken = context.CancellationToken;
@@ -23,17 +25,18 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
2325
if (diagnostic == null)
2426
return;
2527

26-
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
27-
var headerFacts = document.GetRequiredLanguageService<IHeaderFactsService>();
28-
2928
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
29+
var headerFacts = document.GetRequiredLanguageService<IHeaderFactsService>();
3030
if (!headerFacts.IsOnTypeHeader(root, diagnostic.Location.SourceSpan.Start, fullHeader: true, out var typeDecl))
3131
return;
3232

33-
var typeName = syntaxFacts.GetIdentifierOfTypeDeclaration(typeDecl);
33+
var typeName = TryGetTypeName(typeDecl);
34+
if (typeName == null)
35+
return;
36+
3437
var service = document.GetRequiredLanguageService<IGenerateDefaultConstructorsService>();
3538
var actions = await service.GenerateDefaultConstructorsAsync(
36-
document, new TextSpan(typeName.Span.Start, 0), forRefactoring: false, cancellationToken).ConfigureAwait(false);
39+
document, new TextSpan(typeName.Value.Span.Start, 0), forRefactoring: false, cancellationToken).ConfigureAwait(false);
3740
context.RegisterFixes(actions, diagnostic);
3841
}
3942
}

src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,11 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context)
8888
// Only supported on classes/structs.
8989
var containingType = semanticModel.GetDeclaredSymbol(typeDeclaration) as INamedTypeSymbol;
9090
if (containingType?.TypeKind is not TypeKind.Class and not TypeKind.Struct)
91-
{
9291
return;
93-
}
9492

9593
// No overrides in static classes.
9694
if (containingType.IsStatic)
97-
{
9895
return;
99-
}
10096

10197
// Find all the possible instance fields/properties. If there are any, then
10298
// show a dialog to the user to select the ones they want.
@@ -108,9 +104,7 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context)
108104
.ToImmutableArray();
109105

110106
if (viableMembers.Length == 0)
111-
{
112107
return;
113-
}
114108

115109
GetExistingMemberInfo(
116110
containingType, out var hasEquals, out var hasGetHashCode);

src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Imports System.Composition
77
Imports Microsoft.CodeAnalysis.CodeFixes
88
Imports Microsoft.CodeAnalysis.GenerateDefaultConstructors
99
Imports Microsoft.CodeAnalysis.Host.Mef
10+
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
1011

1112
Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors
1213
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.GenerateDefaultConstructors), [Shared]>
@@ -23,5 +24,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors
2324

2425
Public Overrides ReadOnly Property FixableDiagnosticIds As Immutable.ImmutableArray(Of String) =
2526
ImmutableArray.Create(BC30387, BC40056)
27+
28+
Protected Overrides Function TryGetTypeName(typeDeclaration As SyntaxNode) As SyntaxToken?
29+
Return TryCast(typeDeclaration, TypeBlockSyntax)?.BlockStatement.Identifier
30+
End Function
2631
End Class
2732
End Namespace

src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicHeaderFacts.vb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices
2828
End If
2929

3030
Dim typeStatement = typeBlock.BlockStatement
31-
typeDeclaration = typeStatement
31+
typeDeclaration = typeBlock
3232

3333
Dim lastToken = If(typeStatement.TypeParameterList?.GetLastToken(), typeStatement.Identifier)
3434
If fullHeader Then

src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SymbolDeclarationService/ISymbolDeclarationService.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
using System.Collections.Immutable;
86
using Microsoft.CodeAnalysis.Host;
97

0 commit comments

Comments
 (0)