public override AdjustSpacesOperation GetAdjustSpacesOperation(SyntaxToken previousToken, SyntaxToken currentToken, OptionSet optionSet, NextOperation<AdjustSpacesOperation> nextOperation) { if (optionSet == null) { return nextOperation.Invoke(); } System.Diagnostics.Debug.Assert(previousToken.Parent != null && currentToken.Parent != null); var previousKind = previousToken.Kind(); var currentKind = currentToken.Kind(); var previousParentKind = previousToken.Parent.Kind(); var currentParentKind = currentToken.Parent.Kind(); // For Method Declaration if (currentToken.IsOpenParenInParameterList() && previousKind == SyntaxKind.IdentifierToken) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpacingAfterMethodDeclarationName); } // Case: public static implicit operator string(Program p) { return null; } if (previousToken.IsKeyword() && currentToken.IsOpenParenInParameterListOfAConversionOperator()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpacingAfterMethodDeclarationName); } // Case: public static Program operator !(Program p) { return null; } if (previousToken.Parent.IsKind(SyntaxKind.OperatorDeclaration) && currentToken.IsOpenParenInParameterListOfAOperationDeclaration()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpacingAfterMethodDeclarationName); } if (previousToken.IsOpenParenInParameterList() && currentToken.IsCloseParenInParameterList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBetweenEmptyMethodDeclarationParentheses); } if (previousToken.IsOpenParenInParameterList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodDeclarationParenthesis); } if (currentToken.IsCloseParenInParameterList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodDeclarationParenthesis); } // For Method Call if (currentToken.IsOpenParenInArgumentList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterMethodCallName); } if (previousToken.IsOpenParenInArgumentList() && currentToken.IsCloseParenInArgumentList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBetweenEmptyMethodCallParentheses); } if (previousToken.IsOpenParenInArgumentList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodCallParentheses); } if (currentToken.IsCloseParenInArgumentList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodCallParentheses); } // For spacing around: typeof, default, and sizeof; treat like a Method Call if (currentKind == SyntaxKind.OpenParenToken && IsFunctionLikeKeywordExpressionKind(currentParentKind)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterMethodCallName); } if (previousKind == SyntaxKind.OpenParenToken && IsFunctionLikeKeywordExpressionKind(previousParentKind)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodCallParentheses); } if (currentKind == SyntaxKind.CloseParenToken && IsFunctionLikeKeywordExpressionKind(currentParentKind)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinMethodCallParentheses); } // For Spacing b/n control flow keyword and paren. Parent check not needed. if (currentKind == SyntaxKind.OpenParenToken && (previousKind == SyntaxKind.IfKeyword || previousKind == SyntaxKind.WhileKeyword || previousKind == SyntaxKind.SwitchKeyword || previousKind == SyntaxKind.ForKeyword || previousKind == SyntaxKind.ForEachKeyword || previousKind == SyntaxKind.CatchKeyword || previousKind == SyntaxKind.UsingKeyword)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterControlFlowStatementKeyword); } // For spacing between parenthesis and expression if ((previousParentKind == SyntaxKind.ParenthesizedExpression && previousKind == SyntaxKind.OpenParenToken) || (currentParentKind == SyntaxKind.ParenthesizedExpression && currentKind == SyntaxKind.CloseParenToken)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinExpressionParentheses); } // For spacing between the parenthesis and the cast expression if ((previousParentKind == SyntaxKind.CastExpression && previousKind == SyntaxKind.OpenParenToken) || (currentParentKind == SyntaxKind.CastExpression && currentKind == SyntaxKind.CloseParenToken)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinCastParentheses); } // For spacing between the parenthesis and the expression inside the control flow expression if (previousKind == SyntaxKind.OpenParenToken && IsControlFlowLikeKeywordStatementKind(previousParentKind)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinOtherParentheses); } // Semicolons in an empty for statement. i.e. for(;;) if (previousKind == SyntaxKind.OpenParenToken || previousKind == SyntaxKind.SemicolonToken) { if (previousToken.Parent.Kind() == SyntaxKind.ForStatement) { var forStatement = (ForStatementSyntax)previousToken.Parent; if (forStatement.Initializers.Count == 0 && forStatement.Declaration == null && forStatement.Condition == null && forStatement.Incrementors.Count == 0) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } } } if (currentKind == SyntaxKind.CloseParenToken && IsControlFlowLikeKeywordStatementKind(currentParentKind)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinOtherParentheses); } // For spacing after the cast if (previousParentKind == SyntaxKind.CastExpression && previousKind == SyntaxKind.CloseParenToken) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterCast); } // For spacing Before Square Braces if (currentKind == SyntaxKind.OpenBracketToken && HasFormattableBracketParent(currentToken) && !previousToken.IsOpenBraceOrCommaOfObjectInitializer()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBeforeOpenSquareBracket); } // For spacing empty square braces if (previousKind == SyntaxKind.OpenBracketToken && (currentKind == SyntaxKind.CloseBracketToken || currentKind == SyntaxKind.OmittedArraySizeExpressionToken) && HasFormattableBracketParent(previousToken)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBetweenEmptySquareBrackets); } // For spacing square brackets within if (previousKind == SyntaxKind.OpenBracketToken && HasFormattableBracketParent(previousToken)) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinSquareBrackets); } else if (currentKind == SyntaxKind.CloseBracketToken && HasFormattableBracketParent(currentToken)) { if (currentToken.Parent is ArrayRankSpecifierSyntax) { var parent = currentToken.Parent as ArrayRankSpecifierSyntax; if ((parent.Sizes.Any() && parent.Sizes.First().Kind() != SyntaxKind.OmittedArraySizeExpression) || parent.Sizes.SeparatorCount > 0) { // int []: added spacing operation on open [ // int[1], int[,]: need spacing operation return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinSquareBrackets); } } else { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceWithinSquareBrackets); } } // For spacing delimiters - after colon if (previousToken.IsColonInTypeBaseList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterColonInBaseTypeDeclaration); } // For spacing delimiters - before colon if (currentToken.IsColonInTypeBaseList()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBeforeColonInBaseTypeDeclaration); } // For spacing delimiters - after comma if ((previousToken.IsCommaInArgumentOrParameterList() && currentKind != SyntaxKind.OmittedTypeArgumentToken) || previousToken.IsCommaInInitializerExpression()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterComma); } // For spacing delimiters - before comma if ((currentToken.IsCommaInArgumentOrParameterList() && previousKind != SyntaxKind.OmittedTypeArgumentToken) || currentToken.IsCommaInInitializerExpression()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBeforeComma); } // For Spacing delimiters - after Dot if (previousToken.IsDotInMemberAccessOrQualifiedName()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterDot); } // For spacing delimiters - before Dot if (currentToken.IsDotInMemberAccessOrQualifiedName()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBeforeDot); } // For spacing delimiters - after semicolon if (previousToken.IsSemicolonInForStatement() && currentKind != SyntaxKind.CloseParenToken) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceAfterSemicolonsInForStatement); } // For spacing delimiters - before semicolon if (currentToken.IsSemicolonInForStatement()) { return AdjustSpacesOperationZeroOrOne(optionSet, CSharpFormattingOptions.SpaceBeforeSemicolonsInForStatement); } // For spacing around the binary operators if (currentToken.Parent is BinaryExpressionSyntax || previousToken.Parent is BinaryExpressionSyntax || currentToken.Parent is AssignmentExpressionSyntax || previousToken.Parent is AssignmentExpressionSyntax) { switch (optionSet.GetOption(CSharpFormattingOptions.SpacingAroundBinaryOperator)) { case BinaryOperatorSpacingOptions.Single: return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); case BinaryOperatorSpacingOptions.Remove: return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); case BinaryOperatorSpacingOptions.Ignore: return CreateAdjustSpacesOperation(0, AdjustSpacesOption.PreserveSpaces); default: System.Diagnostics.Debug.Assert(false, "Invalid BinaryOperatorSpacingOptions"); break; } } // No space after $" and $@" at the start of an interpolated string if (previousKind == SyntaxKind.InterpolatedStringStartToken || previousKind == SyntaxKind.InterpolatedVerbatimStringStartToken) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } // No space before " at the end of an interpolated string if (currentKind == SyntaxKind.InterpolatedStringEndToken) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } // No space before { or after } in interpolations if ((currentKind == SyntaxKind.OpenBraceToken && currentToken.Parent is InterpolationSyntax) || (previousKind == SyntaxKind.CloseBraceToken && previousToken.Parent is InterpolationSyntax)) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } // Preserve space after { or before } in interpolations (i.e. between the braces and the expression) if ((previousKind == SyntaxKind.OpenBraceToken && previousToken.Parent is InterpolationSyntax) || (currentKind == SyntaxKind.CloseBraceToken && currentToken.Parent is InterpolationSyntax)) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.PreserveSpaces); } // No space before or after , in interpolation alignment clause if ((previousKind == SyntaxKind.CommaToken && previousToken.Parent is InterpolationAlignmentClauseSyntax) || (currentKind == SyntaxKind.CommaToken && currentToken.Parent is InterpolationAlignmentClauseSyntax)) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } // No space before or after : in interpolation format clause if ((previousKind == SyntaxKind.ColonToken && previousToken.Parent is InterpolationFormatClauseSyntax) || (currentKind == SyntaxKind.ColonToken && currentToken.Parent is InterpolationFormatClauseSyntax)) { return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); } return nextOperation.Invoke(); }