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

Fixed reivew notes.

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