public Object visit(ConcatenateExpression node) {
            Expression left = node.getLeftExpression();
            Expression right = node.getRightExpression();
            Type leftType = left.getType();
            Type rightType = right.getType();

            // If concatenation requires a chain of more than two append calls,
            // generate a StringBuffer append chain.
            if (left instanceof ConcatenateExpression ||
                // Note: These are just sanity checks since the type checker is
                // supposed to ensure that sub nodes are converted to non-null
                // strings.
                leftType.isNullable() ||
                leftType.getObjectClass() != String.class ||
                rightType.isNullable() ||
                rightType.getObjectClass() != String.class) {

                generateAppend(node, estimateBufferRequirement(node));
                mBuilder.invokeVirtual("java.lang.StringBuilder", "toString",
                                       TypeDesc.STRING);
            }
            else {
                // Concatenation is of the form 'a & b' or 'a & (b & c)' so
                // call String.concat as an optimization. It allocates less
                // objects, and it does no synchronization.
                generate(left);
                generate(right);
                mBuilder.invokeVirtual("java.lang.String", "concat",
                                       TypeDesc.STRING, cStringParam);
            }

            return null;
        }