public void traverseExpression(Expression expr, Function<ExprSite, Boolean> func) {
    Preconditions.checkNotNull(expr);
    if (!func.apply(new ExprSite(expr))) {
      return;
    }
    traverseChildren(expr, func);
  }
@Test
  public void testTraverseExpression() throws InvocationTargetException, IllegalAccessException {
    Expression.Reference ref =
        new Expression.Reference("a", TypeRef.of(ExpressionVisitorTest.class));
    Expression e1 = new Expression.Invoke(ref, "testTraverseExpression");
    Literal start = Literal.ofInt(0);
    Literal end = Literal.ofInt(10);
    Literal step = Literal.ofInt(1);
    ExpressionVisitor.ExprHolder holder =
        ExpressionVisitor.ExprHolder.of("e1", e1, "e2", new Expression.ListExpression());
    // FIXME ListExpression#add in lambda don't get executed, so ListExpression is the last expr.
    Expression.ForLoop forLoop =
        new Expression.ForLoop(
            start,
            end,
            step,
            expr -> ((Expression.ListExpression) (holder.get("e2"))).add(holder.get("e1")));
    List<Expression> expressions = new ArrayList<>();
    new ExpressionVisitor()
        .traverseExpression(forLoop, exprSite -> expressions.add(exprSite.current));
    Preconditions.checkArgument(forLoop.action != null);
    Method writeReplace =
        ReflectionUtils.findMethods(forLoop.action.getClass(), "writeReplace").get(0);
    writeReplace.setAccessible(true);
    SerializedLambda serializedLambda = (SerializedLambda) writeReplace.invoke(forLoop.action);
    assertEquals(serializedLambda.getCapturedArgCount(), 1);
    ExpressionVisitor.ExprHolder exprHolder =
        (ExpressionVisitor.ExprHolder) (serializedLambda.getCapturedArg(0));
    assertEquals(
        expressions, Arrays.asList(forLoop, start, end, step, e1, ref, exprHolder.get("e2")));
  }