Refactor l-value tracking to a separate traverser parent class

This makes TIntermTraverser implementation easier to understand and
removes the overhead of maintaining the user-defined GLSL function table
from the traversers that don't need it.

Some logic is duplicated between TIntermTraverser and its new subclass
TLValueTrackingTraverser, but duplication is hard to eliminate completely
since there are some differences scattered throughout the code.

BUG=angleproject:1116
TEST=angle_unittests

Change-Id: Iab4a0c1d4320ecfafaf18ea3a45824d756890774
Reviewed-on: https://chromium-review.googlesource.com/292721
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index 09d52e2..d39e779 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -151,29 +151,29 @@
     ++(*mTemporaryIndex);
 }
 
-void TIntermTraverser::addToFunctionMap(const TString &name, TIntermSequence *paramSequence)
+void TLValueTrackingTraverser::addToFunctionMap(const TString &name, TIntermSequence *paramSequence)
 {
     mFunctionMap[name] = paramSequence;
 }
 
-bool TIntermTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
+bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
 {
     ASSERT(callNode->getOp() == EOpFunctionCall || callNode->getOp() == EOpInternalFunctionCall);
     return (mFunctionMap.find(callNode->getName()) != mFunctionMap.end());
 }
 
-TIntermSequence *TIntermTraverser::getFunctionParameters(const TIntermAggregate *callNode)
+TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
 {
     ASSERT(isInFunctionMap(callNode));
     return mFunctionMap[callNode->getName()];
 }
 
-void TIntermTraverser::setInFunctionCallOutParameter(bool inOutParameter)
+void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
 {
     mInFunctionCallOutParameter = inOutParameter;
 }
 
-bool TIntermTraverser::isInFunctionCallOutParameter() const
+bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
 {
     return mInFunctionCallOutParameter;
 }
@@ -222,6 +222,43 @@
     {
         incrementDepth(node);
 
+        if (node->getLeft())
+            node->getLeft()->traverse(this);
+
+        if (inVisit)
+            visit = visitBinary(InVisit, node);
+
+        if (visit && node->getRight())
+            node->getRight()->traverse(this);
+
+        decrementDepth();
+    }
+
+    //
+    // Visit the node after the children, if requested and the traversal
+    // hasn't been cancelled yet.
+    //
+    if (visit && postVisit)
+        visitBinary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
+{
+    bool visit = true;
+
+    //
+    // visit the node before children if pre-visiting.
+    //
+    if (preVisit)
+        visit = visitBinary(PreVisit, node);
+
+    //
+    // Visit the children, in the right order.
+    //
+    if (visit)
+    {
+        incrementDepth(node);
+
         // Some binary operations like indexing can be inside an expression which must be an
         // l-value.
         bool parentOperatorRequiresLValue     = operatorRequiresLValue();
@@ -282,6 +319,26 @@
     {
         incrementDepth(node);
 
+        node->getOperand()->traverse(this);
+
+        decrementDepth();
+    }
+
+    if (visit && postVisit)
+        visitUnary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
+{
+    bool visit = true;
+
+    if (preVisit)
+        visit = visitUnary(PreVisit, node);
+
+    if (visit)
+    {
+        incrementDepth(node);
+
         ASSERT(!operatorRequiresLValue());
         switch (node->getOp())
         {
@@ -314,6 +371,45 @@
     bool visit = true;
 
     TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitAggregate(PreVisit, node);
+
+    if (visit)
+    {
+        incrementDepth(node);
+
+        if (node->getOp() == EOpSequence)
+            pushParentBlock(node);
+
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitAggregate(InVisit, node);
+            }
+
+            if (node->getOp() == EOpSequence)
+                incrementParentBlockPos();
+        }
+
+        if (node->getOp() == EOpSequence)
+            popParentBlock();
+
+        decrementDepth();
+    }
+
+    if (visit && postVisit)
+        visitAggregate(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
+{
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
     switch (node->getOp())
     {
         case EOpFunction: