Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -1166,8 +1166,8 @@ public override bool Equals(object obj)
}
Copy link
Member Author

Choose a reason for hiding this comment

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

View with whitespace off.

}
""",
CodeActionEquivalenceKey = FeaturesResources.Generate_Equals_object,
CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Generate_Equals_object, codeAction.Title),
CodeActionEquivalenceKey = FeaturesResources.Generate_Equals,
CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Generate_Equals, codeAction.Title),
}.RunAsync();

[Fact]
Expand Down Expand Up @@ -3891,4 +3891,271 @@ class C(int a)
""",
LanguageVersion = LanguageVersion.CSharp12,
}.RunAsync();

[Fact]
public Task TestRecord_Equals1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record Program
{
int a;

public virtual bool Equals(Program program)
Copy link
Member

Choose a reason for hiding this comment

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

question - should this be generated as Program?

Copy link
Member Author

Choose a reason for hiding this comment

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

yup :)

{
return program is not null &&
a == program.a;
}
}
""",
LanguageVersion = LanguageVersion.Preview,
}.RunAsync();

[Fact]
public Task TestRecord_EqualsAndGetHashCode1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record Program
{
int a;

public virtual bool Equals(Program program)
{
return program is not null &&
a == program.a;
}

public override int GetHashCode()
{
return -1757793268 + a.GetHashCode();
}
}
""",
LanguageVersion = LanguageVersion.Preview,
CodeActionIndex = 1,
}.RunAsync();

[Fact]
public Task TestSealedRecord_Equals1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

sealed record Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

sealed record Program
{
int a;

public bool Equals(Program program)
{
return program is not null &&
a == program.a;
}
}
""",
LanguageVersion = LanguageVersion.Preview,
}.RunAsync();

[Fact]
public Task TestSealedRecord_EqualsAndGetHashCode1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

sealed record Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

sealed record Program
{
int a;

public bool Equals(Program program)
{
return program is not null &&
a == program.a;
}

public override int GetHashCode()
{
return -1757793268 + a.GetHashCode();
}
}
""",
LanguageVersion = LanguageVersion.Preview,
CodeActionIndex = 1,
}.RunAsync();

[Fact]
public Task TestRecordStruct_Equals1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record struct Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record struct Program
{
int a;

public bool Equals(Program program)
{
return a == program.a;
}
}
""",
LanguageVersion = LanguageVersion.Preview,
}.RunAsync();

[Fact]
public Task TestRecordStruct_EqualsAndGetHashCode1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record struct Program
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record struct Program
{
int a;

public bool Equals(Program program)
{
return a == program.a;
}

public override int GetHashCode()
{
return -1757793268 + a.GetHashCode();
}
}
""",
LanguageVersion = LanguageVersion.Preview,
CodeActionIndex = 1,
}.RunAsync();

[Fact]
public Task TestDerived_Equals1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record Base { }

record Program : Base
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record Base { }

record Program : Base
{
int a;

public virtual bool Equals(Program program)
{
return program is not null &&
base.Equals(program) &&
a == program.a;
}
}
""",
LanguageVersion = LanguageVersion.Preview,
}.RunAsync();

[Fact]
public Task TestDerivedRecord_EqualsAndGetHashCode1()
=> new VerifyCS.Test
{
TestCode = """
using System.Collections.Generic;

record Base { }

record Program : Base
{
[|int a;|]
}
""",
FixedCode = """
using System.Collections.Generic;

record Base { }

