translator: Refactor node replacement APIs.

BUG=angleproject:851

Change-Id: I50c3b3a4f00b27fed85f09509738513a441c7b5b
Reviewed-on: https://chromium-review.googlesource.com/363990
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 3c1a71e..af5bb9c 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -103,7 +103,8 @@
                 replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
                 replacementParams->setLine(params->getLine());
 
-                replaceWithParent(node, params, replacementParams);
+                queueReplacementWithParent(node, params, replacementParams,
+                                           OriginalNode::IS_DROPPED);
 
                 node->setType(TType(EbtVoid));
 
@@ -122,7 +123,7 @@
                 replacement->setLine(node->getLine());
                 replacement->setType(TType(EbtVoid));
 
-                replace(node, replacement);
+                queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
             }
             else if (node->getOp() == EOpFunctionCall)
             {
@@ -192,7 +193,7 @@
         if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined())
         {
             TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft());
-            replace(node, replacementCall);
+            queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED);
         }
     }
     return false;
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index 6904f94..76addf2 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -130,7 +130,7 @@
                 ASSERT(symbolNode->getQualifier() == EvqGlobal);
             }
             // Remove the initializer from the global scope and just declare the global instead.
-            mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, symbolNode, false));
+            queueReplacement(node, symbolNode, OriginalNode::IS_DROPPED);
         }
     }
     return false;
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 11fa35e..5f1454b 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -495,9 +495,8 @@
 {
     if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere())
     {
-        TIntermNode *parent = getParentNode();
         TIntermNode *replacement = createRoundingFunctionCallNode(node);
-        mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
+        queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
     }
 }
 
@@ -543,7 +542,7 @@
                 break;
             }
             TIntermNode *replacement = createRoundingFunctionCallNode(node);
-            mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
+            queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
             break;
           }
 
@@ -553,10 +552,9 @@
               mEmulateCompoundAdd.insert(
                   TypePair(type.getBuiltInTypeNameString(),
                            node->getRight()->getType().getBuiltInTypeNameString()));
-              TIntermNode *parent      = getParentNode();
               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
                   node->getLeft(), node->getRight(), "add");
-              mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false));
+              queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
               break;
           }
           case EOpSubAssign:
@@ -564,10 +562,9 @@
               mEmulateCompoundSub.insert(
                   TypePair(type.getBuiltInTypeNameString(),
                            node->getRight()->getType().getBuiltInTypeNameString()));
-              TIntermNode *parent      = getParentNode();
               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
                   node->getLeft(), node->getRight(), "sub");
-              mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false));
+              queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
               break;
           }
           case EOpMulAssign:
@@ -579,10 +576,9 @@
               mEmulateCompoundMul.insert(
                   TypePair(type.getBuiltInTypeNameString(),
                            node->getRight()->getType().getBuiltInTypeNameString()));
-              TIntermNode *parent      = getParentNode();
               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
                   node->getLeft(), node->getRight(), "mul");
-              mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false));
+              queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
               break;
           }
           case EOpDivAssign:
@@ -590,10 +586,9 @@
               mEmulateCompoundDiv.insert(
                   TypePair(type.getBuiltInTypeNameString(),
                            node->getRight()->getType().getBuiltInTypeNameString()));
-              TIntermNode *parent      = getParentNode();
               TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
                   node->getLeft(), node->getRight(), "div");
-              mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false));
+              queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
               break;
           }
           default:
@@ -649,7 +644,7 @@
                 parentUsesResult(parent, node))
             {
                 TIntermNode *replacement = createRoundingFunctionCallNode(node);
-                mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
+                queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
             }
         }
         break;
@@ -659,7 +654,7 @@
         if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node))
         {
             TIntermNode *replacement = createRoundingFunctionCallNode(node);
-            mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
+            queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
         }
         break;
     }
@@ -681,9 +676,8 @@
       default:
         if (canRoundFloat(node->getType()) && visit == PreVisit)
         {
-            TIntermNode *parent = getParentNode();
             TIntermNode *replacement = createRoundingFunctionCallNode(node);
-            mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
+            queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD);
         }
         break;
     }
diff --git a/src/compiler/translator/ExpandIntegerPowExpressions.cpp b/src/compiler/translator/ExpandIntegerPowExpressions.cpp
index 162925a..93ded88 100644
--- a/src/compiler/translator/ExpandIntegerPowExpressions.cpp
+++ b/src/compiler/translator/ExpandIntegerPowExpressions.cpp
@@ -122,7 +122,7 @@
         current = div;
     }
 
