未验证 提交 0457da1b 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #44453 from sharwell/top-extract-method

Update Extract Method to support top-level statements
......@@ -4746,14 +4746,61 @@ void NewMethod()
[Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)]
public async Task TopLevelStatement_ArgumentInInvocation()
{
// ExtractLocalFunction currently disabled in the presence of top-level statements
// https://github.com/dotnet/roslyn/issues/44260
var code = @"
System.Console.WriteLine([|""string""|]);
";
var expected = @"
System.Console.WriteLine({|Rename:NewMethod|}());
static string NewMethod()
{
return ""string"";
}";
await TestAsync(code, expected, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9), index: CodeActionIndex);
}
[WorkItem(44260, "https://github.com/dotnet/roslyn/issues/44260")]
[Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)]
public async Task TopLevelStatement_InBlock_ArgumentInInvocation()
{
var code = @"
{
System.Console.WriteLine([|""string""|]);
}
";
var expected = @"
{
System.Console.WriteLine({|Rename:NewMethod|}());
static string NewMethod()
{
return ""string"";
}
}
";
await TestInRegularAndScriptAsync(code, expected, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9), index: CodeActionIndex);
}
[WorkItem(44260, "https://github.com/dotnet/roslyn/issues/44260")]
[Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)]
public async Task TopLevelStatement_ArgumentInInvocation_InInteractive()
{
var code = @"
System.Console.WriteLine([|""string""|]);
";
await TestExactActionSetOfferedAsync(code, new[] { FeaturesResources.Extract_method },
new TestParameters(parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp8)));
var expected =
@"{
System.Console.WriteLine({|Rename:NewMethod|}());
static string NewMethod()
{
return ""string"";
}
}";
await TestAsync(code, expected, TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp9), index: CodeActionIndex);
}
}
}
......@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.ExtractMethod;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ExtractMethod
......@@ -102,7 +103,7 @@ protected static async Task NotSupported_ExtractMethodAsync(string codeWithMarke
{
if (expected != "")
{
Assert.Equal(expected, actual);
AssertEx.EqualOrDiff(expected, actual);
}
else
{
......
......@@ -11246,12 +11246,14 @@ public async Task TopLevelStatement_ValueInAssignment()
";
var expected = @"
bool local;
local = NewMethod();
bool NewMethod()
{
return true;
}";
}
local = NewMethod();
";
await TestExtractMethodAsync(code, expected);
}
......
......@@ -69,6 +69,13 @@ protected override async Task<InsertionPoint> GetInsertionPointAsync(SemanticDoc
return await InsertionPoint.CreateAsync(document, globalStatement.Parent, cancellationToken).ConfigureAwait(false);
}
// check whether the global statement is a statement container
if (!globalStatement.Statement.IsStatementContainerNode() && !root.SyntaxTree.IsScript())
{
// The extracted function will be a new global statement
return await InsertionPoint.CreateAsync(document, globalStatement.Parent, cancellationToken).ConfigureAwait(false);
}
return await InsertionPoint.CreateAsync(document, globalStatement.Statement, cancellationToken).ConfigureAwait(false);
}
......
......@@ -4,9 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.ExtractMethod
......@@ -38,15 +36,6 @@ internal abstract class AbstractExtractMethodService<TValidator, TExtractor, TRe
return new FailedExtractMethodResult(selectionResult.Status);
}
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (localFunction && syntaxFacts.ContainsGlobalStatement(root))
{
// ExtractLocalFunction doesn't yet support local functions in top-level statements
// https://github.com/dotnet/roslyn/issues/44260
return new FailedExtractMethodResult(OperationStatus.FailedWithUnknownReason);
}
cancellationToken.ThrowIfCancellationRequested();
// extract method
......
......@@ -482,6 +482,21 @@ protected override TDeclarationNode AddMembers<TDeclarationNode>(TDeclarationNod
{
return (accessorDeclaration.Body == null) ? destinationMember : Cast<TDeclarationNode>(accessorDeclaration.AddBodyStatements(StatementGenerator.GenerateStatements(statements).ToArray()));
}
else if (destinationMember is CompilationUnitSyntax compilationUnit && options is null)
{
// Insert the new global statement(s) at the end of any current global statements
var insertionIndex = compilationUnit.Members.LastIndexOf(memberDeclaration => memberDeclaration.IsKind(SyntaxKind.GlobalStatement)) + 1;
var wrappedStatements = StatementGenerator.GenerateStatements(statements).Select(generated => SyntaxFactory.GlobalStatement(generated)).ToArray();
return Cast<TDeclarationNode>(compilationUnit.WithMembers(compilationUnit.Members.InsertRange(insertionIndex, wrappedStatements)));
}
else if (destinationMember is StatementSyntax statement && statement.IsParentKind(SyntaxKind.GlobalStatement))
{
// We are adding a statement to a global statement in script, where the CompilationUnitSyntax is not a
// statement container. If the global statement is not already a block, create a block which can hold
// both the original statement and any new statements we are adding to it.
var block = statement as BlockSyntax ?? SyntaxFactory.Block(statement);
return Cast<TDeclarationNode>(block.AddStatements(StatementGenerator.GenerateStatements(statements).ToArray()));
}
else
{
return AddStatementsWorker(destinationMember, statements, options, cancellationToken);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册