record Program : Base
{
int a;

public virtual bool Equals(Program program)
{
return program is not null &&
base.Equals(program) &&
a == program.a;
}

public override int GetHashCode()
{
int hashCode = 155057090;
hashCode = hashCode * -1521134295 + base.GetHashCode();
hashCode = hashCode * -1521134295 + a.GetHashCode();
return hashCode;
}
}
""",
LanguageVersion = LanguageVersion.Preview,
CodeActionIndex = 1,
}.RunAsync();
}
4 changes: 2 additions & 2 deletions src/Features/Core/Portable/FeaturesResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@
<data name="Generate_Equals_and_GetHashCode" xml:space="preserve">
<value>Generate Equals and GetHashCode</value>
</data>
<data name="Generate_Equals_object" xml:space="preserve">
<value>Generate Equals(object)</value>
<data name="Generate_Equals" xml:space="preserve">
<value>Generate Equals(...)</value>
</data>
<data name="Generate_GetHashCode" xml:space="preserve">
<value>Generate GetHashCode()</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ public async Task<IMethodSymbol> GenerateEqualsMethodAsync(
Document document, INamedTypeSymbol namedType, ImmutableArray<ISymbol> members,
string? localNameOpt, CancellationToken cancellationToken)
{
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var generator = document.GetLanguageService<SyntaxGenerator>();
var generatorInternal = document.GetLanguageService<SyntaxGeneratorInternal>();
var generator = document.GetRequiredLanguageService<SyntaxGenerator>();
var generatorInternal = document.GetRequiredLanguageService<SyntaxGeneratorInternal>();
return generator.CreateEqualsMethod(
generatorInternal, compilation, tree.Options, namedType, members, localNameOpt, s_specializedFormattingAnnotation);
}
Expand All @@ -51,17 +51,17 @@ public async Task<IMethodSymbol> GenerateIEquatableEqualsMethodAsync(
Document document, INamedTypeSymbol namedType,
ImmutableArray<ISymbol> members, INamedTypeSymbol constructedEquatableType, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var generator = document.GetLanguageService<SyntaxGenerator>();
var generatorInternal = document.GetLanguageService<SyntaxGeneratorInternal>();
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var generator = document.GetRequiredLanguageService<SyntaxGenerator>();
var generatorInternal = document.GetRequiredLanguageService<SyntaxGeneratorInternal>();
return generator.CreateIEquatableEqualsMethod(
generatorInternal, semanticModel, namedType, members, constructedEquatableType, s_specializedFormattingAnnotation);
}

public async Task<IMethodSymbol> GenerateEqualsMethodThroughIEquatableEqualsAsync(
Document document, INamedTypeSymbol containingType, CancellationToken cancellationToken)
{
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var generator = document.GetRequiredLanguageService<SyntaxGenerator>();

Expand Down Expand Up @@ -110,8 +110,7 @@ public async Task<IMethodSymbol> GenerateEqualsMethodThroughIEquatableEqualsAsyn
var statement = generator.ReturnStatement(
expressions.Aggregate(generator.LogicalAndExpression));

return compilation.CreateEqualsMethod(
[statement]);
return compilation.CreateEqualsMethod([statement]);
}

public async Task<IMethodSymbol> GenerateGetHashCodeMethodAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ internal static string GetTitle(bool generateEquals, bool generateGetHashCode)
=> generateEquals
? generateGetHashCode
? FeaturesResources.Generate_Equals_and_GetHashCode
: FeaturesResources.Generate_Equals_object
: FeaturesResources.Generate_Equals
: FeaturesResources.Generate_GetHashCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ private static bool CanImplementIEquatable(

private static void GetExistingMemberInfo(INamedTypeSymbol containingType, out bool hasEquals, out bool hasGetHashCode)
{
hasEquals = containingType.GetMembers(EqualsName)
.OfType<IMethodSymbol>()
.Any(m => m.Parameters.Length == 1 && !m.IsStatic);
hasEquals = containingType
.GetMembers(EqualsName)
.Any(m => m is IMethodSymbol { Parameters.Length: 1, IsStatic: false, IsImplicitlyDeclared: false });

hasGetHashCode = containingType.GetMembers(GetHashCodeName)
.OfType<IMethodSymbol>()
.Any(m => m.Parameters.Length == 0 && !m.IsStatic);
hasGetHashCode = containingType
.GetMembers(GetHashCodeName)
.Any(m => m is IMethodSymbol { Parameters.Length: 0, IsStatic: false, IsImplicitlyDeclared: false });
}

public async Task<ImmutableArray<CodeAction>> GenerateEqualsAndGetHashCodeFromMembersAsync(
Expand Down Expand Up @@ -206,7 +206,7 @@ private async Task<ImmutableArray<CodeAction>> CreateActionsAsync(
{
// if we don't have either Equals or GetHashCode then offer:
// "Generate Equals" and
// "Generate Equals and GethashCode"
// "Generate Equals and GetHashCode"
//
// Don't bother offering to just "Generate GetHashCode" as it's very unlikely
// the user would need to bother just generating that member without also
Expand Down
Loading
Loading