diff --git a/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb b/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb index fe7d492b11c25..477f37b305063 100644 --- a/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb +++ b/src/EditorFeatures/Test2/Simplification/TypeNameSimplifierTest.vb @@ -1426,6 +1426,42 @@ public class C Test(input, expected) End Sub + + + Public Sub TestCSRemoveThisPreservesTrivia() + Dim input = + + + +class C1 +{ + int _field; + + void M() + { + this /*comment 1*/ . /* comment 2 */ {|SimplifyParent:_field|} /* comment 3 */ = 0; + } +} + + + + + Dim expected = + +class C1 +{ + int _field; + + void M() + { + /*comment 1*/ /* comment 2 */ _field /* comment 3 */ = 0; + } +} + + + Test(input, expected) + End Sub + Public Sub CSharpSimplifyToVarCorrect() diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs index e027af8cba07b..7325344aa8b91 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs @@ -773,7 +773,19 @@ private static bool TryReduce( } } - replacementNode = memberAccess.Name.WithLeadingTrivia(memberAccess.GetLeadingTrivia()).WithTrailingTrivia(memberAccess.GetTrailingTrivia()); + // We want to include any user-typed trivia that may be present between the 'Expression', 'OperatorToken' and 'Identifier' of the MemberAccessExpression. + // However, we don't want to include any elastic trivia that may have been introduced by the expander in these locations. This is to avoid triggering + // aggressive formatting. Otherwise, formatter will see this elastic trivia added by the expander and use that as a cue to introduce unnecessary blank lines + // etc. around the user's original code. + Func isNotElastic = t => !t.IsElastic(); + replacementNode = memberAccess.Name + .WithLeadingTrivia( + memberAccess.GetLeadingTrivia() + .AddRange(memberAccess.Expression.GetTrailingTrivia().Where(isNotElastic)) + .AddRange(memberAccess.OperatorToken.LeadingTrivia.Where(isNotElastic)) + .AddRange(memberAccess.OperatorToken.TrailingTrivia.Where(isNotElastic)) + .AddRange(memberAccess.Name.GetLeadingTrivia().Where(isNotElastic))) + .WithTrailingTrivia(memberAccess.GetTrailingTrivia()); issueSpan = memberAccess.Expression.Span; if (replacementNode == null) diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb index 6c16af518aab1..61b51924aac36 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb @@ -1018,12 +1018,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions End If End If + ' We want to include any user-typed trivia that may be present between the 'Expression', 'OperatorToken' and 'Identifier' of the MemberAccessExpression. + ' However, we don't want to include any elastic trivia that may have been introduced by the expander in these locations. This is to avoid triggering + ' aggressive formatting. Otherwise, formatter will see this elastic trivia added by the expander And use that as a cue to introduce unnecessary blank lines + ' etc. around the user's original code. + Dim isNotElastic = Function(t As SyntaxTrivia) Not t.IsElastic() replacementNode = memberAccess.Name replacementNode = DirectCast(replacementNode, SimpleNameSyntax) _ .WithIdentifier(VisualBasicSimplificationService.TryEscapeIdentifierToken( memberAccess.Name.Identifier, semanticModel)) _ - .WithLeadingTrivia(memberAccess.GetLeadingTrivia()) + .WithLeadingTrivia(memberAccess.GetLeadingTrivia() _ + .AddRange(memberAccess.Expression.GetTrailingTrivia().Where(isNotElastic)) _ + .AddRange(memberAccess.OperatorToken.LeadingTrivia.Where(isNotElastic)) _ + .AddRange(memberAccess.OperatorToken.TrailingTrivia.Where(isNotElastic)) _ + .AddRange(memberAccess.Name.GetLeadingTrivia().Where(isNotElastic))) _ + .WithTrailingTrivia(memberAccess.GetTrailingTrivia()) issueSpan = memberAccess.Expression.Span If memberAccess.CanReplaceWithReducedName(replacementNode, semanticModel, cancellationToken) Then