未验证 提交 cce6b0ea 编写于 作者: D Dustin Campbell 提交者: GitHub

Merge pull request #25700 from Neme12/generateEqualsIndexers

"Generate Equals" should ignore indexers and setter-only properties
......@@ -945,5 +945,81 @@ public async Task ProtectedConstructorShouldBeGeneratedForAbstractClass()
}",
options: Option(CodeStyleOptions.QualifyFieldAccess, CodeStyleOptions.TrueWithSuggestionEnforcement));
}
[WorkItem(17643, "https://github.com/dotnet/roslyn/issues/17643")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)]
public async Task TestWithDialogNoBackingField()
{
await TestWithPickMembersDialogAsync(
@"
class Program
{
public int F { get; set; }
[||]
}",
@"
class Program
{
public int F { get; set; }
public Program(int f{|Navigation:)|}
{
F = f;
}
}",
chosenSymbols: null);
}
[WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)]
public async Task TestWithDialogNoIndexer()
{
await TestWithPickMembersDialogAsync(
@"
class Program
{
public int P { get => 0; set { } }
public int this[int index] { get => 0; set { } }
[||]
}",
@"
class Program
{
public int P { get => 0; set { } }
public int this[int index] { get => 0; set { } }
public Program(int p{|Navigation:)|}
{
P = p;
}
}",
chosenSymbols: null);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestWithDialogSetterOnlyProperty()
{
await TestWithPickMembersDialogAsync(
@"
class Program
{
public int P { get => 0; set { } }
public int S { set { } }
[||]
}",
@"
class Program
{
public int P { get => 0; set { } }
public int S { set { } }
public Program(int p, int s{|Navigation:)|}
{
P = p;
S = s;
}
}",
chosenSymbols: null);
}
}
}
......@@ -951,7 +951,7 @@ public override bool Equals(object obj)
[WorkItem(17643, "https://github.com/dotnet/roslyn/issues/17643")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestWithDialogNoBackingFields()
public async Task TestWithDialogNoBackingField()
{
await TestWithPickMembersDialogAsync(
@"
......@@ -975,6 +975,62 @@ public override bool Equals(object obj)
chosenSymbols: null);
}
[WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestWithDialogNoIndexer()
{
await TestWithPickMembersDialogAsync(
@"
class Program
{
public int P => 0;
public int this[int index] => 0;
[||]
}",
@"
class Program
{
public int P => 0;
public int this[int index] => 0;
public override bool Equals(object obj)
{
var program = obj as Program;
return program != null &&
P == program.P;
}
}",
chosenSymbols: null);
}
[WorkItem(25707, "https://github.com/dotnet/roslyn/issues/25707")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestWithDialogNoSetterOnlyProperty()
{
await TestWithPickMembersDialogAsync(
@"
class Program
{
public int P => 0;
public int S { set { } }
[||]
}",
@"
class Program
{
public int P => 0;
public int S { set { } }
public override bool Equals(object obj)
{
var program = obj as Program;
return program != null &&
P == program.P;
}
}",
chosenSymbols: null);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public async Task TestGenerateOperators1()
{
......
......@@ -308,5 +308,157 @@ Class Program
End Sub
End Class")
End Function
<WorkItem(17643, "https://github.com/dotnet/roslyn/issues/17643")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)>
Public Async Function TestWithDialogNoBackingField() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public Property F() As Integer
[||]
End Class",
"
Class Program
Public Property F() As Integer
Public Sub New(f As Integer{|Navigation:)|}
Me.F = f
End Sub
End Class",
chosenSymbols:=Nothing)
End Function
<WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)>
Public Async Function TestWithDialogNoParameterizedProperty() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public Property I(index As Integer) As Integer
Get
Return 0
End Get
Set
End Set
End Property
[||]
End Class",
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public Property I(index As Integer) As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public Sub New(p As Integer{|Navigation:)|}
Me.P = p
End Sub
End Class",
chosenSymbols:=Nothing)
End Function
<WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)>
Public Async Function TestWithDialogNoIndexer() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Default Public Property I(index As Integer) As Integer
Get
Return 0
End Get
Set
End Set
End Property
[||]
End Class",
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Default Public Property I(index As Integer) As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public Sub New(p As Integer{|Navigation:)|}
Me.P = p
End Sub
End Class",
chosenSymbols:=Nothing)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)>
Public Async Function TestWithDialogSetterOnlyProperty() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public WriteOnly Property S() As Integer
Set
End Set
End Property
[||]
End Class",
"
Class Program
Public Property P() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public WriteOnly Property S() As Integer
Set
End Set
End Property
Public Sub New(p As Integer, s As Integer{|Navigation:)|}
Me.P = p
Me.S = s
End Sub
End Class",
chosenSymbols:=Nothing)
End Function
End Class
End Namespace
......@@ -106,6 +106,146 @@ Partial Class c1(Of V As {New}, U)
End Class")
End Function
<WorkItem(17643, "https://github.com/dotnet/roslyn/issues/17643")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
Public Async Function TestWithDialogNoBackingField() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public Property F() As Integer
[||]
End Class",
"
Class Program
Public Property F() As Integer
Public Overrides Function Equals(obj As Object) As Boolean
Dim program = TryCast(obj, Program)
Return program IsNot Nothing AndAlso
F = program.F
End Function
End Class",
chosenSymbols:=Nothing)
End Function
<WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
Public Async Function TestWithDialogNoParameterizedProperty() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Public ReadOnly Property I(index As Integer) As Integer
Get
Return 0
End Get
End Property
[||]
End Class",
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Public ReadOnly Property I(index As Integer) As Integer
Get
Return 0
End Get
End Property
Public Overrides Function Equals(obj As Object) As Boolean
Dim program = TryCast(obj, Program)
Return program IsNot Nothing AndAlso
P = program.P
End Function
End Class",
chosenSymbols:=Nothing)
End Function
<WorkItem(25690, "https://github.com/dotnet/roslyn/issues/25690")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
Public Async Function TestWithDialogNoIndexer() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Default Public ReadOnly Property I(index As Integer) As Integer
Get
Return 0
End Get
End Property
[||]
End Class",
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Default Public ReadOnly Property I(index As Integer) As Integer
Get
Return 0
End Get
End Property
Public Overrides Function Equals(obj As Object) As Boolean
Dim program = TryCast(obj, Program)
Return program IsNot Nothing AndAlso
P = program.P
End Function
End Class",
chosenSymbols:=Nothing)
End Function
<WorkItem(25707, "https://github.com/dotnet/roslyn/issues/25707")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
Public Async Function TestWithDialogNoSetterOnlyProperty() As Task
Await TestWithPickMembersDialogAsync(
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Public WriteOnly Property S() As Integer
Set
End Set
End Property
[||]
End Class",
"
Class Program
Public ReadOnly Property P() As Integer
Get
Return 0
End Get
End Property
Public WriteOnly Property S() As Integer
Set
End Set
End Property
Public Overrides Function Equals(obj As Object) As Boolean
Dim program = TryCast(obj, Program)
Return program IsNot Nothing AndAlso
P = program.P
End Function
End Class",
chosenSymbols:=Nothing)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)>
Public Async Function TestGenerateOperators1() As Task
Await TestWithPickMembersDialogAsync(
......
......@@ -91,7 +91,7 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context)
// Find all the possible instance fields/properties. If there are any, then
// show a dialog to the user to select the ones they want.
var viableMembers = containingType.GetMembers().WhereAsArray(IsViableInstanceFieldOrProperty);
var viableMembers = containingType.GetMembers().WhereAsArray(IsReadableInstanceFieldOrProperty);
if (viableMembers.Length == 0)
{
return;
......@@ -173,7 +173,7 @@ private void GetExistingMemberInfo(INamedTypeSymbol containingType, out bool has
{
var info = await this.GetSelectedMemberInfoAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
if (info != null &&
info.SelectedMembers.All(IsViableInstanceFieldOrProperty))
info.SelectedMembers.All(IsReadableInstanceFieldOrProperty))
{
if (info.ContainingType != null && info.ContainingType.TypeKind != TypeKind.Interface)
{
......
......@@ -72,29 +72,38 @@ protected AbstractGenerateFromMembersCodeRefactoringProvider()
return null;
}
// Can use non const fields and properties with setters in them.
protected static bool IsReadableInstanceFieldOrProperty(ISymbol symbol)
=> !symbol.IsStatic && IsReadableFieldOrProperty(symbol);
protected static bool IsWritableInstanceFieldOrProperty(ISymbol symbol)
=> IsViableInstanceFieldOrProperty(symbol) &&
IsWritableFieldOrProperty(symbol);
=> !symbol.IsStatic && IsWritableFieldOrProperty(symbol);
private static bool IsWritableFieldOrProperty(ISymbol symbol)
private static bool IsReadableFieldOrProperty(ISymbol symbol)
{
switch (symbol)
{
case IFieldSymbol field: return !field.IsConst && IsViableField(field);
case IPropertySymbol property: return property.IsWritableInConstructor();
case IFieldSymbol field: return IsViableField(field);
case IPropertySymbol property: return IsViableProperty(property) && !property.IsWriteOnly;
default: return false;
}
}
protected static bool IsViableInstanceFieldOrProperty(ISymbol symbol)
=> !symbol.IsStatic && (IsViableField(symbol) || IsViableProperty(symbol));
private static bool IsWritableFieldOrProperty(ISymbol symbol)
{
switch (symbol)
{
// Can use non const fields and properties with setters in them.
case IFieldSymbol field: return IsViableField(field) && !field.IsConst;
case IPropertySymbol property: return IsViableProperty(property) && property.IsWritableInConstructor();
default: return false;
}
}
private static bool IsViableProperty(ISymbol symbol)
=> symbol.Kind == SymbolKind.Property;
private static bool IsViableField(IFieldSymbol field)
=> field.AssociatedSymbol == null;
private static bool IsViableField(ISymbol symbol)
=> symbol is IFieldSymbol field && field.AssociatedSymbol == null;
private static bool IsViableProperty(IPropertySymbol property)
=> property.Parameters.IsEmpty;
protected ImmutableArray<IParameterSymbol> DetermineParameters(
ImmutableArray<ISymbol> selectedMembers)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册