|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Formatting
{
internal sealed class NewLineUserSettingFormattingRule : BaseFormattingRule
{
private readonly CSharpSyntaxFormattingOptions _options;
public NewLineUserSettingFormattingRule()
: this(CSharpSyntaxFormattingOptions.Default)
{
}
private NewLineUserSettingFormattingRule(CSharpSyntaxFormattingOptions options)
{
_options = options;
}
public override AbstractFormattingRule WithOptions(SyntaxFormattingOptions options)
{
var newOptions = options as CSharpSyntaxFormattingOptions ?? CSharpSyntaxFormattingOptions.Default;
if (_options.NewLines == newOptions.NewLines &&
_options.WrappingKeepStatementsOnSingleLine == newOptions.WrappingKeepStatementsOnSingleLine)
{
return this;
}
return new NewLineUserSettingFormattingRule(newOptions);
}
private static bool IsControlBlock(SyntaxNode node)
{
RoslynDebug.Assert(node != null);
if (node.IsKind(SyntaxKind.SwitchStatement))
{
return true;
}
var parentKind = node.Parent?.Kind();
switch (parentKind.GetValueOrDefault())
{
case SyntaxKind.IfStatement:
case SyntaxKind.ElseClause:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.ForEachStatement:
case SyntaxKind.ForEachVariableStatement:
case SyntaxKind.UsingStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.TryStatement:
case SyntaxKind.CatchClause:
case SyntaxKind.FinallyClause:
case SyntaxKind.LockStatement:
case SyntaxKind.CheckedStatement:
case SyntaxKind.UncheckedStatement:
case SyntaxKind.SwitchSection:
case SyntaxKind.FixedStatement:
case SyntaxKind.UnsafeStatement:
return true;
default:
return false;
}
}
public override AdjustSpacesOperation? GetAdjustSpacesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustSpacesOperation nextOperation)
{
RoslynDebug.AssertNotNull(currentToken.Parent);
var operation = nextOperation.Invoke(in previousToken, in currentToken);
// } else in the if else context
if (previousToken.IsKind(SyntaxKind.CloseBraceToken)
&& currentToken.IsKind(SyntaxKind.ElseKeyword)
&& previousToken.Parent!.Parent == currentToken.Parent.Parent)
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeElse))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * catch in the try catch context
if (currentToken.IsKind(SyntaxKind.CatchKeyword))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeCatch))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * finally
if (currentToken.IsKind(SyntaxKind.FinallyKeyword))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeFinally))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { in the type declaration context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent is BaseTypeDeclarationSyntax or NamespaceDeclarationSyntax)
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInTypes))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// new { - Anonymous object creation
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AnonymousObjectCreationExpression))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousTypes))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// new { - Object Initialization, or with { - Record with initializer, or is { - property pattern clauses
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) &&
currentToken.Parent.Kind() is
SyntaxKind.ObjectInitializerExpression or
SyntaxKind.CollectionInitializerExpression or
SyntaxKind.ArrayInitializerExpression or
SyntaxKind.ImplicitArrayCreationExpression or
SyntaxKind.WithInitializerExpression or
SyntaxKind.PropertyPatternClause)
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
var currentTokenParentParent = currentToken.Parent.Parent;
// * { - in the member declaration context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent is MemberDeclarationSyntax)
{
var option = currentTokenParentParent is BasePropertyDeclarationSyntax
? _options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInProperties)
: _options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods);
if (!option)
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent is AccessorDeclarationSyntax)
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAccessors))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { - in the anonymous Method context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent.IsKind(SyntaxKind.AnonymousMethodExpression))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousMethods))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { - in the local function context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent.IsKind(SyntaxKind.LocalFunctionStatement))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { - in the Lambda context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) &&
currentTokenParentParent is (kind: SyntaxKind.SimpleLambdaExpression or SyntaxKind.ParenthesizedLambdaExpression))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { - in the switch expression context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.SwitchExpression))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
// * { - in the control statement context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && IsControlBlock(currentToken.Parent))
{
if (!_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInControlBlocks))
{
operation = CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces);
}
}
return operation;
}
public override AdjustNewLinesOperation? GetAdjustNewLinesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustNewLinesOperation nextOperation)
{
RoslynDebug.AssertNotNull(currentToken.Parent);
var operation = nextOperation.Invoke(in previousToken, in currentToken);
// else condition is actually handled in the GetAdjustSpacesOperation()
// For Object Initialization Expression
if (previousToken.IsKind(SyntaxKind.CommaToken) && previousToken.Parent.IsKind(SyntaxKind.ObjectInitializerExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeMembersInObjectInitializers))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
// we never force it to move up unless it is already on same line
return CreateAdjustNewLinesOperation(0, AdjustNewLinesOption.PreserveLines);
}
}
// For Anonymous Object Creation Expression
if (previousToken.IsKind(SyntaxKind.CommaToken) && previousToken.Parent.IsKind(SyntaxKind.AnonymousObjectCreationExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeMembersInAnonymousTypes))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
// we never force it to move up unless it is already on same line
return CreateAdjustNewLinesOperation(0, AdjustNewLinesOption.PreserveLines);
}
}
// } else in the if else context
if (previousToken.IsKind(SyntaxKind.CloseBraceToken) && currentToken.IsKind(SyntaxKind.ElseKeyword))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeElse)
|| previousToken.Parent!.Parent != currentToken.Parent.Parent)
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * catch in the try catch context
if (currentToken.IsKind(SyntaxKind.CatchKeyword))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeCatch))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * Finally
if (currentToken.IsKind(SyntaxKind.FinallyKeyword))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeFinally))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * { - in the type declaration context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent is BaseTypeDeclarationSyntax or NamespaceDeclarationSyntax)
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInTypes))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// new { - Anonymous object creation
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AnonymousObjectCreationExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousTypes))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// new MyObject { - Object Initialization
// new List<int> { - Collection Initialization
// with { - Record with initializer
// is { - property pattern clauses
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) &&
currentToken.Parent.Kind() is SyntaxKind.ObjectInitializerExpression or SyntaxKind.CollectionInitializerExpression or SyntaxKind.WithInitializerExpression or SyntaxKind.PropertyPatternClause)
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// Array Initialization Expression
// int[] arr = new int[] {
// new[] {
// { - Implicit Array
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) &&
currentToken.Parent.Kind() is SyntaxKind.ArrayInitializerExpression or SyntaxKind.ImplicitArrayCreationExpression)
{
return null;
}
var currentTokenParentParent = currentToken.Parent.Parent;
// * { - in the member declaration context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent is MemberDeclarationSyntax)
{
var option = currentTokenParentParent is BasePropertyDeclarationSyntax
? _options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInProperties)
: _options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods);
if (option)
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * { - in the property accessor context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent is AccessorDeclarationSyntax)
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAccessors))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * { - in the anonymous Method context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent.IsKind(SyntaxKind.AnonymousMethodExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousMethods))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.ForceLinesIfOnSingleLine);
}
else
{
return null;
}
}
// * { - in the local function context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentTokenParentParent.IsKind(SyntaxKind.LocalFunctionStatement))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * { - in the simple Lambda context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) &&
currentTokenParentParent is (kind: SyntaxKind.SimpleLambdaExpression or SyntaxKind.ParenthesizedLambdaExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.ForceLinesIfOnSingleLine);
}
else
{
return null;
}
}
// * { - in the switch expression context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.SwitchExpression))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// * { - in the control statement context
if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && IsControlBlock(currentToken.Parent))
{
if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInControlBlocks))
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
else
{
return null;
}
}
// Wrapping - Leave statements on same line (false):
// Insert a newline between the previous statement and this one.
// ; *
if (previousToken.IsKind(SyntaxKind.SemicolonToken)
&& (previousToken.Parent is StatementSyntax && !previousToken.Parent.IsKind(SyntaxKind.ForStatement))
&& !_options.WrappingKeepStatementsOnSingleLine)
{
return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines);
}
return operation;
}
}
}
|