BREAKING: Lucene.Net.QueryParser.Flexible.Core.Nodes.IQueryNode: Added RemoveChildren() method from Lucene 8.8.1 to fix broken RemoveFromParent() method behavior (applies patch LUCENE-5805).
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
index a42b93c..4ea4544 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
@@ -102,5 +102,12 @@
/// Removes this query node from its parent.
/// </summary>
void RemoveFromParent();
+
+ // LUCENENET: From Lucene 8.8.1, patch to broken RemoveFromParent() behavior
+ /// <summary>
+ /// Remove a child node.
+ /// </summary>
+ /// <param name="childNode">Which child to remove.</param>
+ void RemoveChildren(IQueryNode childNode);
}
}
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
index be6599d..3be4de4 100644
--- a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Resources;
+using JCG = J2N.Collections.Generic;
namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
{
@@ -41,13 +41,13 @@
private Dictionary<string, object> tags = new Dictionary<string, object>();
- private List<IQueryNode> clauses = null;
+ private JCG.List<IQueryNode> clauses = null;
protected virtual void Allocate()
{
if (this.clauses == null)
{
- this.clauses = new List<IQueryNode>();
+ this.clauses = new JCG.List<IQueryNode>();
}
else
{
@@ -129,7 +129,7 @@
// copy children
if (this.clauses != null)
{
- List<IQueryNode> localClauses = new List<IQueryNode>();
+ JCG.List<IQueryNode> localClauses = new JCG.List<IQueryNode>();
foreach (IQueryNode clause in this.clauses)
{
localClauses.Add(clause.CloneTree());
@@ -155,7 +155,7 @@
{
return null;
}
- return new List<IQueryNode>(this.clauses);
+ return new JCG.List<IQueryNode>(this.clauses);
}
public virtual void SetTag(string tagName, object value)
@@ -240,23 +240,24 @@
/// </summary>
public virtual IDictionary<string, object> TagMap => new Dictionary<string, object>(this.tags);
+ // LUCENENET NOTE: There was a bug in 4.8.1 here because parent.GetChildren() returns a copy of the
+ // children, so removing items from it is pointless. We therefore diverge to the version 8.8.1 source of Lucene
+ // from this point. Not sure when this patch was applied.
+
+ public virtual void RemoveChildren(IQueryNode childNode)
+ {
+ // LUCENENET: Use RemoveAll() method for optimal performance.
+ clauses.RemoveAll((value) => value == childNode);
+ childNode.RemoveFromParent();
+ }
+
public virtual void RemoveFromParent()
{
if (this.parent != null)
{
- IList<IQueryNode> parentChildren = this.parent.GetChildren();
-
- // LUCENENET NOTE: Loop in reverse so we can remove items
- // without screwing up our iterator.
- for (int i = parentChildren.Count - 1; i >= 0; i--)
- {
- if (parentChildren[i] == this)
- {
- parentChildren.RemoveAt(i);
- }
- }
-
+ IQueryNode parent = this.parent;
this.parent = null;
+ parent.RemoveChildren(this);
}
}
diff --git a/src/Lucene.Net.Tests.QueryParser/Flexible/Core/Nodes/TestQueryNode.cs b/src/Lucene.Net.Tests.QueryParser/Flexible/Core/Nodes/TestQueryNode.cs
index 980aad7..346150a 100644
--- a/src/Lucene.Net.Tests.QueryParser/Flexible/Core/Nodes/TestQueryNode.cs
+++ b/src/Lucene.Net.Tests.QueryParser/Flexible/Core/Nodes/TestQueryNode.cs
@@ -62,6 +62,8 @@
fieldNode.RemoveFromParent();
assertNull(fieldNode.Parent);
+ /* LUCENE-5805 - QueryNodeImpl.removeFromParent does a lot of work without any effect */
+ assertFalse(booleanNode.GetChildren().Contains(fieldNode));
booleanNode.Add(fieldNode);
assertNotNull(fieldNode.Parent);
@@ -69,5 +71,20 @@
booleanNode.Set(Collections.EmptyList<IQueryNode>());
assertNull(fieldNode.Parent);
}
+
+ // LUCENENET: Added this patch in Lucene.NET 4.8.0 from Lucene 5.3.0
+ [Test]
+ public void TestRemoveChildren()
+ {
+ BooleanQueryNode booleanNode = new BooleanQueryNode(Collections.EmptyList<IQueryNode>());
+ FieldQueryNode fieldNode = new FieldQueryNode("foo", "A", 0, 1);
+
+ booleanNode.Add(fieldNode);
+ assertTrue(booleanNode.GetChildren().Count == 1);
+
+ booleanNode.RemoveChildren(fieldNode);
+ assertTrue(booleanNode.GetChildren().Count == 0);
+ assertNull(fieldNode.Parent);
+ }
}
}