mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-19 00:15:04 +00:00
ecj @Builder @Singular support for j.u. sets and maps.
This commit is contained in:
1 parent
d700d54ed6
commit
a05360a8ea
16 files changed
+1810
-483
No files matched your search
@@ -8,7 +8,7 @@ statuses = status
|
||||
aliases = alias
|
||||
alias = !
|
||||
species = !
|
||||
Axes = axis
|
||||
Axes = !
|
||||
-axes = axe
|
||||
sexes = sex
|
||||
Testes = testis
|
||||
|
||||
@@ -143,7 +143,7 @@ public class EclipseHandlerUtil {
|
||||
return getGeneratedBy(node) != null;
|
||||
}
|
||||
|
||||
public static ASTNode setGeneratedBy(ASTNode node, ASTNode source) {
|
||||
public static <T extends ASTNode> T setGeneratedBy(T node, ASTNode source) {
|
||||
ASTNode_generatedBy.set(node, source);
|
||||
return node;
|
||||
}
|
||||
@@ -298,6 +298,10 @@ public class EclipseHandlerUtil {
|
||||
return new SingleTypeReference(typeName, p);
|
||||
}
|
||||
|
||||
public static TypeReference[] copyTypes(TypeReference[] refs) {
|
||||
return copyTypes(refs, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a new array and copies each TypeReference in the source array via
|
||||
* {@link #copyType(TypeReference, ASTNode)}.
|
||||
@@ -312,6 +316,10 @@ public class EclipseHandlerUtil {
|
||||
return outs;
|
||||
}
|
||||
|
||||
public static TypeReference copyType(TypeReference ref) {
|
||||
return copyType(ref, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* You can't share TypeReference objects or subtle errors start happening.
|
||||
* Unfortunately the TypeReference type hierarchy is complicated and there's no clone
|
||||
@@ -336,22 +344,23 @@ public class EclipseHandlerUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeReference typeRef = new ParameterizedQualifiedTypeReference(iRef.tokens, args, iRef.dimensions(), copy(iRef.sourcePositions));
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
if (ref instanceof ArrayQualifiedTypeReference) {
|
||||
ArrayQualifiedTypeReference iRef = (ArrayQualifiedTypeReference) ref;
|
||||
TypeReference typeRef = new ArrayQualifiedTypeReference(iRef.tokens, iRef.dimensions(), copy(iRef.sourcePositions));
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
if (ref instanceof QualifiedTypeReference) {
|
||||
QualifiedTypeReference iRef = (QualifiedTypeReference) ref;
|
||||
TypeReference typeRef = new QualifiedTypeReference(iRef.tokens, copy(iRef.sourcePositions));
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
@@ -368,14 +377,14 @@ public class EclipseHandlerUtil {
|
||||
}
|
||||
|
||||
TypeReference typeRef = new ParameterizedSingleTypeReference(iRef.token, args, iRef.dimensions(), (long)iRef.sourceStart << 32 | iRef.sourceEnd);
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
if (ref instanceof ArrayTypeReference) {
|
||||
ArrayTypeReference iRef = (ArrayTypeReference) ref;
|
||||
TypeReference typeRef = new ArrayTypeReference(iRef.token, iRef.dimensions(), (long)iRef.sourceStart << 32 | iRef.sourceEnd);
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
@@ -386,14 +395,14 @@ public class EclipseHandlerUtil {
|
||||
wildcard.sourceStart = original.sourceStart;
|
||||
wildcard.sourceEnd = original.sourceEnd;
|
||||
if (original.bound != null) wildcard.bound = copyType(original.bound, source);
|
||||
setGeneratedBy(wildcard, source);
|
||||
if (source != null) setGeneratedBy(wildcard, source);
|
||||
return wildcard;
|
||||
}
|
||||
|
||||
if (ref instanceof SingleTypeReference) {
|
||||
SingleTypeReference iRef = (SingleTypeReference) ref;
|
||||
TypeReference typeRef = new SingleTypeReference(iRef.token, (long)iRef.sourceStart << 32 | iRef.sourceEnd);
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
return typeRef;
|
||||
}
|
||||
|
||||
@@ -444,8 +453,12 @@ public class EclipseHandlerUtil {
|
||||
return typeMatches(type, node, ((Annotation)node.get()).type);
|
||||
}
|
||||
|
||||
public static TypeReference cloneSelfType(EclipseNode context) {
|
||||
return cloneSelfType(context, null);
|
||||
}
|
||||
|
||||
public static TypeReference cloneSelfType(EclipseNode context, ASTNode source) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
|
||||
long p = (long)pS << 32 | pE;
|
||||
EclipseNode type = context;
|
||||
TypeReference result = null;
|
||||
@@ -457,7 +470,7 @@ public class EclipseHandlerUtil {
|
||||
int idx = 0;
|
||||
for (TypeParameter param : typeDecl.typeParameters) {
|
||||
TypeReference typeRef = new SingleTypeReference(param.name, (long)param.sourceStart << 32 | param.sourceEnd);
|
||||
setGeneratedBy(typeRef, source);
|
||||
if (source != null) setGeneratedBy(typeRef, source);
|
||||
refs[idx++] = typeRef;
|
||||
}
|
||||
result = new ParameterizedSingleTypeReference(typeDecl.name, refs, 0, p);
|
||||
@@ -465,7 +478,7 @@ public class EclipseHandlerUtil {
|
||||
result = new SingleTypeReference(((TypeDeclaration)type.get()).name, p);
|
||||
}
|
||||
}
|
||||
if (result != null) setGeneratedBy(result, source);
|
||||
if (result != null && source != null) setGeneratedBy(result, source);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -865,7 +878,7 @@ public class EclipseHandlerUtil {
|
||||
}
|
||||
|
||||
static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
|
||||
long p = (long)pS << 32 | pE;
|
||||
|
||||
boolean lookForGetter = lookForGetter(field, fieldAccess);
|
||||
@@ -881,14 +894,17 @@ public class EclipseHandlerUtil {
|
||||
ref.receiver = new SingleNameReference(((TypeDeclaration)containerNode.get()).name, p);
|
||||
} else {
|
||||
Expression smallRef = new FieldReference(field.getName().toCharArray(), p);
|
||||
setGeneratedBy(smallRef, source);
|
||||
if (source != null) setGeneratedBy(smallRef, source);
|
||||
return smallRef;
|
||||
}
|
||||
} else {
|
||||
ref.receiver = new ThisReference(pS, pE);
|
||||
}
|
||||
setGeneratedBy(ref, source);
|
||||
setGeneratedBy(ref.receiver, source);
|
||||
|
||||
if (source != null) {
|
||||
setGeneratedBy(ref, source);
|
||||
setGeneratedBy(ref.receiver, source);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -1489,7 +1505,7 @@ public class EclipseHandlerUtil {
|
||||
* with eclipse versions before 3.7.
|
||||
*/
|
||||
public static IntLiteral makeIntLiteral(char[] token, ASTNode source) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
|
||||
IntLiteral result;
|
||||
try {
|
||||
if (intLiteralConstructor != null) {
|
||||
@@ -1504,7 +1520,8 @@ public class EclipseHandlerUtil {
|
||||
} catch (InstantiationException e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
setGeneratedBy(result, source);
|
||||
|
||||
if (source != null) setGeneratedBy(result, source);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
package lombok.eclipse.handlers;
|
||||
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.SpiLoadUtil;
|
||||
import lombok.core.TypeLibrary;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
public class EclipseSingularsRecipes {
|
||||
private static final EclipseSingularsRecipes INSTANCE = new EclipseSingularsRecipes();
|
||||
private final Map<String, EclipseSingularizer> singularizers = new HashMap<String, EclipseSingularizer>();
|
||||
private final TypeLibrary singularizableTypes = new TypeLibrary();
|
||||
|
||||
private EclipseSingularsRecipes() {
|
||||
try {
|
||||
loadAll(singularizableTypes, singularizers);
|
||||
singularizableTypes.lock();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Lombok's @Singularizable feature is broken due to misconfigured SPI files: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadAll(TypeLibrary library, Map<String, EclipseSingularizer> map) throws IOException {
|
||||
for (EclipseSingularizer handler : SpiLoadUtil.findServices(EclipseSingularizer.class, EclipseSingularizer.class.getClassLoader())) {
|
||||
for (String type : handler.getSupportedTypes()) {
|
||||
EclipseSingularizer existingSingularizer = map.get(type);
|
||||
if (existingSingularizer != null) {
|
||||
EclipseSingularizer toKeep = existingSingularizer.getClass().getName().compareTo(handler.getClass().getName()) > 0 ? handler : existingSingularizer;
|
||||
System.err.println("Multiple singularizers found for type " + type + "; the alphabetically first class is used: " + toKeep.getClass().getName());
|
||||
map.put(type, toKeep);
|
||||
} else {
|
||||
map.put(type, handler);
|
||||
library.addType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static EclipseSingularsRecipes get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public String toQualified(String typeReference) {
|
||||
return singularizableTypes.toQualified(typeReference);
|
||||
}
|
||||
|
||||
public EclipseSingularizer getSingularizer(String fqn) {
|
||||
return singularizers.get(fqn);
|
||||
}
|
||||
|
||||
public static final class SingularData {
|
||||
private final EclipseNode annotation;
|
||||
private final char[] singularName;
|
||||
private final char[] pluralName;
|
||||
private final List<TypeReference> typeArgs;
|
||||
private final String targetFqn;
|
||||
private final EclipseSingularizer singularizer;
|
||||
|
||||
public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer) {
|
||||
this.annotation = annotation;
|
||||
this.singularName = singularName;
|
||||
this.pluralName = pluralName;
|
||||
this.typeArgs = typeArgs;
|
||||
this.targetFqn = targetFqn;
|
||||
this.singularizer = singularizer;
|
||||
}
|
||||
|
||||
public EclipseNode getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public char[] getSingularName() {
|
||||
return singularName;
|
||||
}
|
||||
|
||||
public char[] getPluralName() {
|
||||
return pluralName;
|
||||
}
|
||||
|
||||
public List<TypeReference> getTypeArgs() {
|
||||
return typeArgs;
|
||||
}
|
||||
|
||||
public String getTargetFqn() {
|
||||
return targetFqn;
|
||||
}
|
||||
|
||||
public EclipseSingularizer getSingularizer() {
|
||||
return singularizer;
|
||||
}
|
||||
|
||||
public String getTargetSimpleType() {
|
||||
int idx = targetFqn.lastIndexOf(".");
|
||||
return idx == -1 ? targetFqn : targetFqn.substring(idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class EclipseSingularizer {
|
||||
protected static final long[] NULL_POSS = {0L};
|
||||
public abstract LombokImmutableList<String> getSupportedTypes();
|
||||
|
||||
public abstract java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType);
|
||||
public abstract void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain);
|
||||
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName);
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
return !getClass().getMethod("appendCleaningCode", SingularData.class, EclipseNode.class, List.class).getDeclaringClass().equals(EclipseSingularizer.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void appendCleaningCode(SingularData data, EclipseNode builderType, List<Statement> statements) {
|
||||
}
|
||||
|
||||
// -- Utility methods --
|
||||
|
||||
/**
|
||||
* Adds the requested number of type arguments to the provided type, copying each argument in {@code typeArgs}. If typeArgs is too long, the extra elements are ignored.
|
||||
* If {@code typeArgs} is null or too short, {@code java.lang.Object} will be substituted for each missing type argument.
|
||||
*
|
||||
* @param count The number of type arguments requested.
|
||||
* @param addExtends If {@code true}, all bounds are either '? extends X' or just '?'. If false, the reverse is applied, and '? extends Foo' is converted to Foo, '?' to Object, etc.
|
||||
* @param node Some node in the same AST. Just used to obtain makers and contexts and such.
|
||||
* @param type The type to add generics to.
|
||||
* @param typeArgs the list of type args to clone.
|
||||
* @param source The source annotation that is the root cause of this code generation.
|
||||
*/
|
||||
protected TypeReference addTypeArgs(int count, boolean addExtends, EclipseNode node, TypeReference type, List<TypeReference> typeArgs) {
|
||||
if (count < 0) throw new IllegalArgumentException("count is negative");
|
||||
if (count == 0) return type;
|
||||
List<TypeReference> arguments = new ArrayList<TypeReference>();
|
||||
|
||||
if (typeArgs != null) for (TypeReference orig : typeArgs) {
|
||||
Wildcard wildcard = orig instanceof Wildcard ? (Wildcard) orig : null;
|
||||
if (!addExtends) {
|
||||
if (wildcard != null && (wildcard.kind == Wildcard.UNBOUND || wildcard.kind == Wildcard.SUPER)) {
|
||||
arguments.add(new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS));
|
||||
} else if (wildcard != null && wildcard.kind == Wildcard.EXTENDS) {
|
||||
try {
|
||||
arguments.add(copyType(wildcard.bound));
|
||||
} catch (Exception e) {
|
||||
arguments.add(new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS));
|
||||
}
|
||||
} else {
|
||||
arguments.add(copyType(orig));
|
||||
}
|
||||
} else {
|
||||
if (wildcard != null && (wildcard.kind == Wildcard.UNBOUND || wildcard.kind == Wildcard.SUPER)) {
|
||||
Wildcard w = new Wildcard(Wildcard.UNBOUND);
|
||||
arguments.add(w);
|
||||
} else if (wildcard != null && wildcard.kind == Wildcard.EXTENDS) {
|
||||
arguments.add(copyType(orig));
|
||||
} else {
|
||||
Wildcard w = new Wildcard(Wildcard.EXTENDS);
|
||||
w.bound = copyType(orig);
|
||||
arguments.add(w);
|
||||
}
|
||||
}
|
||||
if (--count == 0) break;
|
||||
}
|
||||
|
||||
while (count-- > 0) {
|
||||
if (addExtends) {
|
||||
arguments.add(new Wildcard(Wildcard.UNBOUND));
|
||||
} else {
|
||||
arguments.add(new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS));
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof SingleTypeReference) {
|
||||
type = new ParameterizedSingleTypeReference(((SingleTypeReference) type).token, arguments.toArray(new TypeReference[arguments.size()]), 0, 0L);
|
||||
} else if (type instanceof QualifiedTypeReference) {
|
||||
QualifiedTypeReference qtr = (QualifiedTypeReference) type;
|
||||
TypeReference[][] trs = new TypeReference[qtr.tokens.length][];
|
||||
trs[qtr.tokens.length - 1] = arguments.toArray(new TypeReference[arguments.size()]);
|
||||
type = new ParameterizedQualifiedTypeReference(((QualifiedTypeReference) type).tokens, trs, 0, NULL_POSS);
|
||||
} else {
|
||||
node.addError("Don't know how to clone-and-parameterize type: " + type);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private static final char[] SIZE_TEXT = new char[] {'s', 'i', 'z', 'e'};
|
||||
|
||||
/** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected Expression getSize(EclipseNode builderType, char[] name, boolean nullGuard) {
|
||||
MessageSend invoke = new MessageSend();
|
||||
ThisReference thisRef = new ThisReference(0, 0);
|
||||
FieldReference thisDotName = new FieldReference(name, 0L);
|
||||
thisDotName.receiver = thisRef;
|
||||
invoke.receiver = thisDotName;
|
||||
invoke.selector = SIZE_TEXT;
|
||||
if (!nullGuard) return invoke;
|
||||
|
||||
ThisReference cdnThisRef = new ThisReference(0, 0);
|
||||
FieldReference cdnThisDotName = new FieldReference(name, 0L);
|
||||
cdnThisDotName.receiver = cdnThisRef;
|
||||
NullLiteral nullLiteral = new NullLiteral(0, 0);
|
||||
EqualExpression isNull = new EqualExpression(cdnThisDotName, nullLiteral, OperatorIds.EQUAL_EQUAL);
|
||||
IntLiteral zeroLiteral = makeIntLiteral(new char[] {'0'}, null);
|
||||
ConditionalExpression conditional = new ConditionalExpression(isNull, zeroLiteral, invoke);
|
||||
return conditional;
|
||||
}
|
||||
|
||||
protected TypeReference cloneParamType(int index, List<TypeReference> typeArgs, EclipseNode builderType) {
|
||||
if (typeArgs != null && typeArgs.size() > index) {
|
||||
TypeReference originalType = typeArgs.get(index);
|
||||
if (originalType instanceof Wildcard) {
|
||||
Wildcard wOriginalType = (Wildcard) originalType;
|
||||
if (wOriginalType.kind == Wildcard.EXTENDS) {
|
||||
try {
|
||||
return copyType(wOriginalType.bound);
|
||||
} catch (Exception e) {
|
||||
// fallthrough
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return copyType(originalType);
|
||||
}
|
||||
}
|
||||
|
||||
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2014 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2015 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -32,49 +32,74 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Annotation;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Assignment;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
|
||||
import lombok.experimental.NonFinal;
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
|
||||
public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray();
|
||||
private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray();
|
||||
|
||||
private static final boolean toBoolean(Object expr, boolean defaultValue) {
|
||||
if (expr == null) return defaultValue;
|
||||
return ((Boolean) expr).booleanValue();
|
||||
}
|
||||
|
||||
private static class BuilderFieldData {
|
||||
TypeReference type;
|
||||
char[] name;
|
||||
SingularData singularData;
|
||||
|
||||
List<EclipseNode> createdFields = new ArrayList<EclipseNode>();
|
||||
}
|
||||
|
||||
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
|
||||
|
||||
@@ -102,21 +127,21 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
EclipseNode parent = annotationNode.up();
|
||||
|
||||
List<TypeReference> typesOfParameters = new ArrayList<TypeReference>();
|
||||
List<char[]> namesOfParameters = new ArrayList<char[]>();
|
||||
List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
|
||||
TypeReference returnType;
|
||||
TypeParameter[] typeParams;
|
||||
TypeReference[] thrownExceptions;
|
||||
char[] nameOfStaticBuilderMethod;
|
||||
EclipseNode tdParent;
|
||||
|
||||
AbstractMethodDeclaration fillParametersFrom = null;
|
||||
EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null;
|
||||
boolean addCleaning = false;
|
||||
|
||||
if (parent.get() instanceof TypeDeclaration) {
|
||||
tdParent = parent;
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
|
||||
List<EclipseNode> fields = new ArrayList<EclipseNode>();
|
||||
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
|
||||
@SuppressWarnings("deprecation")
|
||||
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent));
|
||||
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
|
||||
@@ -125,12 +150,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
// non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves.
|
||||
// Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that.
|
||||
if (fd.initialization != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue;
|
||||
namesOfParameters.add(removePrefixFromField(fieldNode));
|
||||
typesOfParameters.add(fd.type);
|
||||
fields.add(fieldNode);
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
bfd.name = removePrefixFromField(fieldNode);
|
||||
bfd.type = fd.type;
|
||||
bfd.singularData = getSingularData(fieldNode);
|
||||
builderFields.add(bfd);
|
||||
allFields.add(fieldNode);
|
||||
}
|
||||
|
||||
new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, fields, null, SkipIfConstructorExists.I_AM_BUILDER, null,
|
||||
new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, null, SkipIfConstructorExists.I_AM_BUILDER, null,
|
||||
Collections.<Annotation>emptyList(), annotationNode);
|
||||
|
||||
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
|
||||
@@ -147,7 +175,6 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
tdParent = parent.up();
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
fillParametersFrom = cd;
|
||||
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
|
||||
typeParams = td.typeParameters;
|
||||
thrownExceptions = cd.thrownExceptions;
|
||||
@@ -160,7 +187,6 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
annotationNode.addError("@Builder is only supported on types, constructors, and static methods.");
|
||||
return;
|
||||
}
|
||||
fillParametersFrom = md;
|
||||
returnType = copyType(md.returnType, ast);
|
||||
typeParams = md.typeParameters;
|
||||
thrownExceptions = md.thrownExceptions;
|
||||
@@ -200,9 +226,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
if (fillParametersFrom != null) {
|
||||
if (fillParametersFrom.arguments != null) for (Argument a : fillParametersFrom.arguments) {
|
||||
namesOfParameters.add(a.name);
|
||||
typesOfParameters.add(a.type);
|
||||
for (EclipseNode param : fillParametersFrom.down()) {
|
||||
if (param.getKind() != Kind.ARGUMENT) continue;
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
Argument arg = (Argument) param.get();
|
||||
bfd.name = arg.name;
|
||||
bfd.type = arg.type;
|
||||
bfd.singularData = getSingularData(param);
|
||||
builderFields.add(bfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,11 +243,23 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
} else {
|
||||
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
|
||||
}
|
||||
List<EclipseNode> fieldNodes = addFieldsToBuilder(builderType, namesOfParameters, typesOfParameters, ast);
|
||||
List<AbstractMethodDeclaration> newMethods = new ArrayList<AbstractMethodDeclaration>();
|
||||
for (EclipseNode fieldNode : fieldNodes) {
|
||||
MethodDeclaration newMethod = makeSetterMethodForBuilder(builderType, fieldNode, annotationNode, fluent, chain);
|
||||
if (newMethod != null) newMethods.add(newMethod);
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
if (bfd.singularData.getSingularizer().requiresCleaning()) {
|
||||
addCleaning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateBuilderFields(builderType, builderFields);
|
||||
if (addCleaning) {
|
||||
FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1);
|
||||
cleanDecl.declarationSourceEnd = -1;
|
||||
cleanDecl.modifiers = ClassFileConstants.AccPrivate;
|
||||
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
|
||||
injectField(builderType, cleanDecl);
|
||||
}
|
||||
|
||||
if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
|
||||
@@ -226,21 +269,119 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
if (cd != null) injectMethod(builderType, cd);
|
||||
}
|
||||
|
||||
for (AbstractMethodDeclaration newMethod : newMethods) injectMethod(builderType, newMethod);
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain);
|
||||
}
|
||||
|
||||
if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
MethodDeclaration md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, namesOfParameters, builderType, ast, thrownExceptions);
|
||||
MethodDeclaration md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning);
|
||||
if (md != null) injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
|
||||
List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
fieldNodes.addAll(bfd.createdFields);
|
||||
}
|
||||
MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD);
|
||||
if (md != null) injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType));
|
||||
|
||||
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, tdParent, typeParams, ast);
|
||||
if (md != null) injectMethod(tdParent, md);
|
||||
}
|
||||
|
||||
builderType.get().traverse(new SetGeneratedByVisitor(ast), null);
|
||||
}
|
||||
|
||||
private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType) {
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, builderType, statements);
|
||||
}
|
||||
}
|
||||
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0));
|
||||
MethodDeclaration decl =new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
decl.selector = CLEAN_METHOD_NAME;
|
||||
decl.modifiers = ClassFileConstants.AccPrivate;
|
||||
decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
decl.statements = statements.toArray(new Statement[0]);
|
||||
return decl;
|
||||
}
|
||||
|
||||
public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning) {
|
||||
MethodDeclaration out = new MethodDeclaration(
|
||||
((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
Expression notClean = new UnaryExpression(thisUnclean, OperatorIds.NOT);
|
||||
MessageSend invokeClean = new MessageSend();
|
||||
invokeClean.selector = CLEAN_METHOD_NAME;
|
||||
statements.add(new IfStatement(notClean, invokeClean, 0, 0));
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.name);
|
||||
}
|
||||
}
|
||||
|
||||
List<Expression> args = new ArrayList<Expression>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
args.add(new SingleNameReference(bfd.name, 0L));
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
statements.add(new Assignment(thisUnclean, new TrueLiteral(0, 0), 0));
|
||||
}
|
||||
|
||||
out.modifiers = ClassFileConstants.AccPublic;
|
||||
out.selector = name.toCharArray();
|
||||
out.thrownExceptions = copyTypes(thrownExceptions);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.returnType = returnType;
|
||||
|
||||
if (staticName == null) {
|
||||
AllocationExpression allocationStatement = new AllocationExpression();
|
||||
allocationStatement.type = copyType(out.returnType);
|
||||
allocationStatement.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]);
|
||||
statements.add(new ReturnStatement(allocationStatement, 0, 0));
|
||||
} else {
|
||||
MessageSend invoke = new MessageSend();
|
||||
invoke.selector = staticName;
|
||||
invoke.receiver = new SingleNameReference(type.up().getName().toCharArray(), 0);
|
||||
TypeParameter[] tps = ((TypeDeclaration) type.get()).typeParameters;
|
||||
if (tps != null) {
|
||||
TypeReference[] trs = new TypeReference[tps.length];
|
||||
for (int i = 0; i < trs.length; i++) {
|
||||
trs[i] = new SingleTypeReference(tps[i].name, 0);
|
||||
}
|
||||
invoke.typeArguments = trs;
|
||||
}
|
||||
invoke.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]);
|
||||
if (returnType instanceof SingleTypeReference && Arrays.equals(TypeConstants.VOID, ((SingleTypeReference) returnType).token)) {
|
||||
statements.add(invoke);
|
||||
} else {
|
||||
statements.add(new ReturnStatement(invoke, 0, 0));
|
||||
}
|
||||
}
|
||||
out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]);
|
||||
return out;
|
||||
}
|
||||
|
||||
public MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) {
|
||||
@@ -262,92 +403,47 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return out;
|
||||
}
|
||||
|
||||
public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<char[]> fieldNames, EclipseNode type, ASTNode source, TypeReference[] thrownExceptions) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long) pS << 32 | pE;
|
||||
|
||||
MethodDeclaration out = new MethodDeclaration(
|
||||
((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
|
||||
out.modifiers = ClassFileConstants.AccPublic;
|
||||
TypeDeclaration typeDecl = (TypeDeclaration) type.get();
|
||||
out.selector = name.toCharArray();
|
||||
out.thrownExceptions = copyTypes(thrownExceptions, source);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.returnType = returnType;
|
||||
|
||||
List<Expression> assigns = new ArrayList<Expression>();
|
||||
for (char[] fieldName : fieldNames) {
|
||||
SingleNameReference nameRef = new SingleNameReference(fieldName, p);
|
||||
assigns.add(nameRef);
|
||||
public void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields) {
|
||||
int len = builderFields.size();
|
||||
List<EclipseNode> existing = new ArrayList<EclipseNode>();
|
||||
for (EclipseNode child : builderType.down()) {
|
||||
if (child.getKind() == Kind.FIELD) existing.add(child);
|
||||
}
|
||||
|
||||
Statement statement;
|
||||
|
||||
if (staticName == null) {
|
||||
AllocationExpression allocationStatement = new AllocationExpression();
|
||||
allocationStatement.type = copyType(out.returnType, source);
|
||||
allocationStatement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]);
|
||||
statement = new ReturnStatement(allocationStatement, (int)(p >> 32), (int)p);
|
||||
} else {
|
||||
MessageSend invoke = new MessageSend();
|
||||
invoke.selector = staticName;
|
||||
invoke.receiver = new SingleNameReference(type.up().getName().toCharArray(), p);
|
||||
TypeParameter[] tps = ((TypeDeclaration) type.get()).typeParameters;
|
||||
if (tps != null) {
|
||||
TypeReference[] trs = new TypeReference[tps.length];
|
||||
for (int i = 0; i < trs.length; i++) {
|
||||
trs[i] = new SingleTypeReference(tps[i].name, p);
|
||||
}
|
||||
invoke.typeArguments = trs;
|
||||
}
|
||||
invoke.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]);
|
||||
if (returnType instanceof SingleTypeReference && Arrays.equals(TypeConstants.VOID, ((SingleTypeReference) returnType).token)) {
|
||||
statement = invoke;
|
||||
} else {
|
||||
statement = new ReturnStatement(invoke, (int)(p >> 32), (int)p);
|
||||
}
|
||||
}
|
||||
|
||||
out.statements = new Statement[] { statement };
|
||||
|
||||
out.traverse(new SetGeneratedByVisitor(source), typeDecl.scope);
|
||||
return out;
|
||||
}
|
||||
|
||||
public List<EclipseNode> addFieldsToBuilder(EclipseNode builderType, List<char[]> namesOfParameters, List<TypeReference> typesOfParameters, ASTNode source) {
|
||||
int len = namesOfParameters.size();
|
||||
TypeDeclaration td = (TypeDeclaration) builderType.get();
|
||||
FieldDeclaration[] existing = td.fields;
|
||||
if (existing == null) existing = new FieldDeclaration[0];
|
||||
|
||||
List<EclipseNode> out = new ArrayList<EclipseNode>();
|
||||
|
||||
top:
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
char[] name = namesOfParameters.get(i);
|
||||
for (FieldDeclaration exists : existing) {
|
||||
if (Arrays.equals(exists.name, name)) {
|
||||
out.add(builderType.getNodeFor(exists));
|
||||
continue top;
|
||||
BuilderFieldData bfd = builderFields.get(i);
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType));
|
||||
} else {
|
||||
for (EclipseNode exists : existing) {
|
||||
char[] n = ((FieldDeclaration) exists.get()).name;
|
||||
if (Arrays.equals(n, bfd.name)) {
|
||||
bfd.createdFields.add(exists);
|
||||
continue top;
|
||||
}
|
||||
}
|
||||
|
||||
FieldDeclaration fd = new FieldDeclaration(bfd.name, 0, 0);
|
||||
fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
fd.modifiers = ClassFileConstants.AccPrivate;
|
||||
fd.type = copyType(bfd.type);
|
||||
bfd.createdFields.add(injectField(builderType, fd));
|
||||
}
|
||||
TypeReference fieldReference = copyType(typesOfParameters.get(i), source);
|
||||
FieldDeclaration newField = new FieldDeclaration(name, 0, 0);
|
||||
newField.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
newField.modifiers = ClassFileConstants.AccPrivate;
|
||||
newField.type = fieldReference;
|
||||
out.add(injectField(builderType, newField));
|
||||
}
|
||||
|
||||
Collections.reverse(out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static final AbstractMethodDeclaration[] EMPTY = {};
|
||||
|
||||
public MethodDeclaration makeSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, EclipseNode sourceNode, boolean fluent, boolean chain) {
|
||||
public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain) {
|
||||
if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) {
|
||||
makeSimpleSetterMethodForBuilder(builderType, bfd.createdFields.get(0), sourceNode, fluent, chain);
|
||||
} else {
|
||||
bfd.singularData.getSingularizer().generateMethods(bfd.singularData, builderType, fluent, chain);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, EclipseNode sourceNode, boolean fluent, boolean chain) {
|
||||
TypeDeclaration td = (TypeDeclaration) builderType.get();
|
||||
AbstractMethodDeclaration[] existing = td.methods;
|
||||
if (existing == null) existing = EMPTY;
|
||||
@@ -358,14 +454,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!(existing[i] instanceof MethodDeclaration)) continue;
|
||||
char[] existingName = existing[i].selector;
|
||||
if (Arrays.equals(name, existingName)) return null;
|
||||
if (Arrays.equals(name, existingName)) return;
|
||||
}
|
||||
|
||||
boolean isBoolean = isBoolean(fd.type);
|
||||
String setterName = fluent ? fieldNode.getName() : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean);
|
||||
|
||||
return HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic,
|
||||
MethodDeclaration setter = HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic,
|
||||
sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
|
||||
injectMethod(builderType, setter);
|
||||
}
|
||||
|
||||
public EclipseNode findInnerClass(EclipseNode parent, String name) {
|
||||
@@ -388,4 +485,59 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the explicitly requested singular annotation on this node (field
|
||||
* or parameter), or null if there's no {@code @Singular} annotation on it.
|
||||
*
|
||||
* @param node The node (field or method param) to inspect for its name and potential {@code @Singular} annotation.
|
||||
*/
|
||||
private SingularData getSingularData(EclipseNode node) {
|
||||
for (EclipseNode child : node.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Singular.class, child)) {
|
||||
char[] pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((AbstractVariableDeclaration) node.get()).name;
|
||||
AnnotationValues<Singular> ann = createAnnotation(Singular.class, child);
|
||||
String explicitSingular = ann.getInstance().value();
|
||||
if (explicitSingular.isEmpty()) {
|
||||
explicitSingular = autoSingularize(node.getName());
|
||||
if (explicitSingular == null) {
|
||||
node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))");
|
||||
explicitSingular = pluralName.toString();
|
||||
}
|
||||
}
|
||||
char[] singularName = explicitSingular.toCharArray();
|
||||
|
||||
TypeReference type = ((AbstractVariableDeclaration) node.get()).type;
|
||||
TypeReference[] typeArgs = null;
|
||||
String typeName;
|
||||
if (type instanceof ParameterizedSingleTypeReference) {
|
||||
typeArgs = ((ParameterizedSingleTypeReference) type).typeArguments;
|
||||
typeName = new String(((ParameterizedSingleTypeReference) type).token);
|
||||
} else if (type instanceof ParameterizedQualifiedTypeReference) {
|
||||
TypeReference[][] tr = ((ParameterizedQualifiedTypeReference) type).typeArguments;
|
||||
if (tr != null) typeArgs = tr[tr.length - 1];
|
||||
char[][] tokens = ((ParameterizedQualifiedTypeReference) type).tokens;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (i > 0) sb.append(".");
|
||||
sb.append(tokens[i]);
|
||||
}
|
||||
typeName = sb.toString();
|
||||
} else {
|
||||
typeName = type.toString();
|
||||
}
|
||||
|
||||
String targetFqn = EclipseSingularsRecipes.get().toQualified(typeName);
|
||||
EclipseSingularizer singularizer = EclipseSingularsRecipes.get().getSingularizer(targetFqn);
|
||||
if (singularizer == null) {
|
||||
node.addError("Lombok does not know how to create the singular-form builder methods for type '" + typeName + "'; they won't be generated.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.eclipse.handlers.singulars;
|
||||
|
||||
import static lombok.eclipse.Eclipse.*;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Block;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
|
||||
@ProviderFor(EclipseSingularizer.class)
|
||||
public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer {
|
||||
@Override public LombokImmutableList<String> getSupportedTypes() {
|
||||
return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap");
|
||||
}
|
||||
|
||||
@Override public java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) {
|
||||
char[] keyName = (new String(data.getPluralName()) + "$key").toCharArray();
|
||||
char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
|
||||
FieldDeclaration buildKeyField; {
|
||||
TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
type = addTypeArgs(1, false, builderType, type, data.getTypeArgs());
|
||||
buildKeyField = new FieldDeclaration(keyName, 0, -1);
|
||||
buildKeyField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
buildKeyField.modifiers = ClassFileConstants.AccPrivate;
|
||||
buildKeyField.declarationSourceEnd = -1;
|
||||
buildKeyField.type = type;
|
||||
}
|
||||
FieldDeclaration buildValueField; {
|
||||
TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
List<TypeReference> tArgs = data.getTypeArgs();
|
||||
if (tArgs != null && tArgs.size() > 1) tArgs = Collections.singletonList(tArgs.get(1));
|
||||
else tArgs = Collections.emptyList();
|
||||
type = addTypeArgs(1, false, builderType, type, tArgs);
|
||||
buildValueField = new FieldDeclaration(valueName, 0, -1);
|
||||
buildValueField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
buildValueField.modifiers = ClassFileConstants.AccPrivate;
|
||||
buildValueField.declarationSourceEnd = -1;
|
||||
buildValueField.type = type;
|
||||
}
|
||||
EclipseNode valueFieldNode = injectField(builderType, buildValueField);
|
||||
EclipseNode keyFieldNode = injectField(builderType, buildKeyField);
|
||||
return Arrays.asList(keyFieldNode, valueFieldNode);
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain) {
|
||||
TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateSingularMethod(returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generatePluralMethod(returnType, returnStatement, data, builderType, fluent);
|
||||
}
|
||||
|
||||
private void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
|
||||
MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
md.modifiers = ClassFileConstants.AccPublic;
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
statements.add(createConstructBuilderVarIfNeeded(data, builderType, true));
|
||||
|
||||
String sN = new String(data.getSingularName());
|
||||
String pN = new String(data.getPluralName());
|
||||
char[] keyParamName = (sN + "Key").toCharArray();
|
||||
char[] valueParamName = (sN + "Value").toCharArray();
|
||||
char[] keyFieldName = (pN + "$key").toCharArray();
|
||||
char[] valueFieldName = (pN + "$value").toCharArray();
|
||||
|
||||
/* this.pluralname$key.add(singularnameKey); */ {
|
||||
FieldReference thisDotKeyField = new FieldReference(keyFieldName, 0L);
|
||||
thisDotKeyField.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotKeyFieldDotAdd = new MessageSend();
|
||||
thisDotKeyFieldDotAdd.arguments = new Expression[] {new SingleNameReference(keyParamName, 0L)};
|
||||
thisDotKeyFieldDotAdd.receiver = thisDotKeyField;
|
||||
thisDotKeyFieldDotAdd.selector = "add".toCharArray();
|
||||
statements.add(thisDotKeyFieldDotAdd);
|
||||
}
|
||||
|
||||
/* this.pluralname$value.add(singularnameValue); */ {
|
||||
FieldReference thisDotValueField = new FieldReference(valueFieldName, 0L);
|
||||
thisDotValueField.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotValueFieldDotAdd = new MessageSend();
|
||||
thisDotValueFieldDotAdd.arguments = new Expression[] {new SingleNameReference(valueParamName, 0L)};
|
||||
thisDotValueFieldDotAdd.receiver = thisDotValueField;
|
||||
thisDotValueFieldDotAdd.selector = "add".toCharArray();
|
||||
statements.add(thisDotValueFieldDotAdd);
|
||||
}
|
||||
if (returnStatement != null) statements.add(returnStatement);
|
||||
|
||||
md.statements = statements.toArray(new Statement[statements.size()]);
|
||||
TypeReference keyParamType = cloneParamType(0, data.getTypeArgs(), builderType);
|
||||
Argument keyParam = new Argument(keyParamName, 0, keyParamType, 0);
|
||||
TypeReference valueParamType = cloneParamType(1, data.getTypeArgs(), builderType);
|
||||
Argument valueParam = new Argument(valueParamName, 0, valueParamType, 0);
|
||||
md.arguments = new Argument[] {keyParam, valueParam};
|
||||
md.returnType = returnType;
|
||||
md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("put", new String(data.getSingularName())).toCharArray();
|
||||
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
private void generatePluralMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
|
||||
MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
md.modifiers = ClassFileConstants.AccPublic;
|
||||
|
||||
String pN = new String(data.getPluralName());
|
||||
char[] keyFieldName = (pN + "$key").toCharArray();
|
||||
char[] valueFieldName = (pN + "$value").toCharArray();
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
statements.add(createConstructBuilderVarIfNeeded(data, builderType, true));
|
||||
|
||||
char[] entryName = "$lombokEntry".toCharArray();
|
||||
|
||||
TypeReference forEachType = new QualifiedTypeReference(JAVA_UTIL_MAP_ENTRY, NULL_POSS);
|
||||
forEachType = addTypeArgs(2, true, builderType, forEachType, data.getTypeArgs());
|
||||
|
||||
MessageSend keyArg = new MessageSend();
|
||||
keyArg.receiver = new SingleNameReference(entryName, 0L);
|
||||
keyArg.selector = "getKey".toCharArray();
|
||||
MessageSend addKey = new MessageSend();
|
||||
FieldReference thisDotKeyField = new FieldReference(keyFieldName, 0L);
|
||||
thisDotKeyField.receiver = new ThisReference(0, 0);
|
||||
addKey.receiver = thisDotKeyField;
|
||||
addKey.selector = new char[] {'a', 'd', 'd'};
|
||||
addKey.arguments = new Expression[] {keyArg};
|
||||
|
||||
MessageSend valueArg = new MessageSend();
|
||||
valueArg.receiver = new SingleNameReference(entryName, 0L);
|
||||
valueArg.selector = "getValue".toCharArray();
|
||||
MessageSend addValue = new MessageSend();
|
||||
FieldReference thisDotValueField = new FieldReference(valueFieldName, 0L);
|
||||
thisDotValueField.receiver = new ThisReference(0, 0);
|
||||
addValue.receiver = thisDotValueField;
|
||||
addValue.selector = new char[] {'a', 'd', 'd'};
|
||||
addValue.arguments = new Expression[] {valueArg};
|
||||
|
||||
LocalDeclaration elementVariable = new LocalDeclaration(entryName, 0, 0);
|
||||
elementVariable.type = forEachType;
|
||||
ForeachStatement forEach = new ForeachStatement(elementVariable, 0);
|
||||
MessageSend invokeEntrySet = new MessageSend();
|
||||
invokeEntrySet.selector = new char[] { 'e', 'n', 't', 'r', 'y', 'S', 'e', 't'};
|
||||
invokeEntrySet.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
forEach.collection = invokeEntrySet;
|
||||
Block forEachContent = new Block(0);
|
||||
forEachContent.statements = new Statement[] {addKey, addValue};
|
||||
forEach.action = forEachContent;
|
||||
statements.add(forEach);
|
||||
if (returnStatement != null) statements.add(returnStatement);
|
||||
|
||||
md.statements = statements.toArray(new Statement[statements.size()]);
|
||||
|
||||
TypeReference paramType = new QualifiedTypeReference(JAVA_UTIL_MAP, NULL_POSS);
|
||||
paramType = addTypeArgs(2, true, builderType, paramType, data.getTypeArgs());
|
||||
Argument param = new Argument(data.getPluralName(), 0, paramType, 0);
|
||||
md.arguments = new Argument[] {param};
|
||||
md.returnType = returnType;
|
||||
md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName("putAll", new String(data.getPluralName())).toCharArray();
|
||||
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
if (data.getTargetFqn().equals("java.util.Map")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap"));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.eclipse.handlers.singulars;
|
||||
|
||||
import static lombok.eclipse.Eclipse.*;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@ProviderFor(EclipseSingularizer.class)
|
||||
public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilSingularizer {
|
||||
@Override public LombokImmutableList<String> getSupportedTypes() {
|
||||
return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
|
||||
}
|
||||
|
||||
@Override public List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) {
|
||||
TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
type = addTypeArgs(1, false, builderType, type, data.getTypeArgs());
|
||||
|
||||
FieldDeclaration buildField = new FieldDeclaration(data.getPluralName(), 0, -1);
|
||||
buildField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
buildField.modifiers = ClassFileConstants.AccPrivate;
|
||||
buildField.declarationSourceEnd = -1;
|
||||
buildField.type = type;
|
||||
return Collections.singletonList(injectField(builderType, buildField));
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain) {
|
||||
TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateSingularMethod(returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generatePluralMethod(returnType, returnStatement, data, builderType, fluent);
|
||||
}
|
||||
|
||||
private void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
|
||||
MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
md.modifiers = ClassFileConstants.AccPublic;
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
statements.add(createConstructBuilderVarIfNeeded(data, builderType, false));
|
||||
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotFieldDotAdd = new MessageSend();
|
||||
thisDotFieldDotAdd.arguments = new Expression[] {new SingleNameReference(data.getSingularName(), 0L)};
|
||||
thisDotFieldDotAdd.receiver = thisDotField;
|
||||
thisDotFieldDotAdd.selector = "add".toCharArray();
|
||||
statements.add(thisDotFieldDotAdd);
|
||||
if (returnStatement != null) statements.add(returnStatement);
|
||||
|
||||
md.statements = statements.toArray(new Statement[statements.size()]);
|
||||
TypeReference paramType = cloneParamType(0, data.getTypeArgs(), builderType);
|
||||
Argument param = new Argument(data.getSingularName(), 0, paramType, 0);
|
||||
md.arguments = new Argument[] {param};
|
||||
md.returnType = returnType;
|
||||
md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray();
|
||||
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
private void generatePluralMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
|
||||
MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
md.modifiers = ClassFileConstants.AccPublic;
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
statements.add(createConstructBuilderVarIfNeeded(data, builderType, false));
|
||||
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotFieldDotAddAll = new MessageSend();
|
||||
thisDotFieldDotAddAll.arguments = new Expression[] {new SingleNameReference(data.getPluralName(), 0L)};
|
||||
thisDotFieldDotAddAll.receiver = thisDotField;
|
||||
thisDotFieldDotAddAll.selector = "addAll".toCharArray();
|
||||
statements.add(thisDotFieldDotAddAll);
|
||||
if (returnStatement != null) statements.add(returnStatement);
|
||||
|
||||
md.statements = statements.toArray(new Statement[statements.size()]);
|
||||
|
||||
TypeReference paramType = new QualifiedTypeReference(TypeConstants.JAVA_UTIL_COLLECTION, NULL_POSS);
|
||||
paramType = addTypeArgs(1, true, builderType, paramType, data.getTypeArgs());
|
||||
Argument param = new Argument(data.getPluralName(), 0, paramType, 0);
|
||||
md.arguments = new Argument[] {param};
|
||||
md.returnType = returnType;
|
||||
md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray();
|
||||
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
if (data.getTargetFqn().equals("java.util.Set")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet"));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.eclipse.handlers.singulars;
|
||||
|
||||
import static lombok.eclipse.Eclipse.*;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Assignment;
|
||||
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Block;
|
||||
import org.eclipse.jdt.internal.compiler.ast.BreakStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ForStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
|
||||
abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
protected static final char[][] JAVA_UTIL_ARRAYLIST = {
|
||||
{'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'A', 'r', 'r', 'a', 'y', 'L', 'i', 's', 't'}
|
||||
};
|
||||
|
||||
protected static final char[][] JAVA_UTIL_MAP = {
|
||||
{'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'}
|
||||
};
|
||||
|
||||
protected static final char[][] JAVA_UTIL_MAP_ENTRY = {
|
||||
{'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'}, {'E', 'n', 't', 'r', 'y'}
|
||||
};
|
||||
|
||||
protected static final char[][] JAVA_UTIL_COLLECTIONS = {
|
||||
{'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 's'}
|
||||
};
|
||||
|
||||
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) {
|
||||
List<Statement> switchContents = new ArrayList<Statement>();
|
||||
char[] keyName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
if (emptyCollectionMethod != null) { // case 0: (empty); break;
|
||||
switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'0'}, null), 0, 0));
|
||||
|
||||
/* pluralName = java.util.Collections.emptyCollectionMethod(); */ {
|
||||
MessageSend invoke = new MessageSend();
|
||||
invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
|
||||
invoke.selector = emptyCollectionMethod.toCharArray();
|
||||
switchContents.add(new Assignment(new SingleNameReference(data.getPluralName(), 0), invoke, 0));
|
||||
}
|
||||
|
||||
switchContents.add(new BreakStatement(null, 0, 0));
|
||||
}
|
||||
|
||||
if (singletonCollectionMethod != null) { // case 1: (singleton); break;
|
||||
switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'1'}, null), 0, 0));
|
||||
/* !mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName.get(0));
|
||||
mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName$key.get(0), this.pluralName$value.get(0)); */ {
|
||||
FieldReference thisDotKey = new FieldReference(keyName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotKeyGet0 = new MessageSend();
|
||||
thisDotKeyGet0.receiver = thisDotKey;
|
||||
thisDotKeyGet0.selector = new char[] {'g', 'e', 't'};
|
||||
thisDotKeyGet0.arguments = new Expression[] {makeIntLiteral(new char[] {'0'}, null)};
|
||||
|
||||
Expression[] args;
|
||||
if (mapMode) {
|
||||
char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
|
||||
FieldReference thisDotValue = new FieldReference(valueName, 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
MessageSend thisDotValueGet0 = new MessageSend();
|
||||
thisDotValueGet0.receiver = thisDotValue;
|
||||
thisDotValueGet0.selector = new char[] {'g', 'e', 't'};
|
||||
thisDotValueGet0.arguments = new Expression[] {makeIntLiteral(new char[] {'0'}, null)};
|
||||
args = new Expression[] {thisDotKeyGet0, thisDotValueGet0};
|
||||
} else {
|
||||
args = new Expression[] {thisDotKeyGet0};
|
||||
}
|
||||
|
||||
MessageSend invoke = new MessageSend();
|
||||
invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
|
||||
invoke.selector = singletonCollectionMethod.toCharArray();
|
||||
invoke.arguments = args;
|
||||
switchContents.add(new Assignment(new SingleNameReference(data.getPluralName(), 0), invoke, 0));
|
||||
}
|
||||
switchContents.add(new BreakStatement(null, 0, 0));
|
||||
}
|
||||
|
||||
{ // default:
|
||||
switchContents.add(new CaseStatement(null, 0, 0));
|
||||
switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType));
|
||||
}
|
||||
|
||||
SwitchStatement switchStat = new SwitchStatement();
|
||||
switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
|
||||
switchStat.expression = getSize(builderType, keyName, true);
|
||||
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
LocalDeclaration varDefStat = new LocalDeclaration(data.getPluralName(), 0, 0);
|
||||
varDefStat.type = localShadowerType;
|
||||
return Arrays.asList(varDefStat, switchStat);
|
||||
}
|
||||
|
||||
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType) {
|
||||
char[] varName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
Statement createStat; {
|
||||
// pluralName = new java.util.TargetType(initialCap);
|
||||
Expression[] constructorArgs = null;
|
||||
if (addInitialCapacityArg) {
|
||||
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
|
||||
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
|
||||
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
|
||||
FieldReference integerMaxValue = new FieldReference("MAX_VALUE".toCharArray(), 0L);
|
||||
integerMaxValue.receiver = new QualifiedNameReference(TypeConstants.JAVA_LANG_INTEGER, NULL_POSS, 0, 0);
|
||||
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] {'1'}, null), getSize(builderType, varName, nullGuard), OperatorIds.PLUS);
|
||||
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral(new char[] {'3'}, null), OperatorIds.MINUS);
|
||||
Expression sizeFormulaRight = new BinaryExpression(sizeFormulaRightLeft, makeIntLiteral(new char[] {'3'}, null), OperatorIds.DIVIDE);
|
||||
Expression sizeFormula = new BinaryExpression(sizeFormulaLeft, sizeFormulaRight, OperatorIds.PLUS);
|
||||
Expression cond = new ConditionalExpression(lessThanCutoff, sizeFormula, integerMaxValue);
|
||||
constructorArgs = new Expression[] {cond};
|
||||
}
|
||||
|
||||
TypeReference targetTypeRef = new QualifiedTypeReference(new char[][] {TypeConstants.JAVA, TypeConstants.UTIL, targetType.toCharArray()}, NULL_POSS);
|
||||
targetTypeRef = addTypeArgs(mapMode ? 2 : 1, false, builderType, targetTypeRef, data.getTypeArgs());
|
||||
AllocationExpression constructorCall = new AllocationExpression();
|
||||
constructorCall.type = targetTypeRef;
|
||||
constructorCall.arguments = constructorArgs;
|
||||
|
||||
if (defineVar) {
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
LocalDeclaration localShadowerDecl = new LocalDeclaration(data.getPluralName(), 0, 0);
|
||||
localShadowerDecl.type = localShadowerType;
|
||||
localShadowerDecl.initialization = constructorCall;
|
||||
createStat = localShadowerDecl;
|
||||
} else {
|
||||
createStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), constructorCall, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Statement fillStat; {
|
||||
if (mapMode) {
|
||||
// for (int $i = 0; $i < this.pluralname$key.size(); i++) pluralname.put(this.pluralname$key.get($i), this.pluralname$value.get($i));
|
||||
char[] iVar = new char[] {'$', 'i'};
|
||||
MessageSend pluralnameDotPut = new MessageSend();
|
||||
pluralnameDotPut.selector = new char[] {'p', 'u', 't'};
|
||||
pluralnameDotPut.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotKey = new FieldReference(varName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
FieldReference thisDotValue = new FieldReference((new String(data.getPluralName()) + "$value").toCharArray(), 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
MessageSend keyArg = new MessageSend();
|
||||
keyArg.receiver = thisDotKey;
|
||||
keyArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
|
||||
keyArg.selector = new char[] {'g', 'e', 't'};
|
||||
MessageSend valueArg = new MessageSend();
|
||||
valueArg.receiver = thisDotValue;
|
||||
valueArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
|
||||
valueArg.selector = new char[] {'g', 'e', 't'};
|
||||
pluralnameDotPut.arguments = new Expression[] {keyArg, valueArg};
|
||||
|
||||
LocalDeclaration forInit = new LocalDeclaration(iVar, 0, 0);
|
||||
forInit.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
forInit.initialization = makeIntLiteral(new char[] {'0'}, null);
|
||||
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard), OperatorIds.LESS);
|
||||
Expression incrementExpr = new PostfixExpression(new SingleNameReference(iVar, 0L), IntLiteral.One, OperatorIds.PLUS, 0);
|
||||
fillStat = new ForStatement(new Statement[] {forInit}, checkExpr, new Statement[] {incrementExpr}, pluralnameDotPut, true, 0, 0);
|
||||
} else {
|
||||
// pluralname.addAll(this.pluralname);
|
||||
MessageSend pluralnameDotAddAll = new MessageSend();
|
||||
pluralnameDotAddAll.selector = new char[] {'a', 'd', 'd', 'A', 'l', 'l'};
|
||||
pluralnameDotAddAll.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotPluralname = new FieldReference(varName, 0L);
|
||||
thisDotPluralname.receiver = new ThisReference(0, 0);
|
||||
pluralnameDotAddAll.arguments = new Expression[] {thisDotPluralname};
|
||||
fillStat = pluralnameDotAddAll;
|
||||
}
|
||||
|
||||
if (nullGuard) {
|
||||
FieldReference thisDotField = new FieldReference(varName, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
|
||||
fillStat = new IfStatement(cond, fillStat, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Statement unmodifiableStat; {
|
||||
// pluralname = Collections.unmodifiableInterfaceType(pluralname);
|
||||
Expression arg = new SingleNameReference(data.getPluralName(), 0L);
|
||||
MessageSend invoke = new MessageSend();
|
||||
invoke.arguments = new Expression[] {arg};
|
||||
invoke.selector = ("unmodifiable" + data.getTargetSimpleType()).toCharArray();
|
||||
invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
|
||||
unmodifiableStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), invoke, 0);
|
||||
}
|
||||
|
||||
return Arrays.asList(createStat, fillStat, unmodifiableStat);
|
||||
}
|
||||
|
||||
protected Statement createConstructBuilderVarIfNeeded(SingularData data, EclipseNode builderType, boolean mapMode) {
|
||||
char[] v1Name, v2Name;
|
||||
if (mapMode) {
|
||||
String n = new String(data.getPluralName());
|
||||
v1Name = (n + "$key").toCharArray();
|
||||
v2Name = (n + "$value").toCharArray();
|
||||
} else {
|
||||
v1Name = data.getPluralName();
|
||||
v2Name = null;
|
||||
}
|
||||
|
||||
FieldReference thisDotField = new FieldReference(v1Name, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
|
||||
|
||||
thisDotField = new FieldReference(v1Name, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
TypeReference v1Type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
v1Type = addTypeArgs(1, false, builderType, v1Type, data.getTypeArgs());
|
||||
AllocationExpression constructArrayList = new AllocationExpression();
|
||||
constructArrayList.type = v1Type;
|
||||
Assignment initV1 = new Assignment(thisDotField, constructArrayList, 0);
|
||||
Statement thenPart;
|
||||
if (mapMode) {
|
||||
thisDotField = new FieldReference(v2Name, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
TypeReference v2Type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
List<TypeReference> tArgs = data.getTypeArgs();
|
||||
if (tArgs != null && tArgs.size() > 1) tArgs = Collections.singletonList(tArgs.get(1));
|
||||
else tArgs = Collections.emptyList();
|
||||
v2Type = addTypeArgs(1, false, builderType, v2Type, tArgs);
|
||||
constructArrayList = new AllocationExpression();
|
||||
constructArrayList.type = v2Type;
|
||||
Assignment initV2 = new Assignment(thisDotField, constructArrayList, 0);
|
||||
Block b = new Block(0);
|
||||
b.statements = new Statement[] {initV1, initV2};
|
||||
thenPart = b;
|
||||
} else {
|
||||
thenPart = initV1;
|
||||
}
|
||||
|
||||
return new IfStatement(cond, thenPart, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -156,6 +156,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
tdParent = parent.up();
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
|
||||
@@ -248,8 +249,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
if (cd != null) injectMethod(builderType, cd);
|
||||
}
|
||||
|
||||
for (BuilderFieldData builderFieldData : builderFields) {
|
||||
makeSetterMethodForBuilder(builderType, builderFieldData, annotationNode, fluent, chain);
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain);
|
||||
}
|
||||
|
||||
if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
@@ -287,7 +288,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
}
|
||||
|
||||
statements.append(maker.Exec(maker.Assign(maker.Ident(type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, false))));
|
||||
statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, false))));
|
||||
JCBlock body = maker.Block(0, statements.toList());
|
||||
return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(maker, CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
/*
|
||||
@@ -311,7 +312,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
if (addCleaning) {
|
||||
JCExpression notClean = maker.Unary(CTC_NOT, maker.Ident(type.toName("$lombokUnclean")));
|
||||
JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")));
|
||||
JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName("$lombokClean")), List.<JCExpression>nil()));
|
||||
JCIf ifUnclean = maker.If(notClean, invokeClean, null);
|
||||
statements.append(ifUnclean);
|
||||
@@ -329,7 +330,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
statements.append(maker.Exec(maker.Assign(maker.Ident(type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, true))));
|
||||
statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, true))));
|
||||
}
|
||||
|
||||
if (staticName == null) {
|
||||
@@ -398,7 +399,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
}
|
||||
|
||||
public void makeSetterMethodForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain) {
|
||||
public void makeSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain) {
|
||||
if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) {
|
||||
makeSimpleSetterMethodForBuilder(builderType, fieldNode.createdFields.get(0), source, fluent, chain);
|
||||
} else {
|
||||
|
||||
@@ -143,7 +143,7 @@ public class JavacSingularsRecipes {
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
return !getClass().getMethod("appendCleaningCode", ListBuffer.class).getDeclaringClass().equals(JavacSingularizer.class);
|
||||
return !getClass().getMethod("appendCleaningCode", SingularData.class, JavacNode.class, JCTree.class, ListBuffer.class).getDeclaringClass().equals(JavacSingularizer.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.junit.Test;
|
||||
public class TestSingulars {
|
||||
@Test
|
||||
public void testSingulars() {
|
||||
assertEquals("axis", autoSingularize("axes"));
|
||||
assertEquals(null, autoSingularize("axes"));
|
||||
assertEquals("adjective", autoSingularize("adjectives"));
|
||||
assertEquals("bus", autoSingularize("buses"));
|
||||
assertEquals("octopus", autoSingularize("octopodes"));
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import lombok.Singular;
|
||||
@lombok.Builder class BuilderSingletonMaps<K, V> {
|
||||
public static @java.lang.SuppressWarnings("all") class BuilderSingletonMapsBuilder<K, V> {
|
||||
private java.util.ArrayList<K> women$key;
|
||||
private java.util.ArrayList<V> women$value;
|
||||
private java.util.ArrayList<K> men$key;
|
||||
private java.util.ArrayList<Number> men$value;
|
||||
private java.util.ArrayList<java.lang.Object> rawMap$key;
|
||||
private java.util.ArrayList<java.lang.Object> rawMap$value;
|
||||
private java.util.ArrayList<String> stringMap$key;
|
||||
private java.util.ArrayList<V> stringMap$value;
|
||||
@java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> woman(K womanKey, V womanValue) {
|
||||
if ((this.women$key == null))
|
||||
{
|
||||
this.women$key = new java.util.ArrayList<K>();
|
||||
this.women$value = new java.util.ArrayList<V>();
|
||||
}
|
||||
this.women$key.add(womanKey);
|
||||
this.women$value.add(womanValue);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> women(java.util.Map<? extends K, ? extends V> women) {
|
||||
if ((this.women$key == null))
|
||||
{
|
||||
this.women$key = new java.util.ArrayList<K>();
|
||||
this.women$value = new java.util.ArrayList<V>();
|
||||
}
|
||||
for (java.util.Map.Entry<? extends K, ? extends V> $lombokEntry : women.entrySet())
|
||||
{
|
||||
this.women$key.add($lombokEntry.getKey());
|
||||
this.women$value.add($lombokEntry.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> man(K manKey, Number manValue) {
|
||||
if ((this.men$key == null))
|
||||
{
|
||||
this.men$key = new java.util.ArrayList<K>();
|
||||
this.men$value = new java.util.ArrayList<Number>();
|
||||
}
|
||||
this.men$key.add(manKey);
|
||||
this.men$value.add(manValue);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> men(java.util.Map<? extends K, ? extends Number> men) {
|
||||
if ((this.men$key == null))
|
||||
{
|
||||
this.men$key = new java.util.ArrayList<K>();
|
||||
this.men$value = new java.util.ArrayList<Number>();
|
||||
}
|
||||
for (java.util.Map.Entry<? extends K, ? extends Number> $lombokEntry : men.entrySet())
|
||||
{
|
||||
this.men$key.add($lombokEntry.getKey());
|
||||
this.men$value.add($lombokEntry.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> rawMap(java.lang.Object rawMapKey, java.lang.Object rawMapValue) {
|
||||
if ((this.rawMap$key == null))
|
||||
{
|
||||
this.rawMap$key = new java.util.ArrayList<java.lang.Object>();
|
||||
this.rawMap$value = new java.util.ArrayList<java.lang.Object>();
|
||||
}
|
||||
this.rawMap$key.add(rawMapKey);
|
||||
this.rawMap$value.add(rawMapValue);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> rawMap(java.util.Map<?, ?> rawMap) {
|
||||
if ((this.rawMap$key == null))
|
||||
{
|
||||
this.rawMap$key = new java.util.ArrayList<java.lang.Object>();
|
||||
this.rawMap$value = new java.util.ArrayList<java.lang.Object>();
|
||||
}
|
||||
for (java.util.Map.Entry<?, ?> $lombokEntry : rawMap.entrySet())
|
||||
{
|
||||
this.rawMap$key.add($lombokEntry.getKey());
|
||||
this.rawMap$value.add($lombokEntry.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> stringMap(String stringMapKey, V stringMapValue) {
|
||||
if ((this.stringMap$key == null))
|
||||
{
|
||||
this.stringMap$key = new java.util.ArrayList<String>();
|
||||
this.stringMap$value = new java.util.ArrayList<V>();
|
||||
}
|
||||
this.stringMap$key.add(stringMapKey);
|
||||
this.stringMap$value.add(stringMapValue);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMapsBuilder<K, V> stringMap(java.util.Map<? extends String, ? extends V> stringMap) {
|
||||
if ((this.stringMap$key == null))
|
||||
{
|
||||
this.stringMap$key = new java.util.ArrayList<String>();
|
||||
this.stringMap$value = new java.util.ArrayList<V>();
|
||||
}
|
||||
for (java.util.Map.Entry<? extends String, ? extends V> $lombokEntry : stringMap.entrySet())
|
||||
{
|
||||
this.stringMap$key.add($lombokEntry.getKey());
|
||||
this.stringMap$value.add($lombokEntry.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonMaps<K, V> build() {
|
||||
java.util.Map<K, V> women;
|
||||
switch (((this.women$key == null) ? 0 : this.women$key.size())) {
|
||||
case 0 :
|
||||
women = java.util.Collections.emptyMap();
|
||||
break;
|
||||
case 1 :
|
||||
women = java.util.Collections.singletonMap(this.women$key.get(0), this.women$value.get(0));
|
||||
break;
|
||||
default :
|
||||
women = new java.util.LinkedHashMap<K, V>(((this.women$key.size() < 0x40000000) ? ((1 + this.women$key.size()) + ((this.women$key.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
for (int $i = 0;; ($i < this.women$key.size()); $i ++)
|
||||
women.put(this.women$key.get($i), this.women$value.get($i));
|
||||
women = java.util.Collections.unmodifiableMap(women);
|
||||
}
|
||||
java.util.SortedMap<K, Number> men = new java.util.TreeMap<K, Number>();
|
||||
if ((this.men$key != null))
|
||||
for (int $i = 0;; ($i < ((this.men$key == null) ? 0 : this.men$key.size())); $i ++)
|
||||
men.put(this.men$key.get($i), this.men$value.get($i));
|
||||
men = java.util.Collections.unmodifiableSortedMap(men);
|
||||
java.util.Map<java.lang.Object, java.lang.Object> rawMap;
|
||||
switch (((this.rawMap$key == null) ? 0 : this.rawMap$key.size())) {
|
||||
case 0 :
|
||||
rawMap = java.util.Collections.emptyMap();
|
||||
break;
|
||||
case 1 :
|
||||
rawMap = java.util.Collections.singletonMap(this.rawMap$key.get(0), this.rawMap$value.get(0));
|
||||
break;
|
||||
default :
|
||||
rawMap = new java.util.LinkedHashMap<java.lang.Object, java.lang.Object>(((this.rawMap$key.size() < 0x40000000) ? ((1 + this.rawMap$key.size()) + ((this.rawMap$key.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
for (int $i = 0;; ($i < this.rawMap$key.size()); $i ++)
|
||||
rawMap.put(this.rawMap$key.get($i), this.rawMap$value.get($i));
|
||||
rawMap = java.util.Collections.unmodifiableMap(rawMap);
|
||||
}
|
||||
java.util.Map<String, V> stringMap;
|
||||
switch (((this.stringMap$key == null) ? 0 : this.stringMap$key.size())) {
|
||||
case 0 :
|
||||
stringMap = java.util.Collections.emptyMap();
|
||||
break;
|
||||
case 1 :
|
||||
stringMap = java.util.Collections.singletonMap(this.stringMap$key.get(0), this.stringMap$value.get(0));
|
||||
break;
|
||||
default :
|
||||
stringMap = new java.util.LinkedHashMap<String, V>(((this.stringMap$key.size() < 0x40000000) ? ((1 + this.stringMap$key.size()) + ((this.stringMap$key.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
for (int $i = 0;; ($i < this.stringMap$key.size()); $i ++)
|
||||
stringMap.put(this.stringMap$key.get($i), this.stringMap$value.get($i));
|
||||
stringMap = java.util.Collections.unmodifiableMap(stringMap);
|
||||
}
|
||||
return new BuilderSingletonMaps<K, V>(women, men, rawMap, stringMap);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((((((((((((((("BuilderSingletonMaps.BuilderSingletonMapsBuilder(women$key=" + this.women$key) + ", women$value=") + this.women$value) + ", men$key=") + this.men$key) + ", men$value=") + this.men$value) + ", rawMap$key=") + this.rawMap$key) + ", rawMap$value=") + this.rawMap$value) + ", stringMap$key=") + this.stringMap$key) + ", stringMap$value=") + this.stringMap$value) + ")");
|
||||
}
|
||||
}
|
||||
private @Singular Map<K, V> women;
|
||||
private @Singular SortedMap<K, ? extends Number> men;
|
||||
private @SuppressWarnings("all") @Singular("rawMap") Map rawMap;
|
||||
private @Singular("stringMap") Map<String, V> stringMap;
|
||||
@java.lang.SuppressWarnings("all") BuilderSingletonMaps(final Map<K, V> women, final SortedMap<K, ? extends Number> men, final Map rawMap, final Map<String, V> stringMap) {
|
||||
super();
|
||||
this.women = women;
|
||||
this.men = men;
|
||||
this.rawMap = rawMap;
|
||||
this.stringMap = stringMap;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <K, V>BuilderSingletonMapsBuilder<K, V> builder() {
|
||||
return new BuilderSingletonMapsBuilder<K, V>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import lombok.Singular;
|
||||
@lombok.Builder class BuilderSingletonSets<T> {
|
||||
public static @java.lang.SuppressWarnings("all") class BuilderSingletonSetsBuilder<T> {
|
||||
private java.util.ArrayList<T> dangerMice;
|
||||
private java.util.ArrayList<Number> octopodes;
|
||||
private java.util.ArrayList<java.lang.Object> rawSet;
|
||||
private java.util.ArrayList<String> stringSet;
|
||||
@java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> dangerMouse(T dangerMouse) {
|
||||
if ((this.dangerMice == null))
|
||||
this.dangerMice = new java.util.ArrayList<T>();
|
||||
this.dangerMice.add(dangerMouse);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> dangerMice(java.util.Collection<? extends T> dangerMice) {
|
||||
if ((this.dangerMice == null))
|
||||
this.dangerMice = new java.util.ArrayList<T>();
|
||||
this.dangerMice.addAll(dangerMice);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> octopus(Number octopus) {
|
||||
if ((this.octopodes == null))
|
||||
this.octopodes = new java.util.ArrayList<Number>();
|
||||
this.octopodes.add(octopus);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> octopodes(java.util.Collection<? extends Number> octopodes) {
|
||||
if ((this.octopodes == null))
|
||||
this.octopodes = new java.util.ArrayList<Number>();
|
||||
this.octopodes.addAll(octopodes);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> rawSet(java.lang.Object rawSet) {
|
||||
if ((this.rawSet == null))
|
||||
this.rawSet = new java.util.ArrayList<java.lang.Object>();
|
||||
this.rawSet.add(rawSet);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> rawSet(java.util.Collection<?> rawSet) {
|
||||
if ((this.rawSet == null))
|
||||
this.rawSet = new java.util.ArrayList<java.lang.Object>();
|
||||
this.rawSet.addAll(rawSet);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> stringSet(String stringSet) {
|
||||
if ((this.stringSet == null))
|
||||
this.stringSet = new java.util.ArrayList<String>();
|
||||
this.stringSet.add(stringSet);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSetsBuilder<T> stringSet(java.util.Collection<? extends String> stringSet) {
|
||||
if ((this.stringSet == null))
|
||||
this.stringSet = new java.util.ArrayList<String>();
|
||||
this.stringSet.addAll(stringSet);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderSingletonSets<T> build() {
|
||||
java.util.Set<T> dangerMice;
|
||||
switch (((this.dangerMice == null) ? 0 : this.dangerMice.size())) {
|
||||
case 0 :
|
||||
dangerMice = java.util.Collections.emptySet();
|
||||
break;
|
||||
case 1 :
|
||||
dangerMice = java.util.Collections.singleton(this.dangerMice.get(0));
|
||||
break;
|
||||
default :
|
||||
dangerMice = new java.util.LinkedHashSet<T>(((this.dangerMice.size() < 0x40000000) ? ((1 + this.dangerMice.size()) + ((this.dangerMice.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
dangerMice.addAll(this.dangerMice);
|
||||
dangerMice = java.util.Collections.unmodifiableSet(dangerMice);
|
||||
}
|
||||
java.util.SortedSet<Number> octopodes = new java.util.TreeSet<Number>();
|
||||
if ((this.octopodes != null))
|
||||
octopodes.addAll(this.octopodes);
|
||||
octopodes = java.util.Collections.unmodifiableSortedSet(octopodes);
|
||||
java.util.Set<java.lang.Object> rawSet;
|
||||
switch (((this.rawSet == null) ? 0 : this.rawSet.size())) {
|
||||
case 0 :
|
||||
rawSet = java.util.Collections.emptySet();
|
||||
break;
|
||||
case 1 :
|
||||
rawSet = java.util.Collections.singleton(this.rawSet.get(0));
|
||||
break;
|
||||
default :
|
||||
rawSet = new java.util.LinkedHashSet<java.lang.Object>(((this.rawSet.size() < 0x40000000) ? ((1 + this.rawSet.size()) + ((this.rawSet.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
rawSet.addAll(this.rawSet);
|
||||
rawSet = java.util.Collections.unmodifiableSet(rawSet);
|
||||
}
|
||||
java.util.Set<String> stringSet;
|
||||
switch (((this.stringSet == null) ? 0 : this.stringSet.size())) {
|
||||
case 0 :
|
||||
stringSet = java.util.Collections.emptySet();
|
||||
break;
|
||||
case 1 :
|
||||
stringSet = java.util.Collections.singleton(this.stringSet.get(0));
|
||||
break;
|
||||
default :
|
||||
stringSet = new java.util.LinkedHashSet<String>(((this.stringSet.size() < 0x40000000) ? ((1 + this.stringSet.size()) + ((this.stringSet.size() - 3) / 3)) : java.lang.Integer.MAX_VALUE));
|
||||
stringSet.addAll(this.stringSet);
|
||||
stringSet = java.util.Collections.unmodifiableSet(stringSet);
|
||||
}
|
||||
return new BuilderSingletonSets<T>(dangerMice, octopodes, rawSet, stringSet);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((((((("BuilderSingletonSets.BuilderSingletonSetsBuilder(dangerMice=" + this.dangerMice) + ", octopodes=") + this.octopodes) + ", rawSet=") + this.rawSet) + ", stringSet=") + this.stringSet) + ")");
|
||||
}
|
||||
}
|
||||
private @Singular Set<T> dangerMice;
|
||||
private @Singular SortedSet<? extends Number> octopodes;
|
||||
private @SuppressWarnings("all") @Singular("rawSet") Set rawSet;
|
||||
private @Singular("stringSet") Set<String> stringSet;
|
||||
@java.lang.SuppressWarnings("all") BuilderSingletonSets(final Set<T> dangerMice, final SortedSet<? extends Number> octopodes, final Set rawSet, final Set<String> stringSet) {
|
||||
super();
|
||||
this.dangerMice = dangerMice;
|
||||
this.octopodes = octopodes;
|
||||
this.rawSet = rawSet;
|
||||
this.stringSet = stringSet;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <T>BuilderSingletonSetsBuilder<T> builder() {
|
||||
return new BuilderSingletonSetsBuilder<T>();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,6 @@ import lombok.Singular;
|
||||
class BuilderSingletonMaps<K, V> {
|
||||
@Singular private Map<K, V> women;
|
||||
@Singular private SortedMap<K, ? extends Number> men;
|
||||
@Singular("rawMap") private Map rawMap;
|
||||
@SuppressWarnings("all") @Singular("rawMap") private Map rawMap;
|
||||
@Singular("stringMap") private Map<String, V> stringMap;
|
||||
}
|
||||
@@ -7,6 +7,6 @@ import lombok.Singular;
|
||||
class BuilderSingletonSets<T> {
|
||||
@Singular private Set<T> dangerMice;
|
||||
@Singular private SortedSet<? extends Number> octopodes;
|
||||
@Singular("rawSet") private Set rawSet;
|
||||
@SuppressWarnings("all") @Singular("rawSet") private Set rawSet;
|
||||
@Singular("stringSet") private Set<String> stringSet;
|
||||
}
|
||||
@@ -57,4 +57,8 @@ public class TestWithEcj extends DirectoryRunner.TestParams {
|
||||
public File getMessagesDirectory() {
|
||||
return new File("test/transform/resource/messages-ecj");
|
||||
}
|
||||
|
||||
@Override public boolean accept(File file) {
|
||||
return file.getName().startsWith("BuilderSingleton");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user