-    replace(node, current);
+    queueReplacement(node, current, OriginalNode::IS_DROPPED);
     return true;
 }
 
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 4481729..fb6bec1 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -2675,19 +2675,28 @@
         UNUSED_ASSERTION_VARIABLE(replaced);
     }
 
-    mInsertions.clear();
+    clearReplacementQueue();
+}
+
+void TIntermTraverser::clearReplacementQueue()
+{
     mReplacements.clear();
     mMultiReplacements.clear();
+    mInsertions.clear();
 }
 
-void TIntermTraverser::replace(TIntermNode *original, TIntermNode *replacement)
+void TIntermTraverser::queueReplacement(TIntermNode *original,
+                                        TIntermNode *replacement,
+                                        OriginalNode originalStatus)
 {
-    replaceWithParent(getParentNode(), original, replacement);
+    queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
 }
 
-void TIntermTraverser::replaceWithParent(TIntermNode *parent,
-                                         TIntermNode *original,
-                                         TIntermNode *replacement)
+void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
+                                                  TIntermNode *original,
+                                                  TIntermNode *replacement,
+                                                  OriginalNode originalStatus)
 {
-    mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, false));
+    bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
+    mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
 }
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index a9a59ac..33878b7 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -672,17 +672,8 @@
 {
   public:
     POOL_ALLOCATOR_NEW_DELETE();
-    TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
-        : preVisit(preVisit),
-          inVisit(inVisit),
-          postVisit(postVisit),
-          mDepth(0),
-          mMaxDepth(0),
-          mInGlobalScope(true),
-          mTemporaryIndex(nullptr)
-    {
-    }
-    virtual ~TIntermTraverser() {}
+    TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
+    virtual ~TIntermTraverser();
 
     virtual void visitSymbol(TIntermSymbol *node) {}
     virtual void visitRaw(TIntermRaw *node) {}
@@ -763,24 +754,6 @@
         return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node;
     }
 
-    // To replace a single node with another on the parent node
-    struct NodeUpdateEntry
-    {
-        NodeUpdateEntry(TIntermNode *_parent,
-                        TIntermNode *_original,
-                        TIntermNode *_replacement,
-                        bool _originalBecomesChildOfReplacement)
-            : parent(_parent),
-              original(_original),
-              replacement(_replacement),
-              originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {}
-
-        TIntermNode *parent;
-        TIntermNode *original;
-        TIntermNode *replacement;
-        bool originalBecomesChildOfReplacement;
-    };
-
     // To replace a single node with multiple nodes on the parent aggregate node
     struct NodeReplaceWithMultipleEntry
     {
@@ -846,8 +819,20 @@
     // Increment temporary symbol index.
     void nextTemporaryIndex();
 
-    void replace(TIntermNode *original, TIntermNode *replacement);
-    void replaceWithParent(TIntermNode *parent, TIntermNode *original, TIntermNode *replacement);
+    enum class OriginalNode
+    {
+        BECOMES_CHILD,
+        IS_DROPPED
+    };
+
+    void clearReplacementQueue();
+    void queueReplacement(TIntermNode *original,
+                          TIntermNode *replacement,
+                          OriginalNode originalStatus);
+    void queueReplacementWithParent(TIntermNode *parent,
+                                    TIntermNode *original,
+                                    TIntermNode *replacement,
+                                    OriginalNode originalStatus);
 
     const bool preVisit;
     const bool inVisit;
@@ -864,11 +849,30 @@
     // During traversing, save all the changes that need to happen into
     // mReplacements/mMultiReplacements, then do them by calling updateTree().
     // Multi replacements are processed after single replacements.
-    std::vector<NodeUpdateEntry> mReplacements;
     std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
     std::vector<NodeInsertMultipleEntry> mInsertions;
 
   private:
+    // To replace a single node with another on the parent node
+    struct NodeUpdateEntry
+    {
+        NodeUpdateEntry(TIntermNode *_parent,
+                        TIntermNode *_original,
+                        TIntermNode *_replacement,
+                        bool _originalBecomesChildOfReplacement)
+            : parent(_parent),
+              original(_original),
+              replacement(_replacement),
+              originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
+        {
+        }
+
+        TIntermNode *parent;
+        TIntermNode *original;
+        TIntermNode *replacement;
+        bool originalBecomesChildOfReplacement;
+    };
+
     struct ParentBlock
     {
         ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
@@ -880,6 +884,9 @@
         TIntermAggregate *node;
         TIntermSequence::size_type pos;
     };
+
+    std::vector<NodeUpdateEntry> mReplacements;
+
     // All the code blocks from the root to the current node's parent during traversal.
     std::vector<ParentBlock> mParentBlockStack;
 
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index 889bab7..2f66ba7 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -63,6 +63,21 @@
     it->traverseBranch(this);
 }
 
+TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
+    : preVisit(preVisit),
+      inVisit(inVisit),
+      postVisit(postVisit),
+      mDepth(0),
+      mMaxDepth(0),
+      mInGlobalScope(true),
+      mTemporaryIndex(nullptr)
+{
+}
+
+TIntermTraverser::~TIntermTraverser()
+{
+}
+
 void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
 {
     mParentBlockStack.push_back(ParentBlock(node, 0));
diff --git a/src/compiler/translator/RecordConstantPrecision.cpp b/src/compiler/translator/RecordConstantPrecision.cpp
index 14e88b7..af1d1d1 100644
--- a/src/compiler/translator/RecordConstantPrecision.cpp
+++ b/src/compiler/translator/RecordConstantPrecision.cpp
@@ -128,7 +128,7 @@
     TIntermSequence insertions;
     insertions.push_back(createTempInitDeclaration(node, EvqConst));
     insertStatementsInParentBlock(insertions);
-    mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, createTempSymbol(node->getType()), false));
+    queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
     mFoundHigherPrecisionConstant = true;
 }
 
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index e846fcc..37955e7 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -404,8 +404,7 @@
 
             // Replace the index with the temp variable
             TIntermSymbol *tempIndex = createTempSymbol(node->getRight()->getType());
-            NodeUpdateEntry replaceIndex(node, node->getRight(), tempIndex, false);
-            mReplacements.push_back(replaceIndex);
+            queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED);
         }
         else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node))
         {
@@ -469,9 +468,7 @@
                     CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType));
                 insertionsAfter.push_back(indexedWriteCall);
                 insertStatementsInParentBlock(insertionsBefore, insertionsAfter);
-                NodeUpdateEntry replaceIndex(getParentNode(), node, createTempSymbol(fieldType),
-                                             false);
-                mReplacements.push_back(replaceIndex);
+                queueReplacement(node, createTempSymbol(fieldType), OriginalNode::IS_DROPPED);
                 mUsedTreeInsertion = true;
             }
             else
@@ -484,8 +481,7 @@
                 ASSERT(!mRemoveIndexSideEffectsInSubtree);
                 TIntermAggregate *indexingCall = CreateIndexFunctionCall(
                     node, node->getLeft(), EnsureSignedInt(node->getRight()));
-                NodeUpdateEntry replaceIndex(getParentNode(), node, indexingCall, false);
-                mReplacements.push_back(replaceIndex);
+                queueReplacement(node, indexingCall, OriginalNode::IS_DROPPED);
             }
         }
     }
diff --git a/src/compiler/translator/RemovePow.cpp b/src/compiler/translator/RemovePow.cpp
index 6dbb48d..d55e124 100644
--- a/src/compiler/translator/RemovePow.cpp
+++ b/src/compiler/translator/RemovePow.cpp
@@ -75,8 +75,7 @@
         exp->setLine(node->getLine());
         exp->setType(node->getType());
 
-        NodeUpdateEntry replacePow(getParentNode(), node, exp, false);
-        mReplacements.push_back(replacePow);
+        queueReplacement(node, exp, OriginalNode::IS_DROPPED);
 
         // If the x parameter also needs to be replaced, we need to do that in another traversal,
         // since it's parent node will change in a way that's not handled correctly by updateTree().
diff --git a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
index abb0be4..4041be9 100644
--- a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
+++ b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
@@ -93,9 +93,7 @@
     insertions.push_back(createTempInitDeclaration(node->getLeft()));
     insertStatementsInParentBlock(insertions);
 
-    NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()),
-                                    false);
-    mReplacements.push_back(replaceVariable);
+    queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
 
     return false;
 }
@@ -116,9 +114,7 @@
     insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node)));
     insertStatementsInParentBlock(insertions);
 
-    NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()),
-                                    false);
-    mReplacements.push_back(replaceVariable);
+    queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED);
 
     return false;
 }
diff --git a/src/compiler/translator/SplitSequenceOperator.cpp b/src/compiler/translator/SplitSequenceOperator.cpp
index 22f9ec6..3ea29b9 100644
--- a/src/compiler/translator/SplitSequenceOperator.cpp
+++ b/src/compiler/translator/SplitSequenceOperator.cpp
@@ -101,9 +101,7 @@
                 }
                 insertStatementsInParentBlock(insertions);
                 // Replace the sequence with its last operand
