/**
   * Removes unreferenced arguments from a function declaration and when possible the function's
   * callSites.
   *
   * @param fnScope The scope inside the function
   */
  private void removeUnreferencedFunctionArgs(Scope fnScope) {
    // TODO(johnlenz): Update type registry for function signature changes.

    Node function = fnScope.getRootNode();

    Preconditions.checkState(function.getType() == Token.FUNCTION);
    if (NodeUtil.isGetOrSetKey(function.getParent())) {
      // The parameters object literal setters can not be removed.
      return;
    }

    Node argList = getFunctionArgList(function);
    boolean modifyCallers = modifyCallSites && callSiteOptimizer.canModifyCallers(function);
    if (!modifyCallers) {
      // Strip unreferenced args off the end of the function declaration.
      Node lastArg;
      while ((lastArg = argList.getLastChild()) != null) {
        Var var = fnScope.getVar(lastArg.getString());
        if (!referenced.contains(var)) {
          Preconditions.checkNotNull(var == null);
          argList.removeChild(lastArg);
          compiler.reportCodeChange();
        } else {
          break;
        }
      }
    } else {
      callSiteOptimizer.optimize(fnScope, referenced);
    }
  }
 @Override
 public void process(Node externs, Node root, SimpleDefinitionFinder defFinder) {
   if (modifyCallSites) {
     Preconditions.checkNotNull(defFinder);
     callSiteOptimizer = new CallSiteOptimizer(compiler, defFinder);
   }
   traverseAndRemoveUnusedReferences(root);
   if (callSiteOptimizer != null) {
     callSiteOptimizer.applyChanges();
   }
 }