Skip to content

Commit

Permalink
(#3) Use NameAllocator for generating type names
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoss committed Jun 21, 2020
1 parent 22ec0f2 commit db7c91d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@
import com.squareup.javapoet.CodeBlock.Builder;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.NameAllocator;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeKind;

/**
Expand All @@ -59,10 +59,15 @@ public final class GeneratedEnvelopeTypeSpec {
*/
private final String name;

/**
* The name allocator.
*/
private final NameAllocator allocator;

/**
* The processing environment.
*/
private ProcessingEnvironment procenv;
private final ProcessingEnvironment procenv;

/**
* Ctor.
Expand All @@ -72,7 +77,12 @@ public final class GeneratedEnvelopeTypeSpec {
*/
public GeneratedEnvelopeTypeSpec(final TypeElement source,
final ProcessingEnvironment procenv) {
this(source, new GeneratedEnvelopeName(source).get(), procenv);
this(
source,
new GeneratedEnvelopeName(source).get(),
procenv,
new NameAllocator()
);
}

/**
Expand All @@ -81,12 +91,17 @@ public GeneratedEnvelopeTypeSpec(final TypeElement source,
* @param source The source interface
* @param name The name for the generated envelope
* @param procenv The processing environment
* @param alloc The allocator of names
* @checkstyle ParameterNumberCheck (10 lines)
*/
public GeneratedEnvelopeTypeSpec(final TypeElement source,
final String name, final ProcessingEnvironment procenv) {
final String name,
final ProcessingEnvironment procenv,
final NameAllocator alloc) {
this.source = source;
this.name = name;
this.procenv = procenv;
this.allocator = alloc;
}

/**
Expand All @@ -96,9 +111,15 @@ public GeneratedEnvelopeTypeSpec(final TypeElement source,
* @throws Exception If fails
*/
public TypeSpec typeSpec() throws Exception {
for (final TypeParameterElement type : this.source.getTypeParameters()) {
this.allocator.newName(type.getSimpleName().toString());
}
for (final TypeParameterElement type : this.methodTypeParameters()) {
this.allocator.newName(type.getSimpleName().toString());
}
final GenerateEnvelope annotation = this.source.getAnnotation(GenerateEnvelope.class);
final TypeName spr = TypeName.get(this.source.asType());
final TypeVariableName type = TypeVariableName.get(this.genericTypeName(), spr);
final TypeVariableName type = TypeVariableName.get(this.allocator.newName("W"), spr);
final TypeName prm;
if (annotation.generic()) {
prm = type;
Expand Down Expand Up @@ -142,22 +163,15 @@ public TypeSpec typeSpec() throws Exception {
}

/**
* Generic type parameter.
* Method type parameters.
*
* @return Type parameter name
* @return Set of types.
*/
private String genericTypeName() {
final Set<String> occupied = Stream.of(
this.source.getTypeParameters()
.stream(),
this.localAndInheritedMethods()
.stream()
.flatMap(x -> x.getTypeParameters().stream())
)
.flatMap(Function.identity())
.map(x -> x.getSimpleName().toString())
private Set<TypeParameterElement> methodTypeParameters() {
return this.localAndInheritedMethods()
.stream()
.flatMap(elem -> elem.getTypeParameters().stream())
.collect(Collectors.toSet());
return this.genericTypeName("W", occupied);
}

/**
Expand All @@ -171,29 +185,6 @@ private Set<ExecutableElement> localAndInheritedMethods() {
);
}

/**
* Generic type parameter.
*
* @param preferred Preferred name
* @param occupied Names already in use
* @return Type parameter name
*/
private String genericTypeName(final String preferred, final Set<String> occupied) {
final String result;
if (occupied.contains(preferred)) {
final char[] chars = preferred.toCharArray();
chars[chars.length - 1] -= 1;
if (chars[chars.length - 1] < 'A') {
result = this.genericTypeName(preferred + preferred, occupied);
} else {
result = this.genericTypeName(String.valueOf(chars), occupied);
}
} else {
result = preferred;
}
return result;
}

/**
* Generated delegating methods.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public void samInterfaceHandlesMultipleCollisionsTwoLetters() {
"import com.github.victornoel.eo.GenerateEnvelope;",
"import java.util.function.Supplier;",
"@GenerateEnvelope(generic = true)",
"public interface Foo<W> { <V> W get(V x); };"
"public interface Foo<W> { <W_> W get(W_ x); };"
)
);
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
Expand All @@ -160,13 +160,13 @@ public void samInterfaceHandlesMultipleCollisionsTwoLetters() {
"import javax.annotation.Generated;",
// @checkstyle LineLengthCheck (1 line)
"@Generated(\"com.github.victornoel.eo.apt.GenerateEnvelopeProcessor\")",
"public abstract class FooEnvelope<W, U extends Foo<W>> implements Foo<W> {",
" protected final U wrapped;",
" public FooEnvelope(U wrapped) {",
"public abstract class FooEnvelope<W, W__ extends Foo<W>> implements Foo<W> {",
" protected final W__ wrapped;",
" public FooEnvelope(W__ wrapped) {",
" this.wrapped = wrapped;",
" }",
" @Override",
" public final <V> W get(V x) { ",
" public final <W_> W get(W_ x) { ",
" return wrapped.get(x);",
" }",
"}"
Expand All @@ -184,7 +184,7 @@ public void samInterfaceHandlesMultipleCollisions() {
"import com.github.victornoel.eo.GenerateEnvelope;",
"import java.util.function.Supplier;",
"@GenerateEnvelope(generic = true)",
"public interface Foo<W> { <V> W get(V x); };"
"public interface Foo<W> { <W_> W get(W_ x); };"
)
);
CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
Expand All @@ -197,13 +197,13 @@ public void samInterfaceHandlesMultipleCollisions() {
"import javax.annotation.Generated;",
// @checkstyle LineLengthCheck (1 line)
"@Generated(\"com.github.victornoel.eo.apt.GenerateEnvelopeProcessor\")",
"public abstract class FooEnvelope<W, U extends Foo<W>> implements Foo<W> {",
" protected final U wrapped;",
" public FooEnvelope(U wrapped) {",
"public abstract class FooEnvelope<W, W__ extends Foo<W>> implements Foo<W> {",
" protected final W__ wrapped;",
" public FooEnvelope(W__ wrapped) {",
" this.wrapped = wrapped;",
" }",
" @Override",
" public final <V> W get(V x) { ",
" public final <W_> W get(W_ x) { ",
" return wrapped.get(x);",
" }",
"}"
Expand Down Expand Up @@ -234,9 +234,9 @@ public void samInterfaceHandlesCollisionOfTypeParameters() {
"import javax.annotation.Generated;",
// @checkstyle LineLengthCheck (1 line)
"@Generated(\"com.github.victornoel.eo.apt.GenerateEnvelopeProcessor\")",
"public abstract class FooEnvelope<W, V extends Foo<W>> implements Foo<W> {",
" protected final V wrapped;",
" public FooEnvelope(V wrapped) {",
"public abstract class FooEnvelope<W, W_ extends Foo<W>> implements Foo<W> {",
" protected final W_ wrapped;",
" public FooEnvelope(W_ wrapped) {",
" this.wrapped = wrapped;",
" }",
" @Override",
Expand Down

0 comments on commit db7c91d

Please sign in to comment.