diff --git a/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs b/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs index d4fa6dd836..4abbac2f1a 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs @@ -366,6 +366,13 @@ namespace ICSharpCode.NRefactory.CSharp lastChild = child; } } + + public void InsertChildsBefore(AstNode nextSibling, Role role, params T[] child) where T : AstNode + { + foreach (var cur in child) { + InsertChildBefore(nextSibling, cur, role); + } + } public void InsertChildBefore (AstNode nextSibling, T child, Role role) where T : AstNode { diff --git a/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs b/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs index b1c1600ef5..0ffa0428df 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs @@ -49,11 +49,16 @@ namespace ICSharpCode.NRefactory.CSharp VisitChildren (unit); } - public virtual void VisitComment (Comment comment) + public virtual void VisitComment(Comment comment) { - VisitChildren (comment); + VisitChildren(comment); } - + + public virtual void VisitNewLine(NewLineNode newLineNode) + { + VisitChildren(newLineNode); + } + public virtual void VisitDocumentationReference (DocumentationReference documentationReference) { VisitChildren (documentationReference); @@ -637,6 +642,11 @@ namespace ICSharpCode.NRefactory.CSharp return VisitChildren (comment); } + public virtual T VisitNewLine(NewLineNode newLineNode) + { + return VisitChildren(newLineNode); + } + public virtual T VisitDocumentationReference (DocumentationReference documentationReference) { return VisitChildren (documentationReference); @@ -1220,6 +1230,11 @@ namespace ICSharpCode.NRefactory.CSharp return VisitChildren (comment, data); } + public virtual S VisitNewLine(NewLineNode newLineNode, T data) + { + return VisitChildren(newLineNode, data); + } + public virtual S VisitDocumentationReference (DocumentationReference documentationReference, T data) { return VisitChildren (documentationReference, data); diff --git a/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs b/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs new file mode 100644 index 0000000000..23aa04189a --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/NewLineNode.cs @@ -0,0 +1,129 @@ +using System; +namespace ICSharpCode.NRefactory.CSharp +{ + public enum NewLineType { + Unix, + Windows, + Mac + } + + public abstract class NewLineNode : AstNode + { + public override NodeType NodeType { + get { + return NodeType.Whitespace; + } + } + + public abstract NewLineType NewLineType { + get; + } + + TextLocation startLocation; + public override TextLocation StartLocation { + get { + return startLocation; + } + } + + public override TextLocation EndLocation { + get { + return new TextLocation (startLocation.Line + 1, 1); + } + } + + public NewLineNode() : this (TextLocation.Empty) + { + } + + public NewLineNode(TextLocation startLocation) + { + this.startLocation = startLocation; + } + + public override void AcceptVisitor(IAstVisitor visitor) + { + visitor.VisitNewLine (this); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + return visitor.VisitNewLine (this); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return visitor.VisitNewLine (this, data); + } + } + + public class UnixNewLine : NewLineNode + { + public override NewLineType NewLineType { + get { + return NewLineType.Unix; + } + } + + public UnixNewLine() + { + } + + public UnixNewLine(TextLocation startLocation) : base (startLocation) + { + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + var o = other as UnixNewLine; + return o != null; + } + } + + public class WindowsNewLine : NewLineNode + { + public override NewLineType NewLineType { + get { + return NewLineType.Windows; + } + } + + public WindowsNewLine() + { + } + + public WindowsNewLine(TextLocation startLocation) : base (startLocation) + { + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + var o = other as WindowsNewLine; + return o != null; + } + } + + public class MacNewLine : NewLineNode + { + public override NewLineType NewLineType { + get { + return NewLineType.Mac; + } + } + + public MacNewLine() + { + } + + public MacNewLine(TextLocation startLocation) : base (startLocation) + { + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + var o = other as MacNewLine; + return o != null; + } + } +} + diff --git a/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs b/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs index b82d8ca12e..17e64a8f60 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs @@ -137,6 +137,7 @@ namespace ICSharpCode.NRefactory.CSharp void VisitPrimitiveType(PrimitiveType primitiveType); void VisitComment(Comment comment); + void VisitNewLine(NewLineNode newLineNode); void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective); void VisitDocumentationReference(DocumentationReference documentationReference); @@ -265,6 +266,7 @@ namespace ICSharpCode.NRefactory.CSharp S VisitPrimitiveType(PrimitiveType primitiveType); S VisitComment(Comment comment); + S VisitNewLine(NewLineNode newLineNode); S VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective); S VisitDocumentationReference(DocumentationReference documentationReference); @@ -393,6 +395,7 @@ namespace ICSharpCode.NRefactory.CSharp S VisitPrimitiveType(PrimitiveType primitiveType, T data); S VisitComment(Comment comment, T data); + S VisitNewLine(NewLineNode newLineNode, T data); S VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective, T data); S VisitDocumentationReference(DocumentationReference documentationReference, T data); diff --git a/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs b/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs index b55b5fdf14..67bc776dd8 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs @@ -60,9 +60,18 @@ namespace ICSharpCode.NRefactory.CSharp handler (comment, data); return VisitChildren (comment, data); } - - public event Action PreProcessorDirectiveVisited; + public event Action NewLineVisited; + + S IAstVisitor.VisitNewLine(NewLineNode newLineNode, T data) + { + var handler = NewLineVisited; + if (handler != null) + handler(newLineNode, data); + return VisitChildren(newLineNode, data); + } + + public event Action PreProcessorDirectiveVisited; S IAstVisitor.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective, T data) { var handler = PreProcessorDirectiveVisited; diff --git a/ICSharpCode.NRefactory.CSharp/Ast/Roles.cs b/ICSharpCode.NRefactory.CSharp/Ast/Roles.cs index f958e24659..c85f5b950a 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/Roles.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/Roles.cs @@ -68,6 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp public static readonly TokenRole Colon = new TokenRole (":"); public static readonly TokenRole DoubleColon = new TokenRole ("::"); public static readonly Role Comment = new Role ("Comment"); + public static readonly Role NewLine = new Role ("NewLine"); public static readonly Role PreProcessorDirective = new Role ("PreProcessorDirective"); public static readonly Role Error = new Role ("Error"); diff --git a/ICSharpCode.NRefactory.CSharp/Formatter/GeneratedCodeSettings.cs b/ICSharpCode.NRefactory.CSharp/Formatter/GeneratedCodeSettings.cs new file mode 100644 index 0000000000..ae763f849c --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Formatter/GeneratedCodeSettings.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.CSharp +{ + public enum GeneratedCodeMember + { + Unknown, + + StaticFields, + InstanceFields, + StaticProperties, + InstanceProperties, + Constructors, + StaticMethods, + InstanceMethods, + StaticEvents, + InstanceEvents, + NestedTypes + } + + public class GeneratedCodeSettings + { + List codeMemberOrder; + + public List CodeMemberOrder { + get { + return codeMemberOrder; + } + set { + codeMemberOrder = value; + } + } + + public bool GenerateCategoryComments { + get; + set; + } + + public bool SubOrderAlphabetical { + get; + set; + } + + public void Apply (AstNode rootNode) + { + if (rootNode == null) + throw new ArgumentNullException ("rootNode"); + rootNode.AcceptVisitor (new GenerateCodeVisitior (this)); + } + + public virtual string GetCategoryLabel(GeneratedCodeMember memberCategory) + { + switch (memberCategory) { + case GeneratedCodeMember.StaticFields: + return "Static Fields"; + case GeneratedCodeMember.InstanceFields: + return "Fields"; + case GeneratedCodeMember.StaticProperties: + return "Static Properties"; + case GeneratedCodeMember.InstanceProperties: + return "Properties"; + case GeneratedCodeMember.Constructors: + return "Constructors"; + case GeneratedCodeMember.StaticMethods: + return "Static Methods"; + case GeneratedCodeMember.InstanceMethods: + return "Methods"; + case GeneratedCodeMember.StaticEvents: + return "Static Events"; + case GeneratedCodeMember.InstanceEvents: + return "Events"; + case GeneratedCodeMember.NestedTypes: + return "Nested Types"; + } + return null; + } + + class GenerateCodeVisitior : DepthFirstAstVisitor + { + GeneratedCodeSettings settings; + + public GenerateCodeVisitior(GeneratedCodeSettings settings) + { + if (settings == null) + throw new ArgumentNullException("settings"); + this.settings = settings; + } + + GeneratedCodeMember GetCodeMemberCategory(EntityDeclaration x) + { + bool isStatic = x.HasModifier(Modifiers.Static) || x.HasModifier(Modifiers.Const); + if (x is FieldDeclaration) + return isStatic ? GeneratedCodeMember.StaticFields : GeneratedCodeMember.InstanceFields; + if (x is PropertyDeclaration) + return isStatic ? GeneratedCodeMember.StaticProperties : GeneratedCodeMember.InstanceProperties; + if (x is ConstructorDeclaration || x is DestructorDeclaration) + return GeneratedCodeMember.Constructors; + if (x is MethodDeclaration) + return isStatic ? GeneratedCodeMember.StaticMethods : GeneratedCodeMember.InstanceMethods; + if (x is EventDeclaration) + return isStatic ? GeneratedCodeMember.StaticEvents : GeneratedCodeMember.InstanceEvents; + + if (x is TypeDeclaration) + return GeneratedCodeMember.NestedTypes; + + return GeneratedCodeMember.Unknown; + } + + public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) + { + if (typeDeclaration.ClassType == ClassType.Enum) + return; + var entities = new List(typeDeclaration.Members); + entities.Sort((x, y) => { + int i1 = settings.CodeMemberOrder.IndexOf(GetCodeMemberCategory(x)); + int i2 = settings.CodeMemberOrder.IndexOf(GetCodeMemberCategory(y)); + if (i1 != i2) + return i1.CompareTo(i2); + if (settings.SubOrderAlphabetical) + return (x.Name ?? "").CompareTo((y.Name ?? "")); + return entities.IndexOf(x).CompareTo(entities.IndexOf(y)); + }); + typeDeclaration.Members.Clear(); + typeDeclaration.Members.AddRange(entities); + + if (settings.GenerateCategoryComments) { + var curCat = GeneratedCodeMember.Unknown; + foreach (var mem in entities) { + var cat = GetCodeMemberCategory(mem); + if (cat == curCat) + continue; + curCat = cat; + var label = settings.GetCategoryLabel(curCat); + if (string.IsNullOrEmpty(label)) + continue; + + var cmt = new Comment("", CommentType.SingleLine); + var cmt2 = new Comment(" " + label, CommentType.SingleLine); + var cmt3 = new Comment("", CommentType.SingleLine); + mem.Parent.InsertChildsBefore(mem, Roles.Comment, cmt, cmt2, cmt3); + mem.Parent.InsertChildBefore(cmt, new UnixNewLine(), Roles.NewLine); + mem.Parent.InsertChildAfter(cmt3, new UnixNewLine(), Roles.NewLine); + } + } + } + } + + static Lazy defaultSettings = new Lazy( + () => new GeneratedCodeSettings() { + CodeMemberOrder = new List() { + GeneratedCodeMember.StaticFields, + GeneratedCodeMember.InstanceFields, + GeneratedCodeMember.StaticProperties, + GeneratedCodeMember.InstanceProperties, + GeneratedCodeMember.Constructors, + GeneratedCodeMember.StaticMethods, + GeneratedCodeMember.InstanceMethods, + GeneratedCodeMember.StaticEvents, + GeneratedCodeMember.InstanceEvents, + GeneratedCodeMember.NestedTypes + }, + GenerateCategoryComments = true, + SubOrderAlphabetical = true + }); + + public static GeneratedCodeSettings Default { + get { + return defaultSettings.Value; + } + } + } +} \ No newline at end of file diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index b0a5aeccb1..54bd452d79 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -364,6 +364,8 @@ + + diff --git a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs index df2a15ffd9..21ebf28d6e 100644 --- a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -111,7 +111,7 @@ namespace ICSharpCode.NRefactory.CSharp void WriteSpecials(AstNode start, AstNode end) { for (AstNode pos = start; pos != end; pos = pos.NextSibling) { - if (pos.Role == Roles.Comment || pos.Role == Roles.PreProcessorDirective) { + if (pos.Role == Roles.Comment || pos.Role == Roles.NewLine || pos.Role == Roles.PreProcessorDirective) { pos.AcceptVisitor(this); } } @@ -2376,7 +2376,14 @@ namespace ICSharpCode.NRefactory.CSharp formatter.EndNode(comment); lastWritten = LastWritten.Whitespace; } - + + public void VisitNewLine(NewLineNode newLineNode) + { + formatter.StartNode(newLineNode); + formatter.NewLine(); + formatter.EndNode(newLineNode); + } + public void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective) { formatter.StartNode(preProcessorDirective); diff --git a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs index c54b50271f..1838fec113 100644 --- a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs @@ -1244,7 +1244,12 @@ namespace ICSharpCode.NRefactory.CSharp { return new CodeComment (comment.Content, comment.CommentType == CommentType.Documentation); } - + + CodeObject IAstVisitor.VisitNewLine(NewLineNode newLineNode) + { + throw new NotSupportedException(); + } + CodeObject IAstVisitor.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective) { return new CodeComment ("#" + preProcessorDirective.Type.ToString ().ToLower ()); diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index c24f65f4bb..2e796aff12 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -3608,6 +3608,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { return null; } + + ResolveResult IAstVisitor.VisitNewLine (NewLineNode comment) + { + return null; + } ResolveResult IAstVisitor.VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective) {