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.
278 lines
9.2 KiB
278 lines
9.2 KiB
// |
|
// AstFormattingVisitor_Global.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 |
|
{ |
|
int GetGlobalNewLinesFor(AstNode child) |
|
{ |
|
int newLines = 1; |
|
var nextSibling = child.GetNextSibling(NoWhitespacePredicate); |
|
if ((child is UsingDeclaration || child is UsingAliasDeclaration) && !(nextSibling is UsingDeclaration || nextSibling is UsingAliasDeclaration)) { |
|
newLines += policy.BlankLinesAfterUsings; |
|
} else if ((child is TypeDeclaration) && (nextSibling is TypeDeclaration)) { |
|
newLines += policy.BlankLinesBetweenTypes; |
|
} |
|
|
|
return newLines; |
|
} |
|
|
|
public override void VisitSyntaxTree(SyntaxTree unit) |
|
{ |
|
bool first = true; |
|
VisitChildrenToFormat(unit, child => { |
|
if (first && (child is UsingDeclaration || child is UsingAliasDeclaration)) { |
|
EnsureBlankLinesBefore(child, policy.BlankLinesBeforeUsings); |
|
first = false; |
|
} |
|
if (NoWhitespacePredicate(child)) |
|
FixIndentation(child); |
|
child.AcceptVisitor(this); |
|
if (NoWhitespacePredicate(child)) |
|
EnsureNewLinesAfter(child, GetGlobalNewLinesFor(child)); |
|
}); |
|
} |
|
|
|
public override void VisitUsingDeclaration(UsingDeclaration usingDeclaration) |
|
{ |
|
ForceSpacesAfter(usingDeclaration.UsingToken, true); |
|
FixSemicolon(usingDeclaration.SemicolonToken); |
|
} |
|
|
|
public override void VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration) |
|
{ |
|
ForceSpacesAfter(usingDeclaration.UsingToken, true); |
|
FixSemicolon(usingDeclaration.SemicolonToken); |
|
} |
|
|
|
public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) |
|
{ |
|
FixOpenBrace(policy.NamespaceBraceStyle, namespaceDeclaration.LBraceToken); |
|
if (policy.IndentNamespaceBody) |
|
curIndent.Push(IndentType.Block); |
|
|
|
bool first = true; |
|
bool startFormat = false; |
|
VisitChildrenToFormat(namespaceDeclaration, child => { |
|
if (first) { |
|
startFormat = child.StartLocation > namespaceDeclaration.LBraceToken.StartLocation; |
|
} |
|
if (child.Role == Roles.LBrace) { |
|
var next = child.GetNextSibling(NoWhitespacePredicate); |
|
var blankLines = 1; |
|
if (next is UsingDeclaration || next is UsingAliasDeclaration) { |
|
blankLines += policy.BlankLinesBeforeUsings; |
|
} else { |
|
blankLines += policy.BlankLinesBeforeFirstDeclaration; |
|
} |
|
EnsureNewLinesAfter(child, blankLines); |
|
startFormat = true; |
|
return; |
|
} |
|
if (child.Role == Roles.RBrace) { |
|
startFormat = false; |
|
return; |
|
} |
|
if (!startFormat || !NoWhitespacePredicate (child)) |
|
return; |
|
if (first && (child is UsingDeclaration || child is UsingAliasDeclaration)) { |
|
// TODO: policy.BlankLinesBeforeUsings |
|
first = false; |
|
} |
|
if (NoWhitespacePredicate(child)) |
|
FixIndentationForceNewLine(child); |
|
child.AcceptVisitor(this); |
|
if (NoWhitespacePredicate(child)) |
|
EnsureNewLinesAfter(child, GetGlobalNewLinesFor(child)); |
|
}); |
|
|
|
if (policy.IndentNamespaceBody) |
|
curIndent.Pop(); |
|
|
|
FixClosingBrace(policy.NamespaceBraceStyle, namespaceDeclaration.RBraceToken); |
|
} |
|
|
|
void FixAttributesAndDocComment(EntityDeclaration entity) |
|
{ |
|
var node =entity.FirstChild; |
|
while (node != null && node.Role == Roles.Comment) { |
|
FixIndentation(node); |
|
node = node.GetNextSibling(NoWhitespacePredicate); |
|
} |
|
if (entity.Attributes.Count > 0) { |
|
AstNode n = null; |
|
foreach (var attr in entity.Attributes.Skip (1)) { |
|
FixIndentation(attr); |
|
n = attr; |
|
} |
|
if (n != null) { |
|
FixIndentation(n.GetNextNode(NoWhitespacePredicate)); |
|
} else { |
|
FixIndentation(entity.Attributes.First().GetNextNode(NoWhitespacePredicate)); |
|
} |
|
} |
|
} |
|
|
|
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) |
|
{ |
|
FixAttributesAndDocComment(typeDeclaration); |
|
BraceStyle braceStyle; |
|
bool indentBody = false; |
|
switch (typeDeclaration.ClassType) { |
|
case ClassType.Class: |
|
braceStyle = policy.ClassBraceStyle; |
|
indentBody = policy.IndentClassBody; |
|
break; |
|
case ClassType.Struct: |
|
braceStyle = policy.StructBraceStyle; |
|
indentBody = policy.IndentStructBody; |
|
break; |
|
case ClassType.Interface: |
|
braceStyle = policy.InterfaceBraceStyle; |
|
indentBody = policy.IndentInterfaceBody; |
|
break; |
|
case ClassType.Enum: |
|
braceStyle = policy.EnumBraceStyle; |
|
indentBody = policy.IndentEnumBody; |
|
break; |
|
default: |
|
throw new InvalidOperationException("unsupported class type : " + typeDeclaration.ClassType); |
|
} |
|
|
|
foreach (var constraint in typeDeclaration.Constraints) |
|
constraint.AcceptVisitor (this); |
|
|
|
FixOpenBrace(braceStyle, typeDeclaration.LBraceToken); |
|
|
|
if (indentBody) |
|
curIndent.Push(IndentType.Block); |
|
bool startFormat = true; |
|
bool first = true; |
|
VisitChildrenToFormat(typeDeclaration, child => { |
|
if (first) { |
|
startFormat = child.StartLocation > typeDeclaration.LBraceToken.StartLocation; |
|
first = false; |
|
} |
|
if (child.Role == Roles.LBrace) { |
|
startFormat = true; |
|
return; |
|
} |
|
if (child.Role == Roles.RBrace) { |
|
startFormat = false; |
|
return; |
|
} |
|
if (!startFormat || !NoWhitespacePredicate (child)) |
|
return; |
|
if (child.Role == Roles.Comma) { |
|
ForceSpacesBeforeRemoveNewLines (child, false); |
|
EnsureNewLinesAfter(child, 1); |
|
return; |
|
} |
|
if (NoWhitespacePredicate(child)) |
|
FixIndentationForceNewLine(child); |
|
child.AcceptVisitor(this); |
|
if (NoWhitespacePredicate(child) && child.GetNextSibling (NoWhitespacePredicate).Role != Roles.Comma) |
|
EnsureNewLinesAfter(child, GetTypeLevelNewLinesFor(child)); |
|
}); |
|
|
|
if (indentBody) |
|
curIndent.Pop(); |
|
|
|
FixClosingBrace(braceStyle, typeDeclaration.RBraceToken); |
|
} |
|
|
|
int GetTypeLevelNewLinesFor(AstNode child) |
|
{ |
|
var blankLines = 1; |
|
var nextSibling = child.GetNextSibling(NoWhitespacePredicate); |
|
if (child is PreProcessorDirective || child is Comment) |
|
return 1; |
|
if (child is EventDeclaration) { |
|
if (nextSibling is EventDeclaration) { |
|
blankLines += policy.BlankLinesBetweenEventFields; |
|
return blankLines; |
|
} |
|
} |
|
|
|
if (child is FieldDeclaration || child is FixedFieldDeclaration) { |
|
if (nextSibling is FieldDeclaration || nextSibling is FixedFieldDeclaration) { |
|
blankLines += policy.BlankLinesBetweenFields; |
|
return blankLines; |
|
} |
|
} |
|
|
|
if (child is TypeDeclaration) { |
|
if (nextSibling is TypeDeclaration) { |
|
blankLines += policy.BlankLinesBetweenTypes; |
|
return blankLines; |
|
} |
|
} |
|
|
|
if (nextSibling.Role == Roles.TypeMemberRole) |
|
blankLines += policy.BlankLinesBetweenMembers; |
|
return blankLines; |
|
} |
|
|
|
public override void VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) |
|
{ |
|
ForceSpacesBefore(delegateDeclaration.LParToken, policy.SpaceBeforeDelegateDeclarationParentheses); |
|
if (delegateDeclaration.Parameters.Any()) { |
|
ForceSpacesAfter(delegateDeclaration.LParToken, policy.SpaceWithinDelegateDeclarationParentheses); |
|
ForceSpacesBefore(delegateDeclaration.RParToken, policy.SpaceWithinDelegateDeclarationParentheses); |
|
} else { |
|
ForceSpacesAfter(delegateDeclaration.LParToken, policy.SpaceBetweenEmptyDelegateDeclarationParentheses); |
|
ForceSpacesBefore(delegateDeclaration.RParToken, policy.SpaceBetweenEmptyDelegateDeclarationParentheses); |
|
} |
|
FormatCommas(delegateDeclaration, policy.SpaceBeforeDelegateDeclarationParameterComma, policy.SpaceAfterDelegateDeclarationParameterComma); |
|
|
|
base.VisitDelegateDeclaration(delegateDeclaration); |
|
} |
|
|
|
public override void VisitComment(Comment comment) |
|
{ |
|
if (comment.StartsLine && !HadErrors && (!policy.KeepCommentsAtFirstColumn || comment.StartLocation.Column > 1)) |
|
FixIndentation(comment); |
|
} |
|
|
|
public override void VisitConstraint(Constraint constraint) |
|
{ |
|
VisitChildrenToFormat (constraint, node => { |
|
if (node is AstType) { |
|
node.AcceptVisitor (this); |
|
} else if (node.Role == Roles.LPar) { |
|
ForceSpacesBefore (node, false); |
|
ForceSpacesAfter (node, false); |
|
} else if (node.Role ==Roles.Comma) { |
|
ForceSpacesBefore (node, false); |
|
ForceSpacesAfter (node, true); |
|
} |
|
}); |
|
} |
|
} |
|
} |