提交 fc3724ba 编写于 作者: C Cyrus Najmabadi

Fix genarate-equals failing in partial types.

上级 423c52f2
......@@ -2695,5 +2695,177 @@ public override bool Equals(object? obj)
optionsCallback: options => EnableOption(options, GenerateOperatorsId),
parameters: CSharpLatestImplicit);
}
[WorkItem(42574, "https://github.com/dotnet/roslyn/issues/42574")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestPartialTypes1()
{
await TestWithPickMembersDialogAsync(
@"<Workspace>
<Project Language=""C#"" CommonReferences=""true"">
<Document>
partial class Goo
{
int bar;
[||]
}
</Document>
<Document>
partial class Goo
{
}
</Document>
</Project>
</Workspace>",
@"
partial class Goo
{
int bar;
public override bool Equals(object obj)
{
return obj is Goo goo &&
bar == goo.bar;
}
public override int GetHashCode()
{
return 999205674 + bar.GetHashCode();
}
}
",
chosenSymbols: new[] { "bar" },
index: 1);
}
[WorkItem(42574, "https://github.com/dotnet/roslyn/issues/42574")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestPartialTypes2()
{
await TestWithPickMembersDialogAsync(
@"<Workspace>
<Project Language=""C#"" CommonReferences=""true"">
<Document>
partial class Goo
{
int bar;
}
</Document>
<Document>
partial class Goo
{
[||]
}
</Document>
</Project>
</Workspace>",
@"
partial class Goo
{
public override bool Equals(object obj)
{
return obj is Goo goo &&
bar == goo.bar;
}
public override int GetHashCode()
{
return 999205674 + bar.GetHashCode();
}
}
",
chosenSymbols: new[] { "bar" },
index: 1);
}
[WorkItem(42574, "https://github.com/dotnet/roslyn/issues/42574")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestPartialTypes3()
{
await TestWithPickMembersDialogAsync(
@"<Workspace>
<Project Language=""C#"" CommonReferences=""true"">
<Document>
partial class Goo
{
[||]
}
</Document>
<Document>
partial class Goo
{
int bar;
}
</Document>
</Project>
</Workspace>",
@"
partial class Goo
{
public override bool Equals(object obj)
{
return obj is Goo goo &&
bar == goo.bar;
}
public override int GetHashCode()
{
return 999205674 + bar.GetHashCode();
}
}
",
chosenSymbols: new[] { "bar" },
index: 1);
}
[WorkItem(42574, "https://github.com/dotnet/roslyn/issues/42574")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestPartialTypes4()
{
await TestWithPickMembersDialogAsync(
@"<Workspace>
<Project Language=""C#"" CommonReferences=""true"">
<Document>
partial class Goo
{
}
</Document>
<Document>
partial class Goo
{
int bar;
[||]
}
</Document>
</Project>
</Workspace>",
@"
partial class Goo
{
int bar;
public override bool Equals(object obj)
{
return obj is Goo goo &&
bar == goo.bar;
}
public override int GetHashCode()
{
return 999205674 + bar.GetHashCode();
}
}
",
chosenSymbols: new[] { "bar" },
index: 1);
}
}
}
......@@ -2,12 +2,10 @@
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings
Imports Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers
Imports Microsoft.CodeAnalysis.PickMembers
Imports Microsoft.CodeAnalysis.Text
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateConstructorFromMembers
Public Class GenerateEqualsAndGetHashCodeFromMembersTests
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
......@@ -88,7 +90,7 @@ protected override async Task<Document> GetChangedDocumentAsync(CancellationToke
if (constructedTypeToImplement is object)
{
var generator = _document.GetLanguageService<SyntaxGenerator>();
var generator = _document.GetRequiredLanguageService<SyntaxGenerator>();
newType = generator.AddInterfaceType(newType,
generator.TypeExpression(constructedTypeToImplement));
......@@ -97,20 +99,22 @@ protected override async Task<Document> GetChangedDocumentAsync(CancellationToke
var newDocument = await UpdateDocumentAndAddImportsAsync(
oldType, newType, cancellationToken).ConfigureAwait(false);
var service = _document.GetLanguageService<IGenerateEqualsAndGetHashCodeService>();
var service = _document.GetRequiredLanguageService<IGenerateEqualsAndGetHashCodeService>();
var formattedDocument = await service.FormatDocumentAsync(
newDocument, cancellationToken).ConfigureAwait(false);
return formattedDocument;
}
private async Task<INamedTypeSymbol> GetConstructedTypeToImplementAsync(CancellationToken cancellationToken)
private async Task<INamedTypeSymbol?> GetConstructedTypeToImplementAsync(CancellationToken cancellationToken)
{
if (!_implementIEquatable)
return null;
var semanticModel = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await _document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var equatableType = semanticModel.Compilation.GetTypeByMetadataName(typeof(IEquatable<>).FullName);
if (equatableType == null)
return null;
var useNullableTypeArgument =
!_containingType.IsValueType
......@@ -123,7 +127,7 @@ private async Task<INamedTypeSymbol> GetConstructedTypeToImplementAsync(Cancella
private async Task<Document> UpdateDocumentAndAddImportsAsync(SyntaxNode oldType, SyntaxNode newType, CancellationToken cancellationToken)
{
var oldRoot = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var oldRoot = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newDocument = _document.WithSyntaxRoot(
oldRoot.ReplaceNode(oldType, newType));
newDocument = await ImportAdder.AddImportsFromSymbolAnnotationAsync(
......@@ -137,12 +141,12 @@ private async Task<Document> UpdateDocumentAndAddImportsAsync(SyntaxNode oldType
CancellationToken cancellationToken)
{
var workspace = _document.Project.Solution.Workspace;
var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var syntaxTree = await _document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var declarationService = _document.GetLanguageService<ISymbolDeclarationService>();
var declarationService = _document.GetRequiredLanguageService<ISymbolDeclarationService>();
var typeDeclaration = declarationService.GetDeclarations(_containingType)
.Select(r => r.GetSyntax(cancellationToken))
.First(s => s.FullSpan.IntersectsWith(_textSpan.Start));
.First(s => s.SyntaxTree == syntaxTree && s.FullSpan.IntersectsWith(_textSpan.Start));
var newTypeDeclaration = CodeGenerator.AddMemberDeclarations(
typeDeclaration, methods, workspace,
......@@ -153,9 +157,9 @@ private async Task<Document> UpdateDocumentAndAddImportsAsync(SyntaxNode oldType
private async Task AddOperatorsAsync(List<IMethodSymbol> members, CancellationToken cancellationToken)
{
var compilation = await _document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var compilation = await _document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
var generator = _document.GetLanguageService<SyntaxGenerator>();
var generator = _document.GetRequiredLanguageService<SyntaxGenerator>();
// add nullable annotation to the parameter reference type, so that (in)equality operator implementations allow comparison against null
var parameters = ImmutableArray.Create(
......@@ -210,13 +214,13 @@ private IMethodSymbol CreateInequalityOperator(Compilation compilation, SyntaxGe
private Task<IMethodSymbol> CreateGetHashCodeMethodAsync(CancellationToken cancellationToken)
{
var service = _document.GetLanguageService<IGenerateEqualsAndGetHashCodeService>();
var service = _document.GetRequiredLanguageService<IGenerateEqualsAndGetHashCodeService>();
return service.GenerateGetHashCodeMethodAsync(_document, _containingType, _selectedMembers, cancellationToken);
}
private Task<IMethodSymbol> CreateEqualsMethodAsync(CancellationToken cancellationToken)
{
var service = _document.GetLanguageService<IGenerateEqualsAndGetHashCodeService>();
var service = _document.GetRequiredLanguageService<IGenerateEqualsAndGetHashCodeService>();
return _implementIEquatable
? service.GenerateEqualsMethodThroughIEquatableEqualsAsync(_document, _containingType, cancellationToken)
: service.GenerateEqualsMethodAsync(_document, _containingType, _selectedMembers, cancellationToken);
......@@ -224,7 +228,7 @@ private Task<IMethodSymbol> CreateEqualsMethodAsync(CancellationToken cancellati
private async Task<IMethodSymbol> CreateIEquatableEqualsMethodAsync(INamedTypeSymbol constructedEquatableType, CancellationToken cancellationToken)
{
var service = _document.GetLanguageService<IGenerateEqualsAndGetHashCodeService>();
var service = _document.GetRequiredLanguageService<IGenerateEqualsAndGetHashCodeService>();
return await service.GenerateIEquatableEqualsMethodAsync(
_document, _containingType, _selectedMembers, constructedEquatableType, cancellationToken).ConfigureAwait(false);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册