package org.inferred.freebuilder.processor.util;
import static java.util.Arrays.asList;
import static org.inferred.freebuilder.processor.util.feature.SourceLevel.SOURCE_LEVEL;
import com.google.common.collect.ImmutableList;
import org.inferred.freebuilder.processor.util.feature.JavaxPackage;
import java.util.List;
import javax.lang.model.type.TypeMirror;
public class Excerpts {
private static final class AddingExcerpt extends Excerpt {
private final String fmt;
private final Object[] args;
private AddingExcerpt(String fmt, Object[] args) {
this.args = args;
this.fmt = fmt;
}
@Override
public void addTo(SourceBuilder source) {
source.add(fmt, args);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder()
.append("Excerpts.add(\"")
.append(fmt.replaceAll("[\\\"]", "\\\1"))
.append('"');
for (Object arg : args) {
result.append(", ").append(arg);
}
result.append(")");
return result.toString();
}
@Override
protected void addFields(FieldReceiver fields) {
fields.add("fmt", fmt);
fields.add("args", asList(args));
}
}
public static Excerpt add(final String fmt, final Object... args) {
return new AddingExcerpt(fmt, args);
}
private static final class EmptyExcerpt extends Excerpt {
@Override
public void addTo(SourceBuilder source) {}
@Override
protected void addFields(FieldReceiver fields) {}
}
private static final Excerpt EMPTY = new EmptyExcerpt();
public static Excerpt empty() {
return EMPTY;
}
private static final class ForEachExcerpt extends Excerpt {
private final TypeMirror elementType;
private final String iterable;
private final String method;
private ForEachExcerpt(TypeMirror elementType, String iterable, String method) {
this.elementType = elementType;
this.iterable = iterable;
this.method = method;
}
@Override
public void addTo(SourceBuilder code) {
if (code.feature(SOURCE_LEVEL).hasLambdas()) {
code.addLine("%s.forEach(this::%s);", iterable, method);
} else {
code.addLine("for (%s element : %s) {", elementType, iterable)
.addLine(" %s(element);", method)
.addLine("}");
}
}
@Override
protected void addFields(FieldReceiver fields) {
fields.add("elementType", elementType);
fields.add("iterable", iterable);
fields.add("method", method);
}
}
/**
* Returns an excerpt calling {@code method} with each {@code elementType} element of
* {@code iterable}.
*
* <p>Will be {@code iterable.forEach(this::method);} on Java 8+.
*/
public static Excerpt forEach(TypeMirror elementType, String iterable, String method) {
return new ForEachExcerpt(elementType, iterable, method);
}
private static final class GeneratedAnnotationExcerpt extends Excerpt {
private final Class<?> generator;
GeneratedAnnotationExcerpt(Class<?> generator) {
this.generator = generator;
}
@Override
public void addTo(SourceBuilder code) {
QualifiedName generated = code.feature(JavaxPackage.JAVAX).generated().orNull();
if (generated != null) {
code.addLine("@%s(\"%s\")", generated, generator.getName());
}
}
@Override
protected void addFields(FieldReceiver fields) {
fields.add("generator", generator);
}
}
/**
* Returns an excerpt of the {@link javax.annotation.Generated} annotation, if available,
* with value set to the full name of the {@code generator} class as recommended.
*/
public static Excerpt generated(Class<?> generator) {
return new GeneratedAnnotationExcerpt(generator);
}
private static final class JoiningExcerpt extends Excerpt {
private final String separator;
private final List<?> excerpts;
private JoiningExcerpt(String separator, Iterable<?> excerpts) {
this.separator = separator;
this.excerpts = ImmutableList.copyOf(excerpts);
}
@Override
public void addTo(SourceBuilder source) {
String itemPrefix = "";
for (Object object : excerpts) {
source.add("%s%s", itemPrefix, object);
itemPrefix = separator;
}
}
@Override
protected void addFields(FieldReceiver fields) {
fields.add("separator", separator);
fields.add("excerpts", excerpts);
}
}
public static Object join(final String separator, final Iterable<?> excerpts) {
return new JoiningExcerpt(separator, excerpts);
}
private static final class EqualsExcerpt extends Excerpt {
private final Object a;
private final Object b;
private EqualsExcerpt(Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public void addTo(SourceBuilder source) {
QualifiedName objects = source.feature(SOURCE_LEVEL).javaUtilObjects().orNull();
if (objects != null) {
source.add("%s.equals(%s, %s)", objects, a, b);
} else {
source.add("(%1$s == %2$s || (%1$s != null && %1$s.equals(%2$s)))", a, b);
}
}
@Override
protected void addFields(FieldReceiver fields) {
fields.add("a", a);
fields.add("b", b);
}
}
/** Returns an excerpt equivalent to Java 7's {@code Object.equals(a, b)}. */
public static Object equals(Object a, Object b) {
return new EqualsExcerpt(a, b);
}
private Excerpts() {}
}