提交 e76e08bb 编写于 作者: A Allison Chou

Preliminary work

上级 73b18adb
......@@ -10329,7 +10329,7 @@ public async Task ExtractMethod_Argument1()
var service = new CSharpExtractMethodService();
Assert.NotNull(await Record.ExceptionAsync(async () =>
{
var tree = await service.ExtractMethodAsync(null, default, null, CancellationToken.None);
var tree = await service.ExtractMethodAsync(null, default, false, null, CancellationToken.None);
}));
}
......
......@@ -220,7 +220,7 @@ private bool TryNotifyFailureToUser(Document document, ExtractMethodResult resul
{
options = options.WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, true);
var newResult = ExtractMethodService.ExtractMethodAsync(
document, spans.Single().Span.ToTextSpan(), options, cancellationToken).WaitAndGetResult(cancellationToken);
document, spans.Single().Span.ToTextSpan(), false, options, cancellationToken).WaitAndGetResult(cancellationToken);
// retry succeeded, return new result
if (newResult.Succeeded || newResult.SucceededWithSuggestion)
......
......@@ -22,9 +22,9 @@ protected override CSharpSelectionValidator CreateSelectionValidator(SemanticDoc
return new CSharpSelectionValidator(document, textSpan, options);
}
protected override CSharpMethodExtractor CreateMethodExtractor(CSharpSelectionResult selectionResult)
protected override CSharpMethodExtractor CreateMethodExtractor(CSharpSelectionResult selectionResult, bool extractLocalFunction)
{
return new CSharpMethodExtractor(selectionResult);
return new CSharpMethodExtractor(selectionResult, extractLocalFunction);
}
}
}
......@@ -21,8 +21,9 @@ private class ExpressionCodeGenerator : CSharpCodeGenerator
public ExpressionCodeGenerator(
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult)
: base(insertionPoint, selectionResult, analyzerResult)
AnalyzerResult analyzerResult,
bool extractLocalFunction)
: base(insertionPoint, selectionResult, analyzerResult, extractLocalFunction)
{
}
......
......@@ -18,8 +18,9 @@ public class MultipleStatementsCodeGenerator : CSharpCodeGenerator
public MultipleStatementsCodeGenerator(
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult)
: base(insertionPoint, selectionResult, analyzerResult)
AnalyzerResult analyzerResult,
bool extractLocalFunction)
: base(insertionPoint, selectionResult, analyzerResult, extractLocalFunction)
{
}
......
......@@ -18,8 +18,9 @@ public class SingleStatementCodeGenerator : CSharpCodeGenerator
public SingleStatementCodeGenerator(
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult)
: base(insertionPoint, selectionResult, analyzerResult)
AnalyzerResult analyzerResult,
bool extractLocalFunction)
: base(insertionPoint, selectionResult, analyzerResult, extractLocalFunction)
{
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
......@@ -32,30 +33,32 @@ private abstract partial class CSharpCodeGenerator : CodeGenerator<StatementSynt
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult,
bool extractLocalFunction,
CancellationToken cancellationToken)
{
var codeGenerator = Create(insertionPoint, selectionResult, analyzerResult);
var codeGenerator = Create(insertionPoint, selectionResult, analyzerResult, extractLocalFunction);
return codeGenerator.GenerateAsync(cancellationToken);
}
private static CSharpCodeGenerator Create(
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult)
AnalyzerResult analyzerResult,
bool extractLocalFunction)
{
if (ExpressionCodeGenerator.IsExtractMethodOnExpression(selectionResult))
{
return new ExpressionCodeGenerator(insertionPoint, selectionResult, analyzerResult);
return new ExpressionCodeGenerator(insertionPoint, selectionResult, analyzerResult, extractLocalFunction);
}
if (SingleStatementCodeGenerator.IsExtractMethodOnSingleStatement(selectionResult))
{
return new SingleStatementCodeGenerator(insertionPoint, selectionResult, analyzerResult);
return new SingleStatementCodeGenerator(insertionPoint, selectionResult, analyzerResult, extractLocalFunction);
}
if (MultipleStatementsCodeGenerator.IsExtractMethodOnMultipleStatements(selectionResult))
{
return new MultipleStatementsCodeGenerator(insertionPoint, selectionResult, analyzerResult);
return new MultipleStatementsCodeGenerator(insertionPoint, selectionResult, analyzerResult, extractLocalFunction);
}
return Contract.FailWithReturn<CSharpCodeGenerator>("Unknown selection");
......@@ -64,8 +67,9 @@ private abstract partial class CSharpCodeGenerator : CodeGenerator<StatementSynt
protected CSharpCodeGenerator(
InsertionPoint insertionPoint,
SelectionResult selectionResult,
AnalyzerResult analyzerResult)
: base(insertionPoint, selectionResult, analyzerResult)
AnalyzerResult analyzerResult,
bool extractLocalFunction)
: base(insertionPoint, selectionResult, analyzerResult, extractLocalFunction)
{
Contract.ThrowIfFalse(this.SemanticDocument == selectionResult.SemanticDocument);
......@@ -609,12 +613,23 @@ protected override async Task<GeneratedCode> CreateGeneratedCodeAsync(OperationS
// here, we explicitly insert newline at the end of "{" of auto generated method decl so that anchor knows how to find out
// indentation of inserted statements (from users code) with user code style preserved
var root = newDocument.Root;
var methodDefinition = root.GetAnnotatedNodes<MethodDeclarationSyntax>(this.MethodDefinitionAnnotation).First();
var newMethodDefinition = TweakNewLinesInMethod(methodDefinition);
newDocument = await newDocument.WithSyntaxRootAsync(
root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(false);
var methodDefinition = root.GetAnnotatedNodes<SyntaxNode>(this.MethodDefinitionAnnotation).First();
if (methodDefinition is LocalFunctionStatementSyntax localMethod)
{
var newMethodDefinition = TweakNewLinesInMethod(localMethod);
newDocument = await newDocument.WithSyntaxRootAsync(
root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(false);
}
else if (methodDefinition is MethodDeclarationSyntax method)
{
var newMethodDefinition = TweakNewLinesInMethod(method);
newDocument = await newDocument.WithSyntaxRootAsync(
root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(false);
}
else
{
throw new NotSupportedException("methodDefinition expected to be a regular or local method.");
}
}
return await base.CreateGeneratedCodeAsync(status, newDocument, cancellationToken).ConfigureAwait(false);
......@@ -642,6 +657,28 @@ private static MethodDeclarationSyntax TweakNewLinesInMethod(MethodDeclarationSy
}
}
private static LocalFunctionStatementSyntax TweakNewLinesInMethod(LocalFunctionStatementSyntax methodDefinition)
{
if (methodDefinition.Body != null)
{
return methodDefinition.ReplaceToken(
methodDefinition.Body.OpenBraceToken,
methodDefinition.Body.OpenBraceToken.WithAppendedTrailingTrivia(
SpecializedCollections.SingletonEnumerable(SyntaxFactory.ElasticCarriageReturnLineFeed)));
}
else if (methodDefinition.ExpressionBody != null)
{
return methodDefinition.ReplaceToken(
methodDefinition.ExpressionBody.ArrowToken,
methodDefinition.ExpressionBody.ArrowToken.WithPrependedLeadingTrivia(
SpecializedCollections.SingletonEnumerable(SyntaxFactory.ElasticCarriageReturnLineFeed)));
}
else
{
return methodDefinition;
}
}
protected StatementSyntax GetStatementContainingInvocationToExtractedMethodWorker()
{
var callSignature = CreateCallSignature();
......
......@@ -17,8 +17,8 @@ namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod
{
internal partial class CSharpMethodExtractor : MethodExtractor
{
public CSharpMethodExtractor(CSharpSelectionResult result)
: base(result)
public CSharpMethodExtractor(CSharpSelectionResult result, bool extractLocalFunction = false)
: base(result, extractLocalFunction)
{
}
......@@ -67,9 +67,9 @@ protected override async Task<SemanticDocument> ExpandAsync(SelectionResult sele
return await selection.SemanticDocument.WithSyntaxRootAsync(selection.SemanticDocument.Root.ReplaceNode(lastExpression, newExpression), cancellationToken).ConfigureAwait(false);
}
protected override Task<MethodExtractor.GeneratedCode> GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, CancellationToken cancellationToken)
protected override Task<MethodExtractor.GeneratedCode> GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, bool extractLocalFunction, CancellationToken cancellationToken)
{
return CSharpCodeGenerator.GenerateAsync(insertionPoint, selectionResult, analyzeResult, cancellationToken);
return CSharpCodeGenerator.GenerateAsync(insertionPoint, selectionResult, analyzeResult, extractLocalFunction, cancellationToken);
}
protected override IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod;
using Microsoft.CodeAnalysis.ExtractMethod;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeRefactorings.ExtractLocalMethod
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp,
Name = PredefinedCodeRefactoringProviderNames.ExtractLocalMethod), Shared]
internal class ExtractLocalMethodCodeRefactoringProvider : ExtractMethodCodeRefactoringProvider
{
[ImportingConstructor]
public ExtractLocalMethodCodeRefactoringProvider()
{
}
internal override async Task<(CodeAction action, string methodBlock)> GetCodeActionAsync(
Document document,
TextSpan textSpan,
CancellationToken cancellationToken)
{
var result = await ExtractMethodService.ExtractMethodAsync(
document,
textSpan,
extractLocalMethod: true,
cancellationToken: cancellationToken).ConfigureAwait(false);
Contract.ThrowIfNull(result);
if (result.Succeeded || result.SucceededWithSuggestion)
{
var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var description = documentOptions.GetOption(ExtractMethodOptions.AllowMovingDeclaration) ?
FeaturesResources.Extract_Local_Method_plus_Local : FeaturesResources.Extract_Local_Method;
var codeAction = new MyCodeAction(description, c => AddRenameAnnotationAsync(result.Document, result.InvocationNameToken, c));
var methodBlock = result.MethodDeclarationNode;
return (codeAction, methodBlock.ToString());
}
return default;
}
}
}
......@@ -55,7 +55,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
context.RegisterRefactoring(action.action, textSpan);
}
private async Task<(CodeAction action, string methodBlock)> GetCodeActionAsync(
internal virtual async Task<(CodeAction action, string methodBlock)> GetCodeActionAsync(
Document document,
TextSpan textSpan,
CancellationToken cancellationToken)
......@@ -81,7 +81,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
return default;
}
private async Task<Document> AddRenameAnnotationAsync(Document document, SyntaxToken invocationNameToken, CancellationToken cancellationToken)
internal async Task<Document> AddRenameAnnotationAsync(Document document, SyntaxToken invocationNameToken, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
......@@ -92,7 +92,7 @@ private async Task<Document> AddRenameAnnotationAsync(Document document, SyntaxT
return document.WithSyntaxRoot(finalRoot);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
internal class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
......
......@@ -14,6 +14,7 @@ internal static class PredefinedCodeRefactoringProviderNames
public const string ConvertTupleToStruct = "Convert Tuple to Struct Code Action Provider";
public const string EncapsulateField = "Encapsulate Field";
public const string ExtractInterface = "Extract Interface Code Action Provider";
public const string ExtractLocalMethod = "Extract Local Method Code Action Provider";
public const string ExtractMethod = "Extract Method Code Action Provider";
public const string GenerateConstructorFromMembers = "Generate Constructor From Members Code Action Provider";
public const string GenerateDefaultConstructors = "Generate Default Constructors Code Action Provider";
......
......@@ -13,11 +13,12 @@ internal abstract class AbstractExtractMethodService<TValidator, TExtractor, TRe
where TResult : SelectionResult
{
protected abstract TValidator CreateSelectionValidator(SemanticDocument document, TextSpan textSpan, OptionSet options);
protected abstract TExtractor CreateMethodExtractor(TResult selectionResult);
protected abstract TExtractor CreateMethodExtractor(TResult selectionResult, bool extractLocalMethod);
public async Task<ExtractMethodResult> ExtractMethodAsync(
Document document,
TextSpan textSpan,
bool extractLocalFunction,
OptionSet options,
CancellationToken cancellationToken)
{
......@@ -36,7 +37,7 @@ internal abstract class AbstractExtractMethodService<TValidator, TExtractor, TRe
cancellationToken.ThrowIfCancellationRequested();
// extract method
var extractor = CreateMethodExtractor((TResult)selectionResult);
var extractor = CreateMethodExtractor((TResult)selectionResult, extractLocalFunction);
return await extractor.ExtractMethodAsync(cancellationToken).ConfigureAwait(false);
}
......
......@@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.ExtractMethod
{
internal static class ExtractMethodService
{
public static Task<ExtractMethodResult> ExtractMethodAsync(Document document, TextSpan textSpan, OptionSet options = null, CancellationToken cancellationToken = default)
public static Task<ExtractMethodResult> ExtractMethodAsync(Document document, TextSpan textSpan, bool extractLocalMethod = false, OptionSet options = null, CancellationToken cancellationToken = default)
{
return document.GetLanguageService<IExtractMethodService>().ExtractMethodAsync(document, textSpan, options, cancellationToken);
return document.GetLanguageService<IExtractMethodService>().ExtractMethodAsync(document, textSpan, extractLocalMethod, options, cancellationToken);
}
}
}
......@@ -10,6 +10,6 @@ namespace Microsoft.CodeAnalysis.ExtractMethod
{
internal interface IExtractMethodService : ILanguageService
{
Task<ExtractMethodResult> ExtractMethodAsync(Document document, TextSpan textSpan, OptionSet options = null, CancellationToken cancellationToken = default);
Task<ExtractMethodResult> ExtractMethodAsync(Document document, TextSpan textSpan, bool extractLocalFunction = false, OptionSet options = null, CancellationToken cancellationToken = default);
}
}
......@@ -31,7 +31,9 @@ protected abstract partial class CodeGenerator<TStatement, TExpression, TNodeUnd
protected readonly SelectionResult SelectionResult;
protected readonly AnalyzerResult AnalyzerResult;
protected CodeGenerator(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult)
protected readonly bool ExtractLocalFunction;
protected CodeGenerator(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, bool extractLocalFunction = false)
{
Contract.ThrowIfFalse(insertionPoint.SemanticDocument == analyzerResult.SemanticDocument);
......@@ -40,6 +42,7 @@ protected CodeGenerator(InsertionPoint insertionPoint, SelectionResult selection
SelectionResult = selectionResult;
AnalyzerResult = analyzerResult;
ExtractLocalFunction = extractLocalFunction;
MethodNameAnnotation = new SyntaxAnnotation();
CallSiteAnnotation = new SyntaxAnnotation();
......@@ -80,16 +83,36 @@ public async Task<GeneratedCode> GenerateAsync(CancellationToken cancellationTok
var newCallSiteRoot = callSiteDocument.Root;
var previousMemberNode = GetPreviousMember(callSiteDocument);
// it is possible in a script file case where there is no previous member. in that case, insert new text into top level script
var destination = (previousMemberNode.Parent == null) ? previousMemberNode : previousMemberNode.Parent;
SyntaxNode destination;
if (ExtractLocalFunction)
{
destination = InsertionPoint.With(callSiteDocument).GetContext();
}
else
{
// it is possible in a script file case where there is no previous member. in that case, insert new text into top level script
destination = (previousMemberNode.Parent == null) ? previousMemberNode : previousMemberNode.Parent;
}
var codeGenerationService = SemanticDocument.Document.GetLanguageService<ICodeGenerationService>();
var result = GenerateMethodDefinition(cancellationToken);
var newContainer = codeGenerationService.AddMethod(
destination, result.Data,
new CodeGenerationOptions(afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, generateMethodBodies: true),
cancellationToken);
SyntaxNode newContainer;
if (ExtractLocalFunction)
{
newContainer = codeGenerationService.AddMethod(
destination, result.Data,
new CodeGenerationOptions(generateDefaultAccessibility: false),
cancellationToken);
}
else
{
newContainer = codeGenerationService.AddMethod(
destination, result.Data,
new CodeGenerationOptions(afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, generateMethodBodies: true),
cancellationToken);
}
var newDocument = callSiteDocument.Document.WithSyntaxRoot(newCallSiteRoot.ReplaceNode(destination, newContainer));
newDocument = await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, null, cancellationToken).ConfigureAwait(false);
......
......@@ -14,11 +14,13 @@ namespace Microsoft.CodeAnalysis.ExtractMethod
internal abstract partial class MethodExtractor
{
protected readonly SelectionResult OriginalSelectionResult;
protected readonly bool ExtractLocalFunction;
public MethodExtractor(SelectionResult selectionResult)
public MethodExtractor(SelectionResult selectionResult, bool extractLocalFunction = false)
{
Contract.ThrowIfNull(selectionResult);
OriginalSelectionResult = selectionResult;
ExtractLocalFunction = extractLocalFunction;
}
protected abstract Task<AnalyzerResult> AnalyzeAsync(SelectionResult selectionResult, CancellationToken cancellationToken);
......@@ -26,7 +28,7 @@ public MethodExtractor(SelectionResult selectionResult)
protected abstract Task<TriviaResult> PreserveTriviaAsync(SelectionResult selectionResult, CancellationToken cancellationToken);
protected abstract Task<SemanticDocument> ExpandAsync(SelectionResult selection, CancellationToken cancellationToken);
protected abstract Task<GeneratedCode> GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, CancellationToken cancellationToken);
protected abstract Task<GeneratedCode> GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, bool extractLocalFunction, CancellationToken cancellationToken);
protected abstract SyntaxToken GetMethodNameAtInvocation(IEnumerable<SyntaxNodeOrToken> methodNames);
protected abstract IEnumerable<AbstractFormattingRule> GetFormattingRules(Document document);
......@@ -58,6 +60,7 @@ public async Task<ExtractMethodResult> ExtractMethodAsync(CancellationToken canc
insertionPoint.With(expandedDocument),
OriginalSelectionResult.With(expandedDocument),
analyzeResult.With(expandedDocument),
ExtractLocalFunction,
cancellationToken).ConfigureAwait(false);
var applied = await triviaResult.ApplyAsync(generatedCode, cancellationToken).ConfigureAwait(false);
......
......@@ -1329,7 +1329,7 @@ internal class FeaturesResources {
}
/// <summary>
/// Looks up a localized string similar to The current content of source file &apos;{0}&apos; does not match the built source. The file is likely being updated by a background build. The debug session can&apos;t continue until the update is completed..
/// Looks up a localized string similar to The current content of source file &apos;{0}&apos; does not match the built source. The debug session can&apos;t continue until the content of the source file is restored..
/// </summary>
internal static string DocumentIsOutOfSyncWithDebuggee {
get {
......@@ -1499,6 +1499,24 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Extract Local Method.
/// </summary>
internal static string Extract_Local_Method {
get {
return ResourceManager.GetString("Extract_Local_Method", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract Local Method + Local.
/// </summary>
internal static string Extract_Local_Method_plus_Local {
get {
return ResourceManager.GetString("Extract_Local_Method_plus_Local", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract Method.
/// </summary>
......
......@@ -598,6 +598,12 @@
<data name="Unknown" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Extract_Local_Method" xml:space="preserve">
<value>Extract Local Method</value>
</data>
<data name="Extract_Local_Method_plus_Local" xml:space="preserve">
<value>Extract Local Method + Local</value>
</data>
<data name="Extract_Method" xml:space="preserve">
<value>Extract Method</value>
</data>
......
......@@ -217,6 +217,16 @@
<target state="translated">Hodnota výrazu se nikdy nepoužívá.</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Nepovedlo se analyzovat tok dat pro: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">Der Ausdruckswert wird niemals verwendet.</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Fehler beim Analysieren des Datenflusses für: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">El valor de la expresión no se utiliza nunca.</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">No se pudo analizar el flujo de datos para: {0}.</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">La valeur d'expression n'est jamais utilisée</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Impossible d’analyser le flux de données pour : {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">Il valore dell'espressione non viene mai usato</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Non è stato possibile analizzare il flusso di dati per: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">式の値が使用されていません</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">データ フローを分析できませんでした: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">식 값은 절대 사용되지 않습니다.</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">{0}의 데이터 흐름 분석 실패</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">Wartość wyrażenia nie jest nigdy używana.</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Nie można przeanalizować przepływu danych dla: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">O valor da expressão nunca é usado</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Falha ao analisar o fluxo de dados para: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">Значение выражения никогда не используется</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">Не удалось проанализировать поток данных для: {0}</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">İfade değeri asla kullanılmaz</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">{0} için veri akışı analiz edilemedi</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">永远不会使用表达式值</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">未能分析 {0} 的数据流</target>
......
......@@ -217,6 +217,16 @@
<target state="translated">永遠不會使用運算式值</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method">
<source>Extract Local Method</source>
<target state="new">Extract Local Method</target>
<note />
</trans-unit>
<trans-unit id="Extract_Local_Method_plus_Local">
<source>Extract Local Method + Local</source>
<target state="new">Extract Local Method + Local</target>
<note />
</trans-unit>
<trans-unit id="Failed_to_analyze_data_flow_for_0">
<source>Failed to analyze data-flow for: {0}</source>
<target state="translated">無法分析下列項目的資料流程: {0}</target>
......
......@@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod
Return New VisualBasicSelectionValidator(document, textSpan, options)
End Function
Protected Overrides Function CreateMethodExtractor(selectionResult As VisualBasicSelectionResult) As VisualBasicMethodExtractor
Protected Overrides Function CreateMethodExtractor(selectionResult As VisualBasicSelectionResult, extractLocalFunction As Boolean) As VisualBasicMethodExtractor
Return New VisualBasicMethodExtractor(selectionResult)
End Function
End Class
......
......@@ -63,7 +63,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod
Return Await selection.SemanticDocument.WithSyntaxRootAsync(selection.SemanticDocument.Root.ReplaceNode(lastExpression, newStatement), cancellationToken).ConfigureAwait(False)
End Function
Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As SelectionResult, analyzeResult As AnalyzerResult, cancellationToken As CancellationToken) As Task(Of GeneratedCode)
Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As SelectionResult, analyzeResult As AnalyzerResult, extractLocalFunction As Boolean, cancellationToken As CancellationToken) As Task(Of GeneratedCode)
Return VisualBasicCodeGenerator.GenerateResultAsync(insertionPoint, selectionResult, analyzeResult, cancellationToken)
End Function
......
......@@ -168,6 +168,11 @@ public static MemberDeclarationSyntax LastOperator(SyntaxList<MemberDeclarationS
return members.LastOrDefault(m => m is OperatorDeclarationSyntax || m is ConversionOperatorDeclarationSyntax);
}
public static StatementSyntax LastStatement(SyntaxList<StatementSyntax> statements)
{
return statements.LastOrDefault(s => s is StatementSyntax);
}
public static SyntaxList<TDeclaration> Insert<TDeclaration>(
SyntaxList<TDeclaration> declarationList,
TDeclaration declaration,
......
......@@ -111,7 +111,7 @@ protected override TDeclarationNode AddField<TDeclarationNode>(TDeclarationNode
protected override TDeclarationNode AddMethod<TDeclarationNode>(TDeclarationNode destination, IMethodSymbol method, CodeGenerationOptions options, IList<bool> availableIndices)
{
CheckDeclarationNode<TypeDeclarationSyntax, CompilationUnitSyntax, NamespaceDeclarationSyntax>(destination);
CheckDeclarationNode<TypeDeclarationSyntax, CompilationUnitSyntax, NamespaceDeclarationSyntax, MethodDeclarationSyntax>(destination);
// Synthesized methods for properties/events are not things we actually generate
// declarations for.
......@@ -158,6 +158,11 @@ protected override TDeclarationNode AddMethod<TDeclarationNode>(TDeclarationNode
typeDeclaration, method, Workspace, options, availableIndices));
}
if (destination is MethodDeclarationSyntax methodDeclaration)
{
return Cast<TDeclarationNode>(MethodGenerator.AddMethodTo(methodDeclaration, method, Workspace, options, availableIndices));
}
if (method.IsConstructor() ||
method.IsDestructor())
{
......
......@@ -5,7 +5,6 @@
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -61,6 +60,20 @@ internal static class MethodGenerator
return AddMembersTo(destination, members);
}
internal static MethodDeclarationSyntax AddMethodTo(
MethodDeclarationSyntax destination,
IMethodSymbol method,
Workspace workspace,
CodeGenerationOptions options,
IList<bool> availableIndices)
{
var localMethodDeclaration = GenerateLocalMethodDeclaration(
method, GetDestination(destination), workspace, options,
destination?.SyntaxTree.Options ?? options.ParseOptions);
return destination.AddBodyStatements(localMethodDeclaration);
}
public static MethodDeclarationSyntax GenerateMethodDeclaration(
IMethodSymbol method, CodeGenerationDestination destination,
Workspace workspace, CodeGenerationOptions options,
......@@ -111,6 +124,53 @@ internal static class MethodGenerator
return AddFormatterAndCodeGeneratorAnnotationsTo(methodDeclaration);
}
public static LocalFunctionStatementSyntax GenerateLocalMethodDeclaration(
IMethodSymbol method, CodeGenerationDestination destination,
Workspace workspace, CodeGenerationOptions options,
ParseOptions parseOptions)
{
options ??= CodeGenerationOptions.Default;
var reusableSyntax = GetReuseableSyntaxNodeForSymbol<LocalFunctionStatementSyntax>(method, options);
if (reusableSyntax != null)
{
return reusableSyntax;
}
var declaration = GenerateLocalMethodDeclarationWorker(
method, destination, workspace, options, parseOptions);
return AddAnnotationsTo(method,
ConditionallyAddDocumentationCommentTo(declaration, method, options));
}
private static LocalFunctionStatementSyntax GenerateLocalMethodDeclarationWorker(
IMethodSymbol method, CodeGenerationDestination destination,
Workspace workspace, CodeGenerationOptions options, ParseOptions parseOptions)
{
// Don't rely on destination to decide if method body should be generated.
// Users of this service need to express their intention explicitly, either by
// setting `CodeGenerationOptions.GenerateMethodBodies` to true, or making
// `method` abstract. This would provide more flexibility.
var hasNoBody = !options.GenerateMethodBodies || method.IsAbstract;
var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(method.ExplicitInterfaceImplementations);
var localMethodDeclaration = SyntaxFactory.LocalFunctionStatement(
modifiers: GenerateModifiers(method, destination, options),
returnType: method.GenerateReturnTypeSyntax(),
identifier: method.Name.ToIdentifierToken(),
typeParameterList: GenerateTypeParameterList(method, options),
parameterList: ParameterGenerator.GenerateParameterList(method.Parameters, explicitInterfaceSpecifier != null, options),
constraintClauses: GenerateConstraintClauses(method),
body: hasNoBody ? null : StatementGenerator.GenerateBlock(method),
expressionBody: default,
semicolonToken: hasNoBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : new SyntaxToken());
localMethodDeclaration = UseExpressionBodyIfDesired(workspace, localMethodDeclaration, parseOptions);
return AddFormatterAndCodeGeneratorAnnotationsTo(localMethodDeclaration);
}
private static MethodDeclarationSyntax UseExpressionBodyIfDesired(
Workspace workspace, MethodDeclarationSyntax methodDeclaration, ParseOptions options)
{
......@@ -130,6 +190,25 @@ internal static class MethodGenerator
return methodDeclaration;
}
private static LocalFunctionStatementSyntax UseExpressionBodyIfDesired(
Workspace workspace, LocalFunctionStatementSyntax localMethodDeclaration, ParseOptions options)
{
if (localMethodDeclaration.ExpressionBody == null)
{
var expressionBodyPreference = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value;
if (localMethodDeclaration.Body.TryConvertToArrowExpressionBody(
localMethodDeclaration.Kind(), options, expressionBodyPreference,
out var expressionBody, out var semicolonToken))
{
return localMethodDeclaration.WithBody(null)
.WithExpressionBody(expressionBody)
.WithSemicolonToken(semicolonToken);
}
}
return localMethodDeclaration;
}
private static SyntaxList<AttributeListSyntax> GenerateAttributes(
IMethodSymbol method, CodeGenerationOptions options, bool isExplicit)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册