提交 f9401151 编写于 作者: S shyamn

Implements following public API changes to fix bug 1066530.

CodeFixProvider:
1. "Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext)" becomes "Task ComputeFixesAsync(CodeFixContext)".
2. CodeFixContext now has a new method - "void RegisterFix(CodeAction, IEnumerable<Diagnostic>>)".

This API now allows providers to map each returned code action to the set of diagnostics being fixed by this code action.

CodeRefactoringProvider gets identical API changes for consistency:
3. "Task<IEnumerable<CodeAction>> GetRefactoringsAsync(CodeFixContext)" becomes "Task ComputeRefactoringsAsync(CodeFixContext)".
4. CodeRefactoingContext now has a new method - "void RegisterRefactoring(CodeAction)".

Also moves all our existing fix and refactoring providers (including samples and sdk templates) over to the new API. (changeset 1363085)
上级 07a29c28
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Threading.Tasks;
......@@ -11,7 +10,6 @@
using Microsoft.CodeAnalysis.FxCopAnalyzers;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Design;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers.Design
{
......@@ -28,7 +26,7 @@ public sealed override FixAllProvider GetFixAllProvider()
return WellKnownFixAllProviders.BatchFixer;
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var span = context.Span;
......@@ -42,11 +40,10 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
var staticKeyword = SyntaxFactory.Token(SyntaxKind.StaticKeyword).WithAdditionalAnnotations(Formatter.Annotation);
var newDeclaration = classDeclaration.AddModifiers(staticKeyword);
var newRoot = root.ReplaceNode(classDeclaration, newDeclaration);
return SpecializedCollections.SingletonEnumerable(
new MyCodeAction(string.Format(FxCopRulesResources.StaticHolderTypeIsNotStatic, classDeclaration.Identifier.Text), document.WithSyntaxRoot(newRoot)));
context.RegisterFix(
new MyCodeAction(string.Format(FxCopRulesResources.StaticHolderTypeIsNotStatic, classDeclaration.Identifier.Text), document.WithSyntaxRoot(newRoot)),
context.Diagnostics);
}
return null;
}
private class MyCodeAction : CodeAction.DocumentChangeAction
......@@ -57,4 +54,4 @@ private class MyCodeAction : CodeAction.DocumentChangeAction
}
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers
{
......@@ -17,7 +14,7 @@ public abstract class CodeFixProviderBase : CodeFixProvider
internal abstract Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken);
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
......@@ -25,7 +22,6 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var actions = SpecializedCollections.EmptyEnumerable<CodeAction>();
foreach (var diagnostic in context.Diagnostics)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -38,11 +34,9 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
if (newDocument != document)
{
var codeFixDescription = GetCodeFixDescription(diagnostic.Id);
actions = actions.Concat(new MyCodeAction(codeFixDescription, newDocument));
context.RegisterFix(new MyCodeAction(codeFixDescription, newDocument), diagnostic);
}
}
return actions;
}
public override FixAllProvider GetFixAllProvider()
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers
{
......@@ -19,7 +17,7 @@ public override FixAllProvider GetFixAllProvider()
internal abstract Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, CancellationToken cancellationToken);
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
......@@ -27,7 +25,6 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var actions = SpecializedCollections.EmptyEnumerable<CodeAction>();
foreach (var diagnostic in context.Diagnostics)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -38,11 +35,12 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
if (newActions != null)
{
actions = actions.Concat(newActions);
foreach (var a in newActions)
{
context.RegisterFix(a, diagnostic);
}
}
}
return actions;
}
}
}
\ No newline at end of file
......@@ -25,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design
Return WellKnownFixAllProviders.BatchFixer
End Function
Public NotOverridable Overrides Async Function GetFixesAsync(context As CodeFixContext) As Task(Of IEnumerable(Of CodeAction))
Public NotOverridable Overrides Async Function ComputeFixesAsync(context As CodeFixContext) As Task
Dim document = context.Document
Dim span = context.Span
Dim cancellationToken = context.CancellationToken
......@@ -37,10 +37,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design
Dim notInheritableKeyword = SyntaxFactory.Token(SyntaxKind.NotInheritableKeyword).WithAdditionalAnnotations(Formatter.Annotation)
Dim newClassStatement = classStatement.AddModifiers(notInheritableKeyword)
Dim newRoot = root.ReplaceNode(classStatement, newClassStatement)
Return {New MyCodeAction(String.Format(FxCopRulesResources.StaticHolderTypeIsNotStatic, classStatement.Identifier.Text), document.WithSyntaxRoot(newRoot))}
context.RegisterFix(
New MyCodeAction(String.Format(FxCopRulesResources.StaticHolderTypeIsNotStatic, classStatement.Identifier.Text), document.WithSyntaxRoot(newRoot)),
context.Diagnostics)
End If
Return Nothing
End Function
Private Class MyCodeAction
......@@ -51,4 +51,4 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design
End Sub
End Class
End Class
End Namespace
End Namespace
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
......@@ -17,7 +14,7 @@ public abstract class CodeFixProviderBase : CodeFixProvider
internal abstract Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken);
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
......@@ -25,7 +22,6 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var actions = SpecializedCollections.EmptyEnumerable<CodeAction>();
foreach (var diagnostic in context.Diagnostics)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -38,11 +34,9 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
if (newDocument != document)
{
var codeFixDescription = GetCodeFixDescription(diagnostic.Id);
actions = actions.Concat(new MyCodeAction(codeFixDescription, newDocument));
context.RegisterFix(new MyCodeAction(codeFixDescription, newDocument), diagnostic);
}
}
return actions;
}
public override FixAllProvider GetFixAllProvider()
......
// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading;
using System.Threading.Tasks;
......@@ -23,24 +22,21 @@ public sealed override ImmutableArray<string> GetFixableDiagnosticIds()
return ImmutableArray.Create(RoslynDiagnosticIds.DirectlyAwaitingTaskAnalyzerRuleId);
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
return GetFixesCore(context.Document, root, context.Diagnostics, context.CancellationToken);
}
private IEnumerable<CodeAction> GetFixesCore(Document document, SyntaxNode root, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
{
foreach (var diagnostic in diagnostics)
foreach (var diagnostic in context.Diagnostics)
{
var expression = root.FindNode(diagnostic.Location.SourceSpan) as TExpressionSyntax;
if (expression != null)
{
yield return new MyCodeAction(
"Append .ConfigureAwait(" + FalseLiteralString + ")",
c => GetFix(document, root, expression, c));
context.RegisterFix(
new MyCodeAction(
"Append .ConfigureAwait(" + FalseLiteralString + ")",
c => GetFix(context.Document, root, expression, c)),
diagnostic);
}
}
}
......
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
......@@ -51,11 +51,12 @@ private void VerifyFix(Document document, DiagnosticAnalyzer analyzer, CodeFixPr
}
var attempts = analyzerDiagnostics.Length;
for (int i = 0; i < attempts; ++i)
{
var context = new CodeFixContext(document, analyzerDiagnostics[0], CancellationToken.None);
var actions = codeFixProvider.GetFixesAsync(context).Result;
var actions = new List<CodeAction>();
var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
codeFixProvider.ComputeFixesAsync(context).Wait();
if (!actions.Any())
{
break;
......@@ -68,7 +69,7 @@ private void VerifyFix(Document document, DiagnosticAnalyzer analyzer, CodeFixPr
}
document = document.Apply(actions.ElementAt(0));
analyzerDiagnostics = GetSortedDiagnostics(analyzer, document, useCompilerAnalyzerDriver: useCompilerAnalyzerDriver);
var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, document.GetSemanticModelAsync().Result.GetDiagnostics());
if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
......@@ -149,4 +150,4 @@ private static IEnumerable<Diagnostic> GetDiagnosticsUsingCompilerAnalyzerDriver
return diagnostics;
}
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
......@@ -32,11 +31,12 @@ public sealed override FixAllProvider GetFixAllProvider()
return null;
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
Debug.Assert(root != null);
var parent = root.FindToken(diagnosticSpan.Start).Parent;
......@@ -45,11 +45,12 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
// Find the type declaration identified by the diagnostic.
var variableDeclaration = parent.FirstAncestorOrSelf<VariableDeclarationSyntax>();
// Return a code action that will invoke the fix.
return new[] { new AsyncLambdaVariableCodeAction("Async lambdas should not be stored in void-returning delegates", c => ChangeToFunc(context.Document, variableDeclaration, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new AsyncLambdaVariableCodeAction("Async lambdas should not be stored in void-returning delegates",
c => ChangeToFunc(context.Document, variableDeclaration, c)),
diagnostic);
}
return ImmutableArray<CodeAction>.Empty;
}
private async Task<Document> ChangeToFunc(Document document, VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken)
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
......@@ -30,17 +29,21 @@ public sealed override FixAllProvider GetFixAllProvider()
return null;
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
// Return a code action that will invoke the fix.
return new[] { new AsyncVoidCodeAction("Async methods should not return void", c => VoidToTaskAsync(context.Document, methodDeclaration, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new AsyncVoidCodeAction("Async methods should not return void",
c => VoidToTaskAsync(context.Document, methodDeclaration, c)),
diagnostic);
}
private async Task<Document> VoidToTaskAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
......@@ -26,11 +25,12 @@ public sealed override ImmutableArray<string> GetFixableDiagnosticIds()
return ImmutableArray.Create(BlockingAsyncAnalyzer.BlockingAsyncId);
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var invocation = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<InvocationExpressionSyntax>();
......@@ -46,50 +46,72 @@ public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFix
{
var name = invokemethod.Name.Identifier.Text;
// Return a code action that will invoke the fix.
return new[] { new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart", c => ChangetoAwaitAsync(context.Document, invocation, c, name)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitAsync(context.Document, invocation, c, name)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("GetAwaiter"))
{
// Return a code action that will invoke the fix.
return new[] { new CodeActionChangetoAwaitGetAwaiterAsync("Change synchronous operation to asynchronous counterpart", c => ChangetoAwaitGetAwaiterAsync(context.Document, invocation, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionChangetoAwaitGetAwaiterAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitGetAwaiterAsync(context.Document, invocation, c)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("Result"))
{
var name = invokemethod.Name.Identifier.Text;
// Return a code action that will invoke the fix.
return new[] { new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart", c => ChangetoAwaitAsync(context.Document, invocation, c, name)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionChangetoAwaitAsync("Change synchronous operation to asynchronous counterpart",
c => ChangetoAwaitAsync(context.Document, invocation, c, name)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("WaitAny"))
{
var name = invokemethod.Name.Identifier.Text;
// Return a code action that will invoke the fix.
return new[] { new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart", c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("WaitAll"))
{
var name = invokemethod.Name.Identifier.Text;
// Return a code action that will invoke the fix.
return new[] { new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart", c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)),
diagnostic);
return;
}
if (invokemethod != null && invokemethod.Name.Identifier.Text.Equals("Sleep"))
{
var name = invokemethod.Name.Identifier.Text;
// Return a code action that will invoke the fix.
return new[] { new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart", c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CodeActionToDelayWhenAnyWhenAllAsync("Change synchronous operation to asynchronous counterpart",
c => ToDelayWhenAnyWhenAllAsync(context.Document, invocation, c, name)),
diagnostic);
return;
}
}
return ImmutableArray<CodeAction>.Empty;
}
private async Task<Document> ToDelayWhenAnyWhenAllAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken c, string name)
......@@ -139,7 +161,7 @@ private async Task<Document> ChangetoAwaitAsync(Document document, InvocationExp
{
oldExpression = invocation.Parent.FirstAncestorOrSelf<MemberAccessExpressionSyntax>();
newExpression = SyntaxFactory.PrefixUnaryExpression(
SyntaxKind.AwaitExpression,
SyntaxKind.AwaitExpression,
invocation).WithAdditionalAnnotations(Formatter.Annotation);
}
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
......@@ -29,17 +28,21 @@ public sealed override FixAllProvider GetFixAllProvider()
return null;
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var invocation = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<InvocationExpressionSyntax>();
// Return a code action that will invoke the fix.
return new[] { new CancellationCodeAction("Propagate CancellationTokens when possible", c => AddCancellationTokenAsync(context.Document, invocation, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new CancellationCodeAction("Propagate CancellationTokens when possible",
c => AddCancellationTokenAsync(context.Document, invocation, c)),
diagnostic);
}
private async Task<Document> AddCancellationTokenAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
......@@ -25,17 +24,21 @@ public sealed override ImmutableArray<string> GetFixableDiagnosticIds()
return ImmutableArray.Create(RenameAsyncAnalyzer.RenameAsyncId);
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the type declaration identified by the diagnostic.
var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
// Return a code action that will invoke the fix. (The name is intentional; that's my sense of humor)
return new[] { new RenameAsyncCodeAction("Add Async to the end of the method name", c => RenameMethodAsync(context.Document, methodDeclaration, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(
new RenameAsyncCodeAction("Add Async to the end of the method name",
c => RenameMethodAsync(context.Document, methodDeclaration, c)),
diagnostic);
}
private async Task<Solution> RenameMethodAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
......
......@@ -5,6 +5,8 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CodeActions;
namespace TestTemplate
{
......@@ -75,11 +77,12 @@ private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProv
var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document });
var compilerDiagnostics = GetCompilerDiagnostics(document);
var attempts = analyzerDiagnostics.Length;
for (int i = 0; i < attempts; ++i)
{
var context = new CodeFixContext(document, analyzerDiagnostics[0], CancellationToken.None);
var actions = codeFixProvider.GetFixesAsync(context).Result;
var actions = new List<CodeAction>();
var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
codeFixProvider.ComputeFixesAsync(context).Wait();
if (!actions.Any())
{
break;
......@@ -121,4 +124,4 @@ private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProv
Assert.AreEqual(newSource, actual);
}
}
}
}
\ No newline at end of file
......@@ -21,7 +21,6 @@
// *********************************************************
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
......@@ -31,14 +30,13 @@
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace ConvertToAutoPropertyCS
{
[ExportCodeRefactoringProvider("ConvertToAutoPropertyCS", LanguageNames.CSharp), Shared]
internal class ConvertToAutoPropertyCodeRefactoringProvider : CodeRefactoringProvider
{
public sealed override async Task<IEnumerable<CodeAction>> GetRefactoringsAsync(CodeRefactoringContext context)
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var textSpan = context.Span;
......@@ -48,7 +46,7 @@ public sealed override async Task<IEnumerable<CodeAction>> GetRefactoringsAsync(
var token = root.FindToken(textSpan.Start);
if (token.Parent == null)
{
return null;
return;
}
var propertyDeclaration = token.Parent.FirstAncestorOrSelf<PropertyDeclarationSyntax>();
......@@ -58,10 +56,12 @@ public sealed override async Task<IEnumerable<CodeAction>> GetRefactoringsAsync(
!HasBothAccessors(propertyDeclaration) ||
!propertyDeclaration.Identifier.Span.IntersectsWith(textSpan.Start))
{
return null;
return;
}
return new[] { new ConvertToAutoPropertyCodeAction("Convert to auto property", (c) => ConvertToAutoPropertyAsync(document, propertyDeclaration, c)) };
context.RegisterRefactoring(
new ConvertToAutoPropertyCodeAction("Convert to auto property",
(c) => ConvertToAutoPropertyAsync(document, propertyDeclaration, c)));
}
/// <summary>
......
......@@ -20,7 +20,6 @@
//
// *********************************************************
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
......@@ -32,14 +31,13 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
namespace ImplementNotifyPropertyChangedCS
{
[ExportCodeRefactoringProvider("ImplementNotifyPropertyChangedCS", LanguageNames.CSharp), Shared]
internal partial class ImplementNotifyPropertyChangedCodeRefactoringProvider : CodeRefactoringProvider
{
public sealed override async Task<IEnumerable<CodeAction>> GetRefactoringsAsync(CodeRefactoringContext context)
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var textSpan = context.Span;
......@@ -60,11 +58,14 @@ public sealed override async Task<IEnumerable<CodeAction>> GetRefactoringsAsync(
var properties = ExpansionChecker.GetExpandableProperties(textSpan, root, model);
if (properties.Any())
{
#pragma warning disable RS0005
return properties.Any()
? new[] { CodeAction.Create("Apply INotifyPropertyChanged pattern", (c) => ImplementNotifyPropertyChangedAsync(document, root, model, properties, c)) }
: null;
context.RegisterRefactoring(
CodeAction.Create("Apply INotifyPropertyChanged pattern", (c) =>
ImplementNotifyPropertyChangedAsync(document, root, model, properties, c)));
#pragma warning restore RS0005
}
}
private async Task<Document> ImplementNotifyPropertyChangedAsync(Document document, CompilationUnitSyntax root, SemanticModel model, IEnumerable<ExpandablePropertyInfo> properties, CancellationToken cancellationToken)
......@@ -75,4 +76,4 @@ private async Task<Document> ImplementNotifyPropertyChangedAsync(Document docume
return document;
}
}
}
}
\ No newline at end of file
......@@ -20,7 +20,6 @@
//
// *********************************************************
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
......@@ -49,17 +48,18 @@ public sealed override FixAllProvider GetFixAllProvider()
return null;
}
public sealed override async Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context)
public sealed override async Task ComputeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
var diagnosticSpan = context.Diagnostics.First().Location.SourceSpan;
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find the local declaration identified by the diagnostic.
var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<LocalDeclarationStatementSyntax>().First();
// return a code action that will invoke the fix.
return new[] { CodeAction.Create("Make constant", c => MakeConstAsync(context.Document, declaration, c)) };
// Register a code action that will invoke the fix.
context.RegisterFix(CodeAction.Create("Make constant", c => MakeConstAsync(context.Document, declaration, c)), diagnostic);
}
private async Task<Document> MakeConstAsync(Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken)
......
......@@ -36,8 +36,10 @@ public abstract class CodeRefactoringProviderTestFixture : CodeActionProviderTes
private IEnumerable<CodeAction> GetRefactoring(Document document, TextSpan span)
{
var provider = CreateCodeRefactoringProvider();
var context = new CodeRefactoringContext(document, span, CancellationToken.None);
return provider.GetRefactoringsAsync(context).Result;
var actions = new List<CodeAction>();
var context = new CodeRefactoringContext(document, span, (a) => actions.Add(a), CancellationToken.None);
provider.ComputeRefactoringsAsync(context).Wait();
return actions;
}
protected void TestNoActions(string markup)
......@@ -91,4 +93,4 @@ protected void TestNoActions(string markup)
protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider();
}
}
}
\ No newline at end of file
......@@ -36,7 +36,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Class ConvertToAutoPropertyCodeRefactoringProvider
Inherits CodeRefactoringProvider
Public NotOverridable Overrides Async Function GetRefactoringsAsync(context As CodeRefactoringContext) As Task(Of IEnumerable(Of CodeAction))
Public NotOverridable Overrides Async Function ComputeRefactoringsAsync(context As CodeRefactoringContext) As Task
Dim document = context.Document
Dim textSpan = context.Span
Dim cancellationToken = context.CancellationToken
......@@ -44,19 +44,21 @@ Class ConvertToAutoPropertyCodeRefactoringProvider
Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
Dim token = root.FindToken(textSpan.Start)
If token.Parent Is Nothing Then
Return Nothing
Return
End If
Dim propertyBlock = token.Parent.FirstAncestorOrSelf(Of PropertyBlockSyntax)()
If propertyBlock Is Nothing OrElse Not HasBothAccessors(propertyBlock) OrElse Not propertyBlock.Span.IntersectsWith(textSpan.Start) Then
Return Nothing
Return
End If
' TODO: Check that the property can be converted to an auto-property.
' It should be a simple property with a getter and setter that simply retrieves
' and assigns a backing field. In addition, the backing field should be private.
Return {New ConvertToAutopropertyCodeAction("Convert to auto property", Function(c) ConvertToAutoAsync(document, propertyBlock, c))}
context.RegisterRefactoring(
New ConvertToAutopropertyCodeAction("Convert to auto property",
Function(c) ConvertToAutoAsync(document, propertyBlock, c)))
End Function
''' <summary>
......@@ -135,7 +137,7 @@ Class ConvertToAutoPropertyCodeRefactoringProvider
Dim oldRoot = DirectCast(Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False), SyntaxNode)
Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
Dim referenceRewriter = New referenceRewriter(propertyName, backingField, semanticModel)
Dim referenceRewriter = New ReferenceRewriter(propertyName, backingField, semanticModel)
Dim newRoot = referenceRewriter.Visit(oldRoot)
Return document.WithSyntaxRoot(newRoot)
......
......@@ -35,7 +35,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Friend Class ImplementNotifyPropertyChangedCodeRefactoringProvider
Inherits CodeRefactoringProvider
Public NotOverridable Overrides Async Function GetRefactoringsAsync(context As CodeRefactoringContext) As Task(Of IEnumerable(Of CodeAction))
Public NotOverridable Overrides Async Function ComputeRefactoringsAsync(context As CodeRefactoringContext) As Task
Dim document = context.Document
Dim textSpan = context.Span
Dim cancellationToken = context.CancellationToken
......@@ -53,11 +53,13 @@ Friend Class ImplementNotifyPropertyChangedCodeRefactoringProvider
Dim properties = ExpansionChecker.GetExpandableProperties(textSpan, root, model)
If properties.Any Then
#Disable Warning RS0005
Return If(properties.Any(),
{CodeAction.Create("Apply INotifyPropertyChanged pattern", Function(c) ImplementNotifyPropertyChangedAsync(document, root, model, properties, c))},
Nothing)
context.RegisterRefactoring(
CodeAction.Create("Apply INotifyPropertyChanged pattern",
Function(c) ImplementNotifyPropertyChangedAsync(document, root, model, properties, c)))
#Enable Warning RS0005
End If
End Function
Private Async Function ImplementNotifyPropertyChangedAsync(document As Document, root As CompilationUnitSyntax, model As SemanticModel, properties As IEnumerable(Of ExpandablePropertyInfo), cancellationToken As CancellationToken) As Task(Of Document)
......@@ -66,4 +68,4 @@ Friend Class ImplementNotifyPropertyChangedCodeRefactoringProvider
document = Await Formatter.FormatAsync(document, Formatter.Annotation, cancellationToken:=cancellationToken).ConfigureAwait(False)
Return document
End Function
End Class
End Class
\ No newline at end of file
......@@ -43,15 +43,16 @@ Class MakeConstCodeFixProvider
Return Nothing
End Function
Public NotOverridable Overrides Async Function GetFixesAsync(context As CodeFixContext) As Task(Of IEnumerable(Of CodeAction))
Dim diagnosticSpan = context.Diagnostics.First().Location.SourceSpan
Public NotOverridable Overrides Async Function ComputeFixesAsync(context As CodeFixContext) As Task
Dim diagnostic = context.Diagnostics.First()
Dim diagnosticSpan = diagnostic.Location.SourceSpan
Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken)
' Find the local declaration identified by the diagnostic.
Dim declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType(Of LocalDeclarationStatementSyntax)().First()
' return a code action that will invoke the fix
Return {CodeAction.Create("Make constant", Function(c) MakeConstAsync(context.Document, declaration, c))}
' Register a code action that will invoke the fix.
context.RegisterFix(CodeAction.Create("Make constant", Function(c) MakeConstAsync(context.Document, declaration, c)), diagnostic)
End Function
Private Async Function MakeConstAsync(document As Document, localDeclaration As LocalDeclarationStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document)
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeActions;
namespace Microsoft.CodeAnalysis.CodeFixes
{
/// <summary>
/// Represents a single fix. This is essentially a tuple
/// that holds on to a <see cref="CodeAction"/> and the set of
/// <see cref="Diagnostic"/>s that this <see cref="CodeAction"/> will fix.
/// </summary>
internal class CodeFix
{
internal readonly CodeAction Action;
internal readonly ImmutableArray<Diagnostic> Diagnostics;
internal CodeFix(CodeAction action, Diagnostic diagnostic)
{
this.Action = action;
this.Diagnostics = ImmutableArray.Create(diagnostic);
}
internal CodeFix(CodeAction action, IEnumerable<Diagnostic> diagnostics)
{
this.Action = action;
this.Diagnostics = diagnostics.ToImmutableArray();
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. 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;
using System.Threading;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
......@@ -31,35 +36,96 @@ public struct CodeFixContext
/// </summary>
public IEnumerable<Diagnostic> Diagnostics { get { return this.diagnostics; } }
private readonly Action<CodeAction, IEnumerable<Diagnostic>> registerFix;
/// <summary>
/// CancellationToken.
/// </summary>
public CancellationToken CancellationToken { get { return this.cancellationToken; } }
/// <summary>
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.GetFixesAsync(CodeFixContext)"/> method.
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.ComputeFixesAsync(CodeFixContext)"/> method.
/// </summary>
public CodeFixContext(
Document document,
TextSpan span,
IEnumerable<Diagnostic> diagnostics,
Action<CodeAction, IEnumerable<Diagnostic>> registerFix,
CancellationToken cancellationToken)
{
this.document = document;
this.span = span;
this.diagnostics = diagnostics;
this.registerFix = registerFix;
this.cancellationToken = cancellationToken;
}
/// <summary>
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.GetFixesAsync(CodeFixContext)"/> method.
/// Creates a code fix context to be passed into <see cref="CodeFixProvider.ComputeFixesAsync(CodeFixContext)"/> method.
/// </summary>
public CodeFixContext(
Document document,
Diagnostic diagnostic,
Action<CodeAction, IEnumerable<Diagnostic>> registerFix,
CancellationToken cancellationToken)
: this(document, diagnostic.Location.SourceSpan, SpecializedCollections.SingletonEnumerable(diagnostic), cancellationToken)
: this(document, diagnostic.Location.SourceSpan, SpecializedCollections.SingletonEnumerable(diagnostic), registerFix, cancellationToken)
{
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of fixes that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the fix.</param>
/// <param name="diagnostic">The subset of <see cref="Diagnostics"/> being addressed / fixed by the <paramref name="action"/>.</param>
public void RegisterFix(CodeAction action, Diagnostic diagnostic)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
if (diagnostic == null)
{
throw new ArgumentNullException(nameof(diagnostic));
}
this.registerFix(action, ImmutableArray.Create(diagnostic));
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of fixes that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the fix.</param>
/// <param name="diagnostics">The subset of <see cref="Diagnostics"/> being addressed / fixed by the <paramref name="action"/>.</param>
public void RegisterFix(CodeAction action, IEnumerable<Diagnostic> diagnostics)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
if (diagnostics == null)
{
throw new ArgumentNullException(nameof(diagnostics));
}
var diagnosticsArray = diagnostics.ToImmutableArray();
if (diagnosticsArray.Length == 0)
{
throw new ArgumentException(WorkspacesResources.DiagnosticsCannotBeEmpty, nameof(diagnostics));
}
if (diagnosticsArray.Any(d => d == null))
{
throw new ArgumentException(WorkspacesResources.DiagnoisticCannotBeNull, nameof(diagnostics));
}
// TODO:
// - Check that all diagnostics are unique (no duplicates).
// - Check that supplied diagnostics form subset of diagnostics originally
// passed to the provider via CodeFixContext.Diagnostics.
this.registerFix(action, diagnosticsArray);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
namespace Microsoft.CodeAnalysis.CodeFixes
{
......@@ -18,10 +16,9 @@ public abstract class CodeFixProvider
public abstract ImmutableArray<string> GetFixableDiagnosticIds();
/// <summary>
/// Gets one or more fixes for the specified code fix context represented as a list of <see cref="CodeAction"/>'s.
/// Computes one or more fixes for the specified <see cref="CodeFixContext"/>.
/// </summary>
/// <returns>A list of zero or more potential <see cref="CodeAction"/>. It is also safe to return null if there are none.</returns>
public abstract Task<IEnumerable<CodeAction>> GetFixesAsync(CodeFixContext context);
public abstract Task ComputeFixesAsync(CodeFixContext context);
/// <summary>
/// Gets an optional <see cref="FixAllProvider"/> that can fix all/multiple occurrences of diagnostics fixed by this code fix provider.
......@@ -31,4 +28,4 @@ public abstract class CodeFixProvider
/// <returns></returns>
public abstract FixAllProvider GetFixAllProvider();
}
}
}
\ No newline at end of file
......@@ -91,17 +91,30 @@ public async virtual Task AddDocumentFixesAsync(Document document, IEnumerable<D
var diagnostic = diagnosticsArray[i];
fixerTasks[i] = Task.Run(async () =>
{
var context = new CodeFixContext(document, diagnostic, cancellationToken);
var fixes = await fixAllContext.CodeFixProvider.GetFixesAsync(context).ConfigureAwait(false);
var fixes = new List<CodeAction>();
var context = new CodeFixContext(document, diagnostic,
if (fixes != null)
{
foreach (var fix in fixes)
// TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs?
(a, d) =>
{
if (fix != null && fix.Id == fixAllContext.CodeActionId)
// Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from.
lock (fixes)
{
addFix(fix);
fixes.Add(a);
}
},
cancellationToken);
// TODO: Wrap call to ComputeFixesAsync() below in IExtensionManager.PerformFunctionAsync() so that
// a buggy extension that throws can't bring down the host?
var task = fixAllContext.CodeFixProvider.ComputeFixesAsync(context) ?? SpecializedTasks.EmptyTask;
await task.ConfigureAwait(false);
foreach (var fix in fixes)
{
if (fix != null && fix.Id == fixAllContext.CodeActionId)
{
addFix(fix);
}
}
});
......
// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeRefactorings
......@@ -23,22 +26,40 @@ public struct CodeRefactoringContext
/// </summary>
public TextSpan Span { get { return this.span; } }
private readonly Action<CodeAction> registerRefactoring;
/// <summary>
/// CancellationToken.
/// </summary>
public CancellationToken CancellationToken { get { return this.cancellationToken; } }
/// <summary>
/// Creates a code refactoring context to be passed into <see cref="CodeRefactoringProvider.GetRefactoringsAsync(CodeRefactoringContext)"/> method.
/// Creates a code refactoring context to be passed into <see cref="CodeRefactoringProvider.ComputeRefactoringsAsync(CodeRefactoringContext)"/> method.
/// </summary>
public CodeRefactoringContext(
Document document,
TextSpan span,
TextSpan span,
Action<CodeAction> registerRefactoring,
CancellationToken cancellationToken)
{
this.document = document;
this.span = span;
this.registerRefactoring = registerRefactoring;
this.cancellationToken = cancellationToken;
}
/// <summary>
/// Add supplied <paramref name="action"/> to the list of refactorings that will be offered to the user.
/// </summary>
/// <param name="action">The <see cref="CodeAction"/> that will be invoked to apply the refactoring.</param>
public void RegisterRefactoring(CodeAction action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
this.registerRefactoring(action);
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeRefactorings
{
......@@ -14,9 +10,8 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings
public abstract class CodeRefactoringProvider
{
/// <summary>
/// Gets refactorings that are applicable within the span of the document represented as a list of <see cref="CodeAction"/>'s.
/// Computes one or more refactorings for the specified <see cref="CodeRefactoringContext"/>.
/// </summary>
/// <returns>A list of zero or more applicable <see cref="CodeAction"/>'s. It is also safe to return null if there are none.</returns>
public abstract Task<IEnumerable<CodeAction>> GetRefactoringsAsync(CodeRefactoringContext context);
public abstract Task ComputeRefactoringsAsync(CodeRefactoringContext context);
}
}
\ No newline at end of file
......@@ -7,6 +7,7 @@
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Extensions
{
......@@ -56,6 +57,29 @@ public static void PerformAction(this IExtensionManager extensionManager, object
return defaultValue;
}
public static async Task PerformActionAsync(
this IExtensionManager extensionManager,
object extension,
Func<Task> function)
{
try
{
if (!extensionManager.IsDisabled(extension))
{
var task = function() ?? SpecializedTasks.EmptyTask;
await task.ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception e)
{
extensionManager.HandleException(extension, e);
}
}
public static async Task<T> PerformFunctionAsync<T>(
this IExtensionManager extensionManager,
object extension,
......@@ -66,7 +90,8 @@ public static void PerformAction(this IExtensionManager extensionManager, object
{
if (!extensionManager.IsDisabled(extension))
{
return await function().ConfigureAwait(false);
var task = function() ?? SpecializedTasks.Default<T>();
return await task.ConfigureAwait(false);
}
}
catch (OperationCanceledException)
......
......@@ -318,6 +318,7 @@
<Compile Include="CodeFixes\FixAllOccurrences\FixAllContext.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixAllScope.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixAllProvider.cs" />
<Compile Include="CodeFixes\CodeFix.cs" />
<Compile Include="CodeGeneration\AbstractCodeGenerationService.cs" />
<Compile Include="CodeGeneration\AbstractCodeGenerationService_FindDeclaration.cs" />
<Compile Include="CodeGeneration\AbstractFlagsEnumGenerator.cs" />
......
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17
// Runtime Version:4.0.30319.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
......@@ -295,6 +295,24 @@ internal class WorkspacesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Supplied diagnostic cannot be null..
/// </summary>
internal static string DiagnoisticCannotBeNull {
get {
return ResourceManager.GetString("DiagnoisticCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to At least one diagnostic must be supplied..
/// </summary>
internal static string DiagnosticsCannotBeEmpty {
get {
return ResourceManager.GetString("DiagnosticsCannotBeEmpty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The solution already contains the specified document..
/// </summary>
......
......@@ -405,4 +405,10 @@
<data name="WorkspaceServicesUnavailable" xml:space="preserve">
<value>Services required to accomplish the task are not available from the workspace.</value>
</data>
<data name="DiagnoisticCannotBeNull" xml:space="preserve">
<value>Supplied diagnostic cannot be null.</value>
</data>
<data name="DiagnosticsCannotBeEmpty" xml:space="preserve">
<value>At least one diagnostic must be supplied.</value>
</data>
</root>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册