diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj
index e9ef0545a9f7f41335de11d4d585df2edd81cb06..01c6d4a803ce5dddda6e198853279660c63f213f 100644
--- a/src/Features/Core/Portable/Features.csproj
+++ b/src/Features/Core/Portable/Features.csproj
@@ -129,6 +129,7 @@
+
diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs
new file mode 100644
index 0000000000000000000000000000000000000000..df818653a868a67be6b8b8ff97fc683feec34443
--- /dev/null
+++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs
@@ -0,0 +1,54 @@
+// 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.Generic;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.Formatting.Rules;
+using Microsoft.CodeAnalysis.LanguageServices;
+using Microsoft.CodeAnalysis.Options;
+
+namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers
+{
+ internal partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider
+ {
+ private partial class GenerateEqualsAndGetHashCodeAction : CodeAction
+ {
+ private class FormatLargeBinaryExpressionRule : AbstractFormattingRule
+ {
+ private ISyntaxFactsService _syntaxFacts;
+
+ public FormatLargeBinaryExpressionRule(ISyntaxFactsService syntaxFacts)
+ {
+ _syntaxFacts = syntaxFacts;
+ }
+
+ public override AdjustNewLinesOperation GetAdjustNewLinesOperation(
+ SyntaxToken previousToken, SyntaxToken currentToken, OptionSet optionSet, NextOperation nextOperation)
+ {
+ if (_syntaxFacts.IsLogicalAndExpression(previousToken.Parent))
+ {
+ return FormattingOperations.CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
+ }
+
+ return nextOperation.Invoke();
+ }
+
+ public override void AddIndentBlockOperations(
+ List list, SyntaxNode node, OptionSet optionSet, NextAction nextOperation)
+ {
+ if (_syntaxFacts.IsReturnStatement(node))
+ {
+ list.Add(FormattingOperations.CreateRelativeIndentBlockOperation(
+ node.GetFirstToken(),
+ node.GetFirstToken().GetNextToken(),
+ node.GetLastToken(),
+ indentationDelta: 1,
+ option: IndentBlockOption.RelativePosition));
+ return;
+ }
+
+ nextOperation.Invoke(list);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs
index c73ef195e96a9f73a765d0137537fa64de00732f..b562ddbfd3f6074031e3c4a050d5ea84aa12248b 100644
--- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs
+++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs
@@ -7,6 +7,9 @@
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Formatting;
+using Microsoft.CodeAnalysis.Formatting.Rules;
+using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
@@ -14,8 +17,10 @@ namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers
{
internal partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider
{
- private class GenerateEqualsAndGetHashCodeAction : CodeAction
+ private partial class GenerateEqualsAndGetHashCodeAction : CodeAction
{
+ private static readonly SyntaxAnnotation s_specializedFormattingAnnotation = new SyntaxAnnotation();
+
private readonly bool _generateEquals;
private readonly bool _generateGetHashCode;
private readonly GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider _service;
@@ -60,13 +65,21 @@ protected override async Task GetChangedDocumentAsync(CancellationToke
var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
- return await CodeGenerator.AddMemberDeclarationsAsync(
+ var newDocument = await CodeGenerator.AddMemberDeclarationsAsync(
_document.Project.Solution,
_containingType,
members,
new CodeGenerationOptions(contextLocation: syntaxTree.GetLocation(_textSpan)),
- cancellationToken)
- .ConfigureAwait(false);
+ cancellationToken).ConfigureAwait(false);
+
+ var rules = new List { new FormatLargeBinaryExpressionRule(_document.GetLanguageService()) };
+ rules.AddRange(Formatter.GetDefaultFormattingRules(_document));
+
+ var formattedDocument = await Formatter.FormatAsync(
+ newDocument, s_specializedFormattingAnnotation,
+ options: null, rules: rules, cancellationToken: cancellationToken).ConfigureAwait(false);
+
+ return formattedDocument;
}
private async Task CreateGetHashCodeMethodAsync(CancellationToken cancellationToken)
@@ -80,7 +93,8 @@ private async Task CreateEqualsMethodAsync(CancellationToken canc
{
var compilation = await _document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
return _document.GetLanguageService().CreateEqualsMethod(
- compilation, _containingType, _selectedMembers, cancellationToken);
+ compilation, _containingType, _selectedMembers,
+ s_specializedFormattingAnnotation, cancellationToken);
}
public override string Title
diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
index caa7b7dfb4e1ff551b9b40997d6288fef04ed7d8..ce80672788b5ed0e41c4547a21f9ce44ee1e8aad 100644
--- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
+++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
@@ -231,9 +231,10 @@ public bool IsLockStatement(SyntaxNode node)
}
public bool IsUsingStatement(SyntaxNode node)
- {
- return node is UsingStatementSyntax;
- }
+ => node.Kind() == SyntaxKind.UsingStatement;
+
+ public bool IsReturnStatement(SyntaxNode node)
+ => node.Kind() == SyntaxKind.ReturnStatement;
public bool IsThisConstructorInitializer(SyntaxToken token)
{
@@ -1806,6 +1807,9 @@ public void GetPartsOfConditionalExpression(SyntaxNode node, out SyntaxNode cond
public SyntaxNode WalkDownParentheses(SyntaxNode node)
=> (node as ExpressionSyntax)?.WalkDownParentheses() ?? node;
+ public bool IsLogicalAndExpression(SyntaxNode node)
+ => node.Kind() == SyntaxKind.LogicalAndExpression;
+
public bool IsLogicalNotExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.LogicalNotExpression;
diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
index 503ea37f3676540c762b975a6e7f1aa6e6b18ea3..621e3158eb2fdcd150a9a120e3b591c5ec79f845 100644
--- a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
+++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs
@@ -75,6 +75,7 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsExpressionOfAwaitExpression(SyntaxNode node);
SyntaxNode GetExpressionOfAwaitExpression(SyntaxNode node);
+ bool IsLogicalAndExpression(SyntaxNode node);
bool IsLogicalNotExpression(SyntaxNode node);
SyntaxNode GetOperandOfPrefixUnaryExpression(SyntaxNode node);
@@ -164,6 +165,7 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsForEachStatement(SyntaxNode node);
bool IsLockStatement(SyntaxNode node);
bool IsUsingStatement(SyntaxNode node);
+ bool IsReturnStatement(SyntaxNode node);
bool IsLocalDeclarationStatement(SyntaxNode node);
bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declator, SyntaxNode localDeclarationStatement);
diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
index f76196cd481942a4f0ac7ad21ff44b47bc37f3f9..f2a5c8340b09c20971c14407922ba0adbbc29f8c 100644
--- a/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
+++ b/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
@@ -23,9 +24,12 @@ internal static partial class ICodeDefinitionFactoryExtensions
Compilation compilation,
INamedTypeSymbol containingType,
IList symbols,
+ SyntaxAnnotation statementAnnotation,
CancellationToken cancellationToken)
{
- var statements = CreateEqualsMethodStatements(factory, compilation, containingType, symbols, cancellationToken);
+ var statements = CreateEqualsMethodStatements(
+ factory, compilation, containingType, symbols, cancellationToken);
+ statements = statements.SelectAsArray(s => s.WithAdditionalAnnotations(statementAnnotation));
return CodeGenerationSymbolFactory.CreateMethodSymbol(
attributes: null,
@@ -40,7 +44,7 @@ internal static partial class ICodeDefinitionFactoryExtensions
statements: statements);
}
- private static IList CreateEqualsMethodStatements(
+ private static ImmutableArray CreateEqualsMethodStatements(
SyntaxGenerator factory,
Compilation compilation,
INamedTypeSymbol containingType,
@@ -48,11 +52,11 @@ internal static partial class ICodeDefinitionFactoryExtensions
CancellationToken cancellationToken)
{
var iequatableType = compilation.GetTypeByMetadataName("System.IEquatable`1");
- var statements = new List();
+ var statements = ArrayBuilder.GetInstance();
var parts = StringBreaker.BreakIntoWordParts(containingType.Name);
- string localName = "v";
- for (int i = parts.Count - 1; i >= 0; i--)
+ var localName = "v";
+ for (var i = parts.Count - 1; i >= 0; i--)
{
var p = parts[i];
if (char.IsLetter(containingType.Name[p.Start]))
@@ -120,7 +124,8 @@ internal static partial class ICodeDefinitionFactoryExtensions
foreach (var member in members)
{
var symbolNameExpression = factory.IdentifierName(member.Name);
- var thisSymbol = factory.MemberAccessExpression(factory.ThisExpression(), symbolNameExpression).WithAdditionalAnnotations(Simplification.Simplifier.Annotation);
+ var thisSymbol = factory.MemberAccessExpression(factory.ThisExpression(), symbolNameExpression)
+ .WithAdditionalAnnotations(Simplification.Simplifier.Annotation);
var otherSymbol = factory.MemberAccessExpression(localNameExpression, symbolNameExpression);
#if false
@@ -161,7 +166,7 @@ internal static partial class ICodeDefinitionFactoryExtensions
statements.Add(factory.ReturnStatement(
expressions.Aggregate(factory.LogicalAndExpression)));
- return statements;
+ return statements.ToImmutableAndFree();
}
private static bool ImplementsIEquatable(ITypeSymbol memberType, INamedTypeSymbol iequatableType)
diff --git a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
index ba986fa86a33f426f68999fdbd77edaf1b24307b..5f87fe3e5b415f6c989c217e55f29fd876414fc9 100644
--- a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
+++ b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
@@ -205,7 +205,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function
Public Function IsUsingStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUsingStatement
- Return TypeOf node Is UsingStatementSyntax
+ Return node.Kind() = SyntaxKind.UsingStatement
+ End Function
+
+ Public Function IsReturnStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsReturnStatement
+ Return node.Kind() = SyntaxKind.ReturnStatement
End Function
Public Function IsThisConstructorInitializer(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsThisConstructorInitializer
@@ -1607,6 +1611,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return If(TryCast(node, ExpressionSyntax)?.WalkDownParentheses(), node)
End Function
+ Public Function IsLogicalAndExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLogicalAndExpression
+ Return node.IsKind(SyntaxKind.AndAlsoExpression)
+ End Function
+
Public Function IsLogicalNotExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLogicalNotExpression
Return node.IsKind(SyntaxKind.NotExpression)
End Function