code: private void gatherAllProvides(Node root) {
      if (!processClosurePrimitives) {
        return;
      }
  
      Node externs = root.getFirstChild();
      Node js = root.getSecondChild();
      Map<String, ProvidedName> providedNames =
          new ProcessClosureProvidesAndRequires(
                  compiler,
                  /* preprocessorSymbolTable= */ null,
                  CheckLevel.OFF,
                  /* preserveGoogProvidesAndRequires= */ true)
              .collectProvidedNames(externs, js);
  
      for (ProvidedName name : providedNames.values()) {
        if (name.getCandidateDefinition() != null) {
          // This name will be defined eventually. Don't worry about it.
          Node firstDefinitionNode = name.getCandidateDefinition();
          if (NodeUtil.isExprAssign(firstDefinitionNode)
              && firstDefinitionNode.getFirstFirstChild().isName()) {
            // Treat assignments of provided names as declarations.
            undeclaredNamesForClosure.add(firstDefinitionNode.getFirstFirstChild());
          }
        } else if (name.getFirstProvideCall() != null
            && NodeUtil.isExprCall(name.getFirstProvideCall())) {
          // This name is implicitly created by a goog.provide call; declare it in the scope once
          // reaching the provide call.
          providedNamesFromCall.put(name.getFirstProvideCall(), name);
        }
      }
    }
docs: Gathers all namespaces created by goog.provide and any definitions in code.
  
  <p>This method does not actually declare anything in the scope. In order to accurately report
  redefinition warnings, wait to declare implicit names until the actual goog.provide call.
  
  @param root The global ROOT or a SCRIPT