-                NodeUpdateEntry replaceSequence(getParentNode(), node, node->getSequence()->back(),
-                                                false);
-                mReplacements.push_back(replaceSequence);
+                queueReplacement(node, node->getSequence()->back(), OriginalNode::IS_DROPPED);
             }
             mInsideSequenceOperator--;
         }
diff --git a/src/compiler/translator/UnfoldShortCircuitAST.cpp b/src/compiler/translator/UnfoldShortCircuitAST.cpp
index e50bf20..3ef555f 100644
--- a/src/compiler/translator/UnfoldShortCircuitAST.cpp
+++ b/src/compiler/translator/UnfoldShortCircuitAST.cpp
@@ -50,8 +50,7 @@
     }
     if (replacement)
     {
-        mReplacements.push_back(
-            NodeUpdateEntry(getParentNode(), node, replacement, false));
+        queueReplacement(node, replacement, OriginalNode::IS_DROPPED);
     }
     return true;
 }
diff --git a/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
index 830cce6..79d241d 100644
--- a/src/compiler/translator/UnfoldShortCircuitToIf.cpp
+++ b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -108,8 +108,7 @@
 
             insertStatementsInParentBlock(insertions);
 
-            NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
-            mReplacements.push_back(replaceVariable);
+            queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
         }
         return false;
       case EOpLogicalAnd:
@@ -133,8 +132,7 @@
 
             insertStatementsInParentBlock(insertions);
 
-            NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false);
-            mReplacements.push_back(replaceVariable);
+            queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED);
         }
         return false;
       default:
@@ -183,8 +181,7 @@
         insertStatementsInParentBlock(insertions);
 
         TIntermSymbol *ternaryResult = createTempSymbol(node->getType());
-        NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false);
-        mReplacements.push_back(replaceVariable);
+        queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED);
     }
 
     return false;
@@ -207,9 +204,7 @@
             // We need to unfold the sequence (comma) operator, otherwise the evaluation order of
             // statements would be messed up by unfolded operations inside.
             // Don't do any other unfolding on this round of traversal.
-            mReplacements.clear();
-            mMultiReplacements.clear();
-            mInsertions.clear();
+            clearReplacementQueue();
 
             if (!copyLoopConditionOrExpression(getParentNode(), node))
             {
@@ -227,8 +222,7 @@
 
                 insertStatementsInParentBlock(insertions);
 
-                NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false);
-                mReplacements.push_back(replaceVariable);
+                queueReplacement(node, (*seq)[i], OriginalNode::IS_DROPPED);
             }
         }
     }
@@ -295,8 +289,8 @@
 {
     if (mInLoopCondition)
     {
-        mReplacements.push_back(
-            NodeUpdateEntry(parent, node, createTempSymbol(node->getType()), false));
+        queueReplacementWithParent(parent, node, createTempSymbol(node->getType()),
+                                   OriginalNode::IS_DROPPED);
         TIntermAggregate *body = mParentLoop->getBody();
         TIntermSequence empty;
         if (mParentLoop->getType() == ELoopDoWhile)
@@ -323,13 +317,15 @@
             {
                 // Move the initializer to the newly created outer scope, so that condition can
                 // depend on it.
-                mReplacements.push_back(NodeUpdateEntry(mParentLoop, initializer, nullptr, false));
+                queueReplacementWithParent(mParentLoop, initializer, nullptr,
+                                           OriginalNode::IS_DROPPED);
                 loopScope->getSequence()->push_back(initializer);
             }
 
             loopScope->getSequence()->push_back(createTempInitDeclaration(node));
             loopScope->getSequence()->push_back(mParentLoop);
-            mReplacements.push_back(NodeUpdateEntry(mLoopParent, mParentLoop, loopScope, true));
+            queueReplacementWithParent(mLoopParent, mParentLoop, loopScope,
+                                       OriginalNode::BECOMES_CHILD);
 
             // The second copy of the part of the loop condition is executed inside the loop.
             TIntermSequence insertionsInLoop;
@@ -343,7 +339,7 @@
     if (mInLoopExpression)
     {
         TIntermTyped *movedExpression = mParentLoop->getExpression();
-        mReplacements.push_back(NodeUpdateEntry(mParentLoop, movedExpression, nullptr, false));
+        queueReplacementWithParent(mParentLoop, movedExpression, nullptr, OriginalNode::IS_DROPPED);
         TIntermAggregate *body = mParentLoop->getBody();
         TIntermSequence empty;
         TIntermSequence insertions;