提交 a91c6ee9 编写于 作者: S Shlomo Zach Cahlon

Final commit

上级 9edbeefa
......@@ -1359,6 +1359,22 @@ class C
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestNotOnIndexerParameters()
{
await TestMissingAsync(
@"
class C
{
int this[[|object a|], object b, object c]
{
get
{
return 0;
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)]
public async Task TestSpecialStringCheck1()
......
......@@ -54,10 +54,5 @@ protected override bool CanOffer(SyntaxNode body)
return true;
}
protected override ImmutableArray<SyntaxNode> GetParameters(SyntaxNode node, SyntaxGenerator generator)
{
return InitializeParameterHelpers.GetParameters(node, generator);
}
}
}
......@@ -49,10 +49,5 @@ protected override Accessibility DetermineDefaultPropertyAccessibility()
protected override SyntaxNode GetBody(SyntaxNode functionDeclaration)
=> InitializeParameterHelpers.GetBody(functionDeclaration);
protected override ImmutableArray<SyntaxNode> GetParameters(SyntaxNode node, SyntaxGenerator generator)
{
return InitializeParameterHelpers.GetParameters(node, generator);
}
}
}
......@@ -33,16 +33,6 @@ public static SyntaxNode GetBody(SyntaxNode functionDeclaration)
}
}
public static ImmutableArray<SyntaxNode> GetParameters(SyntaxNode node, SyntaxGenerator generator)
{
if (node is SimpleLambdaExpressionSyntax simpleLambda)
{
return ImmutableArray.Create(simpleLambda.Parameter as SyntaxNode);
}
return generator.GetParameters(node).ToImmutableArray();
}
private static SyntaxToken? TryGetSemicolonToken(SyntaxNode functionDeclaration)
{
switch (functionDeclaration)
......
......@@ -33,8 +33,6 @@ internal abstract partial class AbstractInitializeParameterCodeRefactoringProvid
SyntaxEditor editor, SyntaxNode functionDeclaration, IMethodSymbol method,
SyntaxNode statementToAddAfterOpt, TStatementSyntax statement);
protected abstract ImmutableArray<SyntaxNode> GetParameters(SyntaxNode node, SyntaxGenerator generator);
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var (document, textSpan, cancellationToken) = context;
......@@ -42,13 +40,13 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(position);
var firstParameterNode = await context.TryGetRelevantNodeAsync<TParameterSyntax>().ConfigureAwait(false);
if (firstParameterNode == null)
var selectedParameter = await context.TryGetRelevantNodeAsync<TParameterSyntax>().ConfigureAwait(false);
if (selectedParameter == null)
{
return;
}
var functionDeclaration = firstParameterNode.FirstAncestorOrSelf<SyntaxNode>(IsFunctionDeclaration);
var functionDeclaration = selectedParameter.FirstAncestorOrSelf<SyntaxNode>(IsFunctionDeclaration);
if (functionDeclaration is null)
{
return;
......@@ -57,75 +55,86 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
var generator = SyntaxGenerator.GetGenerator(document);
var parameterNodes = generator.GetParameters(functionDeclaration);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
// List with parameterNodes that pass all checks
var listOfPotentiallyValidParametersNodes = ArrayBuilder<SyntaxNode>.GetInstance();
var counter = 0;
// Only offered when there isn't a selection, or the selection exactly selects a parameter name.
if (!context.Span.IsEmpty)
{
var parameterName = syntaxFacts.GetNameOfParameter(selectedParameter);
if (parameterName == null || parameterName.Value.Span != context.Span)
{
return;
}
}
parameterNodes = GetParameters(functionDeclaration, generator);
var parameterDefault = syntaxFacts.GetDefaultOfParameter(selectedParameter);
foreach (var parameterNode in parameterNodes)
// Don't offer inside the "=initializer" of a parameter
if (parameterDefault?.Span.Contains(position) == true)
{
++counter;
return;
}
// Only offered when there isn't a selection, or the selection exactly selects a parameter name.
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (!context.Span.IsEmpty)
{
var parameterName = syntaxFacts.GetNameOfParameter(parameterNode);
if (parameterName == null || parameterName.Value.Span != context.Span)
{
continue;
}
}
// we can't just call GetDeclaredSymbol on functionDeclaration because it could an anonymous function,
// so first we have to get the parameter symbol and then its containing method symbol
if (!TryGetParameterSymbol(selectedParameter, semanticModel, out var parameter, cancellationToken))
{
return;
}
var parameterDefault = syntaxFacts.GetDefaultOfParameter(parameterNode);
var methodSymbol = (IMethodSymbol)parameter.ContainingSymbol;
if (methodSymbol.IsAbstract ||
methodSymbol.IsExtern ||
methodSymbol.PartialImplementationPart != null ||
methodSymbol.ContainingType.TypeKind == TypeKind.Interface)
{
return;
}
// Don't offer inside the "=initializer" of a parameter
if (parameterDefault?.Span.Contains(position) == true)
{
continue;
}
if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt))
{
// Ok. Looks like the selected parameter could be refactored. Defer to subclass to
// actually determine if there are any viable refactorings here.
// we can't just call GetDeclaredSymbol on functionDeclaration because it could an anonymous function,
// so first we have to get the parameter symbol and then its containing method symbol
var parameter = (IParameterSymbol)semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken);
if (parameter == null || parameter.Name == "")
context.RegisterRefactorings(await GetRefactoringsForSingleParameterAsync(
document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false));
}
// List with parameterNodes that pass all checks
var listOfPotentiallyValidParametersNodes = ArrayBuilder<SyntaxNode>.GetInstance();
foreach (var parameterNode in parameterNodes)
{
if (!TryGetParameterSymbol(parameterNode, semanticModel, out parameter, cancellationToken))
{
return;
}
var methodSymbol = (IMethodSymbol)parameter.ContainingSymbol;
if (methodSymbol.IsAbstract ||
methodSymbol.IsExtern ||
methodSymbol.PartialImplementationPart != null ||
methodSymbol.ContainingType.TypeKind == TypeKind.Interface)
{
continue;
}
// Update the list of valid parameter nodes
listOfPotentiallyValidParametersNodes.Add(parameterNode);
}
if (listOfPotentiallyValidParametersNodes.Count > 1)
{
// Looks like we can offer a refactoring for more than one parameter. Defer to subclass to
// actually determine if there are any viable refactorings here.
context.RegisterRefactorings(await GetRefactoringsForAllParametersAsync(
document, functionDeclaration, methodSymbol, blockStatementOpt, listOfPotentiallyValidParametersNodes.ToImmutableAndFree(), position, cancellationToken).ConfigureAwait(false));
}
if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt))
bool TryGetParameterSymbol(
SyntaxNode parameterNode,
SemanticModel semanticModel,
out IParameterSymbol parameter,
CancellationToken cancellationToken)
{
parameter = (IParameterSymbol)semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken);
if (parameter == null || parameter.Name == "")
{
// Ok. Looks like there is at least one reasonable parameter to analyze. Defer to subclass to
// actually determine if there are any viable refactorings here.
// Update the list of valid parameter nodes
listOfPotentiallyValidParametersNodes.Add(parameterNode);
// For single parameter - Only offers for the parameter cursor is on
if (firstParameterNode == parameterNode)
{
context.RegisterRefactorings(await GetRefactoringsForSingleParameterAsync(
document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false));
}
// Calls for a multiple null check only when this is the last iteration and there's more than one possible valid parameter parameter
if (listOfPotentiallyValidParametersNodes.Count > 1 && counter == parameterNodes.Count)
{
context.RegisterRefactorings(await GetRefactoringsForAllParametersAsync(
document, functionDeclaration, methodSymbol, blockStatementOpt, listOfPotentiallyValidParametersNodes.ToImmutableAndFree(), position, cancellationToken).ConfigureAwait(false));
}
return false;
}
return true;
}
}
......@@ -159,8 +168,8 @@ protected bool CanOfferRefactoring(SyntaxNode functionDeclaration, SemanticModel
return true;
}
//In order to get the block operation for the body of an anonymous function, we need to
//get it via `IAnonymousFunctionOperation.Body` instead of getting it directly from the body syntax.GetBlockStatmentOpt does that.
// In order to get the block operation for the body of an anonymous function, we need to
// get it via `IAnonymousFunctionOperation.Body` instead of getting it directly from the body syntax.
var operation = semanticModel.GetOperation(
syntaxFacts.IsAnonymousFunction(functionDeclaration) ? functionDeclaration : functionBody,
......
......@@ -16,16 +16,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter
Return node
End Function
Public Shared Function GetParameters(node As SyntaxNode, generator As SyntaxGenerator) As ImmutableArray(Of SyntaxNode)
If node.GetType() = GetType(LambdaExpressionSyntax) Then
Dim simpleLambda = DirectCast(node, LambdaExpressionSyntax)
Dim simpleLambdaHeader = simpleLambda.SubOrFunctionHeader.GetParameterList.Parameters
Return simpleLambdaHeader.Cast(Of SyntaxNode).ToImmutableArray()
End If
Return generator.GetParameters(node).ToImmutableArray()
End Function
Private Shared Function GetStatements(functionDeclaration As SyntaxNode) As SyntaxList(Of StatementSyntax)
If TypeOf functionDeclaration Is MethodBlockBaseSyntax Then
Dim methodBlock = DirectCast(functionDeclaration, MethodBlockBaseSyntax)
......
......@@ -48,8 +48,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter
Return InitializeParameterHelpers.GetBody(functionDeclaration)
End Function
Protected Overrides Function GetParameters(node As SyntaxNode, generator As SyntaxGenerator) As ImmutableArray(Of SyntaxNode)
Return InitializeParameterHelpers.GetParameters(node, generator)
End Function
End Class
End Namespace
......@@ -56,8 +56,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.InitializeParameter
Return InitializeParameterHelpers.GetBody(functionDeclaration)
End Function
Protected Overrides Function GetParameters(node As SyntaxNode, generator As SyntaxGenerator) As ImmutableArray(Of SyntaxNode)
Return InitializeParameterHelpers.GetParameters(node, generator)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册