You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
18 KiB
448 lines
18 KiB
// |
|
// AstFormattingVisitor_Expressions.cs |
|
// |
|
// Author: |
|
// Mike Krüger <mkrueger@xamarin.com> |
|
// |
|
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy |
|
// of this software and associated documentation files (the "Software"), to deal |
|
// in the Software without restriction, including without limitation the rights |
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
// copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in |
|
// all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
// THE SOFTWARE. |
|
using System; |
|
using System.Linq; |
|
|
|
namespace ICSharpCode.NRefactory.CSharp |
|
{ |
|
partial class FormattingVisitor : DepthFirstAstVisitor |
|
{ |
|
public override void VisitComposedType(ComposedType composedType) |
|
{ |
|
var spec = composedType.ArraySpecifiers.FirstOrDefault(); |
|
if (spec != null) |
|
ForceSpacesBefore(spec.LBracketToken, policy.SpaceBeforeArrayDeclarationBrackets); |
|
|
|
if (composedType.HasNullableSpecifier) |
|
ForceSpacesBefore(composedType.NullableSpecifierToken, false); |
|
|
|
if (composedType.PointerRank > 0) |
|
foreach (var token in composedType.PointerTokens) |
|
ForceSpacesBefore(token, false); |
|
|
|
base.VisitComposedType(composedType); |
|
} |
|
|
|
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) |
|
{ |
|
if (!anonymousMethodExpression.Body.IsNull) { |
|
if (anonymousMethodExpression.Body.LBraceToken.GetNextNode(NoWhitespacePredicate) != anonymousMethodExpression.Body.RBraceToken) { |
|
FixOpenBrace(policy.AnonymousMethodBraceStyle, anonymousMethodExpression.Body.LBraceToken); |
|
VisitBlockWithoutFixingBraces(anonymousMethodExpression.Body, policy.IndentBlocks); |
|
FixClosingBrace(policy.AnonymousMethodBraceStyle, anonymousMethodExpression.Body.RBraceToken); |
|
} else { |
|
VisitBlockWithoutFixingBraces(anonymousMethodExpression.Body, policy.IndentBlocks); |
|
} |
|
return; |
|
} |
|
base.VisitAnonymousMethodExpression(anonymousMethodExpression); |
|
} |
|
|
|
public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression) |
|
{ |
|
ForceSpacesAround(assignmentExpression.OperatorToken, policy.SpaceAroundAssignment); |
|
base.VisitAssignmentExpression(assignmentExpression); |
|
} |
|
|
|
public override void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) |
|
{ |
|
bool forceSpaces = false; |
|
switch (binaryOperatorExpression.Operator) { |
|
case BinaryOperatorType.Equality: |
|
case BinaryOperatorType.InEquality: |
|
forceSpaces = policy.SpaceAroundEqualityOperator; |
|
break; |
|
case BinaryOperatorType.GreaterThan: |
|
case BinaryOperatorType.GreaterThanOrEqual: |
|
case BinaryOperatorType.LessThan: |
|
case BinaryOperatorType.LessThanOrEqual: |
|
forceSpaces = policy.SpaceAroundRelationalOperator; |
|
break; |
|
case BinaryOperatorType.ConditionalAnd: |
|
case BinaryOperatorType.ConditionalOr: |
|
forceSpaces = policy.SpaceAroundLogicalOperator; |
|
break; |
|
case BinaryOperatorType.BitwiseAnd: |
|
case BinaryOperatorType.BitwiseOr: |
|
case BinaryOperatorType.ExclusiveOr: |
|
forceSpaces = policy.SpaceAroundBitwiseOperator; |
|
break; |
|
case BinaryOperatorType.Add: |
|
case BinaryOperatorType.Subtract: |
|
forceSpaces = policy.SpaceAroundAdditiveOperator; |
|
break; |
|
case BinaryOperatorType.Multiply: |
|
case BinaryOperatorType.Divide: |
|
case BinaryOperatorType.Modulus: |
|
forceSpaces = policy.SpaceAroundMultiplicativeOperator; |
|
break; |
|
case BinaryOperatorType.ShiftLeft: |
|
case BinaryOperatorType.ShiftRight: |
|
forceSpaces = policy.SpaceAroundShiftOperator; |
|
break; |
|
case BinaryOperatorType.NullCoalescing: |
|
forceSpaces = policy.SpaceAroundNullCoalescingOperator; |
|
break; |
|
} |
|
ForceSpacesAround(binaryOperatorExpression.OperatorToken, forceSpaces); |
|
|
|
base.VisitBinaryOperatorExpression(binaryOperatorExpression); |
|
// Handle line breaks in binary opeartor expression. |
|
if (binaryOperatorExpression.Left.EndLocation.Line != binaryOperatorExpression.Right.StartLocation.Line) { |
|
curIndent.Push(IndentType.Block); |
|
if (binaryOperatorExpression.OperatorToken.StartLocation.Line == binaryOperatorExpression.Right.StartLocation.Line) { |
|
FixStatementIndentation(binaryOperatorExpression.OperatorToken.StartLocation); |
|
} else { |
|
FixStatementIndentation(binaryOperatorExpression.Right.StartLocation); |
|
} |
|
curIndent.Pop (); |
|
} |
|
} |
|
|
|
public override void VisitConditionalExpression(ConditionalExpression conditionalExpression) |
|
{ |
|
ForceSpacesBefore(conditionalExpression.QuestionMarkToken, policy.SpaceBeforeConditionalOperatorCondition); |
|
ForceSpacesAfter(conditionalExpression.QuestionMarkToken, policy.SpaceAfterConditionalOperatorCondition); |
|
ForceSpacesBefore(conditionalExpression.ColonToken, policy.SpaceBeforeConditionalOperatorSeparator); |
|
ForceSpacesAfter(conditionalExpression.ColonToken, policy.SpaceAfterConditionalOperatorSeparator); |
|
base.VisitConditionalExpression(conditionalExpression); |
|
} |
|
|
|
public override void VisitCastExpression(CastExpression castExpression) |
|
{ |
|
if (castExpression.RParToken != null) { |
|
ForceSpacesAfter(castExpression.LParToken, policy.SpacesWithinCastParentheses); |
|
ForceSpacesBefore(castExpression.RParToken, policy.SpacesWithinCastParentheses); |
|
|
|
ForceSpacesAfter(castExpression.RParToken, policy.SpaceAfterTypecast); |
|
} |
|
base.VisitCastExpression(castExpression); |
|
} |
|
|
|
void ForceSpacesAround(AstNode node, bool forceSpaces) |
|
{ |
|
if (node.IsNull) { |
|
return; |
|
} |
|
ForceSpacesBefore(node, forceSpaces); |
|
ForceSpacesAfter(node, forceSpaces); |
|
} |
|
|
|
void FormatCommas(AstNode parent, bool before, bool after) |
|
{ |
|
if (parent.IsNull) { |
|
return; |
|
} |
|
foreach (CSharpTokenNode comma in parent.Children.Where (node => node.Role == Roles.Comma)) { |
|
ForceSpacesAfter(comma, after); |
|
ForceSpacesBefore(comma, before); |
|
} |
|
} |
|
|
|
bool DoWrap (Wrapping wrapping, AstNode wrapNode, int argumentCount) |
|
{ |
|
return wrapping == Wrapping.WrapAlways || |
|
options.WrapLineLength > 0 && argumentCount > 1 && wrapping == Wrapping.WrapIfTooLong && wrapNode.StartLocation.Column >= options.WrapLineLength; |
|
} |
|
|
|
void FormatArguments(AstNode node) |
|
{ |
|
Wrapping methodCallArgumentWrapping; |
|
bool newLineAferMethodCallOpenParentheses; |
|
bool methodClosingParenthesesOnNewLine; |
|
bool spaceWithinMethodCallParentheses; |
|
bool spaceWithinEmptyParentheses; |
|
bool spaceAfterMethodCallParameterComma; |
|
bool spaceBeforeMethodCallParameterComma; |
|
|
|
CSharpTokenNode rParToken; |
|
AstNodeCollection<Expression> arguments; |
|
var indexer = node as IndexerExpression; |
|
if (indexer != null) { |
|
methodCallArgumentWrapping = policy.IndexerArgumentWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferIndexerOpenBracket; |
|
methodClosingParenthesesOnNewLine = policy.IndexerClosingBracketOnNewLine; |
|
spaceWithinMethodCallParentheses = policy.SpacesWithinBrackets; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterBracketComma; |
|
spaceWithinEmptyParentheses = spaceWithinMethodCallParentheses; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeBracketComma; |
|
rParToken = indexer.RBracketToken; |
|
arguments = indexer.Arguments; |
|
} else if (node is ObjectCreateExpression) { |
|
var oce = node as ObjectCreateExpression; |
|
methodCallArgumentWrapping = policy.MethodCallArgumentWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferMethodCallOpenParentheses; |
|
methodClosingParenthesesOnNewLine = policy.MethodCallClosingParenthesesOnNewLine; |
|
spaceWithinMethodCallParentheses = policy.SpacesWithinNewParentheses; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterNewParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeNewParameterComma; |
|
spaceWithinEmptyParentheses = policy.SpacesBetweenEmptyNewParentheses; |
|
|
|
rParToken = oce.RParToken; |
|
arguments = oce.Arguments; |
|
} else { |
|
InvocationExpression invocationExpression = node as InvocationExpression; |
|
methodCallArgumentWrapping = policy.MethodCallArgumentWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferMethodCallOpenParentheses; |
|
methodClosingParenthesesOnNewLine = policy.MethodCallClosingParenthesesOnNewLine; |
|
spaceWithinMethodCallParentheses = policy.SpaceWithinMethodCallParentheses; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterMethodCallParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeMethodCallParameterComma; |
|
spaceWithinEmptyParentheses = policy.SpaceBetweenEmptyMethodCallParentheses; |
|
|
|
rParToken = invocationExpression.RParToken; |
|
arguments = invocationExpression.Arguments; |
|
} |
|
|
|
if (formatter.FormattingMode == ICSharpCode.NRefactory.CSharp.FormattingMode.OnTheFly) |
|
methodCallArgumentWrapping = Wrapping.DoNotChange; |
|
|
|
bool wrapMethodCall = DoWrap(methodCallArgumentWrapping, rParToken, arguments.Count); |
|
if (wrapMethodCall && arguments.Any()) { |
|
if (newLineAferMethodCallOpenParentheses) { |
|
curIndent.Push(IndentType.Continuation); |
|
foreach (var arg in arguments) { |
|
FixStatementIndentation(arg.StartLocation); |
|
} |
|
curIndent.Pop(); |
|
} else { |
|
int extraSpaces = arguments.First().StartLocation.Column - 1 - curIndent.IndentString.Length; |
|
curIndent.ExtraSpaces += extraSpaces; |
|
foreach (var arg in arguments.Skip(1)) { |
|
FixStatementIndentation(arg.StartLocation); |
|
} |
|
curIndent.ExtraSpaces -= extraSpaces; |
|
} |
|
if (!rParToken.IsNull) { |
|
if (methodClosingParenthesesOnNewLine) { |
|
FixStatementIndentation(rParToken.StartLocation); |
|
} else { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); |
|
} |
|
} |
|
} else { |
|
foreach (var arg in arguments) { |
|
if (arg.GetPrevSibling(NoWhitespacePredicate) != null) { |
|
if (methodCallArgumentWrapping == Wrapping.DoNotWrap) { |
|
ForceSpacesBeforeRemoveNewLines(arg, spaceAfterMethodCallParameterComma && arg.GetPrevSibling(NoWhitespacePredicate).Role == Roles.Comma); |
|
} else { |
|
ForceSpacesBefore(arg, spaceAfterMethodCallParameterComma && arg.GetPrevSibling(NoWhitespacePredicate).Role == Roles.Comma); |
|
} |
|
} |
|
arg.AcceptVisitor(this); |
|
} |
|
if (!rParToken.IsNull) { |
|
if (methodCallArgumentWrapping == Wrapping.DoNotWrap) { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, arguments.Any() ? spaceWithinMethodCallParentheses : spaceWithinEmptyParentheses); |
|
} else { |
|
bool sameLine = rParToken.GetPrevNode().EndLocation.Line == rParToken.StartLocation.Line; |
|
if (sameLine) { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, arguments.Any() ? spaceWithinMethodCallParentheses : spaceWithinEmptyParentheses); |
|
} else { |
|
FixStatementIndentation(rParToken.StartLocation); |
|
} |
|
} |
|
} |
|
} |
|
if (!rParToken.IsNull) { |
|
foreach (CSharpTokenNode comma in rParToken.Parent.Children.Where(n => n.Role == Roles.Comma)) { |
|
ForceSpacesBefore(comma, spaceBeforeMethodCallParameterComma); |
|
} |
|
} |
|
} |
|
|
|
public override void VisitInvocationExpression(InvocationExpression invocationExpression) |
|
{ |
|
ForceSpacesBefore(invocationExpression.LParToken, policy.SpaceBeforeMethodCallParentheses); |
|
if (invocationExpression.Arguments.Any()) { |
|
ForceSpacesAfter(invocationExpression.LParToken, policy.SpaceWithinMethodCallParentheses); |
|
} else { |
|
ForceSpacesAfter(invocationExpression.LParToken, policy.SpaceBetweenEmptyMethodCallParentheses); |
|
ForceSpacesBefore(invocationExpression.RParToken, policy.SpaceBetweenEmptyMethodCallParentheses); |
|
} |
|
|
|
if (!invocationExpression.Target.IsNull) |
|
invocationExpression.Target.AcceptVisitor(this); |
|
|
|
if (invocationExpression.Target is MemberReferenceExpression) { |
|
var mt = (MemberReferenceExpression)invocationExpression.Target; |
|
if (mt.Target is InvocationExpression) { |
|
if (DoWrap(policy.ChainedMethodCallWrapping, mt.DotToken, 2)) { |
|
curIndent.Push(IndentType.Continuation); |
|
FixStatementIndentation(mt.DotToken.StartLocation); |
|
curIndent.Pop(); |
|
} else { |
|
if (policy.ChainedMethodCallWrapping == Wrapping.DoNotWrap) |
|
ForceSpacesBeforeRemoveNewLines(mt.DotToken, false); |
|
} |
|
} |
|
} |
|
FormatArguments(invocationExpression); |
|
} |
|
|
|
public override void VisitIndexerExpression(IndexerExpression indexerExpression) |
|
{ |
|
ForceSpacesBefore(indexerExpression.LBracketToken, policy.SpacesBeforeBrackets); |
|
ForceSpacesAfter(indexerExpression.LBracketToken, policy.SpacesWithinBrackets); |
|
|
|
if (!indexerExpression.Target.IsNull) |
|
indexerExpression.Target.AcceptVisitor(this); |
|
|
|
FormatArguments(indexerExpression); |
|
|
|
|
|
|
|
} |
|
|
|
public override void VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression) |
|
{ |
|
ForceSpacesAfter(parenthesizedExpression.LParToken, policy.SpacesWithinParentheses); |
|
ForceSpacesBefore(parenthesizedExpression.RParToken, policy.SpacesWithinParentheses); |
|
base.VisitParenthesizedExpression(parenthesizedExpression); |
|
} |
|
|
|
public override void VisitSizeOfExpression(SizeOfExpression sizeOfExpression) |
|
{ |
|
ForceSpacesBefore(sizeOfExpression.LParToken, policy.SpaceBeforeSizeOfParentheses); |
|
ForceSpacesAfter(sizeOfExpression.LParToken, policy.SpacesWithinSizeOfParentheses); |
|
ForceSpacesBefore(sizeOfExpression.RParToken, policy.SpacesWithinSizeOfParentheses); |
|
base.VisitSizeOfExpression(sizeOfExpression); |
|
} |
|
|
|
public override void VisitTypeOfExpression(TypeOfExpression typeOfExpression) |
|
{ |
|
ForceSpacesBefore(typeOfExpression.LParToken, policy.SpaceBeforeTypeOfParentheses); |
|
ForceSpacesAfter(typeOfExpression.LParToken, policy.SpacesWithinTypeOfParentheses); |
|
ForceSpacesBefore(typeOfExpression.RParToken, policy.SpacesWithinTypeOfParentheses); |
|
base.VisitTypeOfExpression(typeOfExpression); |
|
} |
|
|
|
public override void VisitCheckedExpression(CheckedExpression checkedExpression) |
|
{ |
|
ForceSpacesAfter(checkedExpression.LParToken, policy.SpacesWithinCheckedExpressionParantheses); |
|
ForceSpacesBefore(checkedExpression.RParToken, policy.SpacesWithinCheckedExpressionParantheses); |
|
base.VisitCheckedExpression(checkedExpression); |
|
} |
|
|
|
public override void VisitUncheckedExpression(UncheckedExpression uncheckedExpression) |
|
{ |
|
ForceSpacesAfter(uncheckedExpression.LParToken, policy.SpacesWithinCheckedExpressionParantheses); |
|
ForceSpacesBefore(uncheckedExpression.RParToken, policy.SpacesWithinCheckedExpressionParantheses); |
|
base.VisitUncheckedExpression(uncheckedExpression); |
|
} |
|
|
|
public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) |
|
{ |
|
ForceSpacesBefore(objectCreateExpression.LParToken, policy.SpaceBeforeNewParentheses); |
|
|
|
if (objectCreateExpression.Arguments.Any()) { |
|
if (!objectCreateExpression.LParToken.IsNull) |
|
ForceSpacesAfter(objectCreateExpression.LParToken, policy.SpacesWithinNewParentheses); |
|
} else { |
|
if (!objectCreateExpression.LParToken.IsNull) |
|
ForceSpacesAfter(objectCreateExpression.LParToken, policy.SpacesBetweenEmptyNewParentheses); |
|
} |
|
|
|
if (!objectCreateExpression.Type.IsNull) |
|
objectCreateExpression.Type.AcceptVisitor(this); |
|
objectCreateExpression.Initializer.AcceptVisitor(this); |
|
FormatArguments(objectCreateExpression); |
|
|
|
} |
|
|
|
public override void VisitArrayCreateExpression(ArrayCreateExpression arrayObjectCreateExpression) |
|
{ |
|
FormatCommas(arrayObjectCreateExpression, policy.SpaceBeforeMethodCallParameterComma, policy.SpaceAfterMethodCallParameterComma); |
|
base.VisitArrayCreateExpression(arrayObjectCreateExpression); |
|
} |
|
|
|
public override void VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression) |
|
{ |
|
if (DoWrap(policy.ArrayInitializerWrapping, arrayInitializerExpression.RBraceToken, arrayInitializerExpression.Elements.Count)) { |
|
FixOpenBrace(policy.ArrayInitializerBraceStyle, arrayInitializerExpression.LBraceToken); |
|
curIndent.Push(IndentType.Block); |
|
foreach (var init in arrayInitializerExpression.Elements) { |
|
FixStatementIndentation(init.StartLocation); |
|
init.AcceptVisitor(this); |
|
} |
|
curIndent.Pop(); |
|
FixClosingBrace(policy.ArrayInitializerBraceStyle, arrayInitializerExpression.RBraceToken); |
|
} else if (policy.ArrayInitializerWrapping == Wrapping.DoNotWrap) { |
|
ForceSpacesBeforeRemoveNewLines(arrayInitializerExpression.LBraceToken); |
|
ForceSpacesBeforeRemoveNewLines(arrayInitializerExpression.RBraceToken); |
|
foreach (var init in arrayInitializerExpression.Elements) { |
|
ForceSpacesBeforeRemoveNewLines(init); |
|
init.AcceptVisitor(this); |
|
} |
|
} else { |
|
foreach (var child in arrayInitializerExpression.Children) { |
|
if (child.Role == Roles.LBrace) { |
|
FixOpenBrace(policy.ArrayInitializerBraceStyle, child); |
|
curIndent.Push(IndentType.Block); |
|
continue; |
|
} |
|
if (child.Role == Roles.RBrace) { |
|
curIndent.Pop(); |
|
FixClosingBrace(policy.ArrayInitializerBraceStyle, child); |
|
continue; |
|
} |
|
if (child.Role == Roles.Expression) { |
|
if (child.PrevSibling.Role == Roles.NewLine) |
|
FixIndentation(child); |
|
if (child.PrevSibling.Role == Roles.Comma) |
|
ForceSpaceBefore(child, true); |
|
if (child.NextSibling.Role == Roles.Comma) |
|
ForceSpacesAfter(child, false); |
|
continue; |
|
} |
|
|
|
child.AcceptVisitor(this); |
|
} |
|
} |
|
} |
|
|
|
public override void VisitLambdaExpression(LambdaExpression lambdaExpression) |
|
{ |
|
ForceSpacesAfter(lambdaExpression.ArrowToken, true); |
|
ForceSpacesBefore(lambdaExpression.ArrowToken, true); |
|
|
|
base.VisitLambdaExpression(lambdaExpression); |
|
} |
|
|
|
public override void VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression) |
|
{ |
|
ForceSpacesAfter(namedArgumentExpression.ColonToken, policy.SpaceInNamedArgumentAfterDoubleColon); |
|
base.VisitNamedArgumentExpression(namedArgumentExpression); |
|
} |
|
|
|
public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression) |
|
{ |
|
ForceSpacesAfter(memberReferenceExpression.DotToken, false); |
|
base.VisitMemberReferenceExpression(memberReferenceExpression); |
|
} |
|
} |
|
} |
|
|
|
|