code: private void traverseFunction(Node function, Scope parentScope) {
      checkState(function.getChildCount() == 3, function);
      checkState(function.isFunction(), function);
  
      final Node paramlist = NodeUtil.getFunctionParameters(function);
      final Node body = function.getLastChild();
      checkState(body.getNext() == null && body.isBlock(), body);
  
      // Checking the parameters
      Scope fparamScope = scopeCreator.createScope(function, parentScope);
  
      // Checking the function body
      Scope fbodyScope = scopeCreator.createScope(body, fparamScope);
  
      Node nameNode = function.getFirstChild();
      if (!nameNode.getString().isEmpty()) {
        // var x = function funcName() {};
        // make sure funcName gets into the varInfoMap so it will be considered for removal.
        VarInfo varInfo = traverseNameNode(nameNode, fparamScope);
        if (NodeUtil.isExpressionResultUsed(function)) {
          // var f = function g() {};
          // The f is an alias for g, so g escapes from the scope where it is defined.
          varInfo.hasNonLocalOrNonLiteralValue = true;
        }
      }
  
      traverseChildren(paramlist, fparamScope);
      traverseChildren(body, fbodyScope);
  
      allFunctionParamScopes.add(fparamScope);
    }
docs: Traverses a function
  
  ES6 scopes of a function include the parameter scope and the body scope
  of the function.
  
  Note that CATCH blocks also create a new scope, but only for the
  catch variable. Declarations within the block actually belong to the
  enclosing scope. Because we don't remove catch variables, there's
  no need to treat CATCH blocks differently like we do functions.