code: def _index(self, hydrated_targets):
      
      all_addresses = set()
      new_targets = list()
  
      # Index the ProductGraph.
      for hydrated_target in hydrated_targets:
        target_adaptor = hydrated_target.adaptor
        address = target_adaptor.address
        all_addresses.add(address)
        if address not in self._target_by_address:
          new_targets.append(self._index_target(target_adaptor))
  
      # Once the declared dependencies of all targets are indexed, inject their
      # additional "traversable_(dependency_)?specs".
      deps_to_inject = OrderedSet()
      addresses_to_inject = set()
      def inject(target, dep_spec, is_dependency):
        address = Address.parse(dep_spec, relative_to=target.address.spec_path)
        if not any(address == t.address for t in target.dependencies):
          addresses_to_inject.add(address)
          if is_dependency:
            deps_to_inject.add((target.address, address))
  
      self.apply_injectables(new_targets)
  
      for target in new_targets:
        for spec in target.compute_dependency_specs(payload=target.payload):
          inject(target, spec, is_dependency=True)
  
        for spec in target.compute_injectable_specs(payload=target.payload):
          inject(target, spec, is_dependency=False)
  
      # Inject all addresses, then declare injected dependencies.
      self.inject_addresses_closure(addresses_to_inject)
      for target_address, dep_address in deps_to_inject:
        self.inject_dependency(dependent=target_address, dependency=dep_address)
  
      return all_addresses
docs: Index from the given roots into the storage provided by the base class.
  
      This is an additive operation: any existing connections involving these nodes are preserved.