code: private void rewriteAliasReferences(Name aliasingName, Ref aliasingRef, Set<AstChange> newNodes) {
      List<Ref> refs = new ArrayList<>(aliasingName.getRefs());
      for (Ref ref : refs) {
        switch (ref.type) {
          case SET_FROM_GLOBAL:
            continue;
          case DIRECT_GET:
          case ALIASING_GET:
          case PROTOTYPE_GET:
          case CALL_GET:
          case SUBCLASSING_GET:
            if (ref.getTwin() != null) {
              // The reference is the left-hand side of a nested assignment. This means we store two
              // separate 'twin' Refs with the same node of types ALIASING_GET and SET_FROM_GLOBAL.
              // For example, the read of `c.d` has a twin reference in
              //   a.b = c.d = e.f;
              // We handle this case later.
              checkState(ref.type == Type.ALIASING_GET, ref);
              break;
            }
            if (ref.getNode().isStringKey()) {
              // e.g. `y` in `const {y} = x;`
              DestructuringGlobalNameExtractor.reassignDestructringLvalue(
                  ref.getNode(), aliasingRef.getNode().cloneTree(), newNodes, ref, compiler);
            } else {
              // e.g. `x.y`
              checkState(ref.getNode().isGetProp() || ref.getNode().isName());
              Node newNode = aliasingRef.getNode().cloneTree();
              Node node = ref.getNode();
              node.replaceWith(newNode);
              compiler.reportChangeToEnclosingScope(newNode);
              newNodes.add(new AstChange(ref.module, ref.scope, newNode));
            }
            aliasingName.removeRef(ref);
            break;
          default:
            throw new IllegalStateException();
        }
      }
    }
docs: Replaces all reads of a name with the name it aliases