提交 5b299fed 编写于 作者: M Manish Vasani

Handle recursive patterns in IOperation based GetValueUsageInfo method

Added unit tests for remove unused values analyzer/fix, which invokes this method, and was asserting with the repro in the issue.
Fixes #32271
上级 9cb17ff3
......@@ -1972,6 +1972,129 @@ void M(object p)
}}", optionName: optionName);
}
[WorkItem(32271, "https://github.com/dotnet/roslyn/issues/32271")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DeclarationPatternInRecursivePattern_WithNoReference_PreferDiscard()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int [|x1|], int x2) => false };
}
}",
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int _, int x2) => false };
}
}", options: PreferDiscard, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
[WorkItem(32271, "https://github.com/dotnet/roslyn/issues/32271")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DeclarationPatternInRecursivePattern_WithNoReference_PreferUnusedLocal()
{
await TestMissingInRegularAndScriptAsync(
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int [|x1|], int x2) => false };
}
}", options: PreferUnusedLocal, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
[WorkItem(32271, "https://github.com/dotnet/roslyn/issues/32271")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DeclarationPatternInRecursivePattern_WithOnlyWriteReference_PreferDiscard()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int [|x1|], int x2) => M2(out x1) };
}
bool M2(out int x)
{
x = 0;
return false;
}
}",
@"class C
{
void M(object p1, object p2)
{
int x1;
var isZero = (p1, p2) switch { (0, 0) => true, (int _, int x2) => M2(out x1) };
}
bool M2(out int x)
{
x = 0;
return false;
}
}", options: PreferDiscard, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
[WorkItem(32271, "https://github.com/dotnet/roslyn/issues/32271")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
public async Task DeclarationPatternInRecursivePattern_WithOnlyWriteReference_PreferUnusedLocal()
{
await TestMissingInRegularAndScriptAsync(
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int [|x1|], int x2) => M2(out x1) };
}
bool M2(out int x)
{
x = 0;
return false;
}
}", options: PreferUnusedLocal, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
[WorkItem(32271, "https://github.com/dotnet/roslyn/issues/32271")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard), "_")]
[InlineData(nameof(PreferUnusedLocal), "unused")]
public async Task DeclarationPatternInRecursivePattern_WithReadAndWriteReference(string optionName, string fix)
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(object p1, object p2)
{
var isZero = (p1, p2) switch { (0, 0) => true, (int [|x1|], int x2) => M2(x1 = 0) && M2(x1) };
}
bool M2(int x)
{
return false;
}
}",
$@"class C
{{
void M(object p1, object p2)
{{
int x1;
var isZero = (p1, p2) switch {{ (0, 0) => true, (int {fix}, int x2) => M2(x1 = 0) && M2(x1) }};
}}
bool M2(int x)
{{
return false;
}}
}}", optionName: optionName, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));
}
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
......
......@@ -34,27 +34,27 @@ internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProvider
}
}
protected Task TestMissingInRegularAndScriptAsync(string initialMarkup, IDictionary<OptionKey, object> options)
=> TestMissingInRegularAndScriptAsync(initialMarkup, new TestParameters(options: options));
protected Task TestMissingInRegularAndScriptAsync(string initialMarkup, string optionName)
=> TestMissingInRegularAndScriptAsync(initialMarkup, GetOptions(optionName));
protected Task TestInRegularAndScriptAsync(string initialMarkup, string expectedMarkup, string optionName)
=> TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: GetOptions(optionName));
protected Task TestMissingInRegularAndScriptAsync(string initialMarkup, IDictionary<OptionKey, object> options, ParseOptions parseOptions = null)
=> TestMissingInRegularAndScriptAsync(initialMarkup, new TestParameters(options: options, parseOptions: parseOptions));
protected Task TestMissingInRegularAndScriptAsync(string initialMarkup, string optionName, ParseOptions parseOptions = null)
=> TestMissingInRegularAndScriptAsync(initialMarkup, GetOptions(optionName), parseOptions);
protected Task TestInRegularAndScriptAsync(string initialMarkup, string expectedMarkup, string optionName, ParseOptions parseOptions = null)
=> TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: GetOptions(optionName), parseOptions: parseOptions);
// Helpers to test all options - only used by tests which already have InlineData for custom input test code snippets.
protected async Task TestInRegularAndScriptWithAllOptionsAsync(string initialMarkup, string expectedMarkup)
protected async Task TestInRegularAndScriptWithAllOptionsAsync(string initialMarkup, string expectedMarkup, ParseOptions parseOptions = null)
{
foreach (var options in new[] { PreferDiscard, PreferUnusedLocal })
{
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: options);
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: options, parseOptions: parseOptions);
}
}
protected async Task TestMissingInRegularAndScriptWithAllOptionsAsync(string initialMarkup)
protected async Task TestMissingInRegularAndScriptWithAllOptionsAsync(string initialMarkup, ParseOptions parseOptions = null)
{
foreach (var options in new[] { PreferDiscard, PreferUnusedLocal })
{
await TestMissingInRegularAndScriptAsync(initialMarkup, new TestParameters(options: options));
await TestMissingInRegularAndScriptAsync(initialMarkup, new TestParameters(options: options, parseOptions: parseOptions));
}
}
}
......
......@@ -57,6 +57,17 @@ public static ValueUsageInfo GetValueUsageInfo(this IOperation operation)
//
return ValueUsageInfo.Write;
case IRecursivePatternOperation _:
// A declaration pattern within a recursive pattern is a
// write for the declared local.
// For example, 'x' is defined and assigned the value from 'obj' below:
// (obj) switch
// {
// (X x) => ...
// };
//
return ValueUsageInfo.Write;
case IIsPatternOperation _:
// A declaration pattern within an is pattern is a
// write for the declared local.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册