提交 adf8298e 编写于 作者: V Victor Z

Fixed reivew notes.

上级 45cb3c46
...@@ -1436,10 +1436,10 @@ public void Caller() ...@@ -1436,10 +1436,10 @@ public void Caller()
} }
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")] [WorkItem(22672, "https://github.com/dotnet/roslyn/issues/22672")]
public async Task TestWithInvokeMethod() public async Task TestMissingIfUsedInMemberAccess1()
{ {
await TestInRegularAndScript1Async( await TestMissingAsync(
@"using System; @"using System;
class Enclosing<T> where T : class class Enclosing<T> where T : class
...@@ -1452,10 +1452,17 @@ public void Caller() ...@@ -1452,10 +1452,17 @@ public void Caller()
{ {
MyDelegate [||]local = x => x; MyDelegate [||]local = x => x;
local.Invoke(); var str = local.ToString();
} }
} }
}", }");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")]
public async Task TestMissingIfUsedInMemberAccess2()
{
await TestMissingAsync(
@"using System; @"using System;
class Enclosing<T> where T : class class Enclosing<T> where T : class
...@@ -1464,11 +1471,14 @@ class Enclosing<T> where T : class ...@@ -1464,11 +1471,14 @@ class Enclosing<T> where T : class
public class Class public class Class
{ {
public void Caller() public void Caller(T t)
{ {
T local(T x = null) => x; MyDelegate[||]local = x => x;
local(); Console.Write(local.Invoke(t));
var str = local.ToString();
local.Invoke(t);
} }
} }
}"); }");
...@@ -1495,6 +1505,174 @@ public void Caller() ...@@ -1495,6 +1505,174 @@ public void Caller()
Expression<Action> expression = () => local(null); Expression<Action> expression = () => local(null);
} }
} }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")]
public async Task TestWithInvokeMethod1()
{
await TestInRegularAndScript1Async(
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller()
{
MyDelegate [||]local = x => x;
local.Invoke();
}
}
}",
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller()
{
T local(T x = null) => x;
local();
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")]
public async Task TestWithInvokeMethod2()
{
await TestInRegularAndScript1Async(
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
MyDelegate [||]local = x => x;
Console.Write(local.Invoke(t));
}
}
}",
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
T local(T x = null) => x;
Console.Write(local(t));
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")]
public async Task TestWithInvokeMethod3()
{
await TestInRegularAndScript1Async(
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
MyDelegate [||]local = x => x;
Console.Write(local.Invoke(t));
var val = local.Invoke(t);
local.Invoke(t);
}
}
}",
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
T local(T x = null) => x;
Console.Write(local(t));
var val = local(t);
local(t);
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseLocalFunction)]
[WorkItem(23150, "https://github.com/dotnet/roslyn/issues/23150")]
public async Task TestWithInvokeMethod4()
{
await TestInRegularAndScript1Async(
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
MyDelegate [||]local = x => x;
Console.Write(local.Invoke(t));
var val = local.Invoke(t);
local(t);
}
}
}",
@"using System;
class Enclosing<T> where T : class
{
delegate T MyDelegate(T t = null);
public class Class
{
public void Caller(T t)
{
T local(T x = null) => x;
Console.Write(local(t));
var val = local(t);
local(t);
}
}
}"); }");
} }
} }
......
...@@ -48,7 +48,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -48,7 +48,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var localDeclarationToLambda = new Dictionary<LocalDeclarationStatementSyntax, LambdaExpressionSyntax>(); var localDeclarationToLambda = new Dictionary<LocalDeclarationStatementSyntax, LambdaExpressionSyntax>();
var nodesToTrack = new HashSet<SyntaxNode>(); var nodesToTrack = new HashSet<SyntaxNode>();
var memberAccess = new List<MemberAccessExpressionSyntax>(); var explicitInvokeCalls = new List<MemberAccessExpressionSyntax>();
foreach (var diagnostic in diagnostics) foreach (var diagnostic in diagnostics)
{ {
var localDeclaration = (LocalDeclarationStatementSyntax)diagnostic.AdditionalLocations[0].FindNode(cancellationToken); var localDeclaration = (LocalDeclarationStatementSyntax)diagnostic.AdditionalLocations[0].FindNode(cancellationToken);
...@@ -59,16 +59,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -59,16 +59,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
nodesToTrack.Add(localDeclaration); nodesToTrack.Add(localDeclaration);
nodesToTrack.Add(lambda); nodesToTrack.Add(lambda);
if (diagnostic.AdditionalLocations.Count > 2) for (var i = 2; i < diagnostic.AdditionalLocations.Count; i++)
{ {
for (var i = 2; i < diagnostic.AdditionalLocations.Count; i++) explicitInvokeCalls.Add((MemberAccessExpressionSyntax)diagnostic.AdditionalLocations[i].FindNode(getInnermostNodeForTie: true, cancellationToken));
{
memberAccess.Add((MemberAccessExpressionSyntax)diagnostic.AdditionalLocations[i].FindNode(cancellationToken));
}
} }
} }
nodesToTrack.AddRange(memberAccess); nodesToTrack.AddRange(explicitInvokeCalls);
var root = editor.OriginalRoot; var root = editor.OriginalRoot;
var currentRoot = root.TrackNodes(nodesToTrack); var currentRoot = root.TrackNodes(nodesToTrack);
...@@ -85,7 +82,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -85,7 +82,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
currentRoot = ReplaceAnonymousWithLocalFunction( currentRoot = ReplaceAnonymousWithLocalFunction(
document.Project.Solution.Workspace, currentRoot, document.Project.Solution.Workspace, currentRoot,
currentLocalDeclaration, currentLambda, currentLocalDeclaration, currentLambda,
delegateType, parameterList, memberAccess.Select(node => currentRoot.GetCurrentNode(node)).ToImmutableArray(), delegateType, parameterList, explicitInvokeCalls.Select(node => currentRoot.GetCurrentNode(node)).ToImmutableArray(),
cancellationToken); cancellationToken);
} }
...@@ -96,7 +93,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -96,7 +93,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
Workspace workspace, SyntaxNode currentRoot, Workspace workspace, SyntaxNode currentRoot,
LocalDeclarationStatementSyntax localDeclaration, LambdaExpressionSyntax lambda, LocalDeclarationStatementSyntax localDeclaration, LambdaExpressionSyntax lambda,
INamedTypeSymbol delegateType, ParameterListSyntax parameterList, INamedTypeSymbol delegateType, ParameterListSyntax parameterList,
ImmutableArray<MemberAccessExpressionSyntax> notDirectInvocationUsages, ImmutableArray<MemberAccessExpressionSyntax> explicitInvokeCalls,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var newLocalFunctionStatement = CreateLocalFunctionStatement( var newLocalFunctionStatement = CreateLocalFunctionStatement(
...@@ -116,14 +113,11 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -116,14 +113,11 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
editor.RemoveNode(lambdaStatement); editor.RemoveNode(lambdaStatement);
} }
if (!notDirectInvocationUsages.IsEmpty) foreach (var usage in explicitInvokeCalls)
{ {
foreach (var usage in notDirectInvocationUsages) editor.ReplaceNode(
{ usage.Parent,
editor.ReplaceNode( (usage.Parent as InvocationExpressionSyntax).WithExpression(usage.Expression).WithTriviaFrom(usage.Parent));
usage.Parent,
SyntaxFactory.InvocationExpression(usage.Expression, (usage.Parent as InvocationExpressionSyntax).ArgumentList));
}
} }
return editor.GetChangedRoot(); return editor.GetChangedRoot();
...@@ -166,27 +160,27 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -166,27 +160,27 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
} }
private ParameterListSyntax GenerateParameterList( private ParameterListSyntax GenerateParameterList(
SemanticModel semanticModel, AnonymousFunctionExpressionSyntax anonymousFunction, INamedTypeSymbol namedTypeSymbol, CancellationToken cancellationToken) SemanticModel semanticModel, AnonymousFunctionExpressionSyntax anonymousFunction, INamedTypeSymbol delegateType, CancellationToken cancellationToken)
{ {
switch (anonymousFunction) switch (anonymousFunction)
{ {
case SimpleLambdaExpressionSyntax simpleLambda: case SimpleLambdaExpressionSyntax simpleLambda:
return GenerateSimpleLambdaParameterList(semanticModel, simpleLambda, namedTypeSymbol, cancellationToken); return GenerateSimpleLambdaParameterList(semanticModel, simpleLambda, delegateType.DelegateInvokeMethod, cancellationToken);
case ParenthesizedLambdaExpressionSyntax parenthesizedLambda: case ParenthesizedLambdaExpressionSyntax parenthesizedLambda:
return GenerateParenthesizedLambdaParameterList(semanticModel, parenthesizedLambda, namedTypeSymbol, cancellationToken); return GenerateParenthesizedLambdaParameterList(semanticModel, parenthesizedLambda, delegateType.DelegateInvokeMethod, cancellationToken);
default: default:
throw ExceptionUtilities.UnexpectedValue(anonymousFunction); throw ExceptionUtilities.UnexpectedValue(anonymousFunction);
} }
} }
private ParameterListSyntax GenerateSimpleLambdaParameterList( private ParameterListSyntax GenerateSimpleLambdaParameterList(
SemanticModel semanticModel, SimpleLambdaExpressionSyntax lambdaExpression, INamedTypeSymbol namedTypeSymbol, CancellationToken cancellationToken) SemanticModel semanticModel, SimpleLambdaExpressionSyntax lambdaExpression, IMethodSymbol delegateInvokeMethod, CancellationToken cancellationToken)
{ {
var parameter = semanticModel.GetDeclaredSymbol(lambdaExpression.Parameter, cancellationToken); var parameter = semanticModel.GetDeclaredSymbol(lambdaExpression.Parameter, cancellationToken);
var type = parameter?.Type.GenerateTypeSyntax() ?? s_objectType; var type = parameter?.Type.GenerateTypeSyntax() ?? s_objectType;
var parameterSyntax = SyntaxFactory.Parameter(lambdaExpression.Parameter.Identifier).WithType(type); var parameterSyntax = SyntaxFactory.Parameter(lambdaExpression.Parameter.Identifier).WithType(type);
var param = namedTypeSymbol.DelegateInvokeMethod.Parameters[0]; var param = delegateInvokeMethod.Parameters[0];
if (param.HasExplicitDefaultValue) if (param.HasExplicitDefaultValue)
{ {
parameterSyntax = parameterSyntax.WithDefault(GetDefaultValue(param)); parameterSyntax = parameterSyntax.WithDefault(GetDefaultValue(param));
...@@ -197,7 +191,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -197,7 +191,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
} }
private ParameterListSyntax GenerateParenthesizedLambdaParameterList( private ParameterListSyntax GenerateParenthesizedLambdaParameterList(
SemanticModel semanticModel, ParenthesizedLambdaExpressionSyntax lambdaExpression, INamedTypeSymbol namedTypeSymbol, CancellationToken cancellationToken) SemanticModel semanticModel, ParenthesizedLambdaExpressionSyntax lambdaExpression, IMethodSymbol delegateInvokeMethod, CancellationToken cancellationToken)
{ {
int i = 0; int i = 0;
return lambdaExpression.ParameterList.ReplaceNodes( return lambdaExpression.ParameterList.ReplaceNodes(
...@@ -211,7 +205,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -211,7 +205,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var parameter = semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken); var parameter = semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken);
parameterNode = parameterNode.WithType(parameter?.Type.GenerateTypeSyntax() ?? s_objectType); parameterNode = parameterNode.WithType(parameter?.Type.GenerateTypeSyntax() ?? s_objectType);
var param = namedTypeSymbol.DelegateInvokeMethod.Parameters[i++]; var param = delegateInvokeMethod.Parameters[i++];
if (param.HasExplicitDefaultValue) if (param.HasExplicitDefaultValue)
{ {
parameterNode = parameterNode.WithDefault(GetDefaultValue(param)); parameterNode = parameterNode.WithDefault(GetDefaultValue(param));
...@@ -222,9 +216,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -222,9 +216,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
} }
private static EqualsValueClauseSyntax GetDefaultValue(IParameterSymbol parameter) private static EqualsValueClauseSyntax GetDefaultValue(IParameterSymbol parameter)
{ => SyntaxFactory.EqualsValueClause(ExpressionGenerator.GenerateExpression(parameter.Type, parameter.ExplicitDefaultValue, canUseFieldReference: true));
return SyntaxFactory.EqualsValueClause(ExpressionGenerator.GenerateExpression(parameter.Type, parameter.ExplicitDefaultValue, canUseFieldReference: true));
}
private class MyCodeAction : CodeAction.DocumentChangeAction private class MyCodeAction : CodeAction.DocumentChangeAction
{ {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.UseLocalFunction namespace Microsoft.CodeAnalysis.CSharp.UseLocalFunction
...@@ -117,7 +118,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp ...@@ -117,7 +118,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
return; return;
} }
if (!CanReplaceAnonymousWithLocalFunction(semanticModel, expressionTypeOpt, local, block, anonymousFunction, out var locations, cancellationToken)) if (!CanReplaceAnonymousWithLocalFunction(semanticModel, expressionTypeOpt, local, block, anonymousFunction, out var explicitInvokeCallLocations, cancellationToken))
{ {
return; return;
} }
...@@ -127,10 +128,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp ...@@ -127,10 +128,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
localDeclaration.GetLocation(), localDeclaration.GetLocation(),
anonymousFunction.GetLocation()); anonymousFunction.GetLocation());
if (!locations.IsEmpty) additionalLocations = additionalLocations.AddRange(explicitInvokeCallLocations);
{
additionalLocations = additionalLocations.AddRange(locations);
}
if (severity != DiagnosticSeverity.Hidden) if (severity != DiagnosticSeverity.Hidden)
{ {
...@@ -203,12 +201,12 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp ...@@ -203,12 +201,12 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
private bool CanReplaceAnonymousWithLocalFunction( private bool CanReplaceAnonymousWithLocalFunction(
SemanticModel semanticModel, INamedTypeSymbol expressionTypeOpt, ISymbol local, BlockSyntax block, SemanticModel semanticModel, INamedTypeSymbol expressionTypeOpt, ISymbol local, BlockSyntax block,
AnonymousFunctionExpressionSyntax anonymousFunction, out ImmutableArray<Location> locations, CancellationToken cancellationToken) AnonymousFunctionExpressionSyntax anonymousFunction, out ImmutableArray<Location> explicitInvokeCallLocations, CancellationToken cancellationToken)
{ {
// Check all the references to the anonymous function and disallow the conversion if // Check all the references to the anonymous function and disallow the conversion if
// they're used in certain ways. // they're used in certain ways.
List<Location> delegateInvokeMethodLocations = null; var explicitInvokeCalls = ArrayBuilder<Location>.GetInstance();
locations = ImmutableArray<Location>.Empty; explicitInvokeCallLocations = ImmutableArray<Location>.Empty;
var anonymousFunctionStart = anonymousFunction.SpanStart; var anonymousFunctionStart = anonymousFunction.SpanStart;
foreach (var descendentNode in block.DescendantNodes()) foreach (var descendentNode in block.DescendantNodes())
{ {
...@@ -250,8 +248,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp ...@@ -250,8 +248,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
} }
else else
{ {
delegateInvokeMethodLocations = delegateInvokeMethodLocations ?? new List<Location>(); explicitInvokeCalls.Add(memberAccessExpression.GetLocation());
delegateInvokeMethodLocations.Add(memberAccessExpression.GetLocation());
} }
} }
...@@ -274,7 +271,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp ...@@ -274,7 +271,7 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTyp
} }
} }
locations = delegateInvokeMethodLocations.AsImmutableOrEmpty(); explicitInvokeCallLocations = explicitInvokeCalls.ToImmutableAndFree();
return true; return true;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册