function variablesInBlock(tree, includeFunctionScope = undefined) {
  let builder = new ScopeChainBuilder(null);
  builder.visitAny(tree);
  let scope = builder.getScopeForTree(tree);
  let names = scope.getLexicalBindingNames();
  if (!includeFunctionScope) {
    return names;
  }

  let variableBindingNames = scope.getVariableBindingNames();
  variableBindingNames.forEach((name) => names.add(name));
  return names;
}
Gets the identifiers bound in {@code tree}. The tree should be a block
statement. This means if {@code tree} is:

{ function f(x) { var y; } }

Then only {@code "f"} is bound; {@code "x"} and {@code "y"} are bound in
the separate lexical scope of {@code f}. Note that only const/let bound
variables (such as {@code "f"} in this example) are returned. Variables
declared with "var" are only returned when {@code includeFunctionScope} is
set to true.

If {@code tree} was instead:

{ var z = function f(x) { var y; }; }


Then only {@code "z"} is bound

@param {Block} tree
@param {boolean=} includeFunctionScope
@return {StringSet}