code: private Stream<Push> selectPushes(IntermediateQuery query, JoinOrFilterNode providerNode,
                                             ImmutableList<QueryNode> candidateSubtreeRoots,
                                             ImmutableExpression expression) {
          ImmutableList.Builder<QueryNode> selectedSubtreeRootsBuilder = ImmutableList.builder();
  
          ImmutableSet<Variable> expressionVariables = expression.getVariables();
          for (QueryNode candidateSubtreeRoot : candidateSubtreeRoots) {
              ImmutableSet<Variable> projectedVariables = query.getVariables(candidateSubtreeRoot);
              if (projectedVariables.containsAll(expressionVariables)) {
                  selectedSubtreeRootsBuilder.add(candidateSubtreeRoot);
              }
          }
  
          ImmutableList<QueryNode> selectedSubtreeRoots = selectedSubtreeRootsBuilder.build();
          /*
           * If no candidate subtree has been selected,
           * keep the expression at the provider's level (otherwise the expression will be dropped)
           */
          if (selectedSubtreeRoots.isEmpty()) {
              return Stream.of(getProviderAsPush(providerNode, expression));
          }
  
          return selectedSubtreeRoots.stream()
                  .flatMap(subtreeRoot -> findPushesInSelectedSubtree(query, subtreeRoot, providerNode, expression))
                  .distinct();
      }
docs: For an expression e, a (filter or join) node p providing e,
  and a list S of preselected candidate subtrees for propagation,
  decides whether e should remain attached to p,
  and/or which subtree in S e should be propagated to.
  Also selects the recipient for e in each of these selected subtrees.
  <p>
  If e should remain attached to p,
  then p is simply returned among the recipients (not that p may or may not be the only recipient)
  
  TODO: update the comment