collect() {
      const mangler = this;
      const { scopeTracker } = mangler;

      scopeTracker.addScope(this.program.scope);

      /**
       * Same usage as in DCE, whichever runs first
       */
      if (!isEvalScopesMarked(mangler.program)) {
        markEvalScopes(mangler.program);
      }

      /**
       * The visitors to be used in traversal.
       *
       * Note: BFS traversal supports only the `enter` handlers, `exit`
       * handlers are simply dropped without Errors
       *
       * Collects items defined in the ScopeTracker
       */
      const collectVisitor = {
        Scopable({ scope }) {
          scopeTracker.addScope(scope);

          // Collect bindings defined in the scope
          Object.keys(scope.bindings).forEach(name => {
            scopeTracker.addBinding(scope.bindings[name]);

            // add all constant violations as references
            scope.bindings[name].constantViolations.forEach(() => {
              scopeTracker.addReference(scope, scope.bindings[name], name);
            });
          });
        },

        /**
         * This is required because after function name transformation
         * plugin (part of es2015), the function name is NOT added to the
         * scope's bindings. So to fix this issue, we simply add a hack to
         * handle that case - fix it to the scope tree.
         *
         * Related:
         * - https://github.com/babel/minify/issues/829
         */
        BindingIdentifier(path) {
          if (
            // the parent has this id as the name
            (path.parentPath.isFunctionExpression({ id: path.node }) ||
              path.parentPath.isClassExpression({ id: path.node })) &&
            // and the id isn't yet added to the scope
            !hop.call(path.parentPath.scope.bindings, path.node.name)
          ) {
            path.parentPath.scope.registerBinding("local", path.parentPath);
          }
        },

        /**
         * This is necessary because, in Babel, the scope.references
         * does NOT contain the references in that scope. Only the program
         * scope (top most level) contains all the references.
         *
         * We collect the references in a fashion where all the scopes between
         * and including the referenced scope and scope where it is declared
         * is considered as scope referencing that identifier
         */
        ReferencedIdentifier(path) {
          if (isLabelIdentifier(path)) {
            return;
          }
          const {
            scope,
            node: { name }
          } = path;
          const binding = scope.getBinding(name);
          if (!binding) {
            // Do not collect globals as they are already available via
            // babel's API
            if (scope.hasGlobal(name)) {
              return;
            }
            // This should NOT happen ultimately. Panic if this code block is
            // reached
            throw new Error(
              `Binding not found for ReferencedIdentifier "${name}" ` +
                `present in "${path.parentPath.type}". ` +
                `Please report this at ${newIssueUrl}`
            );
          } else {
            // Add it to our scope tracker if everything is fine
            scopeTracker.addReference(scope, binding, name);
          }
        }
      };

      /**
       * These visitors are for collecting the Characters used in the program
       * to measure the frequency and generate variable names for mangling so
       * as to improve the gzip compression - as gzip likes repetition
       */
      if (this.charset.shouldConsider) {
        collectVisitor.Identifier = function Identifer(path) {
          const { node } = path;

          // We don't mangle properties, so we collect them as they contribute
          // to the frequency of characters
          if (
            path.parentPath.isMemberExpression({ property: node }) ||
            path.parentPath.isObjectProperty({ key: node })
          ) {
            mangler.charset.consider(node.name);
          }
        };
        collectVisitor.Literal = function Literal({ node }) {
          mangler.charset.consider(String(node.value));
        };
      }

      // Traverse the AST
      bfsTraverse(mangler.program, collectVisitor);
    }
A single pass through the AST to collect info for

1. Scope Tracker
2. Unsafe Scopes (direct eval scopes)
3. Charset considerations for better gzip compression

Traversed in the same fashion(BFS) the mangling is done