diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs index 266cf1f0dbe505043f02ba5b874345c1f615d544..00375be3b46a504935ae6c4cb13f2df8b7c4a01d 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs @@ -59,7 +59,7 @@ static void Main() { int x = 2; int i = 1; - Goo((x < i), x > (2 + 3)); + Goo(x < (i), x > (2 + 3)); } static void Goo(bool a, bool b) { } @@ -3550,7 +3550,7 @@ class C { void Goo(Task x) { - x.Result(); + (x.Result)(); } } "); diff --git a/src/EditorFeatures/Test2/Simplification/CastSimplificationTests.vb b/src/EditorFeatures/Test2/Simplification/CastSimplificationTests.vb index 8970ae9341b13d21e9093f729fe153afc39ce84e..43646030879258aff03a4ff26759cae2b57d42f9 100644 --- a/src/EditorFeatures/Test2/Simplification/CastSimplificationTests.vb +++ b/src/EditorFeatures/Test2/Simplification/CastSimplificationTests.vb @@ -367,7 +367,7 @@ class C { void M() { - System.Action a = (() => { }); + System.Action a = () => { }; } } @@ -401,13 +401,12 @@ class C void M() { System.Action a = null; - a = (() => { }); + a = () => { }; } } Await TestAsync(input, expected) - End Function @@ -435,7 +434,7 @@ class C { void M() { - Goo((() => "Goo")); + Goo(() => "Goo"); } void Goo<T>(System.Func<T> f) { } @@ -471,7 +470,7 @@ class C { void M() { - Goo(f: (() => "Goo")); + Goo(f: () => "Goo"); } void Goo<T>(System.Func<T> f) { } @@ -3207,7 +3206,7 @@ static class Program { static void Main() { - new Action((y => Goo(1)))(null); + new Action(y => Goo(1))(null); } static void Goo(this object x) { Console.WriteLine(1); } @@ -3254,7 +3253,7 @@ static class Program { static void Main() { - new Action(((y) => { string x = y; x.Goo(); }))(null); + new Action((y) => { string x = y; x.Goo(); })(null); } static void Goo(this object x) { Console.WriteLine(1); } @@ -3397,7 +3396,7 @@ static class Program { static void Main() { - new Action(((y, z) => { object x = y; z.Goo(); }))(null, null); + new Action((y, z) => { object x = y; z.Goo(); })(null, null); } static void Goo(this object x) { Console.WriteLine(1); } @@ -3533,7 +3532,7 @@ class Program { static void Main(string[] args) { - Func f = (() => new ArgumentException()); + Func f = () => new ArgumentException(); } } ]]> diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index 6ea4c2bf68eaeb26c11b82fa01f32c55a8285f77..85cdd571a9b0e5ff1a3e304b68bedb08aae21e02 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs @@ -215,15 +215,6 @@ internal class CSharpFeaturesResources { } } - /// - /// Looks up a localized string similar to Cast is redundant. - /// - internal static string Cast_is_redundant { - get { - return ResourceManager.GetString("Cast_is_redundant", resourceCulture); - } - } - /// /// Looks up a localized string similar to catch clause. /// @@ -827,15 +818,6 @@ internal class CSharpFeaturesResources { } } - /// - /// Looks up a localized string similar to Remove Unnecessary Cast. - /// - internal static string Remove_Unnecessary_Cast { - get { - return ResourceManager.GetString("Remove_Unnecessary_Cast", resourceCulture); - } - } - /// /// Looks up a localized string similar to Remove Unnecessary Usings. /// diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 8a6e64efd658b39660ab7d69ad9d96c7513a4d98..e74b5f75fada2b203c7e4e7e18612d836f31f7be 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -159,12 +159,6 @@ Autoselect disabled due to potential range variable declaration. - - Remove Unnecessary Cast - - - Cast is redundant - Simplify name '{0}' diff --git a/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.cs b/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.cs deleted file mode 100644 index 88533ac702aaf17a1aeec38a11720cf20bebdec2..0000000000000000000000000000000000000000 --- a/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveUnnecessaryCast -{ - internal partial class RemoveUnnecessaryCastCodeFixProvider : CodeFixProvider - { - private class RemoveUnnecessaryCastFixAllProvider : BatchSimplificationFixAllProvider - { - internal static new readonly RemoveUnnecessaryCastFixAllProvider Instance = new RemoveUnnecessaryCastFixAllProvider(); - - protected override SyntaxNode GetNodeToSimplify(SyntaxNode root, SemanticModel model, Diagnostic diagnostic, DocumentOptionSet options, out string codeActionId, CancellationToken cancellationToken) - { - codeActionId = null; - return GetCastNode(root, model, diagnostic.Location.SourceSpan, cancellationToken); - } - - protected override bool NeedsParentFixup => true; - - protected override async Task AddSimplifyAnnotationsAsync(Document document, SyntaxNode nodeToSimplify, CancellationToken cancellationToken) - { - var cast = nodeToSimplify as CastExpressionSyntax; - if (cast == null) - { - return null; - } - - return await RemoveUnnecessaryCastAsync(document, cast, cancellationToken).ConfigureAwait(false); - } - } - } -} diff --git a/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.cs index 85d0d29bd672b768d0be47275a842a910b545c4d..43e6db9346f41f8cc50273df64c4f1914d4a9407 100644 --- a/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -21,89 +22,68 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.RemoveUnnecessaryCast { [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.RemoveUnnecessaryCast), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.ImplementInterface)] - internal partial class RemoveUnnecessaryCastCodeFixProvider : CodeFixProvider + internal partial class RemoveUnnecessaryCastCodeFixProvider : SyntaxEditorBasedCodeFixProvider { - public sealed override ImmutableArray FixableDiagnosticIds - { - get { return ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId); } - } - - public sealed override FixAllProvider GetFixAllProvider() - { - return RemoveUnnecessaryCastFixAllProvider.Instance; - } - - private static CastExpressionSyntax GetCastNode(SyntaxNode root, SemanticModel model, TextSpan span, CancellationToken cancellationToken) - { - var token = root.FindToken(span.Start); - if (!token.Span.IntersectsWith(span)) - { - return null; - } - - return token.GetAncestors() - .FirstOrDefault(c => c.Span.IntersectsWith(span) && c.IsUnnecessaryCast(model, cancellationToken)); - } + public sealed override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId); public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { - context.RegisterCodeFix( - new MyCodeAction( - CSharpFeaturesResources.Remove_Unnecessary_Cast, - c => RemoveUnnecessaryCastAsync(context.Document, context.Span, c)), + context.RegisterCodeFix(new MyCodeAction( + FeaturesResources.Remove_Unnecessary_Cast, + c => FixAsync(context.Document, context.Diagnostics.First(), c)), context.Diagnostics); return SpecializedTasks.EmptyTask; } - private static async Task RemoveUnnecessaryCastAsync( - Document document, TextSpan span, CancellationToken cancellationToken) + protected override async Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var cast = GetCastNode(root, model, span, cancellationToken); - return await RemoveUnnecessaryCastAsync(document, cast, cancellationToken).ConfigureAwait(false); + var castNodes = diagnostics.SelectAsArray( + d => (CastExpressionSyntax)d.AdditionalLocations[0].FindNode(getInnermostNodeForTie: true, cancellationToken)); + + await editor.ApplyExpressionLevelSemanticEditsAsync( + document, castNodes, + (semanticModel, castExpression) => castExpression.IsUnnecessaryCast(semanticModel, cancellationToken), + (_, currentRoot, castExpression) => + { + var (oldParent, newParent) = Update(castExpression); + return currentRoot.ReplaceNode(oldParent, newParent); + }, + cancellationToken).ConfigureAwait(false); } - private static async Task RemoveUnnecessaryCastAsync( - Document document, CastExpressionSyntax cast, CancellationToken cancellationToken) + private (ExpressionSyntax, ExpressionSyntax) Update(CastExpressionSyntax castExpression) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var oldParent = castExpression.WalkUpParentheses(); + var newParent = Recurse(oldParent); - var annotatedCast = cast.WithAdditionalAnnotations(Simplifier.Annotation); + return (oldParent, newParent); + } - if (annotatedCast.Expression is ParenthesizedExpressionSyntax) + private ExpressionSyntax Recurse(ExpressionSyntax old) + { + if (old is ParenthesizedExpressionSyntax parenthesizedExpression) { - annotatedCast = annotatedCast.WithExpression( - annotatedCast.Expression.WithAdditionalAnnotations(Simplifier.Annotation)); + // It's common in C# to have to write ((Goo)expr).Etc(). we don't just want to + // remove the cast and produce (expr).Etc(). So we mark all parent parenthesized + // expressions as worthy of simplification. The simplifier will remove these + // if possible, or leave them alone if not. + return parenthesizedExpression.ReplaceNode(parenthesizedExpression.Expression, Recurse(parenthesizedExpression.Expression)) + .WithAdditionalAnnotations(Simplifier.Annotation); } - else + else if (old is CastExpressionSyntax castExpression) { - annotatedCast = annotatedCast.WithExpression( - annotatedCast.Expression.Parenthesize()); + // parenthesize the uncasted value to help ensure any proper parsing. The excess + // parens will be removed if unnecessary. + return castExpression.Uncast().WithAdditionalAnnotations(Formatter.Annotation) + .Parenthesize(); } - - ExpressionSyntax oldNode = cast; - ExpressionSyntax newNode = annotatedCast; - - // Ensure that we simplify any parenting parenthesized expressions not just on the syntax tree level but also on Token based - // Case 1: - // In the syntax, (((Task)x).Result)() - // oldNode = (Task)x - // newNode = (Task)(x) - // Final newNode will be (((Task)(x)).Result) - while (oldNode.Parent.IsKind(SyntaxKind.ParenthesizedExpression) || oldNode.GetFirstToken().GetPreviousToken().Parent.IsKind(SyntaxKind.ParenthesizedExpression)) + else { - var parenthesizedExpression = (ParenthesizedExpressionSyntax)oldNode.GetFirstToken().GetPreviousToken().Parent; - newNode = parenthesizedExpression.ReplaceNode(oldNode, newNode) - .WithAdditionalAnnotations(Simplifier.Annotation); - oldNode = parenthesizedExpression; + throw ExceptionUtilities.UnexpectedValue(old); } - - newNode = newNode.WithAdditionalAnnotations(Formatter.Annotation); - - var newRoot = root.ReplaceNode(oldNode, newNode); - - return document.WithSyntaxRoot(newRoot); } private class MyCodeAction : CodeAction.DocumentChangeAction diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpRemoveUnnecessaryCastDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpRemoveUnnecessaryCastDiagnosticAnalyzer.cs index bc4e1917b08523e22b87b3ab184321b8d80b64f3..6e8c3c00ade8b6d25cda6bd016675077773d9fb6 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpRemoveUnnecessaryCastDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpRemoveUnnecessaryCastDiagnosticAnalyzer.cs @@ -11,22 +11,17 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.RemoveUnnecessaryCast { [DiagnosticAnalyzer(LanguageNames.CSharp)] - internal sealed class CSharpRemoveUnnecessaryCastDiagnosticAnalyzer : RemoveUnnecessaryCastDiagnosticAnalyzerBase + internal sealed class CSharpRemoveUnnecessaryCastDiagnosticAnalyzer + : RemoveUnnecessaryCastDiagnosticAnalyzerBase { private static readonly ImmutableArray s_kindsOfInterest = ImmutableArray.Create(SyntaxKind.CastExpression); - public override ImmutableArray SyntaxKindsOfInterest => s_kindsOfInterest; + protected override ImmutableArray SyntaxKindsOfInterest => s_kindsOfInterest; - protected override bool IsUnnecessaryCast(SemanticModel model, SyntaxNode node, CancellationToken cancellationToken) - { - var cast = (CastExpressionSyntax)node; - return cast.IsUnnecessaryCast(model, cancellationToken); - } + protected override bool IsUnnecessaryCast(SemanticModel model, CastExpressionSyntax cast, CancellationToken cancellationToken) + => cast.IsUnnecessaryCast(model, cancellationToken); - protected override TextSpan GetDiagnosticSpan(SyntaxNode node) - { - var cast = (CastExpressionSyntax)node; - return TextSpan.FromBounds(cast.OpenParenToken.SpanStart, cast.CloseParenToken.Span.End); - } + protected override TextSpan GetFadeSpan(CastExpressionSyntax node) + => TextSpan.FromBounds(node.OpenParenToken.SpanStart, node.CloseParenToken.Span.End); } } diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index 2632d9284e0b95a15f01f29cefe9c1223cac75c7..2c430aed63b564c7ec872237d1d1e6145a45acdb 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -67,16 +67,6 @@ Automatický výběr je zakázaný kvůli možné deklaraci proměnné rozsahu. - - Remove Unnecessary Cast - Odebrat nepotřebné přetypování - - - - Cast is redundant - Přetypování je redundantní. - - Simplify name '{0}' Zjednodušit název {0} diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index eb24dda8f94b27b6c410fa361331fa4332a50e7e..0dc859f31938e5b79f03a233f9e369069e15db8c 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -67,16 +67,6 @@ Automatische Auswahl aufgrund einer potzenziellen Bereichvariablendeklaration deaktiviert. - - Remove Unnecessary Cast - Nicht erforderliche Umwandlung entfernen - - - - Cast is redundant - Cast ist redundant - - Simplify name '{0}' Name '{0}' vereinfachen diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index a1794e7b5eaf370b7a1ee8b3c464e1bf714543b8..0524f1f87af30e97484381db8633cacb98bcb97f 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -67,16 +67,6 @@ La selección automática se ha deshabilitado debido posiblemente a una declaración de variable de rango. - - Remove Unnecessary Cast - Quitar conversión innecesaria - - - - Cast is redundant - Cast es redundante - - Simplify name '{0}' Simplificar nombre '{0}' diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 1f3c71d7002d1de8ffcfd6f53575f9a256e0d1b3..3979916863018bb3c1681d2b20978aa764d6827a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -67,16 +67,6 @@ Sélection automatique désactivée en raison d'une déclaration de variable de plage éventuelle. - - Remove Unnecessary Cast - Supprimer le cast inutile - - - - Cast is redundant - Cast redondant - - Simplify name '{0}' Simplifier le nom '{0}' diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index 66f29826349505108c26291532e87611c3c1f2b9..f1a3606ec51ba6a30198fcce13378fc7d74db16f 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -67,16 +67,6 @@ La selezione automatica è disabilitata a causa di una potenziale dichiarazione della variabile di intervallo. - - Remove Unnecessary Cast - Rimuovi cast non necessario - - - - Cast is redundant - Il cast è ridondante - - Simplify name '{0}' Semplifica il nome '{0}' diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 7078af1bab8879e6dd2f185df8136adbfd3890e3..6d52eb45c7e17a24b05afb1b0150d138520bc207 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -67,16 +67,6 @@ 範囲変数宣言の可能性があるため、自動選択は無効になっています。 - - Remove Unnecessary Cast - 不要なキャストの削除 - - - - Cast is redundant - キャストが冗長です - - Simplify name '{0}' 名前 '{0}' の単純化 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 973b935e20416ce58733082670f2274013434349..939d6b98e7522d6c09106057a958e6f9a1d85140 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -67,16 +67,6 @@ 범위 변수가 선언될 수 있어 자동 선택을 사용하지 않도록 설정했습니다. - - Remove Unnecessary Cast - 불필요한 캐스트 제거 - - - - Cast is redundant - 캐스팅이 중복됩니다. - - Simplify name '{0}' {0}' 이름 단순화 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 4e42b1314e171ad352cecd8b80fb7f7326b3b840..ba409e270426116e7a6456284c42bfbd0599561e 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -67,16 +67,6 @@ Automatyczne zaznaczanie zostało wyłączone z powodu możliwej deklaracji zmiennej zakresu. - - Remove Unnecessary Cast - Usuń niepotrzebne rzutowanie - - - - Cast is redundant - Nadmiarowe określenie elementu Cast - - Simplify name '{0}' Uprość nazwę „{0}” diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index ce4eebbc12f59c19835b695de79a6ce21ffe8fcf..bbe9aac5779c1fe31177a637be36a1149ae38c94 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -67,16 +67,6 @@ Seleção automática desabilitada devido a uma possível declaração de variável de intervalo. - - Remove Unnecessary Cast - Remover Conversão Desnecessária - - - - Cast is redundant - A conversão é redundante - - Simplify name '{0}' Simplificar nome '{0}' diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index 747c1344687da044198e8f76329f6bda4ceb03d6..9e591f8948a7475e5c836b1e66998752698bcd61 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -67,16 +67,6 @@ Автовыбор отключен из-за возможного объявления переменной диапазона. - - Remove Unnecessary Cast - Удалить ненужное приведение - - - - Cast is redundant - Приведение избыточно - - Simplify name '{0}' Упрощение имени "{0}" diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index dd8af44a26d3319120486290b2a45bd7a4c0ff88..2a2a1074116db7be73c8272d84eaeaa851cb2a95 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -67,16 +67,6 @@ Otomatik seçim, olası aralık değişkeni bildirimi nedeniyle devre dışı bırakıldı. - - Remove Unnecessary Cast - Gereksiz Atamayı Kaldır - - - - Cast is redundant - Atama gereksiz - - Simplify name '{0}' {0}' adını basitleştir diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 34285ba061f7885513f32b923c7058186ab37d8e..024d5235a624566e1be57a42c2e073998c7c7891 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -67,16 +67,6 @@ 由于可能出现范围变量声明,已禁用自动选择。 - - Remove Unnecessary Cast - 删除不必要的转换 - - - - Cast is redundant - 强制转换是多余的 - - Simplify name '{0}' 简化名称“{0}” diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index 4623ee17cae25eba2a21afe6b30edf3018d6b46b..220fb967a97eb4d2b1aaf16f391c00e356c6d351 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -67,16 +67,6 @@ 由於可能的範圍變數宣告,所以停用自動選取。 - - Remove Unnecessary Cast - 移除不必要的 Cast - - - - Cast is redundant - Cast 是多餘的 - - Simplify name '{0}' 簡化名稱 '{0}' diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/RemoveUnnecessaryCastDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/RemoveUnnecessaryCastDiagnosticAnalyzerBase.cs index 1669925a3cd7db040f64e45f55a759e362dce781..670462801846370042bc9be423423aa37b56c2c5 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/RemoveUnnecessaryCastDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/RemoveUnnecessaryCastDiagnosticAnalyzerBase.cs @@ -3,76 +3,70 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Diagnostics.RemoveUnnecessaryCast { - internal abstract class RemoveUnnecessaryCastDiagnosticAnalyzerBase : DiagnosticAnalyzer, IBuiltInAnalyzer where TLanguageKindEnum : struct + internal abstract class RemoveUnnecessaryCastDiagnosticAnalyzerBase< + TLanguageKindEnum, + TCastExpression> : AbstractCodeStyleDiagnosticAnalyzer + where TLanguageKindEnum : struct + where TCastExpression : SyntaxNode { - private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(FeaturesResources.Remove_Unnecessary_Cast), FeaturesResources.ResourceManager, typeof(FeaturesResources)); - private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(WorkspacesResources.Cast_is_redundant), WorkspacesResources.ResourceManager, typeof(WorkspacesResources)); + protected RemoveUnnecessaryCastDiagnosticAnalyzerBase() + : base(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId, + new LocalizableResourceString(nameof(FeaturesResources.Remove_Unnecessary_Cast), FeaturesResources.ResourceManager, typeof(FeaturesResources)), + new LocalizableResourceString(nameof(WorkspacesResources.Cast_is_redundant), WorkspacesResources.ResourceManager, typeof(WorkspacesResources))) + { + } + + protected abstract ImmutableArray SyntaxKindsOfInterest { get; } + protected abstract TextSpan GetFadeSpan(TCastExpression node); + protected abstract bool IsUnnecessaryCast(SemanticModel model, TCastExpression node, CancellationToken cancellationToken); - private static readonly DiagnosticDescriptor s_descriptor = new DiagnosticDescriptor(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId, - s_localizableTitle, - s_localizableMessage, - DiagnosticCategory.Style, - DiagnosticSeverity.Hidden, - isEnabledByDefault: true, - customTags: DiagnosticCustomTags.Unnecessary); + public override bool OpenFileOnly(Workspace workspace) + => false; - #region Interface methods + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_descriptor); - public bool OpenFileOnly(Workspace workspace) => false; + protected override void InitializeWorker(AnalysisContext context) + => context.RegisterSyntaxNodeAction(AnalyzeSyntax, this.SyntaxKindsOfInterest); - public sealed override void Initialize(AnalysisContext context) + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); - context.EnableConcurrentExecution(); + var diagnostic = TryRemoveCastExpression( + context.SemanticModel, + (TCastExpression)context.Node, + context.CancellationToken); - context.RegisterSyntaxNodeAction( - nodeContext => - { - if (TryRemoveCastExpression(nodeContext.SemanticModel, nodeContext.Node, out var diagnostic, nodeContext.CancellationToken)) - { - nodeContext.ReportDiagnostic(diagnostic); - } - }, - this.SyntaxKindsOfInterest.ToArray()); + if (diagnostic != null) + { + context.ReportDiagnostic(diagnostic); + } } - public abstract ImmutableArray SyntaxKindsOfInterest { get; } - - #endregion - - protected abstract bool IsUnnecessaryCast(SemanticModel model, SyntaxNode node, CancellationToken cancellationToken); - protected abstract TextSpan GetDiagnosticSpan(SyntaxNode node); - - private bool TryRemoveCastExpression( - SemanticModel model, SyntaxNode node, out Diagnostic diagnostic, CancellationToken cancellationToken) + private Diagnostic TryRemoveCastExpression(SemanticModel model, TCastExpression node, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - diagnostic = default; - if (!IsUnnecessaryCast(model, node, cancellationToken)) { - return false; + return null; } var tree = model.SyntaxTree; - var span = GetDiagnosticSpan(node); - if (tree.OverlapsHiddenPosition(span, cancellationToken)) + if (tree.OverlapsHiddenPosition(node.Span, cancellationToken)) { - return false; + return null; } - diagnostic = Diagnostic.Create(s_descriptor, tree.GetLocation(span)); - return true; + return Diagnostic.Create( + UnnecessaryWithSuggestionDescriptor, + node.SyntaxTree.GetLocation(GetFadeSpan(node)), + ImmutableArray.Create(node.GetLocation())); } - - public DiagnosticAnalyzerCategory GetAnalyzerCategory() - => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; } } diff --git a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.vb deleted file mode 100644 index a87cd509aa393139ee8738003e236f86aea5f1a5..0000000000000000000000000000000000000000 --- a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.RemoveUnnecessaryCastFixAllProvider.vb +++ /dev/null @@ -1,38 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports System.Threading -Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.RemoveUnnecessaryCast - Partial Friend Class RemoveUnnecessaryCastCodeFixProvider - Inherits CodeFixProvider - - Private Class RemoveUnnecessaryCastFixAllProvider - Inherits BatchSimplificationFixAllProvider - - Friend Shared Shadows ReadOnly Instance As RemoveUnnecessaryCastFixAllProvider = New RemoveUnnecessaryCastFixAllProvider() - - Protected Overrides Function GetNodeToSimplify(root As SyntaxNode, model As SemanticModel, diagnostic As Diagnostic, options As DocumentOptionSet, ByRef codeActionId As String, cancellationToken As CancellationToken) As SyntaxNode - codeActionId = Nothing - Return GetCastNode(root, model, diagnostic.Location.SourceSpan, cancellationToken) - End Function - - Protected Overrides ReadOnly Property NeedsParentFixup As Boolean - Get - Return True - End Get - End Property - - Protected Overrides Async Function AddSimplifyAnnotationsAsync(document As Document, nodeToSimplify As SyntaxNode, cancellationToken As CancellationToken) As Task(Of Document) - Dim cast = TryCast(nodeToSimplify, ExpressionSyntax) - If cast Is Nothing Then - Return document - End If - - Return Await RemoveUnnecessaryCastAsync(document, cast, cancellationToken).ConfigureAwait(False) - End Function - End Class - End Class -End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.Rewriter.vb b/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.Rewriter.vb deleted file mode 100644 index 20b58230d5b8cbb73254e01c4cb81e0a70b7c4ea..0000000000000000000000000000000000000000 --- a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.Rewriter.vb +++ /dev/null @@ -1,67 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.RemoveUnnecessaryCast - Partial Friend Class RemoveUnnecessaryCastCodeFixProvider - Partial Private Class Rewriter - Inherits VisualBasicSyntaxRewriter - - Private ReadOnly _castExpression As ExpressionSyntax - - Public Sub New(castExpression As ExpressionSyntax) - _castExpression = castExpression - End Sub - - Private Shared Function GetExpression(expression As ExpressionSyntax) As ExpressionSyntax - If TypeOf expression Is ParenthesizedExpressionSyntax Then - Return expression.WithAdditionalAnnotations(Simplifier.Annotation) - Else - Return expression - End If - End Function - - Public Overrides Function VisitCTypeExpression(node As CTypeExpressionSyntax) As SyntaxNode - If node Is _castExpression Then - Return node.WithExpression(GetExpression(node.Expression)) _ - .WithAdditionalAnnotations(Simplifier.Annotation) _ - .Parenthesize() - End If - - Return MyBase.VisitCTypeExpression(node) - End Function - - Public Overrides Function VisitDirectCastExpression(node As DirectCastExpressionSyntax) As SyntaxNode - If node Is _castExpression Then - Return node.WithExpression(GetExpression(node.Expression)) _ - .WithAdditionalAnnotations(Simplifier.Annotation) _ - .Parenthesize() - End If - - Return MyBase.VisitDirectCastExpression(node) - End Function - - Public Overrides Function VisitTryCastExpression(node As TryCastExpressionSyntax) As SyntaxNode - If node Is _castExpression Then - Return node.WithExpression(GetExpression(node.Expression)) _ - .WithAdditionalAnnotations(Simplifier.Annotation) _ - .Parenthesize() - End If - - Return MyBase.VisitTryCastExpression(node) - End Function - - Public Overrides Function VisitPredefinedCastExpression(node As PredefinedCastExpressionSyntax) As SyntaxNode - If node Is _castExpression Then - Return node.WithExpression(GetExpression(node.Expression)) _ - .WithAdditionalAnnotations(Simplifier.Annotation) _ - .Parenthesize() - End If - - Return MyBase.VisitPredefinedCastExpression(node) - End Function - End Class - End Class -End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.vb index 601eab76f975491ee2104b579f3b2164e483ff6d..a393ea0f9d0c774ceb4a615d2e7550b733861985 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.vb @@ -3,57 +3,31 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.RemoveUnnecessaryCast - + Partial Friend Class RemoveUnnecessaryCastCodeFixProvider - Inherits CodeFixProvider + Inherits SyntaxEditorBasedCodeFixProvider - Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) - Get - Return ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId) - End Get - End Property + Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = + ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId) - Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim document = context.Document - Dim span = context.Span - Dim cancellationToken = context.CancellationToken - - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim model = DirectCast(Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), SemanticModel) - - Dim node = GetCastNode(root, model, span, cancellationToken) - If node Is Nothing Then - Return - End If - - context.RegisterCodeFix( - New MyCodeAction( - VBFeaturesResources.Remove_Unnecessary_Cast, - Function(c) RemoveUnnecessaryCastAsync(document, node, c)), + Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task + context.RegisterCodeFix(New MyCodeAction( + FeaturesResources.Remove_Unnecessary_Cast, + Function(c) FixAsync(context.Document, context.Diagnostics.First(), c)), context.Diagnostics) - End Function - - Private Shared Function GetCastNode(root As SyntaxNode, model As SemanticModel, span As TextSpan, cancellationToken As CancellationToken) As ExpressionSyntax - Dim token = root.FindToken(span.Start) - If Not token.Span.IntersectsWith(span) Then - Return Nothing - End If - - Dim node = token.GetAncestors(Of ExpressionSyntax)() _ - .Where(Function(c) TypeOf c Is CastExpressionSyntax OrElse TypeOf c Is PredefinedCastExpressionSyntax) _ - .FirstOrDefault(Function(c) c.Span.IntersectsWith(span) AndAlso IsUnnecessaryCast(c, model, cancellationToken)) - Return node + Return SpecializedTasks.EmptyTask End Function Private Shared Function IsUnnecessaryCast(node As ExpressionSyntax, model As SemanticModel, cancellationToken As CancellationToken) As Boolean @@ -70,117 +44,116 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.RemoveUnnecessaryCast Return False End Function - Private Shared Async Function RemoveUnnecessaryCastAsync(document As Document, node As ExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document) - ' First, annotate our expression so that we can get back to it. - Dim updatedDocument = Await document.ReplaceNodeAsync(node, node.WithAdditionalAnnotations(s_expressionAnnotation), cancellationToken).ConfigureAwait(False) - - Dim expression = Await FindNodeWithAnnotationAsync(Of ExpressionSyntax)(s_expressionAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False) - - ' Next, make the parenting statement of the expression semantically explicit - Dim parentStatement = expression.FirstAncestorOrSelf(Of StatementSyntax)() - Dim explicitParentStatement = Await Simplifier.ExpandAsync(parentStatement, updatedDocument, cancellationToken:=cancellationToken).ConfigureAwait(False) - explicitParentStatement = explicitParentStatement.WithAdditionalAnnotations(Formatter.Annotation, s_statementAnnotation) + Protected Overrides Async Function FixAllAsync( + document As Document, diagnostics As ImmutableArray(Of Diagnostic), + editor As SyntaxEditor, cancellationToken As CancellationToken) As Task + + ' VB parsing is extremely hairy. Unlike C#, it can be very dangerous to go and remove a + ' cast. For example, if the cast is at the statement level, it may contain an + ' expression that itself is not legal on its own at the top level (see below for an + ' example of this). Similarly, removing the cast may make VB parse following code + ' differently. + ' + ' In order to deal with all these concerns safely, we first complexify the surrounding + ' statements containing the casts we want to remove. *Then* we remove the casts from + ' inside that. + ' + ' As an example, consider: DirectCast(New Goo(), IGoo).Blah() This is + ' legal code, but this is not: New Goo().Blah() + ' + ' (because 'new' cannot start a statement). + ' So we need to instead generate: Call New Goo().Blah() + + Dim originalCastNodes = diagnostics.SelectAsArray( + Function(d) DirectCast(d.AdditionalLocations(0).FindNode(getInnermostNodeForTie:=True, cancellationToken), ExpressionSyntax)) + + ' Keep track of the all the casts we want to fix up. We'll fix them up at the end + ' after we've done all other manipulation. + Dim trackedRoot = editor.OriginalRoot.TrackNodes(originalCastNodes) + Dim trackedDocument = document.WithSyntaxRoot(trackedRoot) + + ' Now, go and expand all the containing statements of the nodes we want to edit. + ' This is necessary to ensure that the code remains parseable and preserves semantics. + Dim expandedRoot = Await ExpandSurroundingStatementsAsync(trackedDocument, originalCastNodes, cancellationToken).ConfigureAwait(False) + Dim expandedDocument = document.WithSyntaxRoot(expandedRoot) + + Dim removedRoot = Await RemoveCasts( + expandedDocument, originalCastNodes, cancellationToken).ConfigureAwait(False) + + editor.ReplaceNode(editor.OriginalRoot, removedRoot) + End Function - updatedDocument = Await updatedDocument.ReplaceNodeAsync(parentStatement, explicitParentStatement, cancellationToken).ConfigureAwait(False) + Private Async Function RemoveCasts( + document As Document, originalCastNodes As ImmutableArray(Of ExpressionSyntax), + cancellationToken As CancellationToken) As Task(Of SyntaxNode) - ' Next, make the statement after the parenting statement of the expression semantically explicit. - parentStatement = Await FindNodeWithAnnotationAsync(Of StatementSyntax)(s_statementAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False) - Dim nextStatement = parentStatement.GetNextStatement() - If nextStatement IsNot Nothing Then - Dim explicitNextStatement = Await Simplifier.ExpandAsync(nextStatement, updatedDocument, cancellationToken:=cancellationToken).ConfigureAwait(False) - updatedDocument = Await updatedDocument.ReplaceNodeAsync(nextStatement, explicitNextStatement, cancellationToken).ConfigureAwait(False) - End If + Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - updatedDocument = Await RewriteCoreAsync(updatedDocument, expression, cancellationToken).ConfigureAwait(False) + ' Now, find the cast nodes again in the expanded document + Dim currentCastNodes = root.GetCurrentNodes(originalCastNodes) - ' Remove added _expressionAnnotation and _statementAnnotation. - updatedDocument = Await RemoveNodesAndTokensWithAnnotationAsync(s_expressionAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False) - updatedDocument = Await RemoveNodesAndTokensWithAnnotationAsync(s_statementAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False) + Dim innerEditor = New SyntaxEditor(root, document.Project.Solution.Workspace) + Await innerEditor.ApplyExpressionLevelSemanticEditsAsync( + document, currentCastNodes.ToImmutableArray(), + Function(semanticModel, castExpression) IsUnnecessaryCast(castExpression, semanticModel, cancellationToken), + Function(unused, currentRoot, castExpression) + Dim newCastExpression = Uncast(castExpression).WithAdditionalAnnotations(Formatter.Annotation) + Return currentRoot.ReplaceNode(castExpression, newCastExpression) + End Function, + cancellationToken).ConfigureAwait(False) - Return updatedDocument + Return innerEditor.GetChangedRoot() End Function - Private Shared Async Function RemoveNodesAndTokensWithAnnotationAsync(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function ExpandSurroundingStatementsAsync( + document As Document, originalNodes As ImmutableArray(Of ExpressionSyntax), + cancellationToken As CancellationToken) As Task(Of SyntaxNode) + + Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim nodesWithAnnotation = Await FindNodesWithAnnotationAsync(annotation, document, cancellationToken).ConfigureAwait(False) - root = root.ReplaceSyntax( - nodesWithAnnotation.Where(Function(n) n.IsNode).Select(Function(n) n.AsNode), - Function(o, n) o.WithoutAnnotations(annotation), - nodesWithAnnotation.Where(Function(n) n.IsToken).Select(Function(n) n.AsToken), - Function(o, n) o.WithoutAnnotations(annotation), - SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia), - Nothing) - Return document.WithSyntaxRoot(root) - End Function - Private Shared Async Function RewriteCoreAsync(document As Document, originalExpr As ExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document) - ' Finally, rewrite the cast expression - Dim exprToRewrite As ExpressionSyntax = Nothing - Dim annotatedNodes = Await FindNodesWithAnnotationAsync(s_expressionAnnotation, document, cancellationToken).ConfigureAwait(False) - - For Each annotatedNode In annotatedNodes - exprToRewrite = TryCast(annotatedNode.AsNode, ExpressionSyntax) - If exprToRewrite IsNot Nothing AndAlso exprToRewrite.IsKind(originalExpr.Kind) Then - If annotatedNodes.Count > 1 Then - ' Ensure cast is unnecessary - Dim model = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - If IsUnnecessaryCast(exprToRewrite, model, cancellationToken) Then - Exit For - End If - Else - Exit For - End If - End If - exprToRewrite = Nothing + ' Note: we not only get the containing statement, but also the next statement after + ' that. That's because the removal of the parens in the cast may then cause parsing + ' problems with VB consuming the following line into the current line. This is most + ' common with query clauses. By complexifying the next statement, we prevent that from + ' happening. + Dim trackedNodes = root.GetCurrentNodes(originalNodes) + Dim containingAndNextStatements = trackedNodes.SelectMany( + Function(n) + Dim containingStatement = n.GetAncestorOrThis(Of StatementSyntax) + Dim nextStatement = containingStatement.GetNextStatement() + Return If(nextStatement Is Nothing, + {containingStatement}, + {containingStatement, nextStatement}) + End Function).Distinct() + + Dim workspace = document.Project.Solution.Workspace + Dim editor = New SyntaxEditor(root, workspace) + + For Each containingStatement In containingAndNextStatements + Dim expandedStatement = Simplifier.Expand( + containingStatement, semanticModel, workspace, + cancellationToken:=cancellationToken) + editor.ReplaceNode(containingStatement, expandedStatement) Next - If exprToRewrite Is Nothing Then - Return document - End If - - Dim rewriter = New Rewriter(exprToRewrite) - Dim newExpression = rewriter.Visit(exprToRewrite) - - ' Remove the annotation from the expression so that it isn't hanging around later. - If newExpression.HasAnnotation(s_expressionAnnotation) Then - - newExpression = newExpression.WithoutAnnotations(s_expressionAnnotation) - - ElseIf newExpression.IsKind(SyntaxKind.ParenthesizedExpression) Then - - Dim parenthesizedExpression = DirectCast(newExpression, ParenthesizedExpressionSyntax) - If parenthesizedExpression.Expression.HasAnnotation(s_expressionAnnotation) Then - newExpression = parenthesizedExpression _ - .WithExpression(parenthesizedExpression.Expression.WithoutAnnotations(s_expressionAnnotation)) - End If + Return editor.GetChangedRoot() + End Function + Private Function Uncast(old As ExpressionSyntax) As ExpressionSyntax + ' parenthesize the uncasted value to help ensure any proper parsing. The excess + ' parens will be removed if unnecessary. + Dim castExpression = TryCast(old, CastExpressionSyntax) + If castExpression IsNot Nothing Then + Return castExpression.Uncast().Parenthesize() End If - document = Await document.ReplaceNodeAsync(exprToRewrite, newExpression, cancellationToken).ConfigureAwait(False) - - If annotatedNodes.Count > 1 Then - Return Await RewriteCoreAsync(document, originalExpr, cancellationToken).ConfigureAwait(False) + Dim predefinedCastExpression = TryCast(old, PredefinedCastExpressionSyntax) + If predefinedCastExpression IsNot Nothing Then + Return predefinedCastExpression.Uncast().Parenthesize() End If - Return document - End Function - - Private Shared ReadOnly s_expressionAnnotation As New SyntaxAnnotation - Private Shared ReadOnly s_statementAnnotation As New SyntaxAnnotation - - Private Shared Async Function FindNodeWithAnnotationAsync(Of T As SyntaxNode)(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of T) - Dim annotatedNodes = Await FindNodesWithAnnotationAsync(annotation, document, cancellationToken).ConfigureAwait(False) - Dim result = annotatedNodes.Single().AsNode() - Return DirectCast(result, T) - End Function - - Private Shared Async Function FindNodesWithAnnotationAsync(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of IEnumerable(Of SyntaxNodeOrToken)) - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Return root.GetAnnotatedNodesAndTokens(annotation) - End Function - - Public NotOverridable Overrides Function GetFixAllProvider() As FixAllProvider - Return RemoveUnnecessaryCastFixAllProvider.Instance + Throw ExceptionUtilities.UnexpectedValue(old) End Function Private Class MyCodeAction diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer.vb index cce364b2b7bb51384784642f05f996fd78a9700a..87574095ae0d65a695a28c807cd945de53817ef5 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer.vb @@ -11,19 +11,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Diagnostics.RemoveUnnecessaryCast Friend NotInheritable Class VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer - Inherits RemoveUnnecessaryCastDiagnosticAnalyzerBase(Of SyntaxKind) + Inherits RemoveUnnecessaryCastDiagnosticAnalyzerBase(Of SyntaxKind, ExpressionSyntax) - Private Shared ReadOnly s_kindsOfInterest As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(SyntaxKind.CTypeExpression, - SyntaxKind.DirectCastExpression, - SyntaxKind.TryCastExpression, - SyntaxKind.PredefinedCastExpression) - Public Overrides ReadOnly Property SyntaxKindsOfInterest As ImmutableArray(Of SyntaxKind) - Get - Return s_kindsOfInterest - End Get - End Property + Protected Overrides ReadOnly Property SyntaxKindsOfInterest As ImmutableArray(Of SyntaxKind) = + ImmutableArray.Create(SyntaxKind.CTypeExpression, + SyntaxKind.DirectCastExpression, + SyntaxKind.TryCastExpression, + SyntaxKind.PredefinedCastExpression) - Protected Overrides Function IsUnnecessaryCast(model As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean + Protected Overrides Function IsUnnecessaryCast(model As SemanticModel, node As ExpressionSyntax, cancellationToken As CancellationToken) As Boolean Select Case node.Kind Case SyntaxKind.CTypeExpression, SyntaxKind.DirectCastExpression, SyntaxKind.TryCastExpression Return DirectCast(node, CastExpressionSyntax).IsUnnecessaryCast(model, assumeCallKeyword:=True, cancellationToken:=cancellationToken) @@ -34,15 +30,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Diagnostics.RemoveUnnecessaryCast End Select End Function - Protected Overrides Function GetDiagnosticSpan(node As SyntaxNode) As TextSpan - Select Case node.Kind - Case SyntaxKind.CTypeExpression, SyntaxKind.DirectCastExpression, SyntaxKind.TryCastExpression - Return DirectCast(node, CastExpressionSyntax).Keyword.Span - Case SyntaxKind.PredefinedCastExpression - Return DirectCast(node, PredefinedCastExpressionSyntax).Keyword.Span - Case Else - Throw ExceptionUtilities.UnexpectedValue(node.Kind) - End Select + Protected Overrides Function GetFadeSpan(node As ExpressionSyntax) As TextSpan + Return node.GetFirstToken().Span End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb index 658f74b820b5344a798fbe993acf8bacaf929b43..3a2aaa261e8ce62526d2e9db8708f3d351e62cbe 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb @@ -240,15 +240,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources End Get End Property - ''' - ''' Looks up a localized string similar to Cast is redundant. - ''' - Friend ReadOnly Property Cast_is_redundant() As String - Get - Return ResourceManager.GetString("Cast_is_redundant", resourceCulture) - End Get - End Property - ''' ''' Looks up a localized string similar to Catch clause. ''' @@ -2009,15 +2000,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources End Get End Property - ''' - ''' Looks up a localized string similar to Remove Unnecessary Cast. - ''' - Friend ReadOnly Property Remove_Unnecessary_Cast() As String - Get - Return ResourceManager.GetString("Remove_Unnecessary_Cast", resourceCulture) - End Get - End Property - ''' ''' Looks up a localized string similar to Remove Unnecessary Imports. ''' diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 457bb902fc58f6a6991d868f92f5426ed60faf0f..03110e2b5c59bf0b6c1508cc8383db3e6aa32540 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -213,12 +213,6 @@ Fix Incorrect Function Return Type - - Remove Unnecessary Cast - - - Cast is redundant - Simplify name '{0}' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index bd65eacd8b92a0e5ab91bd1d6a3fbfb0f6c36dae..9c4e60a842f241b895fadf42355979d5c1921c8b 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -157,16 +157,6 @@ Opravit nesprávný návratový typ funkce - - Remove Unnecessary Cast - Odebrat nepotřebné přetypování - - - - Cast is redundant - Přetypování je redundantní. - - Simplify name '{0}' Zjednodušit název {0} diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 3a2abb3c9ddb01a966decf7da24ba3dd875e9410..91941635ffaf8bf0cdcfea901b948887c622ca88 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -157,16 +157,6 @@ Rückgabetyp für unzulässige Funktion beheben - - Remove Unnecessary Cast - Nicht erforderliche Umwandlung entfernen - - - - Cast is redundant - Cast ist redundant - - Simplify name '{0}' Name '{0}' vereinfachen diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index 07acea18b3efe6dc4ad862eb996e7f3f4a61cd7b..9ec6833e3dda1dec10fcefa2740beedac8e9ad40 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -157,16 +157,6 @@ Corregir tipo devuelto de función incorrecto - - Remove Unnecessary Cast - Quitar conversión innecesaria - - - - Cast is redundant - Cast es redundante - - Simplify name '{0}' Simplificar nombre '{0}' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index 4fd343f1722530e95cf116aca8ca5875a5231849..4dafc8fd397d2e431c3082d46eb376128eacde4f 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -157,16 +157,6 @@ Corriger le type de retour de fonction incorrect - - Remove Unnecessary Cast - Supprimer le cast inutile - - - - Cast is redundant - Cast redondant - - Simplify name '{0}' Simplifier le nom '{0}' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index 234ecc7c5686f5936d311669699a60dd794f1664..d5bd4d893779f4166105508dd73a31ba57b5630b 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -157,16 +157,6 @@ Correggi tipo errato restituito da funzione - - Remove Unnecessary Cast - Rimuovi cast non necessario - - - - Cast is redundant - Il cast è ridondante - - Simplify name '{0}' Semplifica il nome '{0}' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index 5d42393e9343af63d756cb8927f506195f98ff42..d37b3b4638864bec2913fe54cc2c984a8626e7c6 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -157,16 +157,6 @@ 無効な関数の戻り値の型を修正する - - Remove Unnecessary Cast - 不要なキャストの削除 - - - - Cast is redundant - キャストが冗長です - - Simplify name '{0}' 名前 '{0}' の単純化 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index 7ffb3a79eb6a2a1ebfd208dc1bdc4edc50b81787..f88f04b308ccef1ebf71e260c3f032465ba12cf8 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -157,16 +157,6 @@ 잘못된 함수 반환 형식 수정 - - Remove Unnecessary Cast - 불필요한 캐스트 제거 - - - - Cast is redundant - 캐스팅이 중복됩니다. - - Simplify name '{0}' {0}' 이름 단순화 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index 38b2fbe35c75e5d0aec90e4fd62b8ce5324658b2..ede1e4ece68cefdd133f266055330dc4a1c2e4df 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -157,16 +157,6 @@ Napraw nieprawidłowy typ zwracany funkcji - - Remove Unnecessary Cast - Usuń niepotrzebne rzutowanie - - - - Cast is redundant - Nadmiarowe określenie elementu Cast - - Simplify name '{0}' Uprość nazwę „{0}” diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index c73f8395b26ea1ecc24fcdf41f669a29e2ce9d23..44bc4a8404074c8ba079355b9dc9f9fa9449b321 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -157,16 +157,6 @@ Corrigir Tipo de Retorno de Função Incorreta - - Remove Unnecessary Cast - Remover Conversão Desnecessária - - - - Cast is redundant - A conversão é redundante - - Simplify name '{0}' Simplificar nome '{0}' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index e11a39f1fe1220cb68b4a6b9e94ac129683cbef1..e6da6370a4adebe40cfe03f917682e5026b64a5f 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -157,16 +157,6 @@ Исправить неверный тип возвращения функции - - Remove Unnecessary Cast - Удалить ненужное приведение - - - - Cast is redundant - Приведение избыточно - - Simplify name '{0}' Упрощение имени "{0}" diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index 41a8b9ec9bc93bf1535cd1a5240f9cf861269fe1..e384b1b2d4d13efea4ee223a59aa7bdef9deb53b 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -157,16 +157,6 @@ Hatalı İşlev Dönüş Türünü Düzelt - - Remove Unnecessary Cast - Gereksiz Atamayı Kaldır - - - - Cast is redundant - Atama gereksiz - - Simplify name '{0}' {0}' adını basitleştir diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index 0d05e7ec3a7f55402cf8286ce45781969b2a7f74..e5269feabd75143d73e9504d5ed8942ff359e26d 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -157,16 +157,6 @@ 修复不正确的函数返回类型 - - Remove Unnecessary Cast - 删除不必要的转换 - - - - Cast is redundant - 强制转换是多余的 - - Simplify name '{0}' 简化名称“{0}” diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index cecbee64e4ab91b726f5977d25819a2f35c343b6..26fb89e3391915abcb51250545008a15e27084cb 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -157,16 +157,6 @@ 修正不正確的函式傳回類型 - - Remove Unnecessary Cast - 移除不必要的 Cast - - - - Cast is redundant - Cast 是多餘的 - - Simplify name '{0}' 簡化名稱 '{0}' diff --git a/src/Workspaces/CSharp/Portable/Extensions/CastExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/CastExpressionSyntaxExtensions.cs index 537f92a36939fef0d2b4695ce7c32d014b77fa9a..91c2cbe84a2d9fb1600a4fca757c537df1b7b129 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/CastExpressionSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/CastExpressionSyntaxExtensions.cs @@ -1,11 +1,13 @@ // 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.Diagnostics; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Extensions { @@ -621,5 +623,28 @@ private static bool IsRequiredImplicitNumericConversion(ITypeSymbol sourceType, return false; } } + + public static ExpressionSyntax Uncast(this CastExpressionSyntax node) + { + var leadingTrivia = node.OpenParenToken.LeadingTrivia + .Concat(node.OpenParenToken.TrailingTrivia) + .Concat(node.Type.GetLeadingTrivia()) + .Concat(node.Type.GetTrailingTrivia()) + .Concat(node.CloseParenToken.LeadingTrivia) + .Concat(node.CloseParenToken.TrailingTrivia) + .Concat(node.Expression.GetLeadingTrivia()) + .Where(t => !t.IsElastic()); + + var trailingTrivia = node.GetTrailingTrivia().Where(t => !t.IsElastic()); + + var resultNode = node.Expression + .WithLeadingTrivia(leadingTrivia) + .WithTrailingTrivia(trailingTrivia) + .WithAdditionalAnnotations(Simplifier.Annotation); + + resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode); + + return resultNode; + } } } diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs index 99b6a39b372ac4410b65d7ab7861fd340b9736d7..88622e615a325145405169b10666bbc383c1371c 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpCastReducer.cs @@ -31,24 +31,7 @@ private static ExpressionSyntax SimplifyCast(CastExpressionSyntax node, Semantic return node; } - var leadingTrivia = node.OpenParenToken.LeadingTrivia - .Concat(node.OpenParenToken.TrailingTrivia) - .Concat(node.Type.GetLeadingTrivia()) - .Concat(node.Type.GetTrailingTrivia()) - .Concat(node.CloseParenToken.LeadingTrivia) - .Concat(node.CloseParenToken.TrailingTrivia) - .Concat(node.Expression.GetLeadingTrivia()) - .Where(t => !t.IsElastic()); - - var trailingTrivia = node.GetTrailingTrivia().Where(t => !t.IsElastic()); - - var resultNode = node.Expression - .WithLeadingTrivia(leadingTrivia) - .WithTrailingTrivia(trailingTrivia); - - resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode); - - return resultNode; + return node.Uncast(); } } } diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/CallStatementSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/CallStatementSyntaxExtensions.vb index 40378ace316c639cd7a66a19794be5474571e83d..6b02f57b740231a09fabee088fb4a3a8e931f9a0 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/CallStatementSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/CallStatementSyntaxExtensions.vb @@ -1,9 +1,6 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. Imports System.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/CastExpressionSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/CastExpressionSyntaxExtensions.vb new file mode 100644 index 0000000000000000000000000000000000000000..96d3286d96f757460ed2e578e6eb6f59ca976165 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/CastExpressionSyntaxExtensions.vb @@ -0,0 +1,28 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Friend Module CastExpressionSyntaxExtensions + + Public Function Uncast(cast As CastExpressionSyntax) As ExpressionSyntax + Return Uncast(cast, cast.Expression) + End Function + + + Public Function Uncast(cast As PredefinedCastExpressionSyntax) As ExpressionSyntax + Return Uncast(cast, cast.Expression) + End Function + + Private Function Uncast(castNode As ExpressionSyntax, innerNode As ExpressionSyntax) As ExpressionSyntax + Dim resultNode = innerNode.WithTriviaFrom(castNode) + + resultNode = SimplificationHelpers.CopyAnnotations(castNode, resultNode) + + Return resultNode + + End Function + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb index 6c9698467f9af2b545a6bccb2e7d83df3326c27b..85dc5d81215e4097193984fe80a7c88d9623f896 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicCastReducer.vb @@ -17,22 +17,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification MyBase.New(s_pool) End Sub - Private Overloads Shared Function SimplifyCast( - castNode As ExpressionSyntax, - innerNode As ExpressionSyntax, - optionSet As OptionSet, - cancellationToken As CancellationToken - ) As ExpressionSyntax - - Dim resultNode = innerNode _ - .WithLeadingTrivia(castNode.GetLeadingTrivia()) _ - .WithTrailingTrivia(castNode.GetTrailingTrivia()) - - resultNode = SimplificationHelpers.CopyAnnotations(castNode, resultNode) - - Return resultNode - End Function - Private Shared ReadOnly s_simplifyCast As Func(Of CastExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyCast Private Overloads Shared Function SimplifyCast( @@ -46,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Return node End If - Return SimplifyCast(node, node.Expression, optionSet, cancellationToken) + Return node.Uncast() End Function Private Shared ReadOnly s_simplifyPredefinedCast As Func(Of PredefinedCastExpressionSyntax, SemanticModel, OptionSet, CancellationToken, SyntaxNode) = AddressOf SimplifyPredefinedCast @@ -62,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Return node End If - Return SimplifyCast(node, node.Expression, optionSet, cancellationToken) + Return node.Uncast() End Function End Class End Namespace