<commit_before>/*
 * Copyright (C) 2018 The Dagger Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dagger.internal.codegen.binding;

import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Verify.verify;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.extension.DaggerGraphs.unreachableNodes;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.Network;
import com.google.common.graph.NetworkBuilder;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.model.BindingGraph.ComponentNode;
import dagger.model.BindingGraph.DependencyEdge;
import dagger.model.BindingGraph.Edge;
import dagger.model.BindingGraph.MissingBinding;
import dagger.model.BindingGraph.Node;
import dagger.model.BindingGraphProxies;
import dagger.model.ComponentPath;
import dagger.model.DependencyRequest;
import java.util.ArrayDeque;
import java.util.Deque;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

/** Converts {@link BindingGraph}s to {@link dagger.model.BindingGraph}s. */
public final class BindingGraphConverter {
  private final BindingDeclarationFormatter bindingDeclarationFormatter;

  @Inject
  BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
    this.bindingDeclarationFormatter = bindingDeclarationFormatter;
  }

  /**
   * Creates the external {@link dagger.model.BindingGraph} representing the given internal {@link
   * BindingGraph}.
   */
  public dagger.model.BindingGraph convert(BindingGraph bindingGraph) {
    MutableNetwork<Node, Edge> network =
        Converter.convert(bindingGraph, bindingDeclarationFormatter);

    // When bindings are copied down into child graphs because they transitively depend on local
    // multibindings or optional bindings, the parent-owned binding is still there. If that
    // parent-owned binding is not reachable from its component, it doesn't need to be in the graph
    // because it will never be used. So remove all nodes that are not reachable from the root
    // component—unless we're converting a full binding graph.
    if (!bindingGraph.isFullBindingGraph()) {
      unreachableNodes(network.asGraph(), rootComponentNode(network)).forEach(network::removeNode);
    }

    return BindingGraphProxies.bindingGraph(network, bindingGraph.isFullBindingGraph());
  }

  // TODO(dpb): Example of BindingGraph logic applied to derived networks.
  private ComponentNode rootComponentNode(Network<Node, Edge> network) {
    return (ComponentNode)
        Iterables.find(
            network.nodes(),
            node -> node instanceof ComponentNode && node.componentPath().atRoot());
  }

  private static final class Converter {
    /**
     * Calls {@link #visitComponent(BindingGraph)} for the root component.
     *
     * @throws IllegalStateException if a traversal is in progress
     */
    private static MutableNetwork<Node, Edge> convert(
        BindingGraph graph, BindingDeclarationFormatter bindingDeclarationFormatter) {
      Converter converter = new Converter(bindingDeclarationFormatter);
      converter.visitRootComponent(graph);
      return converter.network;
    }

    /** The path from the root graph to the currently visited graph. */
    private final Deque<BindingGraph> bindingGraphPath = new ArrayDeque<>();

    /** The {@link ComponentPath} for each component in {@link #bindingGraphPath}. */
    private final Deque<ComponentPath> componentPaths = new ArrayDeque<>();

    private final BindingDeclarationFormatter bindingDeclarationFormatter;
    private final MutableNetwork<Node, Edge> network =
        NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();

    /** Constructs a converter for a root (component, not subcomponent) binding graph. */
    private Converter(BindingDeclarationFormatter bindingDeclarationFormatter) {
      this.bindingDeclarationFormatter = bindingDeclarationFormatter;
    }

    private void visitRootComponent(BindingGraph graph) {
      visitComponent(graph, null);
    }

    /**
     * Called once for each component in a component hierarchy.
     *
     * <p>This implementation does the following:
     *
     * <ol>
     *   <li>If this component is installed in its parent by a subcomponent factory method, calls
     *       {@link #visitSubcomponentFactoryMethod(ComponentNode, ComponentNode,
     *       ExecutableElement)}.
     *   <li>For each entry point in the component, calls {@link #visitEntryPoint(ComponentNode,
     *       DependencyRequest)}.
     *   <li>For each child component, calls {@link #visitComponent(BindingGraph)}, updating the
     *       traversal state.
     * </ol>
     *
     * @param graph the currently visited graph
     */
    private void visitComponent(BindingGraph graph, ComponentNode parentComponent) {
      bindingGraphPath.addLast(graph);
      ComponentPath graphPath =
          ComponentPath.create(
              bindingGraphPath.stream()
                  .map(BindingGraph::componentTypeElement)
                  .collect(toImmutableList()));
      componentPaths.addLast(graphPath);
      ComponentNode currentComponent =
          ComponentNodeImpl.create(componentPath(), graph.componentDescriptor());

      network.addNode(currentComponent);

      for (ComponentMethodDescriptor entryPointMethod :
          graph.componentDescriptor().entryPointMethods()) {
        visitEntryPoint(currentComponent, entryPointMethod.dependencyRequest().get());
      }

      for (ResolvedBindings resolvedBindings : graph.resolvedBindings()) {
        for (BindingNode binding : bindingNodes(resolvedBindings)) {
          network.addNode(binding);
          for (DependencyRequest dependencyRequest : binding.dependencies()) {
            addDependencyEdges(binding, dependencyRequest);
          }
          if (binding.kind().equals(SUBCOMPONENT_CREATOR)
              && binding.componentPath().equals(currentComponent.componentPath())) {
            network.addEdge(
                binding,
                subcomponentNode(binding.key().type(), graph),
                new SubcomponentCreatorBindingEdgeImpl(
                    resolvedBindings.subcomponentDeclarations()));
          }
        }
      }

      if (bindingGraphPath.size() > 1) {
        BindingGraph parent = Iterators.get(bindingGraphPath.descendingIterator(), 1);
        parent
            .componentDescriptor()
            .getFactoryMethodForChildComponent(graph.componentDescriptor())
            .ifPresent(
                childFactoryMethod ->
                    visitSubcomponentFactoryMethod(
                        parentComponent, currentComponent, childFactoryMethod.methodElement()));<commit_msg>Improvements to Dagger BindingGraphConverter performance.<commit_after>/*
 * Copyright (C) 2018 The Dagger Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dagger.internal.codegen.binding;

import static com.google.auto.common.MoreTypes.asTypeElement;
import static com.google.common.base.Verify.verify;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.extension.DaggerGraphs.unreachableNodes;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.Network;
import com.google.common.graph.NetworkBuilder;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.model.BindingGraph.ComponentNode;
import dagger.model.BindingGraph.DependencyEdge;
import dagger.model.BindingGraph.Edge;
import dagger.model.BindingGraph.MissingBinding;
import dagger.model.BindingGraph.Node;
import dagger.model.BindingGraphProxies;
import dagger.model.ComponentPath;
import dagger.model.DependencyRequest;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

/** Converts {@link BindingGraph}s to {@link dagger.model.BindingGraph}s. */
public final class BindingGraphConverter {
  private final BindingDeclarationFormatter bindingDeclarationFormatter;

  @Inject
  BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
    this.bindingDeclarationFormatter = bindingDeclarationFormatter;
  }

  /**
   * Creates the external {@link dagger.model.BindingGraph} representing the given internal {@link
   * BindingGraph}.
   */
  public dagger.model.BindingGraph convert(BindingGraph bindingGraph) {
    MutableNetwork<Node, Edge> network =
        Converter.convert(bindingGraph, bindingDeclarationFormatter);

    // When bindings are copied down into child graphs because they transitively depend on local
    // multibindings or optional bindings, the parent-owned binding is still there. If that
    // parent-owned binding is not reachable from its component, it doesn't need to be in the graph
    // because it will never be used. So remove all nodes that are not reachable from the root
    // component—unless we're converting a full binding graph.
    if (!bindingGraph.isFullBindingGraph()) {
      unreachableNodes(network.asGraph(), rootComponentNode(network)).forEach(network::removeNode);
    }

    return BindingGraphProxies.bindingGraph(network, bindingGraph.isFullBindingGraph());
  }

  // TODO(dpb): Example of BindingGraph logic applied to derived networks.
  private ComponentNode rootComponentNode(Network<Node, Edge> network) {
    return (ComponentNode)
        Iterables.find(
            network.nodes(),
            node -> node instanceof ComponentNode && node.componentPath().atRoot());
  }

  private static final class Converter {
    /**
     * Calls {@link #visitComponent(BindingGraph)} for the root component.
     *
     * @throws IllegalStateException if a traversal is in progress
     */
    private static MutableNetwork<Node, Edge> convert(
        BindingGraph graph, BindingDeclarationFormatter bindingDeclarationFormatter) {
      Converter converter = new Converter(bindingDeclarationFormatter);
      converter.visitRootComponent(graph);
      return converter.network;
    }

    /** The path from the root graph to the currently visited graph. */
    private final Deque<BindingGraph> bindingGraphPath = new ArrayDeque<>();

    /** The {@link ComponentPath} for each component in {@link #bindingGraphPath}. */
    private final Deque<ComponentPath> componentPaths = new ArrayDeque<>();

    private final BindingDeclarationFormatter bindingDeclarationFormatter;
    private final MutableNetwork<Node, Edge> network =
        NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
    private final Set<BindingNode> bindings = new HashSet<>();

    /** Constructs a converter for a root (component, not subcomponent) binding graph. */
    private Converter(BindingDeclarationFormatter bindingDeclarationFormatter) {
      this.bindingDeclarationFormatter = bindingDeclarationFormatter;
    }

    private void visitRootComponent(BindingGraph graph) {
      visitComponent(graph, null);
    }

    /**
     * Called once for each component in a component hierarchy.
     *
     * <p>This implementation does the following:
     *
     * <ol>
     *   <li>If this component is installed in its parent by a subcomponent factory method, calls
     *       {@link #visitSubcomponentFactoryMethod(ComponentNode, ComponentNode,
     *       ExecutableElement)}.
     *   <li>For each entry point in the component, calls {@link #visitEntryPoint(ComponentNode,
     *       DependencyRequest)}.
     *   <li>For each child component, calls {@link #visitComponent(BindingGraph)}, updating the
     *       traversal state.
     * </ol>
     *
     * @param graph the currently visited graph
     */
    private void visitComponent(BindingGraph graph, ComponentNode parentComponent) {
      bindingGraphPath.addLast(graph);
      ComponentPath graphPath =
          ComponentPath.create(
              bindingGraphPath.stream()
                  .map(BindingGraph::componentTypeElement)
                  .collect(toImmutableList()));
      componentPaths.addLast(graphPath);
      ComponentNode currentComponent =
          ComponentNodeImpl.create(componentPath(), graph.componentDescriptor());

      network.addNode(currentComponent);

      for (ComponentMethodDescriptor entryPointMethod :
          graph.componentDescriptor().entryPointMethods()) {
        visitEntryPoint(currentComponent, entryPointMethod.dependencyRequest().get());
      }

      for (ResolvedBindings resolvedBindings : graph.resolvedBindings()) {
        for (BindingNode binding : bindingNodes(resolvedBindings)) {
          if (bindings.add(binding)) {
            network.addNode(binding);
            for (DependencyRequest dependencyRequest : binding.dependencies()) {
              addDependencyEdges(binding, dependencyRequest);
            }
          }
          if (binding.kind().equals(SUBCOMPONENT_CREATOR)
              && binding.componentPath().equals(currentComponent.componentPath())) {
            network.addEdge(
                binding,
                subcomponentNode(binding.key().type(), graph),
                new SubcomponentCreatorBindingEdgeImpl(
                    resolvedBindings.subcomponentDeclarations()));
          }
        }
      }

      if (bindingGraphPath.size() > 1) {
        BindingGraph parent = Iterators.get(bindingGraphPath.descendingIterator(), 1);
        parent
            .componentDescriptor()
            .getFactoryMethodForChildComponent(graph.componentDescriptor())
            .ifPresent(
                childFactoryMethod ->
                    visitSubcomponentFactoryMethod(
                        parentComponent, currentComponent, childFactoryMethod.methodElement()));
{'fraction_non_alphanumeric': 0.08627251966505962, 'fraction_numerical': 0.001268713524486171, 'mean_word_length': 3.6697274881516586, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2768267', 'n_tokens_mistral': 3918, 'n_tokens_neox': 3766, 'n_words': 1039}