From 7ac091e93d8112b369425cceab64829c094e401c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 24 Feb 2011 13:30:54 +0100 Subject: [PATCH] Squashed 'NRefactory/' changes from b28b9a3..2200240 2200240 InsertParenthesesVisitor: don't insert parentheses for "a && b && c" 5a34a9c Fix output of checked and unchecked expressions. 695138d Add visitor support to pattern nodes (IPatternAstVisitor). Add pattern support to output visitor (makes debugging easier if you can print out patterns) 38faf84 Add support for 'any' operator and fix a bug in pattern matching. eeb4ea5 Add simple backtracking support to pattern matching. e6c0091 Implement pattern matching for statements. 93cc19d Determine loop condition from CFG 23190aa NRefactory AST: Add 'Repeat' pattern which matches an arbitrary number of nodes. 379063a OutputVisitor bugfix: show return type for custom events. bce9881 Add some improvements to pattern matching. f5e89bf Add Choice pattern. 84a5ace OutputVisitor: allow writing constructor declarations without writing their parent type declaration. 13c6417 Add some documentation comments. 7e03cf8 Fix output of using statement when the resource acquisition is a VariableDeclarationStatement. 9d5390c Add pattern matching support to the NRefactory C# AST. 1af927c Fix lambda expression output bug. 904b05f NRefactory: remove collection setters from AST; expose AstNodeCollection instead. 0fa2fd6 Fix missing dot in namespace declarations. 8641726 Escape surrogates in string literals. f1ce3e9 Fix order of modifiers. cd9efb5 Fixed infinite loop in AstComparer 3e02950 Merge commit '814b8b3bf3553c719c84be7b0aa71c946731e36a' 7c23366 Merge in the latest NRefactory (8db1fe252f6539e9cde8c9fb5f59aa60e4089d8f) git-subtree-dir: NRefactory git-subtree-split: 2200240ef60fc49f32b89eb85c9f3a8ba796b08d --- .../CSharp/InsertParenthesesVisitorTests.cs | 74 ++++++- .../CSharp/Ast/AstComparer.cs | 42 ---- ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs | 70 +++--- .../CSharp/Ast/AstNodeCollection.cs | 201 ++++++++++++++++++ ICSharpCode.NRefactory/CSharp/Ast/AstType.cs | 6 + .../CSharp/Ast/CSharpModifierToken.cs | 52 +++-- .../CSharp/Ast/CSharpTokenNode.cs | 13 +- .../CSharp/Ast/CompilationUnit.cs | 7 +- .../CSharp/Ast/ComposedType.cs | 15 +- .../Expressions/AnonymousMethodExpression.cs | 11 +- .../Ast/Expressions/ArgListExpression.cs | 11 +- .../Ast/Expressions/ArrayCreateExpression.cs | 12 +- .../Expressions/ArrayInitializerExpression.cs | 16 +- .../CSharp/Ast/Expressions/AsExpression.cs | 8 +- .../Ast/Expressions/AssignmentExpression.cs | 12 +- .../Expressions/BaseReferenceExpression.cs | 8 +- .../Expressions/BinaryOperatorExpression.cs | 18 +- .../CSharp/Ast/Expressions/CastExpression.cs | 8 +- .../Ast/Expressions/CheckedExpression.cs | 8 +- .../Ast/Expressions/ConditionalExpression.cs | 8 +- .../Ast/Expressions/DefaultValueExpression.cs | 8 +- .../Ast/Expressions/DirectionExpression.cs | 8 +- .../CSharp/Ast/Expressions/Expression.cs | 53 +++-- .../Ast/Expressions/IdentifierExpression.cs | 11 +- .../Ast/Expressions/IndexerExpression.cs | 11 +- .../Ast/Expressions/InvocationExpression.cs | 11 +- .../CSharp/Ast/Expressions/IsExpression.cs | 8 +- .../Ast/Expressions/LambdaExpression.cs | 11 +- .../Expressions/MemberReferenceExpression.cs | 11 +- .../Expressions/NamedArgumentExpression.cs | 6 + .../Expressions/NullReferenceExpression.cs | 8 +- .../Ast/Expressions/ObjectCreateExpression.cs | 11 +- .../Expressions/ParenthesizedExpression.cs | 8 +- .../Expressions/PointerReferenceExpression.cs | 11 +- .../Ast/Expressions/PrimitiveExpression.cs | 10 +- .../CSharp/Ast/Expressions/QueryExpression.cs | 29 ++- .../Ast/Expressions/SizeOfExpression.cs | 8 +- .../Ast/Expressions/StackAllocExpression.cs | 8 +- .../Expressions/ThisReferenceExpression.cs | 8 +- .../Ast/Expressions/TypeOfExpression.cs | 8 +- .../Expressions/TypeReferenceExpression.cs | 8 +- .../Expressions/UnaryOperatorExpression.cs | 8 +- .../Ast/Expressions/UncheckedExpression.cs | 8 +- .../CSharp/Ast/GeneralScope/Attribute.cs | 11 +- .../Ast/GeneralScope/AttributeSection.cs | 11 +- .../CSharp/Ast/GeneralScope/Comment.cs | 8 +- .../CSharp/Ast/GeneralScope/Constraint.cs | 11 +- .../Ast/GeneralScope/DelegateDeclaration.cs | 11 +- .../Ast/GeneralScope/NamespaceDeclaration.cs | 16 +- .../Ast/GeneralScope/TypeDeclaration.cs | 14 +- .../GeneralScope/TypeParameterDeclaration.cs | 6 + .../Ast/GeneralScope/UsingAliasDeclaration.cs | 8 +- .../Ast/GeneralScope/UsingDeclaration.cs | 8 +- .../CSharp/Ast/Identifier.cs | 8 +- .../CSharp/Ast/MemberType.cs | 11 +- ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs | 4 +- .../CSharp/Ast/PatternMatching/AnyNode.cs | 35 +++ .../Ast/PatternMatching/Backreference.cs | 70 ++++++ .../CSharp/Ast/PatternMatching/Choice.cs | 54 +++++ .../Ast/PatternMatching/IPatternAstVisitor.cs | 22 ++ .../CSharp/Ast/PatternMatching/Match.cs | 59 +++++ .../CSharp/Ast/PatternMatching/NamedNode.cs | 38 ++++ .../CSharp/Ast/PatternMatching/Pattern.cs | 70 ++++++ .../CSharp/Ast/PatternMatching/Placeholder.cs | 119 +++++++++++ .../CSharp/Ast/PatternMatching/Repeat.cs | 55 +++++ .../CSharp/Ast/PrimitiveType.cs | 8 +- .../CSharp/Ast/SimpleType.cs | 11 +- .../CSharp/Ast/Statements/BlockStatement.cs | 38 +++- .../CSharp/Ast/Statements/BreakStatement.cs | 10 +- .../CSharp/Ast/Statements/CheckedStatement.cs | 8 +- .../Ast/Statements/ContinueStatement.cs | 8 +- .../CSharp/Ast/Statements/DoWhileStatement.cs | 8 +- .../CSharp/Ast/Statements/EmptyStatement.cs | 8 +- .../Ast/Statements/ExpressionStatement.cs | 17 +- .../CSharp/Ast/Statements/FixedStatement.cs | 11 +- .../CSharp/Ast/Statements/ForStatement.cs | 17 +- .../CSharp/Ast/Statements/ForeachStatement.cs | 9 +- .../CSharp/Ast/Statements/GotoStatement.cs | 38 ++-- .../CSharp/Ast/Statements/IfElseStatement.cs | 8 +- .../CSharp/Ast/Statements/LabelStatement.cs | 12 +- .../CSharp/Ast/Statements/LockStatement.cs | 8 +- .../CSharp/Ast/Statements/ReturnStatement.cs | 8 +- .../CSharp/Ast/Statements/Statement.cs | 5 + .../CSharp/Ast/Statements/SwitchStatement.cs | 29 ++- .../CSharp/Ast/Statements/ThrowStatement.cs | 8 +- .../Ast/Statements/TryCatchStatement.cs | 17 +- .../Ast/Statements/UncheckedStatement.cs | 8 +- .../CSharp/Ast/Statements/UnsafeStatement.cs | 8 +- .../CSharp/Ast/Statements/UsingStatement.cs | 8 +- .../VariableDeclarationStatement.cs | 21 +- .../CSharp/Ast/Statements/WhileStatement.cs | 8 +- .../Ast/Statements/YieldBreakStatement.cs | 8 +- .../CSharp/Ast/Statements/YieldStatement.cs | 8 +- .../CSharp/Ast/TypeMembers/Accessor.cs | 9 +- .../CSharp/Ast/TypeMembers/AttributedNode.cs | 13 +- .../Ast/TypeMembers/ConstructorDeclaration.cs | 21 +- .../Ast/TypeMembers/DestructorDeclaration.cs | 9 +- .../Ast/TypeMembers/EventDeclaration.cs | 5 +- .../Ast/TypeMembers/FieldDeclaration.cs | 5 +- .../Ast/TypeMembers/IndexerDeclaration.cs | 5 +- .../Ast/TypeMembers/MethodDeclaration.cs | 11 +- .../Ast/TypeMembers/OperatorDeclaration.cs | 5 +- .../Ast/TypeMembers/ParameterDeclaration.cs | 11 +- .../Ast/TypeMembers/VariableInitializer.cs | 8 +- .../OutputVisitor/InsertParenthesesVisitor.cs | 17 +- .../CSharp/OutputVisitor/OutputVisitor.cs | 124 +++++++++-- .../CSharp/Parser/CSharpParser.cs | 4 +- .../ICSharpCode.NRefactory.csproj | 20 +- 108 files changed, 1801 insertions(+), 341 deletions(-) delete mode 100644 ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs create mode 100644 ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs diff --git a/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs index fd044068f..5fa0b5469 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs @@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp public void MethodCallOnQueryExpression() { Expression expr = new QueryExpression { - Clauses = new QueryClause[] { + Clauses = { new QueryFromClause { Identifier = "a", Expression = new IdentifierExpression("b") @@ -178,7 +178,7 @@ namespace ICSharpCode.NRefactory.CSharp public void SumOfQueries() { QueryExpression query = new QueryExpression { - Clauses = new QueryClause[] { + Clauses = { new QueryFromClause { Identifier = "a", Expression = new IdentifierExpression("b") @@ -206,7 +206,7 @@ namespace ICSharpCode.NRefactory.CSharp public void QueryInTypeTest() { Expression expr = new QueryExpression { - Clauses = new QueryClause[] { + Clauses = { new QueryFromClause { Identifier = "a", Expression = new IdentifierExpression("b") @@ -252,5 +252,73 @@ namespace ICSharpCode.NRefactory.CSharp Assert.AreEqual("(++a)++", InsertRequired(expr)); Assert.AreEqual("(++a)++", InsertReadable(expr)); } + + [Test] + public void Logical1() + { + Expression expr = new BinaryOperatorExpression( + new BinaryOperatorExpression( + new IdentifierExpression("a"), + BinaryOperatorType.ConditionalAnd, + new IdentifierExpression("b") + ), + BinaryOperatorType.ConditionalAnd, + new IdentifierExpression("c") + ); + + Assert.AreEqual("a && b && c", InsertRequired(expr)); + Assert.AreEqual("a && b && c", InsertReadable(expr)); + } + + [Test] + public void Logical2() + { + Expression expr = new BinaryOperatorExpression( + new IdentifierExpression("a"), + BinaryOperatorType.ConditionalAnd, + new BinaryOperatorExpression( + new IdentifierExpression("b"), + BinaryOperatorType.ConditionalAnd, + new IdentifierExpression("c") + ) + ); + + Assert.AreEqual("a && (b && c)", InsertRequired(expr)); + Assert.AreEqual("a && (b && c)", InsertReadable(expr)); + } + + [Test] + public void Logical3() + { + Expression expr = new BinaryOperatorExpression( + new IdentifierExpression("a"), + BinaryOperatorType.ConditionalOr, + new BinaryOperatorExpression( + new IdentifierExpression("b"), + BinaryOperatorType.ConditionalAnd, + new IdentifierExpression("c") + ) + ); + + Assert.AreEqual("a || b && c", InsertRequired(expr)); + Assert.AreEqual("a || (b && c)", InsertReadable(expr)); + } + + [Test] + public void Logical4() + { + Expression expr = new BinaryOperatorExpression( + new IdentifierExpression("a"), + BinaryOperatorType.ConditionalAnd, + new BinaryOperatorExpression( + new IdentifierExpression("b"), + BinaryOperatorType.ConditionalOr, + new IdentifierExpression("c") + ) + ); + + Assert.AreEqual("a && (b || c)", InsertRequired(expr)); + Assert.AreEqual("a && (b || c)", InsertReadable(expr)); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs deleted file mode 100644 index ab74a4fc5..000000000 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstComparer.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under MIT X11 license (for details please see \doc\license.txt) - -using System; -using System.Collections.Generic; - -namespace ICSharpCode.NRefactory.CSharp -{ - /// - /// Compares whether two ASTs are structurally identical. - /// - public static class AstComparer - { - static HashSet nodeTypesWithoutExtraInfo = new HashSet { - typeof(IdentifierExpression) - }; - - public static bool? AreEqual(AstNode node1, AstNode node2) - { - if (node1 == node2) - return true; - if (node1 == null || node1.IsNull || node2 == null || node2.IsNull) - return false; - Type nodeType = node1.GetType(); - if (nodeType != node2.GetType()) - return false; - if (node1.Role != node2.Role) - return false; - AstNode child1 = node1.FirstChild; - AstNode child2 = node2.FirstChild; - bool? result = true; - while (result != false && (child1 != null || child2 != null)) { - result &= AreEqual(child1, child2); - } - if (nodeTypesWithoutExtraInfo.Contains(nodeType)) - return result; - if (nodeType == typeof(Identifier)) - return ((Identifier)node1).Name == ((Identifier)node2).Name; - return null; - } - } -} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index 5a81449d2..a5361ef4f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -1,4 +1,4 @@ -// +// // AstNode.cs // // Author: @@ -25,11 +25,14 @@ // THE SOFTWARE. using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using ICSharpCode.NRefactory.CSharp.PatternMatching; + namespace ICSharpCode.NRefactory.CSharp { public abstract class AstNode @@ -55,6 +58,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion @@ -164,16 +172,9 @@ namespace ICSharpCode.NRefactory.CSharp return role.NullObject; } - public IEnumerable GetChildrenByRole(Role role) where T : AstNode + public AstNodeCollection GetChildrenByRole(Role role) where T : AstNode { - AstNode next; - for (AstNode cur = firstChild; cur != null; cur = next) { - // Remember next before yielding cur. - // This allows removing/replacing nodes while iterating through the list. - next = cur.nextSibling; - if (cur.role == role) - yield return (T)cur; - } + return new AstNodeCollection(this, role); } protected void SetChildByRole(Role role, T newChild) where T : AstNode @@ -185,24 +186,6 @@ namespace ICSharpCode.NRefactory.CSharp oldChild.ReplaceWith(newChild); } - protected void SetChildrenByRole(Role role, IEnumerable newChildren) where T : AstNode - { - // Evaluate 'newChildren' first, since it might change when we remove the old children - // Example: SetChildren(role, GetChildrenByRole(role)); - if (newChildren != null) - newChildren = newChildren.ToList(); - - // remove old children - foreach (AstNode node in GetChildrenByRole(role)) - node.Remove(); - // add new children - if (newChildren != null) { - foreach (T node in newChildren) { - AddChild(node, role); - } - } - } - public void AddChild(T child, Role role) where T : AstNode { if (role == null) @@ -594,6 +577,37 @@ namespace ICSharpCode.NRefactory.CSharp public abstract S AcceptVisitor (IAstVisitor visitor, T data); + #region Pattern Matching + /// + /// Performs a pattern matching operation. + /// this is the pattern, is the AST that is being matched. + /// + /// + /// If successful, a match object containing the matched groups. + /// If the match failed, returns null. + /// + /// + /// Patterns are ASTs that contain special pattern nodes (from the PatternMatching namespace). + /// However, it is also possible to match two ASTs without any pattern nodes - doing so will produce an empty match object + /// if the two ASTs are structurally identical; or will return null if the ASTs are not identical. + /// + public Match Match(AstNode other) + { + Match match = new Match(); + if (DoMatch(other, match)) + return match; + else + return null; + } + + protected static bool MatchString(string name1, string name2) + { + return string.IsNullOrEmpty(name1) || name1 == name2; + } + + protected internal abstract bool DoMatch(AstNode other, Match match); + #endregion + // the Root role must be available when creating the null nodes, so we can't put it in the Roles class static readonly Role RootRole = new Role("Root"); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs new file mode 100644 index 000000000..033ad7913 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -0,0 +1,201 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using ICSharpCode.NRefactory.CSharp.PatternMatching; + +namespace ICSharpCode.NRefactory.CSharp +{ + /// + /// Represents the children of an AstNode that have a specific role. + /// + public class AstNodeCollection : ICollection where T : AstNode + { + readonly AstNode node; + readonly Role role; + + public AstNodeCollection(AstNode node, Role role) + { + if (node == null) + throw new ArgumentNullException("node"); + if (role == null) + throw new ArgumentNullException("role"); + this.node = node; + this.role = role; + } + + public int Count { + get { + var e = GetEnumerator(); + int count = 0; + while (e.MoveNext()) + count++; + return count; + } + } + + public void Add(T element) + { + node.AddChild(element, role); + } + + public void AddRange(IEnumerable nodes) + { + // Evaluate 'nodes' first, since it might change when we add the new children + // Example: collection.AddRange(collection); + if (nodes != null) { + foreach (T node in nodes.ToList()) + Add(node); + } + } + + public void AddRange(T[] nodes) + { + // Fast overload for arrays - we don't need to create a copy + if (nodes != null) { + foreach (T node in nodes) + Add(node); + } + } + + public void ReplaceWith(IEnumerable nodes) + { + // Evaluate 'nodes' first, since it might change when we call Clear() + // Example: collection.ReplaceWith(collection); + if (nodes != null) + nodes = nodes.ToList(); + Clear(); + foreach (T node in nodes) + Add(node); + } + + public void MoveTo(ICollection targetCollection) + { + foreach (T node in this) { + node.Remove(); + targetCollection.Add(node); + } + } + + public bool Contains(T element) + { + return element != null && element.Parent == node && element.Role == role; + } + + public bool Remove(T element) + { + if (Contains(element)) { + element.Remove(); + return true; + } else { + return false; + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + foreach (T item in this) + array[arrayIndex++] = item; + } + + public void Clear() + { + foreach (T item in this) + item.Remove(); + } + + bool ICollection.IsReadOnly { + get { return false; } + } + + public IEnumerator GetEnumerator() + { + AstNode next; + for (AstNode cur = node.FirstChild; cur != null; cur = next) { + // Remember next before yielding cur. + // This allows removing/replacing nodes while iterating through the list. + next = cur.NextSibling; + if (cur.Role == role) + yield return (T)cur; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + if (obj is AstNodeCollection) { + return ((AstNodeCollection)obj) == this; + } else { + return false; + } + } + + public override int GetHashCode() + { + return node.GetHashCode() ^ role.GetHashCode(); + } + + public static bool operator ==(AstNodeCollection left, AstNodeCollection right) + { + return left.role == right.role && left.node == right.node; + } + + public static bool operator !=(AstNodeCollection left, AstNodeCollection right) + { + return !(left.role == right.role && left.node == right.node); + } + #endregion + + internal bool DoMatch(AstNodeCollection other, Match match) + { + Stack patternStack = new Stack(); + Stack stack = new Stack(); + patternStack.Push(this.node.FirstChild); + stack.Push(new Pattern.PossibleMatch(other.node.FirstChild, match.CheckPoint())); + while (stack.Count > 0) { + AstNode cur1 = patternStack.Pop(); + AstNode cur2 = stack.Peek().NextOther; + match.RestoreCheckPoint(stack.Pop().Checkpoint); + bool success = true; + while (cur1 != null && success) { + while (cur1 != null && cur1.Role != role) + cur1 = cur1.NextSibling; + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (cur1 == null) + break; + + Pattern pattern = cur1 as Pattern; + if (pattern == null && cur1.NodeType == NodeType.Placeholder) + pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; + if (pattern != null) { + Debug.Assert(stack.Count == patternStack.Count); + success = pattern.DoMatchCollection(role, cur2, match, stack); + Debug.Assert(stack.Count >= patternStack.Count); + while (stack.Count > patternStack.Count) + patternStack.Push(cur1.NextSibling); + } else { + success = cur1.DoMatch(cur2, match); + } + cur1 = cur1.NextSibling; + if (cur2 != null) + cur2 = cur2.NextSibling; + } + while (cur2 != null && cur2.Role != role) + cur2 = cur2.NextSibling; + if (success && cur2 == null) + return true; + } + return false; + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs index 2c4af725a..08bf473d4 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp { @@ -22,6 +23,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion diff --git a/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs b/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs index 3b48cdf59..6b2b12959 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; using System.Collections.Generic; +using System.Linq; namespace ICSharpCode.NRefactory.CSharp { @@ -36,33 +37,40 @@ namespace ICSharpCode.NRefactory.CSharp public Modifiers Modifier { get { return modifier; } set { - modifier = value; - if (!lengthTable.TryGetValue (modifier, out tokenLength)) - throw new InvalidOperationException ("Modifier " + modifier + " is invalid."); + for (int i = 0; i < lengthTable.Count; i++) { + if (lengthTable[i].Key == value) { + this.modifier = value; + this.tokenLength = lengthTable[i].Value; + return; + } + } + throw new ArgumentException ("Modifier " + value + " is invalid."); } } - static Dictionary lengthTable = new Dictionary () { - { Modifiers.Public, "public".Length }, - { Modifiers.Protected, "protected".Length }, - { Modifiers.Private, "private".Length }, - { Modifiers.Internal, "internal".Length }, - { Modifiers.New, "new".Length }, - { Modifiers.Unsafe, "unsafe".Length }, - { Modifiers.Abstract, "abstract".Length }, - { Modifiers.Virtual, "virtual".Length }, - { Modifiers.Sealed, "sealed".Length }, - { Modifiers.Static, "static".Length }, - { Modifiers.Override, "override".Length }, - { Modifiers.Readonly, "readonly".Length }, - { Modifiers.Volatile, "volatile".Length }, - { Modifiers.Extern, "extern".Length }, - { Modifiers.Partial, "partial".Length }, - { Modifiers.Const, "const".Length }, + // Not worth using a dictionary for such few elements. + // This table is sorted in the order that modifiers should be output when generating code. + static readonly List> lengthTable = new List> () { + new KeyValuePair(Modifiers.Public, "public".Length), + new KeyValuePair(Modifiers.Protected, "protected".Length), + new KeyValuePair(Modifiers.Private, "private".Length), + new KeyValuePair(Modifiers.Internal, "internal".Length), + new KeyValuePair(Modifiers.New, "new".Length), + new KeyValuePair(Modifiers.Unsafe, "unsafe".Length), + new KeyValuePair(Modifiers.Abstract, "abstract".Length), + new KeyValuePair(Modifiers.Virtual, "virtual".Length), + new KeyValuePair(Modifiers.Sealed, "sealed".Length), + new KeyValuePair(Modifiers.Static, "static".Length), + new KeyValuePair(Modifiers.Override, "override".Length), + new KeyValuePair(Modifiers.Readonly, "readonly".Length), + new KeyValuePair(Modifiers.Volatile, "volatile".Length), + new KeyValuePair(Modifiers.Extern, "extern".Length), + new KeyValuePair(Modifiers.Partial, "partial".Length), + new KeyValuePair(Modifiers.Const, "const".Length) }; - public static ICollection AllModifiers { - get { return lengthTable.Keys; } + public static IEnumerable AllModifiers { + get { return lengthTable.Select(p => p.Key); } } public CSharpModifierToken (AstLocation location, Modifiers modifier) : base (location, 0) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs index 659875dec..4e6288963 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs @@ -1,4 +1,4 @@ -// +// // TokenNode.cs // // Author: @@ -46,6 +46,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } @@ -80,6 +85,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitCSharpTokenNode (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CSharpTokenNode o = other as CSharpTokenNode; + return o != null; + } + public override string ToString () { return string.Format ("[CSharpTokenNode: StartLocation={0}, EndLocation={1}, Role={2}]", StartLocation, EndLocation, Role); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs b/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs index 3756d594b..9a5047719 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs @@ -42,6 +42,12 @@ namespace ICSharpCode.NRefactory.CSharp { } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CompilationUnit o = other as CompilationUnit; + return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match); + } + public AstNode GetNodeAt (int line, int column) { return GetNodeAt (new AstLocation (line, column)); @@ -99,7 +105,6 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCompilationUnit (this, data); } - } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs b/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs index 0a22debe1..ce8ad9879 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs @@ -67,9 +67,8 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable ArraySpecifiers { + public AstNodeCollection ArraySpecifiers { get { return GetChildrenByRole (ArraySpecifierRole); } - set { SetChildrenByRole (ArraySpecifierRole, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) @@ -77,6 +76,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitComposedType (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ComposedType o = other as ComposedType; + return o != null && this.HasNullableSpecifier == o.HasNullableSpecifier && this.PointerRank == o.PointerRank && this.ArraySpecifiers.DoMatch(o.ArraySpecifiers, match); + } + public override string ToString() { StringBuilder b = new StringBuilder(); @@ -157,6 +162,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitArraySpecifier(this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ArraySpecifier o = other as ArraySpecifier; + return o != null && this.Dimensions == o.Dimensions; + } + public override string ToString() { return "[" + new string(',', this.Dimensions - 1) + "]"; diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs index 10d497eda..b586d9157 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs @@ -1,4 +1,4 @@ -// +// // AnonymousMethodExpression.cs // // Author: @@ -47,9 +47,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RParToken { @@ -65,5 +64,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitAnonymousMethodExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + AnonymousMethodExpression o = other as AnonymousMethodExpression; + return o != null && this.HasParameterList == o.HasParameterList && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs index 533bf2fb8..c84f87389 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArgListExpression.cs @@ -1,4 +1,4 @@ -// +// // ArgListExpression.cs // // Author: @@ -45,9 +45,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole(Roles.Argument); } - set { SetChildrenByRole(Roles.Argument, value); } } public CSharpTokenNode RParToken { @@ -58,6 +57,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitArgListExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ArgListExpression o = other as ArgListExpression; + return o != null && this.IsAccess == o.IsAccess && this.Arguments.DoMatch(o.Arguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs index 7befd673e..6578c5826 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs @@ -16,18 +16,16 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Type, value); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole (Roles.Argument); } - set { SetChildrenByRole (Roles.Argument, value); } } /// /// Gets additional array ranks (those without size info). /// Empty for "new int[5,1]"; will contain a single element for "new int[5][]". /// - public IEnumerable AdditionalArraySpecifiers { + public AstNodeCollection AdditionalArraySpecifiers { get { return GetChildrenByRole(AdditionalArraySpecifierRole); } - set { SetChildrenByRole (AdditionalArraySpecifierRole, value); } } public ArrayInitializerExpression Initializer { @@ -39,5 +37,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitArrayCreateExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ArrayCreateExpression o = other as ArrayCreateExpression; + return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.Initializer.DoMatch(o.Initializer, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs index 8f897048c..3c33d4d7b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs @@ -1,4 +1,4 @@ -// +// // ArrayInitializerExpression.cs // // Author: @@ -48,6 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion @@ -55,9 +60,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBrace); } } - public IEnumerable Elements { + public AstNodeCollection Elements { get { return GetChildrenByRole(Roles.Expression); } - set { SetChildrenByRole(Roles.Expression, value); } } public CSharpTokenNode RBraceToken { @@ -68,6 +72,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitArrayInitializerExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ArrayInitializerExpression o = other as ArrayInitializerExpression; + return o != null && this.Elements.DoMatch(o.Elements, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AsExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AsExpression.cs index 9880a0f28..b08ecd08d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AsExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AsExpression.cs @@ -1,4 +1,4 @@ -// +// // AsExpression.cs // // Author: @@ -49,6 +49,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitAsExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + AsExpression o = other as AsExpression; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs index fd0ff5c3c..6db96ec89 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs @@ -1,4 +1,4 @@ -// +// // AssignmentExpression.cs // // Author: @@ -72,6 +72,13 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitAssignmentExpression (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + AssignmentExpression o = other as AssignmentExpression; + return o != null && (this.Operator == AssignmentOperatorType.Any || this.Operator == o.Operator) + && this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match); + } + public static string GetOperatorSymbol(AssignmentOperatorType op) { switch (op) { @@ -130,5 +137,8 @@ namespace ICSharpCode.NRefactory.CSharp BitwiseOr, /// left ^= right ExclusiveOr, + + /// Any operator (for pattern matching) + Any } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BaseReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BaseReferenceExpression.cs index ca3f5df24..b75fb9534 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BaseReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BaseReferenceExpression.cs @@ -1,4 +1,4 @@ -// +// // BaseReferenceExpression.cs // // Author: @@ -51,5 +51,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitBaseReferenceExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + BaseReferenceExpression o = other as BaseReferenceExpression; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs index 0d3685721..171e3e31c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs @@ -1,6 +1,6 @@ -// +// // BinaryOperatorExpression.cs -// +// // Author: // Mike Krüger // @@ -72,6 +72,13 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitBinaryOperatorExpression (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + BinaryOperatorExpression o = other as BinaryOperatorExpression; + return o != null && (this.Operator == BinaryOperatorType.Any || this.Operator == o.Operator) + && this.Left.DoMatch(o.Left, match) && this.Right.DoMatch(o.Right, match); + } + public static string GetOperatorSymbol(BinaryOperatorType op) { switch (op) { @@ -167,6 +174,11 @@ namespace ICSharpCode.NRefactory.CSharp ShiftRight, /// left ?? right - NullCoalescing + NullCoalescing, + + /// + /// Any binary operator (used in pattern matching) + /// + Any } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CastExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CastExpression.cs index 7a737aeaa..049376d13 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CastExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CastExpression.cs @@ -1,4 +1,4 @@ -// +// // CastExpression.cs // // Author: @@ -53,6 +53,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCastExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CastExpression o = other as CastExpression; + return o != null && this.Type.DoMatch(o.Type, match) && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CheckedExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CheckedExpression.cs index edb52b3f4..02b229644 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CheckedExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CheckedExpression.cs @@ -1,4 +1,4 @@ -// +// // CheckedExpression.cs // // Author: @@ -52,5 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCheckedExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CheckedExpression o = other as CheckedExpression; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ConditionalExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ConditionalExpression.cs index 502a56676..d0c1ddc5d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ConditionalExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ConditionalExpression.cs @@ -1,4 +1,4 @@ -// +// // ConditionalExpression.cs // // Author: @@ -64,5 +64,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitConditionalExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ConditionalExpression o = other as ConditionalExpression; + return o != null && this.Condition.DoMatch(o.Condition, match) && this.TrueExpression.DoMatch(o.TrueExpression, match) && this.FalseExpression.DoMatch(o.FalseExpression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DefaultValueExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DefaultValueExpression.cs index 7fa19eea3..d171f86b7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DefaultValueExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DefaultValueExpression.cs @@ -1,4 +1,4 @@ -// +// // DefaultValueExpression.cs // // Author: @@ -52,6 +52,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDefaultValueExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DefaultValueExpression o = other as DefaultValueExpression; + return o != null && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DirectionExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DirectionExpression.cs index f815c4579..5ba19bd6b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DirectionExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DirectionExpression.cs @@ -1,4 +1,4 @@ -// +// // DirectionExpression.cs // // Author: @@ -56,5 +56,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDirectionExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DirectionExpression o = other as DirectionExpression; + return o != null && this.FieldDirection == o.FieldDirection && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs index 6a6e3d9a3..3055ae7fb 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace ICSharpCode.NRefactory.CSharp @@ -31,6 +32,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion @@ -45,6 +51,14 @@ namespace ICSharpCode.NRefactory.CSharp return (Expression)base.Clone(); } + // Make debugging easier by giving Expressions a ToString() implementation + public override string ToString() + { + StringWriter w = new StringWriter(); + AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } + public Expression ReplaceWith(Func replaceFunction) { if (replaceFunction == null) @@ -66,7 +80,10 @@ namespace ICSharpCode.NRefactory.CSharp /// public IndexerExpression Indexer(IEnumerable arguments) { - return new IndexerExpression { Target = this, Arguments = arguments }; + IndexerExpression expr = new IndexerExpression(); + expr.Target = this; + expr.Arguments.AddRange(arguments); + return expr; } /// @@ -74,7 +91,10 @@ namespace ICSharpCode.NRefactory.CSharp /// public IndexerExpression Indexer(params Expression[] arguments) { - return new IndexerExpression { Target = this, Arguments = arguments }; + IndexerExpression expr = new IndexerExpression(); + expr.Target = this; + expr.Arguments.AddRange(arguments); + return expr; } /// @@ -98,14 +118,14 @@ namespace ICSharpCode.NRefactory.CSharp /// public InvocationExpression Invoke(string methodName, IEnumerable typeArguments, IEnumerable arguments) { - return new InvocationExpression { - Target = new MemberReferenceExpression { - Target = this, - MemberName = methodName, - TypeArguments = typeArguments - }, - Arguments = arguments - }; + InvocationExpression ie = new InvocationExpression(); + MemberReferenceExpression mre = new MemberReferenceExpression(); + mre.Target = this; + mre.MemberName = methodName; + mre.TypeArguments.AddRange(typeArguments); + ie.Target = mre; + ie.Arguments.AddRange(arguments); + return ie; } /// @@ -113,10 +133,10 @@ namespace ICSharpCode.NRefactory.CSharp /// public InvocationExpression Invoke(IEnumerable arguments) { - return new InvocationExpression { - Target = this, - Arguments = arguments - }; + InvocationExpression ie = new InvocationExpression(); + ie.Target = this; + ie.Arguments.AddRange(arguments); + return ie; } /// @@ -124,7 +144,10 @@ namespace ICSharpCode.NRefactory.CSharp /// public InvocationExpression Invoke(params Expression[] arguments) { - return Invoke(arguments.AsEnumerable()); + InvocationExpression ie = new InvocationExpression(); + ie.Target = this; + ie.Arguments.AddRange(arguments); + return ie; } public CastExpression CastTo(AstType type) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs index c56b9e564..bbc6898c1 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs @@ -1,4 +1,4 @@ -// +// // IdentifierExpression.cs // // Author: @@ -56,14 +56,19 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable TypeArguments { + public AstNodeCollection TypeArguments { get { return GetChildrenByRole (Roles.TypeArgument); } - set { SetChildrenByRole (Roles.TypeArgument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitIdentifierExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IdentifierExpression o = other as IdentifierExpression; + return o != null && MatchString(this.Identifier, o.Identifier) && this.TypeArguments.DoMatch(o.TypeArguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs index 71a8517f3..89ee4ec8b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs @@ -1,4 +1,4 @@ -// +// // IndexerExpression.cs // // Author: @@ -42,9 +42,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBracket); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole(Roles.Argument); } - set { SetChildrenByRole(Roles.Argument, value); } } public CSharpTokenNode RBracketToken { @@ -55,5 +54,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitIndexerExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IndexerExpression o = other as IndexerExpression; + return o != null && this.Target.DoMatch(o.Target, match) && this.Arguments.DoMatch(o.Arguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs index 9efe86284..47f66ac4e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs @@ -1,4 +1,4 @@ -// +// // InvocationExpression.cs // // Author: @@ -42,9 +42,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole(Roles.Argument); } - set { SetChildrenByRole(Roles.Argument, value); } } public CSharpTokenNode RParToken { @@ -55,5 +54,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitInvocationExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + InvocationExpression o = other as InvocationExpression; + return o != null && this.Target.DoMatch(o.Target, match) && this.Arguments.DoMatch(o.Arguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IsExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IsExpression.cs index fc325d884..a8c7b0e00 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IsExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IsExpression.cs @@ -1,4 +1,4 @@ -// +// // TypeOfIsExpression.cs // // Author: @@ -49,6 +49,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitIsExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IsExpression o = other as IsExpression; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs index 06baa857c..774bd6c4a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs @@ -1,4 +1,4 @@ -// +// // LambdaExpression.cs // // Author: @@ -36,9 +36,8 @@ namespace ICSharpCode.NRefactory.CSharp public readonly static Role ArrowRole = new Role("Arrow", CSharpTokenNode.Null); public static readonly Role BodyRole = new Role("Body", AstNode.Null); - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode ArrowToken { @@ -54,5 +53,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitLambdaExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + LambdaExpression o = other as LambdaExpression; + return o != null && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs index c20d2ce07..bcc7a71e6 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs @@ -1,4 +1,4 @@ -// +// // MemberReferenceExpression.cs // // Author: @@ -51,9 +51,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LChevron); } } - public IEnumerable TypeArguments { + public AstNodeCollection TypeArguments { get { return GetChildrenByRole (Roles.TypeArgument); } - set { SetChildrenByRole (Roles.TypeArgument, value); } } public CSharpTokenNode RChevronToken { @@ -64,5 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitMemberReferenceExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + MemberReferenceExpression o = other as MemberReferenceExpression; + return o != null && this.Target.DoMatch(o.Target, match) && MatchString(this.MemberName, o.MemberName) && this.TypeArguments.DoMatch(o.TypeArguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs index 60152c533..a390e33ee 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs @@ -28,5 +28,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitNamedArgumentExpression(this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + NamedArgumentExpression o = other as NamedArgumentExpression; + return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NullReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NullReferenceExpression.cs index de409e297..afd309d18 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NullReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NullReferenceExpression.cs @@ -1,4 +1,4 @@ -// +// // NullReferenceExpression.cs // // Author: @@ -35,5 +35,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitNullReferenceExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + NullReferenceExpression o = other as NullReferenceExpression; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs index efccad91a..fa113d530 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs @@ -1,4 +1,4 @@ -// +// // ObjectCreateExpression.cs // // Author: @@ -48,9 +48,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole (Roles.Argument); } - set { SetChildrenByRole (Roles.Argument, value); } } public CSharpTokenNode RParToken { @@ -66,5 +65,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitObjectCreateExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ObjectCreateExpression o = other as ObjectCreateExpression; + return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.Initializer.DoMatch(o.Initializer, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ParenthesizedExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ParenthesizedExpression.cs index 88a561327..94219bb8a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ParenthesizedExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ParenthesizedExpression.cs @@ -1,4 +1,4 @@ -// +// // ParenthesizedExpression.cs // // Author: @@ -48,5 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitParenthesizedExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ParenthesizedExpression o = other as ParenthesizedExpression; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs index 17bd5b72c..3ac10d387 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs @@ -1,4 +1,4 @@ -// +// // PointerReferenceExpression.cs // // Author: @@ -49,14 +49,19 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable TypeArguments { + public AstNodeCollection TypeArguments { get { return GetChildrenByRole (Roles.TypeArgument); } - set { SetChildrenByRole (Roles.TypeArgument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitPointerReferenceExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + PointerReferenceExpression o = other as PointerReferenceExpression; + return o != null && MatchString(this.MemberName, o.MemberName) && this.TypeArguments.DoMatch(o.TypeArguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs index 427906cbd..cc4fbe1c0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs @@ -1,4 +1,4 @@ -// +// // PrimitiveExpression.cs // // Author: @@ -31,6 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp /// public class PrimitiveExpression : Expression { + public static readonly object AnyValue = new object(); + AstLocation startLocation; public override AstLocation StartLocation { get { @@ -66,5 +68,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitPrimitiveExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + PrimitiveExpression o = other as PrimitiveExpression; + return o != null && (this.Value == AnyValue || object.Equals(this.Value, o.Value)); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs index d71be3d8d..79a357e87 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs @@ -25,18 +25,28 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion - public IEnumerable Clauses { + public AstNodeCollection Clauses { get { return GetChildrenByRole(ClauseRole); } - set { SetChildrenByRole(ClauseRole, value); } } public override S AcceptVisitor(IAstVisitor visitor, T data) { return visitor.VisitQueryExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryExpression o = other as QueryExpression; + return o != null && this.Clauses.DoMatch(o.Clauses, match); + } } public abstract class QueryClause : AstNode @@ -44,6 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.QueryClause; } } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryClause o = other as QueryClause; + throw new NotImplementedException(); + } } /// @@ -260,9 +276,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.Keyword); } } - public IEnumerable Orderings { + public AstNodeCollection Orderings { get { return GetChildrenByRole (OrderingRole); } - set { SetChildrenByRole (OrderingRole, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) @@ -295,6 +310,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryOrdering (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryOrdering o = other as QueryOrdering; + return o != null && this.Direction == o.Direction && this.Expression.DoMatch(o.Expression, match); + } } public enum QueryOrderingDirection diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/SizeOfExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/SizeOfExpression.cs index 5e5062758..2a6e22034 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/SizeOfExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/SizeOfExpression.cs @@ -1,4 +1,4 @@ -// +// // SizeOfExpression.cs // // Author: @@ -52,5 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitSizeOfExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + SizeOfExpression o = other as SizeOfExpression; + return o != null && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/StackAllocExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/StackAllocExpression.cs index ddb7ede92..ad7fc1a7e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/StackAllocExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/StackAllocExpression.cs @@ -1,4 +1,4 @@ -// +// // StackAllocExpression.cs // // Author: @@ -57,5 +57,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitStackAllocExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + StackAllocExpression o = other as StackAllocExpression; + return o != null && this.Type.DoMatch(o.Type, match) && this.CountExpression.DoMatch(o.CountExpression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ThisReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ThisReferenceExpression.cs index 8c6374d29..5428cf04b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ThisReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ThisReferenceExpression.cs @@ -1,4 +1,4 @@ -// +// // ThisReferenceExpression.cs // // Author: @@ -51,5 +51,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitThisReferenceExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ThisReferenceExpression o = other as ThisReferenceExpression; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeOfExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeOfExpression.cs index c18e5f474..e6e7c97dc 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeOfExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeOfExpression.cs @@ -1,4 +1,4 @@ -// +// // TypeOfExpression.cs // // Author: @@ -53,5 +53,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTypeOfExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TypeOfExpression o = other as TypeOfExpression; + return o != null && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs index 910bf69f9..5818340a4 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/TypeReferenceExpression.cs @@ -1,4 +1,4 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; @@ -20,5 +20,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTypeReferenceExpression(this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TypeReferenceExpression o = other as TypeReferenceExpression; + return o != null && this.Type.DoMatch(o.Type, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs index df36a6ab9..fe0b2d264 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UnaryOperatorExpression.cs @@ -1,4 +1,4 @@ -// +// // UnaryOperatorExpression.cs // // Author: @@ -64,6 +64,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitUnaryOperatorExpression (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UnaryOperatorExpression o = other as UnaryOperatorExpression; + return o != null && this.Operator == o.Operator && this.Expression.DoMatch(o.Expression, match); + } + public static string GetOperatorSymbol(UnaryOperatorType op) { switch (op) { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UncheckedExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UncheckedExpression.cs index fd1c162dc..2165437b3 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UncheckedExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/UncheckedExpression.cs @@ -1,4 +1,4 @@ -// +// // UncheckedExpression.cs // // Author: @@ -52,5 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUncheckedExpression (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UncheckedExpression o = other as UncheckedExpression; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs index 162a4e33b..877771736 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs @@ -1,4 +1,4 @@ -// +// // Attribute.cs // // Author: @@ -44,14 +44,19 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Type, value); } } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return base.GetChildrenByRole (Roles.Argument); } - set { SetChildrenByRole (Roles.Argument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitAttribute (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + Attribute o = other as Attribute; + return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs index 35d170dda..a192718da 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs @@ -1,4 +1,4 @@ -// +// // AttributeSection.cs // // Author: @@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp set; } - public IEnumerable Attributes { + public AstNodeCollection Attributes { get { return base.GetChildrenByRole (AttributeRole); } - set { SetChildrenByRole (AttributeRole, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) @@ -59,6 +58,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitAttributeSection (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + AttributeSection o = other as AttributeSection; + return o != null && this.AttributeTarget == o.AttributeTarget && this.Attributes.DoMatch(o.Attributes, match); + } + public static string GetAttributeTargetName(AttributeTarget attributeTarget) { switch (attributeTarget) { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs index dc27a875a..4f757b264 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs @@ -1,4 +1,4 @@ -// +// // Comment.cs // // Author: @@ -86,6 +86,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitComment (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + Comment o = other as Comment; + return o != null && this.CommentType == o.CommentType && MatchString(this.Content, o.Content); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs index dae8d4e19..514a41192 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs @@ -1,4 +1,4 @@ -// +// // Constraint.cs // // Author: @@ -53,15 +53,20 @@ namespace ICSharpCode.NRefactory.CSharp // TODO: what about new(), struct and class constraints? - public IEnumerable BaseTypes { + public AstNodeCollection BaseTypes { get { return GetChildrenByRole (BaseTypeRole); } - set { SetChildrenByRole (BaseTypeRole, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitConstraint (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + Constraint o = other as Constraint; + return o != null && MatchString(this.TypeParameter, o.TypeParameter) && this.BaseTypes.DoMatch(o.BaseTypes, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs index 1b71cd4c6..eccac9382 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs @@ -1,4 +1,4 @@ -// +// // DelegateDeclaration.cs // // Author: @@ -54,27 +54,24 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Type, value); } } - public IEnumerable TypeParameters { + public AstNodeCollection TypeParameters { get { return GetChildrenByRole (Roles.TypeParameter); } - set { SetChildrenByRole (Roles.TypeParameter, value); } } public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RParToken { get { return GetChildByRole (Roles.RPar); } } - public IEnumerable Constraints { + public AstNodeCollection Constraints { get { return GetChildrenByRole (Roles.Constraint); } - set { SetChildrenByRole (Roles.Constraint, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs index f082150b6..41cc39253 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs @@ -1,4 +1,4 @@ -// +// // NamespaceDeclaration.cs // // Author: @@ -54,13 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp return builder.ToString (); } set { - SetChildrenByRole (Roles.Identifier, value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty))); + GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty))); } } - public IEnumerable Identifiers { + public AstNodeCollection Identifiers { get { return GetChildrenByRole (Roles.Identifier); } - set { SetChildrenByRole (Roles.Identifier, value); } } /// @@ -79,9 +78,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBrace); } } - public IEnumerable Members { + public AstNodeCollection Members { get { return GetChildrenByRole(MemberRole); } - set { SetChildrenByRole(MemberRole, value); } } public CSharpTokenNode RBraceToken { @@ -102,5 +100,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitNamespaceDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + NamespaceDeclaration o = other as NamespaceDeclaration; + return o != null && MatchString(this.Name, o.Name) && this.Members.DoMatch(o.Members, match); + } } }; diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs index 36381aafd..fd638f2da 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs @@ -1,4 +1,4 @@ -// +// // TypeDeclaration.cs // // Author: @@ -59,28 +59,24 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable TypeParameters { + public AstNodeCollection TypeParameters { get { return GetChildrenByRole (Roles.TypeParameter); } - set { SetChildrenByRole (Roles.TypeParameter, value); } } - public IEnumerable BaseTypes { + public AstNodeCollection BaseTypes { get { return GetChildrenByRole (BaseTypeRole); } - set { SetChildrenByRole (BaseTypeRole, value); } } - public IEnumerable Constraints { + public AstNodeCollection Constraints { get { return GetChildrenByRole (Roles.Constraint); } - set { SetChildrenByRole (Roles.Constraint, value); } } public CSharpTokenNode LBraceToken { get { return GetChildByRole (Roles.LBrace); } } - public IEnumerable Members { + public AstNodeCollection Members { get { return GetChildrenByRole (MemberRole); } - set { SetChildrenByRole (MemberRole, value); } } public CSharpTokenNode RBraceToken { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs index c089f360d..30e2fdf2f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs @@ -38,5 +38,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTypeParameterDeclaration(this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TypeParameterDeclaration o = other as TypeParameterDeclaration; + return o != null && this.Variance == o.Variance && MatchString(this.Name, o.Name); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs index 044537396..41aee352d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs @@ -1,4 +1,4 @@ -// +// // UsingAliasDeclaration.cs // // Author: @@ -70,5 +70,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUsingAliasDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UsingAliasDeclaration o = other as UsingAliasDeclaration; + return o != null && MatchString(this.Alias, o.Alias) && this.Import.DoMatch(o.Import, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingDeclaration.cs index 68ff822b3..12beb31be 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingDeclaration.cs @@ -1,4 +1,4 @@ -// +// // UsingDeclaration.cs // // Author: @@ -64,5 +64,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUsingDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UsingDeclaration o = other as UsingDeclaration; + return o != null && this.Import.DoMatch(o.Import, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs b/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs index 94656e5ab..f63e97bf7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs @@ -1,4 +1,4 @@ -// +// // Identifier.cs // // Author: @@ -91,5 +91,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitIdentifier (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + Identifier o = other as Identifier; + return o != null && MatchString(this.Name, o.Name); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs b/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs index 8d600b575..70448e56a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs @@ -1,4 +1,4 @@ -// +// // FullTypeName.cs // // Author: @@ -51,9 +51,8 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable TypeArguments { + public AstNodeCollection TypeArguments { get { return GetChildrenByRole (Roles.TypeArgument); } - set { SetChildrenByRole (Roles.TypeArgument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) @@ -61,6 +60,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitMemberType (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + MemberType o = other as MemberType; + return o != null && this.IsDoubleColon == o.IsDoubleColon && MatchString(this.MemberName, o.MemberName) && this.Target.DoMatch(o.Target, match); + } + public override string ToString() { StringBuilder b = new StringBuilder(); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs b/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs index d5d56fb4c..5d831be04 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/NodeType.cs @@ -43,7 +43,9 @@ namespace ICSharpCode.NRefactory.CSharp Statement, Expression, Token, - QueryClause + QueryClause, + Pattern, + Placeholder } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs new file mode 100644 index 000000000..e992da9ce --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/AnyNode.cs @@ -0,0 +1,35 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Matches any node. + /// + public class AnyNode : Pattern + { + readonly string groupName; + + public string GroupName { + get { return groupName; } + } + + public AnyNode(string groupName = null) + { + this.groupName = groupName; + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + match.Add(this.groupName, other); + return other != null && !other.IsNull; + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitAnyNode(this, data); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs new file mode 100644 index 000000000..5d30b072e --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs @@ -0,0 +1,70 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Linq; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Matches the last entry in the specified named group. + /// + public class Backreference : Pattern + { + readonly string referencedGroupName; + + public string ReferencedGroupName { + get { return referencedGroupName; } + } + + public Backreference(string referencedGroupName) + { + if (referencedGroupName == null) + throw new ArgumentNullException("referencedGroupName"); + this.referencedGroupName = referencedGroupName; + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return match.Get(referencedGroupName).Last().Match(other) != null; + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitBackreference(this, data); + } + } + + /// + /// Matches identifier expressions that have the same identifier as the referenced variable/type definition/method definition. + /// + public class IdentifierExpressionBackreference : Pattern + { + readonly string referencedGroupName; + + public string ReferencedGroupName { + get { return referencedGroupName; } + } + + public IdentifierExpressionBackreference(string referencedGroupName) + { + if (referencedGroupName == null) + throw new ArgumentNullException("referencedGroupName"); + this.referencedGroupName = referencedGroupName; + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + IdentifierExpression ident = other as IdentifierExpression; + if (ident == null || ident.TypeArguments.Any()) + return false; + AstNode referenced = match.Get(referencedGroupName).Last(); + return ident.Identifier == referenced.GetChildByRole(AstNode.Roles.Identifier).Name; + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitIdentifierExpressionBackreference(this, data); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs new file mode 100644 index 000000000..b2352e402 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs @@ -0,0 +1,54 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Matches one of several alternatives. + /// + public class Choice : Pattern, IEnumerable + { + public static readonly Role AlternativeRole = new Role("Alternative", AstNode.Null); + + public void Add(string name, AstNode alternative) + { + AddChild(new NamedNode(name, alternative), AlternativeRole); + } + + public void Add(AstNode alternative) + { + AddChild(alternative, AlternativeRole); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + var checkPoint = match.CheckPoint(); + foreach (AstNode alt in GetChildrenByRole(AlternativeRole)) { + if (alt.DoMatch(other, match)) + return true; + else + match.RestoreCheckPoint(checkPoint); + } + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetChildrenByRole(AlternativeRole).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetChildrenByRole(AlternativeRole).GetEnumerator(); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitChoice(this, data); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs new file mode 100644 index 000000000..7b29a00c4 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/IPatternAstVisitor.cs @@ -0,0 +1,22 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Extended AST visitor that works for patterns. + /// + public interface IPatternAstVisitor : IAstVisitor + { + S VisitPlaceholder(AstNode placeholder, AstNode child, T data); + + S VisitAnyNode(AnyNode anyNode, T data); + S VisitBackreference(Backreference backreference, T data); + S VisitChoice(Choice choice, T data); + S VisitNamedNode(NamedNode namedNode, T data); + S VisitRepeat(Repeat repeat, T data); + S VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, T data); + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs new file mode 100644 index 000000000..9b1ff905f --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs @@ -0,0 +1,59 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Represents the result of a pattern matching operation. + /// + public sealed class Match + { + List> results = new List>(); + + internal int CheckPoint() + { + return results.Count; + } + + internal void RestoreCheckPoint(int checkPoint) + { + results.RemoveRange(checkPoint, results.Count - checkPoint); + } + + public IEnumerable Get(string groupName) + { + foreach (var pair in results) { + if (pair.Key == groupName) + yield return pair.Value; + } + } + + public IEnumerable Get(string groupName) where T : AstNode + { + foreach (var pair in results) { + if (pair.Key == groupName) + yield return (T)pair.Value; + } + } + + public bool Has(string groupName) + { + foreach (var pair in results) { + if (pair.Key == groupName) + return true; + } + return false; + } + + public void Add(string groupName, AstNode node) + { + if (groupName != null && node != null) { + results.Add(new KeyValuePair(groupName, node)); + } + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs new file mode 100644 index 000000000..baf955684 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/NamedNode.cs @@ -0,0 +1,38 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Represents a named node within a pattern. + /// + public class NamedNode : Pattern + { + public static readonly Role ElementRole = new Role("Element", AstNode.Null); + + readonly string groupName; + + public string GroupName { + get { return groupName; } + } + + public NamedNode(string groupName, AstNode childNode) + { + this.groupName = groupName; + AddChild(childNode, ElementRole); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + match.Add(this.groupName, other); + return GetChildByRole(ElementRole).DoMatch(other, match); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitNamedNode(this, data); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs new file mode 100644 index 000000000..073415f51 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -0,0 +1,70 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Base class for all patterns. + /// + public abstract class Pattern : AstNode + { + public override NodeType NodeType { + get { return NodeType.Pattern; } + } + + internal struct PossibleMatch + { + public readonly AstNode NextOther; // next node after the last matched node + public readonly int Checkpoint; // checkpoint + + public PossibleMatch(AstNode nextOther, int checkpoint) + { + this.NextOther = nextOther; + this.Checkpoint = checkpoint; + } + } + + internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return DoMatch(pos, match); + } + + public AstType ToType() + { + return new TypePlaceholder(this); + } + + public Expression ToExpression() + { + return new ExpressionPlaceholder(this); + } + + public Statement ToStatement() + { + return new StatementPlaceholder(this); + } + + public BlockStatement ToBlock() + { + return new BlockStatementPlaceholder(this); + } + + public VariableInitializer ToVariable() + { + return new VariablePlaceholder(this); + } + + // Make debugging easier by giving Patterns a ToString() implementation + public override string ToString() + { + StringWriter w = new StringWriter(); + AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs new file mode 100644 index 000000000..2bac1c6e1 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs @@ -0,0 +1,119 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + sealed class TypePlaceholder : AstType + { + public static readonly Role ChildRole = new Role("Child", AstNode.Null); + + public TypePlaceholder(AstNode child) + { + AddChild(child, TypePlaceholder.ChildRole); + } + + public override NodeType NodeType { + get { return NodeType.Placeholder; } + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + } + } + + sealed class ExpressionPlaceholder : Expression + { + public ExpressionPlaceholder(AstNode child) + { + AddChild(child, TypePlaceholder.ChildRole); + } + + public override NodeType NodeType { + get { return NodeType.Placeholder; } + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + } + } + + sealed class StatementPlaceholder : Statement + { + public StatementPlaceholder(AstNode child) + { + AddChild(child, TypePlaceholder.ChildRole); + } + + public override NodeType NodeType { + get { return NodeType.Placeholder; } + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + } + } + + sealed class BlockStatementPlaceholder : BlockStatement + { + public BlockStatementPlaceholder(AstNode child) + { + AddChild(child, TypePlaceholder.ChildRole); + } + + public override NodeType NodeType { + get { return NodeType.Placeholder; } + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + } + } + + sealed class VariablePlaceholder : VariableInitializer + { + public VariablePlaceholder(AstNode child) + { + AddChild(child, TypePlaceholder.ChildRole); + } + + public override NodeType NodeType { + get { return NodeType.Placeholder; } + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs new file mode 100644 index 000000000..c968bce45 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Repeat.cs @@ -0,0 +1,55 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace ICSharpCode.NRefactory.CSharp.PatternMatching +{ + /// + /// Represents an optional node. + /// + public class Repeat : Pattern + { + public static readonly Role ElementRole = new Role("Element", AstNode.Null); + public int MinCount; + public int MaxCount = int.MaxValue; + + public Repeat(AstNode childNode) + { + AddChild(childNode, ElementRole); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + Debug.Assert(pos == null || pos.Role == role); + int matchCount = 0; + if (this.MinCount <= 0) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); + AstNode element = GetChildByRole(ElementRole); + while (matchCount < this.MaxCount && pos != null && element.DoMatch(pos, match)) { + matchCount++; + do { + pos = pos.NextSibling; + } while (pos != null && pos.Role != role); + if (matchCount >= this.MinCount) + backtrackingStack.Push(new PossibleMatch(pos, match.CheckPoint())); + } + return false; // never do a normal (single-element) match; always make the caller look at the results on the back-tracking stack. + } + + protected internal override bool DoMatch(AstNode other, Match match) + { + if (other == null || other.IsNull) + return this.MinCount <= 0; + else + return this.MaxCount >= 1 && GetChildByRole(ElementRole).DoMatch(other, match); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + return ((IPatternAstVisitor)visitor).VisitRepeat(this, data); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PrimitiveType.cs b/ICSharpCode.NRefactory/CSharp/Ast/PrimitiveType.cs index 6bc7d0f73..2a2b41dff 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PrimitiveType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PrimitiveType.cs @@ -1,4 +1,4 @@ -// +// // FullTypeName.cs // // Author: @@ -65,6 +65,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitPrimitiveType (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + PrimitiveType o = other as PrimitiveType; + return o != null && MatchString(this.Keyword, o.Keyword); + } + public override string ToString() { return Keyword ?? base.ToString(); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs b/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs index ac3eb0210..55839229c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs @@ -1,4 +1,4 @@ -// +// // FullTypeName.cs // // Author: @@ -56,9 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable TypeArguments { + public AstNodeCollection TypeArguments { get { return GetChildrenByRole (Roles.TypeArgument); } - set { SetChildrenByRole (Roles.TypeArgument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) @@ -66,6 +65,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitSimpleType (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + SimpleType o = other as SimpleType; + return o != null && MatchString(this.Identifier, o.Identifier) && this.TypeArguments.DoMatch(o.TypeArguments, match); + } + public override string ToString() { StringBuilder b = new StringBuilder(this.Identifier); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs index eb3a6f9a3..d43a0d538 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs @@ -1,4 +1,4 @@ -// +// // BlockStatement.cs // // Author: @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.CSharp /// /// { Statements } /// - public class BlockStatement : Statement + public class BlockStatement : Statement, IEnumerable { public static readonly Role StatementRole = new Role("Statement", Statement.Null); @@ -49,6 +49,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion @@ -56,9 +61,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBrace); } } - public IEnumerable Statements { + public AstNodeCollection Statements { get { return GetChildrenByRole (StatementRole); } - set { SetChildrenByRole (StatementRole, value); } } public CSharpTokenNode RBraceToken { @@ -70,18 +74,24 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitBlockStatement (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + BlockStatement o = other as BlockStatement; + return o != null && this.Statements.DoMatch(o.Statements, match); + } + #region Builder methods - public void AddStatement(Statement statement) + public void Add(Statement statement) { AddChild(statement, StatementRole); } - public void AddStatement(Expression expression) + public void Add(Expression expression) { AddChild(new ExpressionStatement { Expression = expression }, StatementRole); } - public void AddStatements(IEnumerable statements) + public void AddRange(IEnumerable statements) { foreach (Statement st in statements) AddChild(st, StatementRole); @@ -89,13 +99,23 @@ namespace ICSharpCode.NRefactory.CSharp public void AddAssignment(Expression left, Expression right) { - AddStatement(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right }); + Add(new AssignmentExpression { Left = left, Operator = AssignmentOperatorType.Assign, Right = right }); } public void AddReturnStatement(Expression expression) { - AddStatement(new ReturnStatement { Expression = expression }); + Add(new ReturnStatement { Expression = expression }); } #endregion + + IEnumerator IEnumerable.GetEnumerator() + { + return this.Statements.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.Statements.GetEnumerator(); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BreakStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BreakStatement.cs index b6ce929b0..6599b5eaf 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BreakStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BreakStatement.cs @@ -1,6 +1,6 @@ -// +// // BreakStatement.cs -// +// // Author: // Mike Krüger // @@ -39,5 +39,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitBreakStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + BreakStatement o = other as BreakStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs index 1461a6407..d80dc6d57 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/CheckedStatement.cs @@ -1,4 +1,4 @@ -// +// // CheckedStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCheckedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CheckedStatement o = other as CheckedStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs index 7dc06c596..1de6b5d50 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ContinueStatement.cs @@ -1,4 +1,4 @@ -// +// // ContinueStatement.cs // // Author: @@ -39,5 +39,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitContinueStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ContinueStatement o = other as ContinueStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs index 51d5f4708..378fd43ab 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/DoWhileStatement.cs @@ -1,4 +1,4 @@ -// +// // DoWhileStatement.cs // // Author: @@ -68,6 +68,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDoWhileStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DoWhileStatement o = other as DoWhileStatement; + return o != null && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match) && this.Condition.DoMatch(o.Condition, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs index 7a9528b86..3ee53863e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/EmptyStatement.cs @@ -1,4 +1,4 @@ -// +// // EmptyStatement.cs // // Author: @@ -52,5 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEmptyStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EmptyStatement o = other as EmptyStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ExpressionStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ExpressionStatement.cs index 5c6cd41d7..4e76bd5bb 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ExpressionStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ExpressionStatement.cs @@ -1,4 +1,4 @@ -// +// // ExpressionStatement.cs // // Author: @@ -44,5 +44,20 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitExpressionStatement (this, data); } + + public ExpressionStatement() + { + } + + public ExpressionStatement(Expression expression) + { + this.Expression = expression; + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ExpressionStatement o = other as ExpressionStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs index 5d44b66e0..b1b7759f0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs @@ -1,4 +1,4 @@ -// +// // FixedStatement.cs // // Author: @@ -46,9 +46,8 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Type, value); } } - public IEnumerable Variables { + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } - set { SetChildrenByRole (Roles.Variable, value); } } public CSharpTokenNode RParToken { @@ -64,5 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitFixedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + FixedStatement o = other as FixedStatement; + return o != null && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs index c667e6086..ebbe44022 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForStatement.cs @@ -1,6 +1,6 @@ -// +// // ForStatement.cs -// +// // Author: // Mike Krüger // @@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp /// Note: this contains multiple statements for "for (a = 2, b = 1; a > b; a--)", but contains /// only a single statement for "for (int a = 2, b = 1; a > b; a--)" (a single VariableDeclarationStatement with two variables) /// - public IEnumerable Initializers { + public AstNodeCollection Initializers { get { return GetChildrenByRole (InitializerRole); } - set { SetChildrenByRole (InitializerRole, value); } } public Expression Condition { @@ -59,9 +58,8 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Condition, value); } } - public IEnumerable Iterators { + public AstNodeCollection Iterators { get { return GetChildrenByRole (IteratorRole); } - set { SetChildrenByRole (IteratorRole, value); } } public CSharpTokenNode RParToken { @@ -77,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitForStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ForStatement o = other as ForStatement; + return o != null && this.Initializers.DoMatch(o.Initializers, match) && this.Condition.DoMatch(o.Condition, match) + && this.Iterators.DoMatch(o.Iterators, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs index ca75d6d0d..6caf3883e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ForeachStatement.cs @@ -1,4 +1,4 @@ -// +// // ForeachStatement.cs // // Author: @@ -75,5 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitForeachStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ForeachStatement o = other as ForeachStatement; + return o != null && this.VariableType.DoMatch(o.VariableType, match) && MatchString(this.VariableName, o.VariableName) + && this.InExpression.DoMatch(o.InExpression, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs index ee1784ad7..2eeeb0bc3 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/GotoStatement.cs @@ -56,14 +56,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - /// - /// Used for "goto case LabelExpression;" - /// - public Expression LabelExpression { - get { return GetChildByRole (Roles.Expression); } - set { SetChildByRole (Roles.Expression, value); } - } - public CSharpTokenNode SemicolonToken { get { return GetChildByRole (Roles.Semicolon); } } @@ -72,6 +64,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoStatement o = other as GotoStatement; + return o != null && MatchString(this.Label, o.Label); + } } /// @@ -89,18 +87,6 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (CaseKeywordRole); } } - public string Label { - get { - return GetChildByRole (Roles.Identifier).Name; - } - set { - if (string.IsNullOrEmpty(value)) - SetChildByRole(Roles.Identifier, null); - else - SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty)); - } - } - /// /// Used for "goto case LabelExpression;" /// @@ -117,6 +103,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoCaseStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoCaseStatement o = other as GotoCaseStatement; + return o != null && this.LabelExpression.DoMatch(o.LabelExpression, match); + } } /// @@ -142,5 +134,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitGotoDefaultStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + GotoDefaultStatement o = other as GotoDefaultStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs index 85569dfac..8fa84392d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/IfElseStatement.cs @@ -1,4 +1,4 @@ -// +// // IfElseStatement.cs // // Author: @@ -74,6 +74,12 @@ namespace ICSharpCode.NRefactory.CSharp return visitor.VisitIfElseStatement (this, data); } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IfElseStatement o = other as IfElseStatement; + return o != null && this.Condition.DoMatch(o.Condition, match) && this.TrueStatement.DoMatch(o.TrueStatement, match) && this.FalseStatement.DoMatch(o.FalseStatement, match); + } + public IfElseStatement() { } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs index da9dc5273..3ebdc3302 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LabelStatement.cs @@ -1,4 +1,4 @@ -// +// // LabelStatement.cs // // Author: @@ -40,9 +40,19 @@ namespace ICSharpCode.NRefactory.CSharp } } + public CSharpTokenNode Colon { + get { return GetChildByRole (Roles.Colon); } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitLabelStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + LabelStatement o = other as LabelStatement; + return o != null && MatchString(this.Label, o.Label); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs index 3866dbd17..7298e4f1d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/LockStatement.cs @@ -1,4 +1,4 @@ -// +// // LockStatement.cs // // Author: @@ -57,5 +57,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitLockStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + LockStatement o = other as LockStatement; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs index 938fcb679..d8368d442 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ReturnStatement.cs @@ -1,4 +1,4 @@ -// +// // ReturnStatement.cs // // Author: @@ -48,5 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitReturnStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ReturnStatement o = other as ReturnStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs index c3341e2c5..0d678ff59 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs @@ -29,6 +29,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } #endregion diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs index 99fb7009b..09b82be63 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/SwitchStatement.cs @@ -1,4 +1,4 @@ -// +// // SwitchStatement.cs // // Author: @@ -57,9 +57,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBrace); } } - public IEnumerable SwitchSections { + public AstNodeCollection SwitchSections { get { return GetChildrenByRole (SwitchSectionRole); } - set { SetChildrenByRole (SwitchSectionRole, value); } } public CSharpTokenNode RBraceToken { @@ -70,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitSwitchStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + SwitchStatement o = other as SwitchStatement; + return o != null && this.Expression.DoMatch(o.Expression, match) && this.SwitchSections.DoMatch(o.SwitchSections, match); + } } public class SwitchSection : AstNode @@ -82,20 +87,24 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable CaseLabels { + public AstNodeCollection CaseLabels { get { return GetChildrenByRole (CaseLabelRole); } - set { SetChildrenByRole (CaseLabelRole, value); } } - public IEnumerable Statements { + public AstNodeCollection Statements { get { return GetChildrenByRole (Roles.EmbeddedStatement); } - set { SetChildrenByRole (Roles.EmbeddedStatement, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitSwitchSection (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + SwitchSection o = other as SwitchSection; + return o != null && this.CaseLabels.DoMatch(o.CaseLabels, match) && this.Statements.DoMatch(o.Statements, match); + } } public class CaseLabel : AstNode @@ -115,5 +124,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCaseLabel (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CaseLabel o = other as CaseLabel; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs index 545dc6ac3..fc9f34237 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/ThrowStatement.cs @@ -1,4 +1,4 @@ -// +// // ThrowStatement.cs // // Author: @@ -48,5 +48,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitThrowStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ThrowStatement o = other as ThrowStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs index 70f48dd29..bfba09de2 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/TryCatchStatement.cs @@ -1,4 +1,4 @@ -// +// // TryCatchStatement.cs // // Author: @@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (TryBlockRole, value); } } - public IEnumerable CatchClauses { + public AstNodeCollection CatchClauses { get { return GetChildrenByRole (CatchClauseRole); } - set { SetChildrenByRole (CatchClauseRole, value); } } public CSharpTokenNode FinallyToken { @@ -67,6 +66,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTryCatchStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TryCatchStatement o = other as TryCatchStatement; + return o != null && this.TryBlock.DoMatch(o.TryBlock, match) && this.CatchClauses.DoMatch(o.CatchClauses, match) && this.FinallyBlock.DoMatch(o.FinallyBlock, match); + } } /// @@ -116,5 +121,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCatchClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CatchClause o = other as CatchClause; + return o != null && this.Type.DoMatch(o.Type, match) && MatchString(this.VariableName, o.VariableName) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs index ec55c0cbc..a0bef129e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UncheckedStatement.cs @@ -1,4 +1,4 @@ -// +// // UncheckedStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUncheckedStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UncheckedStatement o = other as UncheckedStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs index d9a45a860..c5ccb63af 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UnsafeStatement.cs @@ -1,4 +1,4 @@ -// +// // UnsafeStatement.cs // // Author: @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUnsafeStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UnsafeStatement o = other as UnsafeStatement; + return o != null && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs index d69487563..27714d61b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/UsingStatement.cs @@ -1,4 +1,4 @@ -// +// // UsingStatement.cs // // Author: @@ -62,5 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitUsingStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + UsingStatement o = other as UsingStatement; + return o != null && this.ResourceAcquisition.DoMatch(o.ResourceAcquisition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs index 7be7b5a33..e5066c1c3 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/VariableDeclarationStatement.cs @@ -1,4 +1,4 @@ -// +// // VariableDeclarationStatement.cs // // Author: @@ -33,6 +33,16 @@ namespace ICSharpCode.NRefactory.CSharp { public static readonly Role ModifierRole = AttributedNode.ModifierRole; + public VariableDeclarationStatement() + { + } + + public VariableDeclarationStatement(AstType type, string name, Expression initializer = null) + { + this.Type = type; + this.Variables.Add(new VariableInitializer(name, initializer)); + } + public Modifiers Modifiers { get { return AttributedNode.GetModifiers(this); } set { AttributedNode.SetModifiers(this, value); } @@ -43,9 +53,8 @@ namespace ICSharpCode.NRefactory.CSharp set { SetChildByRole (Roles.Type, value); } } - public IEnumerable Variables { + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } - set { SetChildrenByRole (Roles.Variable, value); } } public CSharpTokenNode SemicolonToken { @@ -56,5 +65,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitVariableDeclarationStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + VariableDeclarationStatement o = other as VariableDeclarationStatement; + return o != null && this.Modifiers == o.Modifiers && this.Type.DoMatch(o.Type, match) && this.Variables.DoMatch(o.Variables, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs index 9eec22b2f..01470b3ab 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/WhileStatement.cs @@ -1,4 +1,4 @@ -// +// // WhileStatement.cs // // Author: @@ -59,5 +59,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitWhileStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + WhileStatement o = other as WhileStatement; + return o != null && this.Condition.DoMatch(o.Condition, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs index 2982dbf41..4c572615a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldBreakStatement.cs @@ -1,4 +1,4 @@ -// +// // YieldBreakStatement.cs // // Author: @@ -50,5 +50,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitYieldBreakStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + YieldBreakStatement o = other as YieldBreakStatement; + return o != null; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs index 531d21ec5..001815f3a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/YieldStatement.cs @@ -1,4 +1,4 @@ -// +// // YieldStatement.cs // // Author: @@ -55,5 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitYieldStatement (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + YieldStatement o = other as YieldStatement; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs index 05eec5e0f..910aec75f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs @@ -1,4 +1,4 @@ -// +// // PropertyDeclaration.cs // // Author: @@ -24,6 +24,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using System; + namespace ICSharpCode.NRefactory.CSharp { /// @@ -59,5 +61,10 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitAccessor (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + throw new NotImplementedException(); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs index 99d8af8ec..1b878d91c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs @@ -1,6 +1,7 @@ // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt) +using System; using System.Collections.Generic; using System.Linq; @@ -11,9 +12,8 @@ namespace ICSharpCode.NRefactory.CSharp public static readonly Role AttributeRole = new Role("Attribute"); public static readonly Role ModifierRole = new Role("Modifier"); - public IEnumerable Attributes { + public AstNodeCollection Attributes { get { return base.GetChildrenByRole (AttributeRole); } - set { SetChildrenByRole (AttributeRole, value); } } public Modifiers Modifiers { @@ -42,7 +42,9 @@ namespace ICSharpCode.NRefactory.CSharp if ((m & newValue) != 0) { if ((m & oldValue) == 0) { // Modifier was added - node.InsertChildAfter(insertionPos, new CSharpModifierToken(AstLocation.Empty, m), ModifierRole); + var newToken = new CSharpModifierToken(AstLocation.Empty, m); + node.InsertChildAfter(insertionPos, newToken, ModifierRole); + insertionPos = newToken; } else { // Modifier already exists insertionPos = node.GetChildrenByRole(ModifierRole).First(t => t.Modifier == m); @@ -55,5 +57,10 @@ namespace ICSharpCode.NRefactory.CSharp } } } + + protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match) + { + throw new NotImplementedException(); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs index 1097605c3..97f808051 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs @@ -1,4 +1,4 @@ -// +// // ConstructorDeclaration.cs // // Author: @@ -33,13 +33,19 @@ namespace ICSharpCode.NRefactory.CSharp { public static readonly Role InitializerRole = new Role("Initializer", ConstructorInitializer.Null); + /// + /// Gets/Sets the name of the class containing the constructor. + /// This property can be used to inform the output visitor about the class name when writing a constructor declaration + /// without writing the complete type declaration. It is ignored when the constructor has a type declaration as parent. + /// + public string Name { get; set; } + public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RParToken { @@ -105,14 +111,19 @@ namespace ICSharpCode.NRefactory.CSharp set; } - public IEnumerable Arguments { + public AstNodeCollection Arguments { get { return GetChildrenByRole (Roles.Argument); } - set { SetChildrenByRole (Roles.Argument, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitConstructorInitializer (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ConstructorInitializer o = other as ConstructorInitializer; + return o != null && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs index 2336d46d2..2798d0660 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs @@ -1,4 +1,4 @@ -// +// // DestructorDeclaration.cs // // Author: @@ -34,6 +34,13 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (TildeRole); } } + /// + /// Gets/Sets the name of the class containing the destructor. + /// This property can be used to inform the output visitor about the class name when writing a destructor declaration + /// without writing the complete type declaration. It is ignored when the destructor has a type declaration as parent. + /// + public string Name { get; set; } + public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs index dde192663..3a916782d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs @@ -1,4 +1,4 @@ -// +// // EventDeclaration.cs // // Author: @@ -30,9 +30,8 @@ namespace ICSharpCode.NRefactory.CSharp { public class EventDeclaration : MemberDeclaration { - public IEnumerable Variables { + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } - set { SetChildrenByRole (Roles.Variable, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs index 8969d50b0..3ca04772d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs @@ -1,4 +1,4 @@ -// +// // FieldDeclaration.cs // // Author: @@ -31,9 +31,8 @@ namespace ICSharpCode.NRefactory.CSharp { public class FieldDeclaration : MemberDeclaration { - public IEnumerable Variables { + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } - set { SetChildrenByRole (Roles.Variable, value); } } public override S AcceptVisitor (IAstVisitor visitor, T data) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs index 88d80ce50..5b63c9c4f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs @@ -1,4 +1,4 @@ -// +// // IndexerDeclaration.cs // // Author: @@ -35,9 +35,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LBracket); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RBracketToken { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs index 84ff90819..ef740bd86 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs @@ -1,4 +1,4 @@ -// +// // MethodDeclaration.cs // // Author: @@ -31,27 +31,24 @@ namespace ICSharpCode.NRefactory.CSharp { public class MethodDeclaration : MemberDeclaration { - public IEnumerable TypeParameters { + public AstNodeCollection TypeParameters { get { return GetChildrenByRole (Roles.TypeParameter); } - set { SetChildrenByRole (Roles.TypeParameter, value); } } public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RParToken { get { return GetChildByRole (Roles.RPar); } } - public IEnumerable Constraints { + public AstNodeCollection Constraints { get { return GetChildrenByRole (Roles.Constraint); } - set { SetChildrenByRole (Roles.Constraint, value); } } public BlockStatement Body { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs index 4b3a1693b..c8a326c49 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs @@ -1,4 +1,4 @@ -// +// // OperatorDeclaration.cs // // Author: @@ -80,9 +80,8 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public IEnumerable Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } - set { SetChildrenByRole (Roles.Parameter, value); } } public CSharpTokenNode RParToken { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs index 21c1f644e..0334d2a3f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs @@ -1,4 +1,4 @@ -// +// // ParameterDeclarationExpression.cs // // Author: @@ -49,9 +49,8 @@ namespace ICSharpCode.NRefactory.CSharp } } - public IEnumerable Attributes { + public AstNodeCollection Attributes { get { return GetChildrenByRole (AttributeRole); } - set { SetChildrenByRole (AttributeRole, value); } } public ParameterModifier ParameterModifier { @@ -82,6 +81,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitParameterDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ParameterDeclaration o = other as ParameterDeclaration; + return o != null && this.Attributes.DoMatch(o.Attributes, match) && this.ParameterModifier == o.ParameterModifier && MatchString(this.Name, o.Name) && this.DefaultExpression.DoMatch(o.DefaultExpression, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs index 745a03b7d..860f52f36 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/VariableInitializer.cs @@ -1,4 +1,4 @@ -// +// // VariableInitializer.cs // // Author: @@ -66,5 +66,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitVariableInitializer (this, data); } + + protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match) + { + VariableInitializer o = other as VariableInitializer; + return o != null && MatchString(this.Name, o.Name) && this.Initializer.DoMatch(o.Initializer, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/OutputVisitor/InsertParenthesesVisitor.cs b/ICSharpCode.NRefactory/CSharp/OutputVisitor/InsertParenthesesVisitor.cs index abdd06e63..cfa12e17a 100644 --- a/ICSharpCode.NRefactory/CSharp/OutputVisitor/InsertParenthesesVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/OutputVisitor/InsertParenthesesVisitor.cs @@ -186,7 +186,13 @@ namespace ICSharpCode.NRefactory.CSharp } } else { if (InsertParenthesesForReadability && precedence < Equality) { - ParenthesizeIfRequired(binaryOperatorExpression.Left, Equality); + // In readable mode, boost the priority of the left-hand side if the operator + // there isn't the same as the operator on this expression. + if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) { + ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence); + } else { + ParenthesizeIfRequired(binaryOperatorExpression.Left, Equality); + } ParenthesizeIfRequired(binaryOperatorExpression.Right, Equality); } else { // all other binary operators are left-associative @@ -197,6 +203,15 @@ namespace ICSharpCode.NRefactory.CSharp return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data); } + BinaryOperatorType? GetBinaryOperatorType(Expression expr) + { + BinaryOperatorExpression boe = expr as BinaryOperatorExpression; + if (boe != null) + return boe.Operator; + else + return null; + } + public override object VisitIsExpression(IsExpression isExpression, object data) { if (InsertParenthesesForReadability) { diff --git a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 8e2b94d0e..1c67668d0 100644 --- a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -8,6 +8,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; + +using ICSharpCode.NRefactory.CSharp.PatternMatching; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.CSharp @@ -15,7 +17,7 @@ namespace ICSharpCode.NRefactory.CSharp /// /// Outputs the AST. /// - public class OutputVisitor : IAstVisitor + public class OutputVisitor : IPatternAstVisitor { readonly IOutputFormatter formatter; readonly CSharpFormattingPolicy policy; @@ -263,7 +265,7 @@ namespace ICSharpCode.NRefactory.CSharp /// void Semicolon() { - if (!(currentContainerNode.Parent is ForStatement)) { + if (currentContainerNode.Role != ForStatement.InitializerRole && currentContainerNode.Role != ForStatement.IteratorRole && currentContainerNode.Role != UsingStatement.ResourceAcquisitionRole) { WriteToken(";", AstNode.Roles.Semicolon); NewLine(); } @@ -371,7 +373,8 @@ namespace ICSharpCode.NRefactory.CSharp formatter.Space(); } else { WriteSpecialsUpToRole(AstNode.Roles.Dot, ident); - + formatter.WriteToken("."); + lastWritten = LastWritten.Other; } WriteSpecialsUpToNode(ident); formatter.WriteIdentifier(ident.Name); @@ -381,6 +384,8 @@ namespace ICSharpCode.NRefactory.CSharp void WriteEmbeddedStatement(Statement embeddedStatement) { + if (embeddedStatement.IsNull) + return; BlockStatement block = embeddedStatement as BlockStatement; if (block != null) VisitBlockStatement(block, null); @@ -561,7 +566,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteKeyword("checked"); LPar(); Space(policy.WithinCheckedExpressionParantheses); - checkedExpression.AcceptVisitor(this, data); + checkedExpression.Expression.AcceptVisitor(this, data); Space(policy.WithinCheckedExpressionParantheses); RPar(); return EndNode(checkedExpression); @@ -674,10 +679,10 @@ namespace ICSharpCode.NRefactory.CSharp bool LambdaNeedsParenthesis(LambdaExpression lambdaExpression) { - if (lambdaExpression.Parameters.Count() != 1) + if (lambdaExpression.Parameters.Count != 1) return true; var p = lambdaExpression.Parameters.Single(); - return p.Type.IsNull && p.ParameterModifier == ParameterModifier.None; + return !(p.Type.IsNull && p.ParameterModifier == ParameterModifier.None); } public object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) @@ -837,7 +842,7 @@ namespace ICSharpCode.NRefactory.CSharp case '\v': return "\\v"; default: - if (char.IsControl(ch)) { + if (char.IsControl(ch) || char.IsSurrogate(ch)) { return "\\u" + ((int)ch).ToString("x4"); } else { return ch.ToString(); @@ -928,7 +933,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteKeyword("unchecked"); LPar(); Space(policy.WithinCheckedExpressionParantheses); - uncheckedExpression.AcceptVisitor(this, data); + uncheckedExpression.Expression.AcceptVisitor(this, data); Space(policy.WithinCheckedExpressionParantheses); RPar(); return EndNode(uncheckedExpression); @@ -1625,12 +1630,13 @@ namespace ICSharpCode.NRefactory.CSharp WriteAttributes(constructorDeclaration.Attributes); WriteModifiers(constructorDeclaration.ModifierTokens); TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration; - if (type != null) { - WriteIdentifier(type.Name); - } + WriteIdentifier(type != null ? type.Name : constructorDeclaration.Name); Space(policy.BeforeConstructorDeclarationParentheses); WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.WithinMethodDeclarationParentheses); - constructorDeclaration.Initializer.AcceptVisitor(this, data); + if (!constructorDeclaration.Initializer.IsNull) { + Space(); + constructorDeclaration.Initializer.AcceptVisitor(this, data); + } WriteMethodBody(constructorDeclaration.Body); return EndNode(constructorDeclaration); } @@ -1657,9 +1663,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteModifiers(destructorDeclaration.ModifierTokens); WriteToken("~", DestructorDeclaration.TildeRole); TypeDeclaration type = destructorDeclaration.Parent as TypeDeclaration; - if (type != null) { - WriteIdentifier(type.Name); - } + WriteIdentifier(type != null ? type.Name : destructorDeclaration.Name); Space(policy.BeforeConstructorDeclarationParentheses); LPar(); RPar(); @@ -1689,6 +1693,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteModifiers(eventDeclaration.ModifierTokens); WriteKeyword("event"); eventDeclaration.ReturnType.AcceptVisitor(this, data); + Space(); WriteCommaSeparatedList(eventDeclaration.Variables); Semicolon(); return EndNode(eventDeclaration); @@ -1700,6 +1705,8 @@ namespace ICSharpCode.NRefactory.CSharp WriteAttributes(customEventDeclaration.Attributes); WriteModifiers(customEventDeclaration.ModifierTokens); WriteKeyword("event"); + customEventDeclaration.ReturnType.AcceptVisitor(this, data); + Space(); WritePrivateImplementationType(customEventDeclaration.PrivateImplementationType); WriteIdentifier(customEventDeclaration.Name); OpenBrace(policy.EventBraceStyle); @@ -1720,6 +1727,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteAttributes(fieldDeclaration.Attributes); WriteModifiers(fieldDeclaration.ModifierTokens); fieldDeclaration.ReturnType.AcceptVisitor(this, data); + Space(); WriteCommaSeparatedList(fieldDeclaration.Variables); Semicolon(); return EndNode(fieldDeclaration); @@ -1983,5 +1991,91 @@ namespace ICSharpCode.NRefactory.CSharp return EndNode(identifier); } #endregion + + #region Pattern Nodes + object IPatternAstVisitor.VisitPlaceholder(AstNode placeholder, AstNode child, object data) + { + StartNode(placeholder); + child.AcceptVisitor(this, data); + return EndNode(placeholder); + } + + object IPatternAstVisitor.VisitAnyNode(AnyNode anyNode, object data) + { + StartNode(anyNode); + if (!string.IsNullOrEmpty(anyNode.GroupName)) { + WriteIdentifier(anyNode.GroupName); + WriteToken(":", AstNode.Roles.Colon); + } + WriteKeyword("anyNode"); + return EndNode(anyNode); + } + + object IPatternAstVisitor.VisitBackreference(Backreference backreference, object data) + { + StartNode(backreference); + WriteKeyword("backreference"); + LPar(); + WriteIdentifier(backreference.ReferencedGroupName); + RPar(); + return EndNode(backreference); + } + + object IPatternAstVisitor.VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference, object data) + { + StartNode(identifierExpressionBackreference); + WriteKeyword("identifierBackreference"); + LPar(); + WriteIdentifier(identifierExpressionBackreference.ReferencedGroupName); + RPar(); + return EndNode(identifierExpressionBackreference); + } + + object IPatternAstVisitor.VisitChoice(Choice choice, object data) + { + StartNode(choice); + WriteKeyword("choice"); + Space(); + LPar(); + NewLine(); + formatter.Indent(); + foreach (AstNode alternative in choice) { + alternative.AcceptVisitor(this, data); + if (alternative != choice.LastChild) + WriteToken(",", AstNode.Roles.Comma); + NewLine(); + } + formatter.Unindent(); + RPar(); + return EndNode(choice); + } + + object IPatternAstVisitor.VisitNamedNode(NamedNode namedNode, object data) + { + StartNode(namedNode); + if (!string.IsNullOrEmpty(namedNode.GroupName)) { + WriteIdentifier(namedNode.GroupName); + WriteToken(":", AstNode.Roles.Colon); + } + namedNode.GetChildByRole(NamedNode.ElementRole).AcceptVisitor(this, data); + return EndNode(namedNode); + } + + object IPatternAstVisitor.VisitRepeat(Repeat repeat, object data) + { + StartNode(repeat); + WriteKeyword("repeat"); + LPar(); + if (repeat.MinCount != 0 || repeat.MaxCount != int.MaxValue) { + WriteIdentifier(repeat.MinCount.ToString()); + WriteToken(",", AstNode.Roles.Comma); + WriteIdentifier(repeat.MaxCount.ToString()); + WriteToken(",", AstNode.Roles.Comma); + } + repeat.GetChildByRole(Repeat.ElementRole).AcceptVisitor(this, data); + RPar(); + return EndNode(repeat); + } + #endregion } } diff --git a/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs index a8cc6acac..bb447f4c6 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs @@ -122,9 +122,7 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) spec.AddChild (new CSharpTokenNode (Convert (location[0]), 1), FieldDeclaration.Roles.RBracket); - result.ArraySpecifiers = new ArraySpecifier[] { - spec - }; + result.ArraySpecifiers.Add(spec); } return result; } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index dbc34bcba..6fdcd0c9f 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -1,4 +1,4 @@ - + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} @@ -55,7 +55,7 @@ - + @@ -95,6 +95,15 @@ + + + + + + + + + @@ -333,6 +342,13 @@ + + + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil +