diff options
author | Lluis Sanchez Gual <lluis@xamarin.com> | 2015-04-20 19:07:51 +0300 |
---|---|---|
committer | Lluis Sanchez Gual <lluis@xamarin.com> | 2015-04-20 19:07:51 +0300 |
commit | 95408b1a41b31b645f3a8c3323ab7d3ca4bff26b (patch) | |
tree | f8f137cddcb9a40499d303be95722fd2c6081bce /main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs | |
parent | b70e4e04b4e41b8ec28d7e4b220b401ecf467e7a (diff) | |
parent | de043d330a8bf5855d4d983c804cd36727cb2406 (diff) |
Merge remote-tracking branch 'origin/roslyn' into new-project-model
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs')
-rw-r--r-- | main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs new file mode 100644 index 0000000000..be3ccc4cd3 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.CodeFixes/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs @@ -0,0 +1,143 @@ +// 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.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; +using Microsoft.CodeAnalysis; +using MonoDevelop.CSharp.Diagnostics; +using ICSharpCode.NRefactory6.CSharp; +using MonoDevelop.Core; +using System; +using Microsoft.CodeAnalysis.CSharp; +using ICSharpCode.NRefactory6.CSharp.Refactoring; +using MonoDevelop.CSharp.Diagnostics.SimplifyTypeNames; + +namespace MonoDevelop.CSharp.CodeFixes.SimplifyTypeNames +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.SimplifyNames), Shared] + [ExtensionOrder(After = PredefinedCodeFixProviderNames.RemoveUnnecessaryCast)] + internal partial class SimplifyTypeNamesCodeFixProvider : CodeFixProvider + { + public sealed override ImmutableArray<string> FixableDiagnosticIds + { + get + { + return ImmutableArray.Create( + IDEDiagnosticIds.SimplifyNamesDiagnosticId, + IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId, + IDEDiagnosticIds.SimplifyThisOrMeDiagnosticId); + } + } + +// public sealed override FixAllProvider GetFixAllProvider() +// { +// return SimplifyTypeNamesFixAllProvider.Instance; +// } + + internal static SyntaxNode GetNodeToSimplify(SyntaxNode root, SemanticModel model, TextSpan span, OptionSet optionSet, out string diagnosticId, CancellationToken cancellationToken) + { + diagnosticId = null; + var token = root.FindToken(span.Start, findInsideTrivia: true); + if (!token.Span.IntersectsWith(span)) + { + return null; + } + + foreach (var n in token.GetAncestors<SyntaxNode>()) + { + if (n.Span.IntersectsWith(span) && CanSimplifyTypeNameExpression(model, n, optionSet, span, out diagnosticId, cancellationToken)) + { + return n; + } + } + + return null; + } + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var document = context.Document; + var span = context.Span; + var cancellationToken = context.CancellationToken; + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var optionSet = document.Project.Solution.Workspace.Options; + string diagnosticId; + var node = GetNodeToSimplify(root, model, span, optionSet, out diagnosticId, cancellationToken); + if (node == null) + { + return; + } + + var id = GetCodeActionId(diagnosticId, node.ToString()); + var title = id; + var codeAction = new DocumentChangeAction(node.Span, DiagnosticSeverity.Warning, title, + (c) => SimplifyTypeNameAsync(document, node, c)); + + context.RegisterCodeFix(codeAction, context.Diagnostics); + } + + // internal for testing purpose + internal static string GetCodeActionId(string diagnosticId, string nodeText) + { + switch (diagnosticId) + { + case IDEDiagnosticIds.SimplifyNamesDiagnosticId: + return string.Format(GettextCatalog.GetString ("Simplify name '{0}'"), nodeText); + + case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId: + return string.Format(GettextCatalog.GetString ("Simplify member access '{0}'"), nodeText); + + case IDEDiagnosticIds.SimplifyThisOrMeDiagnosticId: + return GettextCatalog.GetString ("Remove 'this' qualification"); + + default: + throw new InvalidOperationException(); + } + } + + private static bool CanSimplifyTypeNameExpression(SemanticModel model, SyntaxNode node, OptionSet optionSet, TextSpan span, out string diagnosticId, CancellationToken cancellationToken) + { + diagnosticId = null; + TextSpan issueSpan; + if (!CSharpSimplifyTypeNamesDiagnosticAnalyzer.IsCandidate(node) || + !CSharpSimplifyTypeNamesDiagnosticAnalyzer.CanSimplifyTypeNameExpression(model, node, optionSet, out issueSpan, out diagnosticId, cancellationToken)) + { + return false; + } + + return issueSpan.Equals(span); + } + + private async Task<Document> SimplifyTypeNameAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) + { + var expressionSyntax = node; + var annotatedexpressionSyntax = expressionSyntax.WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation); + + if (annotatedexpressionSyntax.Kind() == SyntaxKind.IsExpression || annotatedexpressionSyntax.Kind() == SyntaxKind.AsExpression) + { + var right = ((BinaryExpressionSyntax)annotatedexpressionSyntax).Right; + annotatedexpressionSyntax = annotatedexpressionSyntax.ReplaceNode(right, right.WithAdditionalAnnotations(Simplifier.Annotation)); + } + + SyntaxNode oldNode = expressionSyntax; + SyntaxNode newNode = annotatedexpressionSyntax; + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = root.ReplaceNode(oldNode, newNode); + + return document.WithSyntaxRoot(newRoot); + } + } +} |