Skip to content

Commit

Permalink
(victornoel#3) Use Names interface for generation class and type names
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoss committed Jun 28, 2020
1 parent 0846abb commit 240ad77
Showing 1 changed file with 29 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,17 @@

import com.github.victornoel.eo.GenerateEnvelope;
import com.google.auto.common.GeneratedAnnotationSpecs;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.CodeBlock;
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.Supplier;
import java.util.stream.Collectors;
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;

/**
* The generated code of a generated envelope.
Expand All @@ -57,12 +47,12 @@ public final class GeneratedEnvelopeTypeSpec {
/**
* The name for the generated envelope.
*/
private final String name;
private final Names name;

/**
* The name allocator.
* The allocated names.
*/
private final NameAllocator allocator;
private final Names allocated;

/**
* The processing environment.
Expand All @@ -75,13 +65,19 @@ public final class GeneratedEnvelopeTypeSpec {
* @param source The source interface
* @param procenv The processing environment
*/
public GeneratedEnvelopeTypeSpec(final TypeElement source,
final ProcessingEnvironment procenv) {
public GeneratedEnvelopeTypeSpec(
final TypeElement source,
final ProcessingEnvironment procenv
) {
this(
source,
new GeneratedEnvelopeName(source).get(),
new GeneratedEnvelopeName(source),
procenv,
new NameAllocator()
new AllocatedNames(
new NameAllocator(),
source,
new LocalMethods(source, procenv)
)
);
}

Expand All @@ -91,17 +87,19 @@ 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
* @param allocated The allocator of names
* @checkstyle ParameterNumberCheck (10 lines)
*/
public GeneratedEnvelopeTypeSpec(final TypeElement source,
final String name,
public GeneratedEnvelopeTypeSpec(
final TypeElement source,
final Names name,
final ProcessingEnvironment procenv,
final NameAllocator alloc) {
final Names allocated
) {
this.source = source;
this.name = name;
this.procenv = procenv;
this.allocator = alloc;
this.allocated = allocated;
}

/**
Expand All @@ -111,15 +109,14 @@ 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 GenerateEnvelope annotation = this.source.getAnnotation(
GenerateEnvelope.class
);
final TypeName spr = TypeName.get(this.source.asType());
final TypeVariableName type = TypeVariableName.get(this.allocator.newName("W"), spr);
final TypeVariableName type = TypeVariableName.get(
this.allocated.make(),
spr
);
final TypeName prm;
if (annotation.generic()) {
prm = type;
Expand All @@ -133,7 +130,7 @@ public TypeSpec typeSpec() throws Exception {
final ParameterSpec parameter = ParameterSpec
.builder(prm, wrapped)
.build();
final TypeSpec.Builder builder = TypeSpec.classBuilder(this.name)
final TypeSpec.Builder builder = TypeSpec.classBuilder(this.name.make())
.addOriginatingElement(this.source)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addSuperinterface(spr)
Expand All @@ -150,7 +147,7 @@ public TypeSpec typeSpec() throws Exception {
.addStatement("this.$N = $N", field, parameter)
.build()
)
.addMethods(new DelegatingMethods(field).get());
.addMethods(new DelegatingMethods(field, this.procenv, this.source));
if (annotation.generic()) {
builder.addTypeVariable(type);
}
Expand All @@ -161,145 +158,4 @@ public TypeSpec typeSpec() throws Exception {
).ifPresent(builder::addAnnotation);
return builder.build();
}

/**
* Method type parameters.
*
* @return Set of types.
*/
private Set<TypeParameterElement> methodTypeParameters() {
return this.localAndInheritedMethods()
.stream()
.flatMap(elem -> elem.getTypeParameters().stream())
.collect(Collectors.toSet());
}

/**
* Local and inherited methods.
*
* @return Set of methods.
*/
private Set<ExecutableElement> localAndInheritedMethods() {
return MoreElements.getLocalAndInheritedMethods(
this.source, this.procenv.getTypeUtils(), this.procenv.getElementUtils()
);
}

/**
* Generated delegating methods.
*
* @since 1.0.0
*/
private final class DelegatingMethods
implements Supplier<Iterable<MethodSpec>> {

/**
* The methods to delegate.
*/
private final Collection<ExecutableElement> sources;

/**
* The field to delegate to.
*/
private final FieldSpec wrapped;

/**
* Ctor.
*
* @param wrapped The field to delegate to
*/
DelegatingMethods(final FieldSpec wrapped) {
this(
GeneratedEnvelopeTypeSpec.this.localAndInheritedMethods(),
wrapped
);
}

/**
* Ctor.
*
* @param sources The methods to delegate
* @param wrapped The field to delegate to
*/
DelegatingMethods(final Collection<ExecutableElement> sources,
final FieldSpec wrapped) {
this.sources = sources;
this.wrapped = wrapped;
}

@Override
public Iterable<MethodSpec> get() {
return this.sources.stream()
.map(m -> new DelegatingMethod(m, this.wrapped).get())
.collect(Collectors.toList());
}
}

/**
* One generated delegating method.
*
* @since 1.0.0
*/
private final class DelegatingMethod implements Supplier<MethodSpec> {

/**
* The method to delegate.
*/
private final ExecutableElement method;

/**
* The field to delegate to.
*/
private final FieldSpec wrapped;

/**
* Ctor.
*
* @param method The method to delegate
* @param wrapped The field to delegate to
*/
DelegatingMethod(final ExecutableElement method,
final FieldSpec wrapped) {
this.method = method;
this.wrapped = wrapped;
}

@Override
public MethodSpec get() {
return MethodSpec
.overriding(
this.method,
MoreTypes.asDeclared(
GeneratedEnvelopeTypeSpec.this.source.asType()
),
GeneratedEnvelopeTypeSpec.this.procenv.getTypeUtils()
)
.addModifiers(Modifier.FINAL)
.addStatement(this.delegation())
.build();
}

/**
* The actual delegation to the field.
*
* @return The delegation code
*/
private CodeBlock delegation() {
Builder statement = CodeBlock.builder();
if (this.method.getReturnType().getKind() != TypeKind.VOID) {
statement = statement.add("return ");
}
return statement
.add("$N.$N", this.wrapped, this.method.getSimpleName())
.add("(")
.add(this.method
.getParameters()
.stream()
.map(ps -> CodeBlock.of("$N", ParameterSpec.get(ps)))
.collect(CodeBlock.joining(","))
)
.add(")")
.build();
}
}
}

0 comments on commit 240ad77

Please sign in to comment.