Skip to content

Commit

Permalink
Generate unique subcomponent implementation names.
Browse files Browse the repository at this point in the history
When subcomponent simple names conflict, prepend the enclosing types (and then package levels) until a unique simple name is generated. This fixes Github issues square#194, square#236, and square#261.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=108989611
  • Loading branch information
ronshapiro authored and cgruber committed Dec 30, 2015
1 parent 37a4688 commit 0771bf0
Show file tree
Hide file tree
Showing 5 changed files with 497 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ abstract class AbstractComponentWriter {
protected final Set<JavaWriter> javaWriters = new LinkedHashSet<>();
protected final ClassName name;
protected final BindingGraph graph;
protected final ImmutableMap<ComponentDescriptor, String> subcomponentImplNames;
private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>();
private final Map<Binding, InitializationState> contributionInitializationStates =
new HashMap<>();
Expand Down Expand Up @@ -154,13 +155,15 @@ abstract class AbstractComponentWriter {
Key.Factory keyFactory,
Diagnostic.Kind nullableValidationType,
ClassName name,
BindingGraph graph) {
BindingGraph graph,
ImmutableMap<ComponentDescriptor, String> subcomponentImplNames) {
this.types = types;
this.elements = elements;
this.keyFactory = keyFactory;
this.nullableValidationType = nullableValidationType;
this.name = name;
this.graph = graph;
this.subcomponentImplNames = subcomponentImplNames;
}

protected final TypeElement componentDefinitionType() {
Expand Down
16 changes: 16 additions & 0 deletions compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@ public Set<TypeElement> apply(ContributionBinding input) {
.toSet();
}

/**
* Returns the {@link ComponentDescriptor}s for this component and its subcomponents.
*/
ImmutableSet<ComponentDescriptor> componentDescriptors() {
return SUBGRAPH_TRAVERSER
.preOrderTraversal(this)
.transform(
new Function<BindingGraph, ComponentDescriptor>() {
@Override
public ComponentDescriptor apply(BindingGraph graph) {
return graph.componentDescriptor();
}
})
.toSet();
}

ImmutableSet<TypeElement> availableDependencies() {
return new ImmutableSet.Builder<TypeElement>()
.addAll(componentDescriptor().transitiveModuleTypes())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,25 @@
*/
package dagger.internal.codegen;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimaps;
import dagger.internal.codegen.writer.ClassName;
import dagger.internal.codegen.writer.ClassWriter;
import dagger.internal.codegen.writer.JavaWriter;
import dagger.internal.codegen.writer.MethodWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Generated;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
Expand All @@ -35,7 +47,7 @@
/**
* Creates the implementation class for a component.
*/
class ComponentWriter extends AbstractComponentWriter {
final class ComponentWriter extends AbstractComponentWriter {

ComponentWriter(
Types types,
Expand All @@ -44,7 +56,89 @@ class ComponentWriter extends AbstractComponentWriter {
Kind nullableValidationType,
ClassName name,
BindingGraph graph) {
super(types, elements, keyFactory, nullableValidationType, name, graph);
super(
types,
elements,
keyFactory,
nullableValidationType,
name,
graph,
new UniqueSubcomponentNamesGenerator(graph).generate());
}

/**
* Generates a map of unique simple names for all subcomponents, keyed by their {@link
* ComponentDescriptor}.
*/
private static class UniqueSubcomponentNamesGenerator {

private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
private static final Joiner QUALIFIED_NAME_JOINER = Joiner.on('_');

private final BindingGraph graph;
private final ImmutableListMultimap<String, ComponentDescriptor>
componentDescriptorsBySimpleName;
private final ImmutableListMultimap<ComponentDescriptor, String> componentQualifiedNamePieces;

private UniqueSubcomponentNamesGenerator(BindingGraph graph) {
this.graph = graph;
componentDescriptorsBySimpleName =
Multimaps.index(
graph.componentDescriptors(),
new Function<ComponentDescriptor, String>() {
@Override
public String apply(ComponentDescriptor componentDescriptor) {
return componentDescriptor.componentDefinitionType().getSimpleName().toString();
}
});
componentQualifiedNamePieces = qualifiedNames(graph.componentDescriptors());
}

private ImmutableBiMap<ComponentDescriptor, String> generate() {
Map<ComponentDescriptor, String> subcomponentImplSimpleNames = new LinkedHashMap<>();
for (Entry<String, Collection<ComponentDescriptor>> componentEntry :
componentDescriptorsBySimpleName.asMap().entrySet()) {
Collection<ComponentDescriptor> components = componentEntry.getValue();
subcomponentImplSimpleNames.putAll(disambiguateConflictingSimpleNames(components));
}
subcomponentImplSimpleNames.remove(graph.componentDescriptor());
return ImmutableBiMap.copyOf(subcomponentImplSimpleNames);
}

private ImmutableBiMap<ComponentDescriptor, String> disambiguateConflictingSimpleNames(
Collection<ComponentDescriptor> components) {
Map<String, ComponentDescriptor> generatedSimpleNames = new LinkedHashMap<>();
// The ending condition is when there is a unique simple name generated for every element
// in components. The sizes should be equivalent (with one generated name per component).
for (int levels = 0; generatedSimpleNames.size() != components.size(); levels++) {
generatedSimpleNames.clear();
for (ComponentDescriptor component : components) {
List<String> pieces = componentQualifiedNamePieces.get(component);
String simpleName =
QUALIFIED_NAME_JOINER.join(
pieces.subList(Math.max(0, pieces.size() - levels - 1), pieces.size()))
+ "Impl";
ComponentDescriptor conflict = generatedSimpleNames.put(simpleName, component);
if (conflict != null) {
// if the map previously contained an entry for the same simple name, stop early since
// 2+ subcomponent descriptors will have the same simple name
break;
}
}
}
return ImmutableBiMap.copyOf(generatedSimpleNames).inverse();
}

private static ImmutableListMultimap<ComponentDescriptor, String> qualifiedNames(
Iterable<ComponentDescriptor> componentDescriptors) {
ImmutableListMultimap.Builder<ComponentDescriptor, String> builder =
ImmutableListMultimap.builder();
for (ComponentDescriptor component : componentDescriptors) {
Name qualifiedName = component.componentDefinitionType().getQualifiedName();
builder.putAll(component, QUALIFIED_NAME_SPLITTER.split(qualifiedName));
}
return builder.build();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
/**
* Creates the nested implementation class for a subcomponent.
*/
class SubcomponentWriter extends AbstractComponentWriter {
final class SubcomponentWriter extends AbstractComponentWriter {

private AbstractComponentWriter parent;
private ExecutableElement subcomponentFactoryMethod;
Expand All @@ -61,16 +61,18 @@ public SubcomponentWriter(
parent.elements,
parent.keyFactory,
parent.nullableValidationType,
parent.name.nestedClassNamed(subcomponentSimpleName(subgraph)),
subgraph);
subcomponentName(parent, subgraph),
subgraph,
parent.subcomponentImplNames);
this.parent = parent;
this.subcomponentFactoryMethod = subcomponentFactoryMethod;
}

private static String subcomponentSimpleName(BindingGraph subgraph) {
return subgraph.componentDescriptor().componentDefinitionType().getSimpleName() + "Impl";
private static ClassName subcomponentName(AbstractComponentWriter parent, BindingGraph subgraph) {
return parent.name.nestedClassNamed(
parent.subcomponentImplNames.get(subgraph.componentDescriptor()));
}

@Override
protected InitializationState getInitializationState(BindingKey bindingKey) {
InitializationState initializationState = super.getInitializationState(bindingKey);
Expand Down

0 comments on commit 0771bf0

Please sign in to comment.