1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
// 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 Microsoft.CodeAnalysis.CodeRefactorings;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using System;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using System.Threading;
using ICSharpCode.NRefactory6.CSharp.ExtractMethod;
using ICSharpCode.NRefactory6.CSharp.Refactoring;
using MonoDevelop.Core;
using MonoDevelop.Ide;
using ICSharpCode.NRefactory6.CSharp;
namespace MonoDevelop.CSharp.CodeRefactorings.ExtractMethod
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ExtractMethod), Shared]
internal class ExtractMethodCodeRefactoringProvider : CodeRefactoringProvider
{
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
// Don't bother if there isn't a selection
var textSpan = context.Span;
if (textSpan.IsEmpty)
{
return;
}
var document = context.Document;
var cancellationToken = context.CancellationToken;
var workspace = document.Project.Solution.Workspace;
if (workspace.Kind == WorkspaceKind.MiscellaneousFiles)
{
return;
}
var activeInlineRenameSession = IdeApp.Workbench.ActiveDocument.Editor.EditMode != MonoDevelop.Ide.Editor.EditMode.Edit;
if (activeInlineRenameSession)
{
return;
}
var model = await context.Document.GetSemanticModelAsync (context.CancellationToken).ConfigureAwait (false);
if (model.IsFromGeneratedCode (context.CancellationToken))
return;
if (cancellationToken.IsCancellationRequested)
{
return;
}
var action = await GetCodeActionAsync(document, textSpan, cancellationToken: cancellationToken).ConfigureAwait(false);
if (action == null)
{
return;
}
context.RegisterRefactoring(action.Item1);
}
static CSharpExtractMethodService service = new CSharpExtractMethodService ();
private async Task<Tuple<CodeAction, string>> GetCodeActionAsync(
Document document,
TextSpan textSpan,
CancellationToken cancellationToken)
{
var options = document.Project.Solution.Workspace.Options;
try {
var result = await service.ExtractMethodAsync(
document,
textSpan,
options,
cancellationToken).ConfigureAwait(false);
if (result.Succeeded || result.SucceededWithSuggestion)
{
var description = options.GetOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language) ?
GettextCatalog.GetString ("Extract Method + Local") : GettextCatalog.GetString ("Extract Method");
var codeAction = new DocumentChangeAction(textSpan, DiagnosticSeverity.Info, description, (c) => AddRenameAnnotationAsync(result.Document, result.InvocationNameToken, c));
var methodBlock = result.MethodDeclarationNode;
return Tuple.Create<CodeAction, string>(codeAction, methodBlock.ToString());
}
} catch (Exception) {
// currently the extract method refactoring crashes often. Ignore the roslyn issues for now.
}
return null;
}
private async Task<Document> AddRenameAnnotationAsync(Document document, SyntaxToken invocationNameToken, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var finalRoot = root.ReplaceToken(
invocationNameToken,
invocationNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()));
return document.WithSyntaxRoot(finalRoot);
}
}
}
|