### Description

As we have more rules doing analysis across plans, a number of methods are useful to add to the `QueryPlan` class itself, mainly around expressions:

```
- expressions() - return the expressions declared by this plan
- references() - return the references from the expressions above
```
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java
return pl;
        }
        /**
         * Prunes attributes from the list not found in the given set.
         * Returns null if no changed occurred.
         */
        private static <N extends NamedExpression> List<N> removeUnused(List<N> named, AttributeSet used) {
            var clone = new ArrayList<>(named);
            var it = clone.listIterator(clone.size());
            
            while (it.hasPrevious()) {
                N prev = it.previous();
                if (used.contains(prev.toAttribute()) == false) {
                    it.remove();
                } else {
                    used.addAll(prev.references());
                }
            }
            return clone.size() != named.size() ? clone : null;
        }
        private static List<Expression> expressions(LogicalPlan plan) {
            List<Expression> exp = new ArrayList<>();
            plan.forEachExpression(exp::add);
            return exp;
        }
        private static AttributeSet references(LogicalPlan plan) {
            return Expressions.references(expressions(plan));
        }
    }
    static class PruneOrderByBeforeStats extends OptimizerRules.OptimizerRule<Aggregate> {