From e00b4cb5c348b1ec5333f9b8bd04df8106f34018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 19 Aug 2010 18:44:47 +0200 Subject: [PATCH] Added formatting visitors. --- .../Formatter/CSharpFormattingPolicy.cs | 705 ++++++++++++++++ .../CSharp/Formatter/DomIndentationVisitor.cs | 758 ++++++++++++++++++ .../CSharp/Formatter/DomSpacingVisitor.cs | 513 ++++++++++++ .../CSharp/Formatter/Indent.cs | 79 ++ 4 files changed, 2055 insertions(+) create mode 100644 ICSharpCode.NRefactory/CSharp/Formatter/CSharpFormattingPolicy.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Formatter/DomIndentationVisitor.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Formatter/DomSpacingVisitor.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Formatter/Indent.cs diff --git a/ICSharpCode.NRefactory/CSharp/Formatter/CSharpFormattingPolicy.cs b/ICSharpCode.NRefactory/CSharp/Formatter/CSharpFormattingPolicy.cs new file mode 100644 index 0000000000..e311deee76 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Formatter/CSharpFormattingPolicy.cs @@ -0,0 +1,705 @@ +// +// CSharpFormattingPolicy.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2009 Novell, Inc (http://www.novell.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.Reflection; + +namespace ICSharpCode.NRefactory.CSharp +{ + public enum BraceStyle { + DoNotChange, + EndOfLine, + EndOfLineWithoutSpace, + NextLine, + NextLineShifted, + NextLineShifted2 + } + + public enum BraceForcement { + DoNotChange, + RemoveBraces, + AddBraces + } + + public enum ArrayInitializerPlacement { + AlwaysNewLine, + AlwaysSameLine + } + + // HACK: Monodevelop internal attribute + public class ItemPropertyAttribute : System.Attribute + { + } + + public class CSharpFormattingPolicy : IEquatable + { + public CSharpFormattingPolicy Clone () + { + return (CSharpFormattingPolicy) MemberwiseClone (); + } + + #region Indentation + [ItemProperty] + public bool IndentNamespaceBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentClassBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentInterfaceBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentStructBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentEnumBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentMethodBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentPropertyBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentEventBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentBlocks { // tested + get; + set; + } + + [ItemProperty] + public bool IndentSwitchBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentCaseBody { // tested + get; + set; + } + + [ItemProperty] + public bool IndentBreakStatements { // tested + get; + set; + } + #endregion + + #region Braces + [ItemProperty] + public BraceStyle NamespaceBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle ClassBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle InterfaceBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle StructBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle EnumBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle MethodBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle AnonymousMethodBraceStyle { + get; + set; + } + + [ItemProperty] + public BraceStyle ConstructorBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle DestructorBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle PropertyBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle PropertyGetBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle PropertySetBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public bool AllowPropertyGetBlockInline { // tested + get; + set; + } + + [ItemProperty] + public bool AllowPropertySetBlockInline { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle EventBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle EventAddBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle EventRemoveBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public bool AllowEventAddBlockInline { // tested + get; + set; + } + + [ItemProperty] + public bool AllowEventRemoveBlockInline { // tested + get; + set; + } + + [ItemProperty] + public BraceStyle StatementBraceStyle { // tested + get; + set; + } + + [ItemProperty] + public bool AllowIfBlockInline { + get; + set; + } + + #endregion + + #region Force Braces + [ItemProperty] + public BraceForcement IfElseBraceForcement { // tested + get; + set; + } + + [ItemProperty] + public BraceForcement ForBraceForcement { // tested + get; + set; + } + + [ItemProperty] + public BraceForcement ForEachBraceForcement { // tested + get; + set; + } + + [ItemProperty] + public BraceForcement WhileBraceForcement { // tested + get; + set; + } + + [ItemProperty] + public BraceForcement UsingBraceForcement { // tested + get; + set; + } + + [ItemProperty] + public BraceForcement FixedBraceForcement { // tested + get; + set; + } + #endregion + + #region NewLines + [ItemProperty] + public bool PlaceElseOnNewLine { // tested + get; + set; + } + + [ItemProperty] + public bool PlaceElseIfOnNewLine { // tested + get; + set; + } + + [ItemProperty] + public bool PlaceCatchOnNewLine { // tested + get; + set; + } + + [ItemProperty] + public bool PlaceFinallyOnNewLine { // tested + get; + set; + } + + [ItemProperty] + public bool PlaceWhileOnNewLine { // tested + get; + set; + } + + [ItemProperty] + public ArrayInitializerPlacement PlaceArrayInitializersOnNewLine { + get; + set; + } + #endregion + + #region Spaces + [ItemProperty] + public bool BeforeMethodCallParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool BeforeMethodDeclarationParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool BeforeConstructorDeclarationParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool BeforeDelegateDeclarationParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool NewParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool IfParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WhileParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool ForParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool ForeachParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool CatchParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool SwitchParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool LockParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool UsingParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundAssignmentParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundLogicalOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundEqualityOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundRelationalOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundBitwiseOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundAdditiveOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundMultiplicativeOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool AroundShiftOperatorParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinMethodCallParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinMethodDeclarationParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinIfParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinWhileParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinForParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinForEachParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinCatchParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinSwitchParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinLockParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinUsingParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinCastParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinSizeOfParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinTypeOfParentheses { // tested + get; + set; + } + + [ItemProperty] + public bool WithinCheckedExpressionParantheses { // tested + get; + set; + } + + [ItemProperty] + public bool ConditionalOperatorBeforeConditionSpace { // tested + get; + set; + } + + [ItemProperty] + public bool ConditionalOperatorAfterConditionSpace { // tested + get; + set; + } + + [ItemProperty] + public bool ConditionalOperatorBeforeSeparatorSpace { // tested + get; + set; + } + + [ItemProperty] + public bool ConditionalOperatorAfterSeparatorSpace { // tested + get; + set; + } + + [ItemProperty] + public bool SpacesWithinBrackets { // tested + get; + set; + } + + [ItemProperty] + public bool SpacesAfterComma { // tested + get; + set; + } + + [ItemProperty] + public bool SpacesBeforeComma { // tested + get; + set; + } + + [ItemProperty] + public bool SpacesAfterSemicolon { // tested + get; + set; + } + + [ItemProperty] + public bool SpacesAfterTypecast { // tested + get; + set; + } + #endregion + + public CSharpFormattingPolicy () + { + IndentNamespaceBody = true; + IndentClassBody = IndentInterfaceBody = IndentStructBody = IndentEnumBody = true; + IndentMethodBody = IndentPropertyBody = IndentEventBody = true; + IndentBlocks = true; + IndentSwitchBody = false; + IndentCaseBody = true; + IndentBreakStatements = true; + NamespaceBraceStyle = BraceStyle.NextLine; + ClassBraceStyle = InterfaceBraceStyle = StructBraceStyle = EnumBraceStyle = BraceStyle.NextLine; + MethodBraceStyle = ConstructorBraceStyle = DestructorBraceStyle = BraceStyle.NextLine; + AnonymousMethodBraceStyle = BraceStyle.EndOfLine; + + PropertyBraceStyle = PropertyGetBraceStyle = PropertySetBraceStyle = BraceStyle.EndOfLine; + AllowPropertyGetBlockInline = AllowPropertySetBlockInline = true; + + EventBraceStyle = EventAddBraceStyle = EventRemoveBraceStyle = BraceStyle.EndOfLine; + AllowEventAddBlockInline = AllowEventRemoveBlockInline = true; + StatementBraceStyle = BraceStyle.EndOfLine; + + PlaceElseOnNewLine = false; + PlaceCatchOnNewLine = false; + PlaceFinallyOnNewLine = false; + PlaceWhileOnNewLine = false; + PlaceArrayInitializersOnNewLine = ArrayInitializerPlacement.AlwaysSameLine; + + BeforeMethodCallParentheses = true; + BeforeMethodDeclarationParentheses = true; + BeforeConstructorDeclarationParentheses = true; + BeforeDelegateDeclarationParentheses = true; + + NewParentheses = true; + IfParentheses = true; + WhileParentheses = true; + ForParentheses = true; + ForeachParentheses = true; + CatchParentheses = true; + SwitchParentheses = true; + LockParentheses = true; + UsingParentheses = true; + AroundAssignmentParentheses = true; + AroundLogicalOperatorParentheses = true; + AroundEqualityOperatorParentheses = true; + AroundRelationalOperatorParentheses = true; + AroundBitwiseOperatorParentheses = true; + AroundAdditiveOperatorParentheses = true; + AroundMultiplicativeOperatorParentheses = true; + AroundShiftOperatorParentheses = true; + WithinParentheses = false; + WithinMethodCallParentheses = false; + WithinMethodDeclarationParentheses = false; + WithinIfParentheses = false; + WithinWhileParentheses = false; + WithinForParentheses = false; + WithinForEachParentheses = false; + WithinCatchParentheses = false; + WithinSwitchParentheses = false; + WithinLockParentheses = false; + WithinUsingParentheses = false; + WithinCastParentheses = false; + WithinSizeOfParentheses = false; + WithinTypeOfParentheses = false; + WithinCheckedExpressionParantheses = false; + ConditionalOperatorBeforeConditionSpace = true; + ConditionalOperatorAfterConditionSpace = true; + ConditionalOperatorBeforeSeparatorSpace = true; + ConditionalOperatorAfterSeparatorSpace = true; + + SpacesWithinBrackets = false; + SpacesAfterComma = true; + SpacesBeforeComma = false; + SpacesAfterSemicolon = true; + SpacesAfterTypecast = false; + } + + public bool Equals (CSharpFormattingPolicy other) + { + foreach (PropertyInfo info in typeof (CSharpFormattingPolicy).GetProperties ()) { + object val = info.GetValue (this, null); + object otherVal = info.GetValue (other, null); + if (!val.Equals (otherVal)) { + //Console.WriteLine ("!equal"); + return false; + } + } + //Console.WriteLine ("== equal"); + return true; + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Formatter/DomIndentationVisitor.cs b/ICSharpCode.NRefactory/CSharp/Formatter/DomIndentationVisitor.cs new file mode 100644 index 0000000000..6555ebec55 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Formatter/DomIndentationVisitor.cs @@ -0,0 +1,758 @@ +// +// DomIndentationVisitor.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2010 Novell, Inc (http://www.novell.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 MonoDevelop.CSharp.Dom; +using System.Text; +using MonoDevelop.Projects.Dom; +using Mono.TextEditor; +using MonoDevelop.Refactoring; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.NRefactory.CSharp +{ + public class DomIndentationVisitor : AbtractCSharpDomVisitor + { + CSharpFormattingPolicy policy; + TextEditorData data; + List changes = new List (); + Indent curIndent = new Indent (); + + public int IndentLevel { + get { + return curIndent.Level; + } + set { + curIndent.Level = value; + } + } + + public int CurrentSpaceIndents { + get; + set; + } + + public List Changes { + get { return this.changes; } + } + + public bool AutoAcceptChanges { get; set; } + + + public DomIndentationVisitor (CSharpFormattingPolicy policy, TextEditorData data) + { + this.policy = policy; + this.data = data; + AutoAcceptChanges = true; + } + + public override object VisitCompilationUnit (MonoDevelop.CSharp.Dom.CompilationUnit unit, object data) + { + base.VisitCompilationUnit (unit, data); + if (AutoAcceptChanges) + RefactoringService.AcceptChanges (null, null, changes); + return null; + } + + public override object VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration, object data) + { + FixIndentation (namespaceDeclaration.StartLocation); + IndentLevel++; + object result = base.VisitNamespaceDeclaration (namespaceDeclaration, data); + IndentLevel--; + FixIndentation (namespaceDeclaration.EndLocation); + return result; + } + + public override object VisitTypeDeclaration (TypeDeclaration typeDeclaration, object data) + { + FixIndentation (typeDeclaration.StartLocation); + 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); + } + EnforceBraceStyle (braceStyle, typeDeclaration.LBrace, typeDeclaration.RBrace); + + if (indentBody) + IndentLevel++; + object result = base.VisitTypeDeclaration (typeDeclaration, data); + if (indentBody) + IndentLevel--; + return result; + } + + public override object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data) + { + FixIndentation (propertyDeclaration.StartLocation); + EnforceBraceStyle (policy.PropertyBraceStyle, propertyDeclaration.LBrace, propertyDeclaration.RBrace); + if (policy.IndentPropertyBody) + IndentLevel++; + + if (propertyDeclaration.GetAccessor != null) { + FixIndentation (propertyDeclaration.GetAccessor.StartLocation); + if (propertyDeclaration.GetAccessor.Body != null) { + if (!policy.AllowPropertyGetBlockInline || propertyDeclaration.GetAccessor.Body.LBrace.StartLocation.Line != propertyDeclaration.GetAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.PropertyGetBraceStyle, propertyDeclaration.GetAccessor.Body.LBrace, propertyDeclaration.GetAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + VisitBlockWithoutFixIndentation (propertyDeclaration.GetAccessor.Body, policy.IndentBlocks, data); + } + } + + if (propertyDeclaration.SetAccessor != null) { + FixIndentation (propertyDeclaration.SetAccessor.StartLocation); + if (propertyDeclaration.SetAccessor.Body != null) { + if (!policy.AllowPropertySetBlockInline || propertyDeclaration.SetAccessor.Body.LBrace.StartLocation.Line != propertyDeclaration.SetAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.PropertySetBraceStyle, propertyDeclaration.SetAccessor.Body.LBrace, propertyDeclaration.SetAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + VisitBlockWithoutFixIndentation (propertyDeclaration.SetAccessor.Body, policy.IndentBlocks, data); + } + } + + if (policy.IndentPropertyBody) + IndentLevel--; + return null; + } + + public override object VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration, object data) + { + FixIndentation (indexerDeclaration.StartLocation); + EnforceBraceStyle (policy.PropertyBraceStyle, indexerDeclaration.LBrace, indexerDeclaration.RBrace); + if (policy.IndentPropertyBody) + IndentLevel++; + + if (indexerDeclaration.GetAccessor != null) { + FixIndentation (indexerDeclaration.GetAccessor.StartLocation); + if (indexerDeclaration.GetAccessor.Body != null) { + if (!policy.AllowPropertyGetBlockInline || indexerDeclaration.GetAccessor.Body.LBrace.StartLocation.Line != indexerDeclaration.GetAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.PropertyGetBraceStyle, indexerDeclaration.GetAccessor.Body.LBrace, indexerDeclaration.GetAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + VisitBlockWithoutFixIndentation (indexerDeclaration.GetAccessor.Body, policy.IndentBlocks, data); + } + } + + if (indexerDeclaration.SetAccessor != null) { + FixIndentation (indexerDeclaration.SetAccessor.StartLocation); + if (indexerDeclaration.SetAccessor.Body != null) { + if (!policy.AllowPropertySetBlockInline || indexerDeclaration.SetAccessor.Body.LBrace.StartLocation.Line != indexerDeclaration.SetAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.PropertySetBraceStyle, indexerDeclaration.SetAccessor.Body.LBrace, indexerDeclaration.SetAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + VisitBlockWithoutFixIndentation (indexerDeclaration.SetAccessor.Body, policy.IndentBlocks, data); + } + } + if (policy.IndentPropertyBody) + IndentLevel--; + return null; + } + + + public override object VisitEventDeclaration (EventDeclaration eventDeclaration, object data) + { + FixIndentation (eventDeclaration.StartLocation); + EnforceBraceStyle (policy.EventBraceStyle, eventDeclaration.LBrace, eventDeclaration.RBrace); + if (policy.IndentEventBody) + IndentLevel++; + + if (eventDeclaration.AddAccessor != null) { + FixIndentation (eventDeclaration.AddAccessor.StartLocation); + if (eventDeclaration.AddAccessor.Body != null) { + if (!policy.AllowEventAddBlockInline || eventDeclaration.AddAccessor.Body.LBrace.StartLocation.Line != eventDeclaration.AddAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.EventAddBraceStyle, eventDeclaration.AddAccessor.Body.LBrace, eventDeclaration.AddAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + + VisitBlockWithoutFixIndentation (eventDeclaration.AddAccessor.Body, policy.IndentBlocks, data); + } + } + + if (eventDeclaration.RemoveAccessor != null) { + FixIndentation (eventDeclaration.RemoveAccessor.StartLocation); + if (eventDeclaration.RemoveAccessor.Body != null) { + if (!policy.AllowEventRemoveBlockInline || eventDeclaration.RemoveAccessor.Body.LBrace.StartLocation.Line != eventDeclaration.RemoveAccessor.Body.RBrace.StartLocation.Line) { + EnforceBraceStyle (policy.EventRemoveBraceStyle, eventDeclaration.RemoveAccessor.Body.LBrace, eventDeclaration.RemoveAccessor.Body.RBrace); + } else { + nextStatementIndent = " "; + } + VisitBlockWithoutFixIndentation (eventDeclaration.RemoveAccessor.Body, policy.IndentBlocks, data); + } + } + + if (policy.IndentEventBody) + IndentLevel--; + return null; + } + + + public override object VisitAccessorDeclaration (Accessor accessorDeclaration, object data) + { + FixIndentation (accessorDeclaration.StartLocation); + object result = base.VisitAccessorDeclaration (accessorDeclaration, data); + return result; + } + + public override object VisitFieldDeclaration (FieldDeclaration fieldDeclaration, object data) + { + Console.WriteLine ("VISIT FIELD:" + fieldDeclaration.StartLocation); + FixIndentation (fieldDeclaration.StartLocation); + return base.VisitFieldDeclaration (fieldDeclaration, data); + } + + public override object VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration, object data) + { + FixIndentation (delegateDeclaration.StartLocation); + return base.VisitDelegateDeclaration (delegateDeclaration, data); + } + + public override object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data) + { + FixIndentation (methodDeclaration.StartLocation); + if (methodDeclaration.Body != null) { + EnforceBraceStyle (policy.MethodBraceStyle, methodDeclaration.Body.LBrace, methodDeclaration.Body.RBrace); + if (policy.IndentMethodBody) + IndentLevel++; + base.VisitBlockStatement (methodDeclaration.Body, data); + if (policy.IndentMethodBody) + IndentLevel--; + } + + return null; + } + + public override object VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration, object data) + { + FixIndentation (operatorDeclaration.StartLocation); + if (operatorDeclaration.Body != null) { + EnforceBraceStyle (policy.MethodBraceStyle, operatorDeclaration.Body.LBrace, operatorDeclaration.Body.RBrace); + if (policy.IndentMethodBody) + IndentLevel++; + base.VisitBlockStatement (operatorDeclaration.Body, data); + if (policy.IndentMethodBody) + IndentLevel--; + } + + return null; + } + + public override object VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, object data) + { + FixIndentation (constructorDeclaration.StartLocation); + if (constructorDeclaration.Body != null) + EnforceBraceStyle (policy.ConstructorBraceStyle, constructorDeclaration.Body.LBrace, constructorDeclaration.Body.RBrace); + object result = base.VisitConstructorDeclaration (constructorDeclaration, data); + return result; + } + + public override object VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration, object data) + { + FixIndentation (destructorDeclaration.StartLocation); + if (destructorDeclaration.Body != null) + EnforceBraceStyle (policy.DestructorBraceStyle, destructorDeclaration.Body.LBrace, destructorDeclaration.Body.RBrace); + object result = base.VisitDestructorDeclaration (destructorDeclaration, data); + return result; + } + + #region Statements + public override object VisitExpressionStatement (ExpressionStatement expressionStatement, object data) + { + FixStatementIndentation (expressionStatement.StartLocation); + return null; + } + + object VisitBlockWithoutFixIndentation (BlockStatement blockStatement, bool indent, object data) + { + if (indent) + IndentLevel++; + object result = base.VisitBlockStatement (blockStatement, data); + if (indent) + IndentLevel--; + return result; + } + + public override object VisitBlockStatement (BlockStatement blockStatement, object data) + { + FixIndentation (blockStatement.StartLocation); + object result = VisitBlockWithoutFixIndentation (blockStatement, policy.IndentBlocks, data); + FixIndentation (blockStatement.EndLocation, -1); + return result; + } + + public override object VisitBreakStatement (BreakStatement breakStatement, object data) + { + FixStatementIndentation (breakStatement.StartLocation); + return null; + } + + public override object VisitCheckedStatement (CheckedStatement checkedStatement, object data) + { + FixStatementIndentation (checkedStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.FixedBraceForcement , checkedStatement.EmbeddedStatement); + } + + public override object VisitContinueStatement (ContinueStatement continueStatement, object data) + { + FixStatementIndentation (continueStatement.StartLocation); + return null; + } + + public override object VisitEmptyStatement (EmptyStatement emptyStatement, object data) + { + FixStatementIndentation (emptyStatement.StartLocation); + return null; + } + + public override object VisitFixedStatement (FixedStatement fixedStatement, object data) + { + FixStatementIndentation (fixedStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.FixedBraceForcement, fixedStatement.EmbeddedStatement); + } + + public override object VisitForeachStatement (ForeachStatement foreachStatement, object data) + { + FixStatementIndentation (foreachStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.ForEachBraceForcement , foreachStatement.EmbeddedStatement); + } + + object FixEmbeddedStatment (MonoDevelop.CSharp.Formatting.BraceStyle braceStyle, MonoDevelop.CSharp.Formatting.BraceForcement braceForcement, ICSharpNode node) + { + return FixEmbeddedStatment (braceStyle, braceForcement, null, false, node); + } + + object FixEmbeddedStatment (MonoDevelop.CSharp.Formatting.BraceStyle braceStyle, MonoDevelop.CSharp.Formatting.BraceForcement braceForcement, CSharpTokenNode token, bool allowInLine, ICSharpNode node) + { + if (node == null) + return null; + bool isBlock = node is BlockStatement; + switch (braceForcement) { + case BraceForcement.DoNotChange: + //nothing + break; + case BraceForcement.AddBraces: + if (!isBlock) { + int offset = data.Document.LocationToOffset (node.StartLocation.Line, node.StartLocation.Column); + int start = SearchWhitespaceStart (offset); + string startBrace = ""; + switch (braceStyle) { + case BraceStyle.EndOfLineWithoutSpace: + startBrace = "{"; + break; + case BraceStyle.EndOfLine: + startBrace = " {"; + break; + case BraceStyle.NextLine: + startBrace = data.EolMarker + curIndent.IndentString + "{"; + break; + case BraceStyle.NextLineShifted2: + case BraceStyle.NextLineShifted: + startBrace = data.EolMarker + curIndent.IndentString + curIndent.SingleIndent + "{"; + break; + } + AddChange (start, offset - start, startBrace); + } + break; + case BraceForcement.RemoveBraces: + if (isBlock) { + BlockStatement block = node as BlockStatement; + if (block.Statements.Count () == 1) { + int offset1 = data.Document.LocationToOffset (node.StartLocation.Line, node.StartLocation.Column); + int start = SearchWhitespaceStart (offset1); + + int offset2 = data.Document.LocationToOffset (node.EndLocation.Line, node.EndLocation.Column); + int end = SearchWhitespaceStart (offset2 - 1); + + AddChange (start, offset1 - start + 1, null); + AddChange (end + 1, offset2 - end, null); + node = (ICSharpNode)block.FirstChild; + isBlock = false; + } + } + break; + } + int originalLevel = curIndent.Level; + if (isBlock) { + BlockStatement block = node as BlockStatement; + if (allowInLine && block.StartLocation.Line == block.EndLocation.Line && block.Statements.Count () <= 1) { + if (block.Statements.Count () == 1) + nextStatementIndent = " "; + } else { + EnforceBraceStyle (braceStyle, block.LBrace, block.RBrace); + } + if (braceStyle == BraceStyle.NextLineShifted2) + curIndent.Level++; + } else { + if (allowInLine && token.StartLocation.Line == node.EndLocation.Line) { + nextStatementIndent = " "; + } + } + if (!(node is IfElseStatement && node.Parent is IfElseStatement || node is UsingStatement && node.Parent is UsingStatement)) + curIndent.Level++; + object result = isBlock ? base.VisitBlockStatement ((BlockStatement)node, null) : node.AcceptVisitor (this, null); + curIndent.Level = originalLevel; + switch (braceForcement) { + case BraceForcement.DoNotChange: + break; + case BraceForcement.AddBraces: + if (!isBlock) { + int offset = data.Document.LocationToOffset (node.EndLocation.Line, node.EndLocation.Column); + string startBrace = ""; + switch (braceStyle) { + case BraceStyle.DoNotChange: + startBrace = null; + break; + case BraceStyle.EndOfLineWithoutSpace: + startBrace = data.EolMarker + curIndent.IndentString + "}"; + break; + case BraceStyle.EndOfLine: + startBrace = data.EolMarker + curIndent.IndentString + "}"; + break; + case BraceStyle.NextLine: + startBrace = data.EolMarker + curIndent.IndentString + "}"; + break; + case BraceStyle.NextLineShifted2: + case BraceStyle.NextLineShifted: + startBrace = data.EolMarker + curIndent.IndentString + curIndent.SingleIndent + "}"; + break; + } + if (startBrace != null) + AddChange (offset, 0, startBrace); + } + break; + } + return result; + } + + void EnforceBraceStyle (MonoDevelop.CSharp.Formatting.BraceStyle braceStyle, ICSharpNode lbrace, ICSharpNode rbrace) + { + if (lbrace == null || rbrace == null) + return; + +// LineSegment lbraceLineSegment = data.Document.GetLine (lbrace.StartLocation.Line); + int lbraceOffset = data.Document.LocationToOffset (lbrace.StartLocation.Line, lbrace.StartLocation.Column); + +// LineSegment rbraceLineSegment = data.Document.GetLine (rbrace.StartLocation.Line); + int rbraceOffset = data.Document.LocationToOffset (rbrace.StartLocation.Line, rbrace.StartLocation.Column); + int whitespaceStart = SearchWhitespaceStart (lbraceOffset); + int whitespaceEnd = SearchWhitespaceStart (rbraceOffset); + string startIndent = ""; + string endIndent = ""; + switch (braceStyle) { + case BraceStyle.DoNotChange: + startIndent = endIndent = null; + break; + case BraceStyle.EndOfLineWithoutSpace: + startIndent = ""; + endIndent = data.EolMarker + curIndent.IndentString; + break; + case BraceStyle.EndOfLine: + startIndent = " "; + endIndent = data.EolMarker + curIndent.IndentString; + break; + case BraceStyle.NextLine: + startIndent = data.EolMarker + curIndent.IndentString; + endIndent = data.EolMarker + curIndent.IndentString; + break; + case BraceStyle.NextLineShifted2: + case BraceStyle.NextLineShifted: + endIndent = startIndent = data.EolMarker + curIndent.IndentString + curIndent.SingleIndent; + break; + } + + if (lbraceOffset > 0 && startIndent != null) + AddChange (whitespaceStart, lbraceOffset - whitespaceStart, startIndent); + if (rbraceOffset > 0 && endIndent != null) + AddChange (whitespaceEnd, rbraceOffset - whitespaceEnd, endIndent); + } + + void AddChange (int offset, int removedChars, string insertedText) + { + if (changes.Cast ().Any (c => c.Offset == offset && c.RemovedChars == removedChars && c.InsertedText == insertedText)) + return; + string currentText = data.Document.GetTextAt (offset, removedChars); + if (currentText == insertedText) + return; + foreach (DomSpacingVisitor.MyTextReplaceChange change in changes) { + if (change.Offset == offset) { + if (removedChars > 0 && insertedText == change.InsertedText) { + change.RemovedChars = removedChars; +// change.InsertedText = insertedText; + return; + } + } + } +// Console.WriteLine ("offset={0}, removedChars={1}, insertedText={2}", offset, removedChars, insertedText.Replace("\n", "\\n").Replace("\t", "\\t").Replace(" ", ".")); +// Console.WriteLine (Environment.StackTrace); + changes.Add (new DomSpacingVisitor.MyTextReplaceChange (data, offset, removedChars, insertedText)); + } + + int SearchWhitespaceStart (int startOffset) + { + for (int offset = startOffset - 1; offset >= 0; offset--) { + char ch = data.Document.GetCharAt (offset); + if (!Char.IsWhiteSpace (ch)) { + return offset + 1; + } + } + return startOffset - 1; + } + + + public override object VisitForStatement (ForStatement forStatement, object data) + { + FixStatementIndentation (forStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.ForBraceForcement, forStatement.EmbeddedStatement); + } + + public override object VisitGotoStatement (GotoStatement gotoStatement, object data) + { + FixStatementIndentation (gotoStatement.StartLocation); + return VisitChildren (gotoStatement, data); + } + + public override object VisitIfElseStatement (IfElseStatement ifElseStatement, object data) + { + if (!(ifElseStatement.Parent is IfElseStatement)) + FixStatementIndentation (ifElseStatement.StartLocation); + + if (ifElseStatement.Condition != null) + ifElseStatement.Condition.AcceptVisitor (this, data); + + if (ifElseStatement.TrueEmbeddedStatement != null) + FixEmbeddedStatment (policy.StatementBraceStyle, policy.IfElseBraceForcement, ifElseStatement.IfKeyword, policy.AllowIfBlockInline, ifElseStatement.TrueEmbeddedStatement); + + if (ifElseStatement.FalseEmbeddedStatement != null) { + PlaceOnNewLine (policy.PlaceElseOnNewLine, ifElseStatement.ElseKeyword); + if (ifElseStatement.FalseEmbeddedStatement is IfElseStatement) { + PlaceOnNewLine (policy.PlaceElseIfOnNewLine, ((IfElseStatement)ifElseStatement.FalseEmbeddedStatement).IfKeyword); + } + FixEmbeddedStatment (policy.StatementBraceStyle, policy.IfElseBraceForcement, ifElseStatement.ElseKeyword, policy.AllowIfBlockInline, ifElseStatement.FalseEmbeddedStatement); + } + + return null; + } + + + public override object VisitLabelStatement (LabelStatement labelStatement, object data) + { + // TODO + return VisitChildren (labelStatement, data); + } + + public override object VisitLockStatement (LockStatement lockStatement, object data) + { + FixStatementIndentation (lockStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.FixedBraceForcement , lockStatement.EmbeddedStatement); + } + + public override object VisitReturnStatement (ReturnStatement returnStatement, object data) + { + FixStatementIndentation (returnStatement.StartLocation); + return VisitChildren (returnStatement, data); + } + + public override object VisitSwitchStatement (SwitchStatement switchStatement, object data) + { + FixStatementIndentation (switchStatement.StartLocation); + EnforceBraceStyle (policy.StatementBraceStyle, switchStatement.LBrace, switchStatement.RBrace); + object result = VisitChildren (switchStatement, data); + return result; + } + + public override object VisitSwitchSection (SwitchSection switchSection, object data) + { + + if (policy.IndentCaseBody) + curIndent.Level++; + + foreach (CaseLabel label in switchSection.CaseLabels) { + FixStatementIndentation (label.StartLocation); + } + if (policy.IndentSwitchBody) + curIndent.Level++; + + foreach (ICSharpNode stmt in switchSection.Statements) { + stmt.AcceptVisitor (this, null); + } + if (policy.IndentSwitchBody) + curIndent.Level--; + + if (policy.IndentCaseBody) + curIndent.Level--; + return null; + } + + public override object VisitCaseLabel (CaseLabel caseLabel, object data) + { + // handled in switchsection + return null; + } + + public override object VisitThrowStatement (ThrowStatement throwStatement, object data) + { + FixStatementIndentation (throwStatement.StartLocation); + return VisitChildren (throwStatement, data); + } + + public override object VisitTryCatchStatement (TryCatchStatement tryCatchStatement, object data) + { + FixStatementIndentation (tryCatchStatement.StartLocation); + + if (tryCatchStatement.TryBlock != null) + FixEmbeddedStatment (policy.StatementBraceStyle, BraceForcement.DoNotChange, tryCatchStatement.TryBlock); + + foreach (CatchClause clause in tryCatchStatement.CatchClauses) { + PlaceOnNewLine (policy.PlaceCatchOnNewLine, clause.CatchKeyword); + + FixEmbeddedStatment (policy.StatementBraceStyle, BraceForcement.DoNotChange, clause.Block); + } + + if (tryCatchStatement.FinallyBlock != null) { + PlaceOnNewLine (policy.PlaceFinallyOnNewLine, tryCatchStatement.FinallyKeyword); + + FixEmbeddedStatment (policy.StatementBraceStyle, BraceForcement.DoNotChange, tryCatchStatement.FinallyBlock); + } + + return VisitChildren (tryCatchStatement, data); + } + + public override object VisitCatchClause (CatchClause catchClause, object data) + { + // Handled in TryCatchStatement + return null; + } + + public override object VisitUncheckedStatement (UncheckedStatement uncheckedStatement, object data) + { + FixStatementIndentation (uncheckedStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.FixedBraceForcement , uncheckedStatement.EmbeddedStatement); + } + + public override object VisitUnsafeStatement (UnsafeStatement unsafeStatement, object data) + { + FixStatementIndentation (unsafeStatement.StartLocation); + Console.WriteLine (unsafeStatement.Block); + return FixEmbeddedStatment (policy.StatementBraceStyle, BraceForcement.DoNotChange, unsafeStatement.Block); + } + + public override object VisitUsingStatement (UsingStatement usingStatement, object data) + { + FixStatementIndentation (usingStatement.StartLocation); + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.UsingBraceForcement , usingStatement.EmbeddedStatement); + } + + public override object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) + { + FixStatementIndentation (variableDeclarationStatement.StartLocation); + return null; + } + + public override object VisitWhileStatement (WhileStatement whileStatement, object data) + { + FixStatementIndentation (whileStatement.StartLocation); + if (whileStatement.WhilePosition == WhilePosition.End) { + PlaceOnNewLine (policy.PlaceWhileOnNewLine, whileStatement.WhileKeyword); + } + + return FixEmbeddedStatment (policy.StatementBraceStyle, policy.WhileBraceForcement , whileStatement.EmbeddedStatement); + } + + public override object VisitYieldStatement (YieldStatement yieldStatement, object data) + { + FixStatementIndentation (yieldStatement.StartLocation); + return null; + } + + #endregion + + void PlaceOnNewLine (bool newLine, ICSharpNode keywordNode) + { + if (keywordNode == null) + return; + int offset = data.Document.LocationToOffset (keywordNode.StartLocation.Line, keywordNode.StartLocation.Column); + + int whitespaceStart = SearchWhitespaceStart (offset); + string indentString = newLine ? data.EolMarker + this.curIndent.IndentString : " "; + AddChange (whitespaceStart, offset - whitespaceStart, indentString); + } + + string nextStatementIndent = null; + void FixStatementIndentation (MonoDevelop.Projects.Dom.DomLocation location) + { + int offset = data.Document.LocationToOffset (location.Line, location.Column); + if (offset == 0) { + Console.WriteLine ("possible wrong offset"); + Console.WriteLine (Environment.StackTrace); + return; + } + int whitespaceStart = SearchWhitespaceStart (offset); + string indentString = nextStatementIndent == null ? data.EolMarker + this.curIndent.IndentString : nextStatementIndent; + nextStatementIndent = null; + AddChange (whitespaceStart, offset - whitespaceStart, indentString); + } + + void FixIndentation (MonoDevelop.Projects.Dom.DomLocation location) + { + FixIndentation (location, 0); + } + + void FixIndentation (MonoDevelop.Projects.Dom.DomLocation location, int relOffset) + { + LineSegment lineSegment = data.Document.GetLine (location.Line); + string lineIndent = lineSegment.GetIndentation (data.Document); + string indentString = this.curIndent.IndentString; + if (indentString != lineIndent && location.Column + relOffset == lineIndent.Length) { + AddChange (lineSegment.Offset, lineIndent.Length, indentString); + } + } + } +} + +*/ \ No newline at end of file diff --git a/ICSharpCode.NRefactory/CSharp/Formatter/DomSpacingVisitor.cs b/ICSharpCode.NRefactory/CSharp/Formatter/DomSpacingVisitor.cs new file mode 100644 index 0000000000..a5adde99fb --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Formatter/DomSpacingVisitor.cs @@ -0,0 +1,513 @@ +// +// DomFormattingVisitor.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2010 Novell, Inc (http://www.novell.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 MonoDevelop.CSharp.Dom; +using System.Text; +using MonoDevelop.Projects.Dom; +using Mono.TextEditor; +using MonoDevelop.Refactoring; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.CSharp +{ + public class DomSpacingVisitor : AbtractCSharpDomVisitor + { + CSharpFormattingPolicy policy; + TextEditorData data; + List changes = new List (); + + public List Changes { + get { return this.changes; } + } + + public bool AutoAcceptChanges { get; set; } + + public DomSpacingVisitor (CSharpFormattingPolicy policy, TextEditorData data) + { + this.policy = policy; + this.data = data; + AutoAcceptChanges = true; + } + + internal class MyTextReplaceChange : TextReplaceChange + { + TextEditorData data; + protected override TextEditorData TextEditorData { + get { + return data; + } + } + + public MyTextReplaceChange (TextEditorData data, int offset, int count, string replaceWith) + { + this.data = data; + this.FileName = data.Document.FileName; + this.Offset = offset; + this.RemovedChars = count; + this.InsertedText = replaceWith; + } + } + + public override object VisitCompilationUnit (MonoDevelop.CSharp.Dom.CompilationUnit unit, object data) + { + base.VisitCompilationUnit (unit, data); + if (AutoAcceptChanges) + RefactoringService.AcceptChanges (null, null, changes); + return null; + } + + public override object VisitTypeDeclaration (TypeDeclaration typeDeclaration, object data) + { + + return base.VisitTypeDeclaration (typeDeclaration, data); + } + + public override object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data) + { + return base.VisitPropertyDeclaration (propertyDeclaration, data); + } + + public override object VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration, object data) + { + ForceSpacesAfter (indexerDeclaration.LBracket, policy.SpacesWithinBrackets); + ForceSpacesBefore (indexerDeclaration.RBracket, policy.SpacesWithinBrackets); + return base.VisitIndexerDeclaration (indexerDeclaration, data); + } + public override object VisitBlockStatement (BlockStatement blockStatement, object data) + { + return base.VisitBlockStatement (blockStatement, data); + } + + public override object VisitAssignmentExpression (AssignmentExpression assignmentExpression, object data) + { + ForceSpacesAround (assignmentExpression.Operator, policy.AroundAssignmentParentheses); + return base.VisitAssignmentExpression (assignmentExpression, data); + } + + public override object VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression, object data) + { + bool forceSpaces = false; + switch (binaryOperatorExpression.BinaryOperatorType) { + case BinaryOperatorType.Equality: + case BinaryOperatorType.InEquality: + forceSpaces = policy.AroundEqualityOperatorParentheses; + break; + case BinaryOperatorType.GreaterThan: + case BinaryOperatorType.GreaterThanOrEqual: + case BinaryOperatorType.LessThan: + case BinaryOperatorType.LessThanOrEqual: + forceSpaces = policy.AroundRelationalOperatorParentheses; + break; + case BinaryOperatorType.LogicalAnd: + case BinaryOperatorType.LogicalOr: + forceSpaces = policy.AroundLogicalOperatorParentheses; + break; + case BinaryOperatorType.BitwiseAnd: + case BinaryOperatorType.BitwiseOr: + case BinaryOperatorType.ExclusiveOr: + forceSpaces = policy.AroundBitwiseOperatorParentheses; + break; + case BinaryOperatorType.Add: + case BinaryOperatorType.Subtract: + forceSpaces = policy.AroundAdditiveOperatorParentheses; + break; + case BinaryOperatorType.Multiply: + case BinaryOperatorType.Divide: + case BinaryOperatorType.Modulus: + forceSpaces = policy.AroundMultiplicativeOperatorParentheses; + break; + case BinaryOperatorType.ShiftLeft: + case BinaryOperatorType.ShiftRight: + forceSpaces = policy.AroundShiftOperatorParentheses; + break; + } + ForceSpacesAround (binaryOperatorExpression.Operator, forceSpaces); + + return base.VisitBinaryOperatorExpression (binaryOperatorExpression, data); + } + + public override object VisitConditionalExpression (ConditionalExpression conditionalExpression, object data) + { + ForceSpacesBefore (conditionalExpression.QuestionMark, policy.ConditionalOperatorBeforeConditionSpace); + ForceSpacesAfter (conditionalExpression.QuestionMark, policy.ConditionalOperatorAfterConditionSpace); + ForceSpacesBefore (conditionalExpression.Colon, policy.ConditionalOperatorBeforeSeparatorSpace); + ForceSpacesAfter (conditionalExpression.Colon, policy.ConditionalOperatorAfterSeparatorSpace); + return base.VisitConditionalExpression (conditionalExpression, data); + } + + public override object VisitCastExpression (CastExpression castExpression, object data) + { + if (castExpression.RPar != null) { + ForceSpacesAfter (castExpression.LPar, policy.WithinCastParentheses); + ForceSpacesBefore (castExpression.RPar, policy.WithinCastParentheses); + + ForceSpacesAfter (castExpression.RPar, 1, policy.SpacesAfterTypecast); + } + return base.VisitCastExpression (castExpression, data); + } + + void ForceSpacesAround (INode node, bool forceSpaces) + { + ForceSpacesBefore (node, forceSpaces); + ForceSpacesAfter (node, forceSpaces); + } + + void ForceSpacesAfter (INode node, bool forceSpaces) + { + DomLocation location = ((ICSharpNode)node).EndLocation; + + int offset = data.Document.LocationToOffset (location.Line, location.Column) - 1; + int i = offset + 1; + while (i < data.Document.Length && Char.IsWhiteSpace (data.Document.GetCharAt (i))) { + i++; + } + ForceSpace (offset, i, forceSpaces); + } + + void ForceSpacesAfter (INode node, int tokenLength, bool forceSpaces) + { + DomLocation location = ((ICSharpNode)node).StartLocation; + int offset = data.Document.LocationToOffset (location.Line, location.Column) + 1; + int i = offset; + while (i < data.Document.Length && Char.IsWhiteSpace (data.Document.GetCharAt (i))) { + i++; + } + ForceSpace (offset - 1, i, forceSpaces); + } + + int ForceSpacesBefore (INode node, bool forceSpaces) + { + DomLocation location = ((ICSharpNode)node).StartLocation; + + int offset = data.Document.LocationToOffset (location.Line, location.Column); + int i = offset - 1; + + while (i >= 0 && Char.IsWhiteSpace (data.Document.GetCharAt (i))) { + i--; + } + ForceSpace (i, offset, forceSpaces); + return i; + } + + public override object VisitFieldDeclaration (FieldDeclaration fieldDeclaration, object data) + { + foreach (INode node in fieldDeclaration.Children) { + if (node is VariableInitializer && node.NextSibling != null && node.NextSibling.Role == FieldDeclaration.Roles.Comma) { + VariableInitializer initializer = node as VariableInitializer; + CSharpTokenNode commaToken = (CSharpTokenNode)node.NextSibling; + int offset = this.data.Document.LocationToOffset (initializer.NameIdentifier.StartLocation.Line, initializer.NameIdentifier.StartLocation.Column); + int commaOffset = this.data.Document.LocationToOffset (commaToken.StartLocation.Line, commaToken.StartLocation.Column); + ForceSpace (offset, commaOffset, policy.SpacesAfterComma); + //Console.WriteLine (initializer.Name +"/" + initializer.NameIdentifier + "/" + commaToken); + + if (node.NextSibling.NextSibling is VariableInitializer) { + DomLocation location = ((VariableInitializer)node.NextSibling.NextSibling).NameIdentifier.StartLocation; + int nextOffset = this.data.Document.LocationToOffset (location.Line, location.Column); + ForceSpace (commaOffset, nextOffset, policy.SpacesAfterComma); + } + } + } + return base.VisitFieldDeclaration (fieldDeclaration, data); + } + + public override object VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration, object data) + { + CSharpTokenNode lParen = (CSharpTokenNode)delegateDeclaration.GetChildByRole (DelegateDeclaration.Roles.LPar); + int offset = this.data.Document.LocationToOffset (lParen.StartLocation.Line, lParen.StartLocation.Column); + ForceSpaceBefore (offset, policy.BeforeDelegateDeclarationParentheses); + return base.VisitDelegateDeclaration (delegateDeclaration, data); + } + + public override object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data) + { + ForceSpacesBefore (methodDeclaration.LPar, policy.BeforeMethodDeclarationParentheses); + + ForceSpacesAfter (methodDeclaration.LPar, policy.WithinMethodDeclarationParentheses); + ForceSpacesBefore (methodDeclaration.RPar, policy.WithinMethodDeclarationParentheses); + + return base.VisitMethodDeclaration (methodDeclaration, data); + } + + public override object VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, object data) + { + CSharpTokenNode lParen = (CSharpTokenNode)constructorDeclaration.GetChildByRole (ConstructorDeclaration.Roles.LPar); + int offset = this.data.Document.LocationToOffset (lParen.StartLocation.Line, lParen.StartLocation.Column); + ForceSpaceBefore (offset, policy.BeforeConstructorDeclarationParentheses); + + return base.VisitConstructorDeclaration (constructorDeclaration, data); + } + + public override object VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration, object data) + { + CSharpTokenNode lParen = (CSharpTokenNode)destructorDeclaration.GetChildByRole (DestructorDeclaration.Roles.LPar); + int offset = this.data.Document.LocationToOffset (lParen.StartLocation.Line, lParen.StartLocation.Column); + ForceSpaceBefore (offset, policy.BeforeConstructorDeclarationParentheses); + return base.VisitDestructorDeclaration (destructorDeclaration, data); + } + + void ForceSpaceBefore (int offset, bool forceSpace) + { + bool insertedSpace = false; + do { + char ch = data.Document.GetCharAt (offset); + //Console.WriteLine (ch); + if (!Char.IsWhiteSpace (ch) && (insertedSpace || !forceSpace)) + break; + if (ch == ' ' && forceSpace) { + if (insertedSpace) { + changes.Add (new MyTextReplaceChange (data, offset, 1, null)); + } else { + insertedSpace = true; + } + } else if (forceSpace) { + if (!insertedSpace) { + changes.Add (new MyTextReplaceChange (data, offset, Char.IsWhiteSpace (ch) ? 1 : 0, " ")); + insertedSpace = true; + } else if (Char.IsWhiteSpace (ch)) { + changes.Add (new MyTextReplaceChange (data, offset, 1, null)); + } + } + + offset--; + } while (offset >= 0); + } + + void ForceSpace (int startOffset, int endOffset, bool forceSpace) + { + int lastNonWs = SearchLastNonWsChar (startOffset, endOffset); + changes.Add (new MyTextReplaceChange (data, lastNonWs + 1, System.Math.Max (0, endOffset - lastNonWs - 1), forceSpace ? " " : "")); + } + + int SearchLastNonWsChar (int startOffset, int endOffset) + { + startOffset = System.Math.Max (0, startOffset); + endOffset = System.Math.Max (startOffset, endOffset); + if (startOffset >= endOffset) + return startOffset; + int result = -1; + bool inComment = false; + + for (int i = startOffset; i < endOffset && i < data.Document.Length; i++) { + char ch = data.Document.GetCharAt (i); + //Console.WriteLine (ch); + if (Char.IsWhiteSpace (ch)) + continue; + if (ch == '/' && i + 1 < data.Document.Length && data.Document.GetCharAt (i + 1) == '/') + return result; + if (ch == '/' && i + 1 < data.Document.Length && data.Document.GetCharAt (i + 1) == '*') { + inComment = true; + i++; + continue; + } + if (inComment && ch == '*' && i + 1 < data.Document.Length && data.Document.GetCharAt (i + 1) == '/') { + inComment = false; + i++; + continue; + } + if (!inComment) + result = i; + } + return result; + } + + public override object VisitInvocationExpression (InvocationExpression invocationExpression, object data) + { + ForceSpacesBefore (invocationExpression.LPar, policy.BeforeMethodCallParentheses); + + ForceSpacesAfter (invocationExpression.LPar, policy.WithinMethodCallParentheses); + ForceSpacesBefore (invocationExpression.RPar, policy.WithinMethodCallParentheses); + + return base.VisitInvocationExpression (invocationExpression, data); + } + + public override object VisitIndexerExpression (IndexerExpression indexerExpression, object data) + { + ForceSpacesAfter (indexerExpression.LBracket, policy.SpacesWithinBrackets); + ForceSpacesBefore (indexerExpression.RBracket, policy.SpacesWithinBrackets); + return base.VisitIndexerExpression (indexerExpression, data); + } + + public override object VisitIfElseStatement (IfElseStatement ifElseStatement, object data) + { + ForceSpacesBefore (ifElseStatement.LPar, policy.IfParentheses); + + ForceSpacesAfter (ifElseStatement.LPar, policy.WithinIfParentheses); + ForceSpacesBefore (ifElseStatement.RPar, policy.WithinIfParentheses); + + + return base.VisitIfElseStatement (ifElseStatement, data); + } + + public override object VisitWhileStatement (WhileStatement whileStatement, object data) + { + ForceSpacesBefore (whileStatement.LPar, policy.WhileParentheses); + + ForceSpacesAfter (whileStatement.LPar, policy.WithinWhileParentheses); + ForceSpacesBefore (whileStatement.RPar, policy.WithinWhileParentheses); + + return base.VisitWhileStatement (whileStatement, data); + } + + public override object VisitForStatement (ForStatement forStatement, object data) + { + foreach (INode node in forStatement.Children) { + if (node.Role == ForStatement.Roles.Semicolon) { + if (node.NextSibling is CSharpTokenNode || node.NextSibling is EmptyStatement) + continue; + ForceSpacesAfter (node, policy.SpacesAfterSemicolon); + } + } + + ForceSpacesBefore (forStatement.LPar, policy.ForParentheses); + + ForceSpacesAfter (forStatement.LPar, policy.WithinForParentheses); + ForceSpacesBefore (forStatement.RPar, policy.WithinForParentheses); + + if (forStatement.EmbeddedStatement != null) + forStatement.EmbeddedStatement.AcceptVisitor (this, data); + + return null; + } + + public override object VisitForeachStatement (ForeachStatement foreachStatement, object data) + { + ForceSpacesBefore (foreachStatement.LPar, policy.ForeachParentheses); + + ForceSpacesAfter (foreachStatement.LPar, policy.WithinForEachParentheses); + ForceSpacesBefore (foreachStatement.RPar, policy.WithinForEachParentheses); + + return base.VisitForeachStatement (foreachStatement, data); + } + + public override object VisitCatchClause (CatchClause catchClause, object data) + { + if (catchClause.LPar != null) { + ForceSpacesBefore (catchClause.LPar, policy.CatchParentheses); + + ForceSpacesAfter (catchClause.LPar, policy.WithinCatchParentheses); + ForceSpacesBefore (catchClause.RPar, policy.WithinCatchParentheses); + } + + return base.VisitCatchClause (catchClause, data); + } + + public override object VisitLockStatement (LockStatement lockStatement, object data) + { + ForceSpacesBefore (lockStatement.LPar, policy.LockParentheses); + + ForceSpacesAfter (lockStatement.LPar, policy.WithinLockParentheses); + ForceSpacesBefore (lockStatement.RPar, policy.WithinLockParentheses); + + + return base.VisitLockStatement (lockStatement, data); + } + + public override object VisitUsingStatement (UsingStatement usingStatement, object data) + { + ForceSpacesBefore (usingStatement.LPar, policy.UsingParentheses); + + ForceSpacesAfter (usingStatement.LPar, policy.WithinUsingParentheses); + ForceSpacesBefore (usingStatement.RPar, policy.WithinUsingParentheses); + + return base.VisitUsingStatement (usingStatement, data); + } + + public override object VisitSwitchStatement (MonoDevelop.CSharp.Dom.SwitchStatement switchStatement, object data) + { + ForceSpacesBefore (switchStatement.LPar, policy.SwitchParentheses); + + ForceSpacesAfter (switchStatement.LPar, policy.WithinSwitchParentheses); + ForceSpacesBefore (switchStatement.RPar, policy.WithinSwitchParentheses); + + return base.VisitSwitchStatement (switchStatement, data); + } + + public override object VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression, object data) + { + ForceSpacesAfter (parenthesizedExpression.LPar, policy.WithinParentheses); + ForceSpacesBefore (parenthesizedExpression.RPar, policy.WithinParentheses); + return base.VisitParenthesizedExpression (parenthesizedExpression, data); + } + + public override object VisitSizeOfExpression (SizeOfExpression sizeOfExpression, object data) + { + ForceSpacesAfter (sizeOfExpression.LPar, policy.WithinSizeOfParentheses); + ForceSpacesBefore (sizeOfExpression.RPar, policy.WithinSizeOfParentheses); + return base.VisitSizeOfExpression (sizeOfExpression, data); + } + + public override object VisitTypeOfExpression (TypeOfExpression typeOfExpression, object data) + { + ForceSpacesAfter (typeOfExpression.LPar, policy.WithinTypeOfParentheses); + ForceSpacesBefore (typeOfExpression.RPar, policy.WithinTypeOfParentheses); + return base.VisitTypeOfExpression (typeOfExpression, data); + } + + public override object VisitCheckedExpression (CheckedExpression checkedExpression, object data) + { + ForceSpacesAfter (checkedExpression.LPar, policy.WithinCheckedExpressionParantheses); + ForceSpacesBefore (checkedExpression.RPar, policy.WithinCheckedExpressionParantheses); + return base.VisitCheckedExpression (checkedExpression, data); + } + + public override object VisitUncheckedExpression (UncheckedExpression uncheckedExpression, object data) + { + ForceSpacesAfter (uncheckedExpression.LPar, policy.WithinCheckedExpressionParantheses); + ForceSpacesBefore (uncheckedExpression.RPar, policy.WithinCheckedExpressionParantheses); + return base.VisitUncheckedExpression (uncheckedExpression, data); + } + + public override object VisitObjectCreateExpression (ObjectCreateExpression objectCreateExpression, object data) + { + ForceSpacesBefore (objectCreateExpression.LPar, policy.NewParentheses); + + return base.VisitObjectCreateExpression (objectCreateExpression, data); + } + + public override object VisitArrayObjectCreateExpression (ArrayObjectCreateExpression arrayObjectCreateExpression, object data) + { + foreach (INode node in arrayObjectCreateExpression.Children) { + if (node.Role == ArrayObjectCreateExpression.Roles.Comma) { + ForceSpacesBefore (node, policy.SpacesBeforeComma); + ForceSpacesAfter (node, policy.SpacesAfterComma); + } + } + return base.VisitArrayObjectCreateExpression (arrayObjectCreateExpression, data); + } + + public override object VisitLambdaExpression (LambdaExpression lambdaExpression, object data) + { + ForceSpacesAfter (lambdaExpression.Arrow, true); + ForceSpacesBefore (lambdaExpression.Arrow, true); + + return base.VisitLambdaExpression (lambdaExpression, data); + } + + + } +} +*/ \ No newline at end of file diff --git a/ICSharpCode.NRefactory/CSharp/Formatter/Indent.cs b/ICSharpCode.NRefactory/CSharp/Formatter/Indent.cs new file mode 100644 index 0000000000..8703b41c88 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Formatter/Indent.cs @@ -0,0 +1,79 @@ +// +// Indent.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2010 Novell, Inc (http://www.novell.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; + +namespace ICSharpCode.NRefactory.CSharp +{ + public class Indent + { + public int Level { + get; + set; + } + + public int ExtraSpaces { + get; + set; + } + + public Indent () + { + } + + public Indent (int level, int extraSpaces) + { + this.Level = level; + this.ExtraSpaces = extraSpaces; + } + + public static Indent operator+(Indent left, Indent right) + { + return new Indent (left.Level + right.Level, left.ExtraSpaces + right.ExtraSpaces); + } + + public static Indent operator-(Indent left, Indent right) + { + return new Indent (left.Level - right.Level, left.ExtraSpaces - right.ExtraSpaces); + } + + public string IndentString { + get { + return new string ('\t', Level) + new string (' ', ExtraSpaces); + } + } + + public string SingleIndent { + get { + return "\t"; + } + } + + public override string ToString () + { + return string.Format ("[Indent: Level={0}, ExtraSpaces={1}]", Level, ExtraSpaces); + } + } +}