aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/lombok/NoArgsConstructor.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleConstructor.java134
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java91
5 files changed, 162 insertions, 83 deletions
diff --git a/src/core/lombok/NoArgsConstructor.java b/src/core/lombok/NoArgsConstructor.java
index ef347273..ff437bba 100644
--- a/src/core/lombok/NoArgsConstructor.java
+++ b/src/core/lombok/NoArgsConstructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2013 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -61,6 +61,12 @@ public @interface NoArgsConstructor {
AccessLevel access() default lombok.AccessLevel.PUBLIC;
/**
+ * If {@code true}, initializes all final fields to 0 / null / false.
+ * Otherwise, a compile time error occurs.
+ */
+ boolean force() default false;
+
+ /**
* Placeholder annotation to enable the placement of annotations on the generated code.
* @deprecated Don't use this annotation, ever - Read the documentation.
*/
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index d011e2b5..5acd9249 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -160,8 +160,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
allFields.add(fieldNode);
}
- new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, null, SkipIfConstructorExists.I_AM_BUILDER, null,
- Collections.<Annotation>emptyList(), annotationNode);
+ new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, null,
+ Collections.<Annotation>emptyList(), annotationNode);
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
typeParams = td.typeParameters;
@@ -278,8 +278,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
ConstructorDeclaration cd = HandleConstructor.createConstructor(
- AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), null,
- annotationNode, Collections.<Annotation>emptyList());
+ AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, null,
+ annotationNode, Collections.<Annotation>emptyList());
if (cd != null) injectMethod(builderType, cd);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index 5bcc803a..85d1d4ed 100644
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2014 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -29,6 +29,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
@@ -48,13 +49,20 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
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.FloatLiteral;
+import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
@@ -63,7 +71,9 @@ import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+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.mangosdk.spi.ProviderFor;
public class HandleConstructor {
@@ -78,11 +88,13 @@ public class HandleConstructor {
AccessLevel level = ann.access();
String staticName = ann.staticName();
if (level == AccessLevel.NONE) return;
- List<EclipseNode> fields = new ArrayList<EclipseNode>();
+ boolean force = ann.force();
+
+ List<EclipseNode> fields = force ? findFinalFields(typeNode) : Collections.<EclipseNode>emptyList();
List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode);
- new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, SkipIfConstructorExists.NO, null, onConstructor, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, fields, force, staticName, SkipIfConstructorExists.NO, null, onConstructor, annotationNode);
}
}
@@ -107,19 +119,27 @@ public class HandleConstructor {
List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode);
new HandleConstructor().generateConstructor(
- typeNode, level, findRequiredFields(typeNode), staticName, SkipIfConstructorExists.NO,
- suppressConstructorProperties, onConstructor, annotationNode);
+ typeNode, level, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO,
+ suppressConstructorProperties, onConstructor, annotationNode);
}
}
private static List<EclipseNode> findRequiredFields(EclipseNode typeNode) {
+ return findFields(typeNode, true);
+ }
+
+ private static List<EclipseNode> findFinalFields(EclipseNode typeNode) {
+ return findFields(typeNode, false);
+ }
+
+ private static List<EclipseNode> findFields(EclipseNode typeNode, boolean nullMarked) {
List<EclipseNode> fields = new ArrayList<EclipseNode>();
for (EclipseNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD) continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (!filterField(fieldDecl)) continue;
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
- boolean isNonNull = findAnnotations(fieldDecl, NON_NULL_PATTERN).length != 0;
+ boolean isNonNull = nullMarked && findAnnotations(fieldDecl, NON_NULL_PATTERN).length != 0;
if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child);
}
return fields;
@@ -161,8 +181,8 @@ public class HandleConstructor {
List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode);
new HandleConstructor().generateConstructor(
- typeNode, level, findAllFields(typeNode), staticName, SkipIfConstructorExists.NO,
- suppressConstructorProperties, onConstructor, annotationNode);
+ typeNode, level, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO,
+ suppressConstructorProperties, onConstructor, annotationNode);
}
}
@@ -184,14 +204,14 @@ public class HandleConstructor {
EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List<Annotation> onConstructor, EclipseNode sourceNode) {
- generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, sourceNode);
+ generateConstructor(typeNode, level, findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, null, onConstructor, sourceNode);
}
public void generateAllArgsConstructor(
EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List<Annotation> onConstructor, EclipseNode sourceNode) {
- generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, null, onConstructor, sourceNode);
+ generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, null, onConstructor, sourceNode);
}
public enum SkipIfConstructorExists {
@@ -199,8 +219,8 @@ public class HandleConstructor {
}
public void generateConstructor(
- EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, SkipIfConstructorExists skipIfConstructorExists,
- Boolean suppressConstructorProperties, List<Annotation> onConstructor, EclipseNode sourceNode) {
+ EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists,
+ Boolean suppressConstructorProperties, List<Annotation> onConstructor, EclipseNode sourceNode) {
ASTNode source = sourceNode.get();
boolean staticConstrRequired = staticName != null && !staticName.equals("");
@@ -210,8 +230,8 @@ public class HandleConstructor {
for (EclipseNode child : typeNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
boolean skipGeneration = (annotationTypeMatches(NoArgsConstructor.class, child) ||
- annotationTypeMatches(AllArgsConstructor.class, child) ||
- annotationTypeMatches(RequiredArgsConstructor.class, child));
+ annotationTypeMatches(AllArgsConstructor.class, child) ||
+ annotationTypeMatches(RequiredArgsConstructor.class, child));
if (!skipGeneration && skipIfConstructorExists == SkipIfConstructorExists.YES) {
skipGeneration = annotationTypeMatches(Builder.class, child);
@@ -224,8 +244,8 @@ public class HandleConstructor {
// the 'staticName' parameter of the @XArgsConstructor you've stuck on your type.
// We should warn that we're ignoring @Data's 'staticConstructor' param.
typeNode.addWarning(
- "Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.",
- source.sourceStart, source.sourceEnd);
+ "Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.",
+ source.sourceStart, source.sourceEnd);
}
return;
}
@@ -234,11 +254,11 @@ public class HandleConstructor {
}
ConstructorDeclaration constr = createConstructor(
- staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields,
- suppressConstructorProperties, sourceNode, onConstructor);
+ staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault,
+ suppressConstructorProperties, sourceNode, onConstructor);
injectMethod(typeNode, constr);
if (staticConstrRequired) {
- MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source);
+ MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, allToDefault ? Collections.<EclipseNode>emptyList() : fields, source);
injectMethod(typeNode, staticConstr);
}
}
@@ -248,7 +268,7 @@ public class HandleConstructor {
if (fields.isEmpty()) return null;
int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
+ long p = (long) pS << 32 | pE;
long[] poss = new long[3];
Arrays.fill(poss, p);
QualifiedTypeReference constructorPropertiesType = new QualifiedTypeReference(JAVA_BEANS_CONSTRUCTORPROPERTIES, poss);
@@ -276,14 +296,14 @@ public class HandleConstructor {
}
public static ConstructorDeclaration createConstructor(
- AccessLevel level, EclipseNode type, Collection<EclipseNode> fields,
- Boolean suppressConstructorProperties, EclipseNode sourceNode, List<Annotation> onConstructor) {
+ AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, boolean allToDefault,
+ Boolean suppressConstructorProperties, EclipseNode sourceNode, List<Annotation> onConstructor) {
ASTNode source = sourceNode.get();
- TypeDeclaration typeDeclaration = ((TypeDeclaration)type.get());
- long p = (long)source.sourceStart << 32 | source.sourceEnd;
+ TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get());
+ long p = (long) source.sourceStart << 32 | source.sourceEnd;
- boolean isEnum = (((TypeDeclaration)type.get()).modifiers & ClassFileConstants.AccEnum) != 0;
+ boolean isEnum = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccEnum) != 0;
if (isEnum) level = AccessLevel.PRIVATE;
@@ -295,8 +315,7 @@ public class HandleConstructor {
}
}
- ConstructorDeclaration constructor = new ConstructorDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
constructor.modifiers = toEclipseModifier(level);
constructor.selector = typeDeclaration.name;
@@ -319,22 +338,27 @@ public class HandleConstructor {
char[] rawName = field.name;
char[] fieldName = removePrefixFromField(fieldNode);
FieldReference thisX = new FieldReference(rawName, p);
- thisX.receiver = new ThisReference((int)(p >> 32), (int)p);
+ int s = (int) (p >> 32);
+ int e = (int) p;
+ thisX.receiver = new ThisReference(s, e);
+
+ Expression assignmentExpr = allToDefault ? getDefaultExpr(field.type, s, e) : new SingleNameReference(fieldName, p);
- SingleNameReference assignmentNameRef = new SingleNameReference(fieldName, p);
- Assignment assignment = new Assignment(thisX, assignmentNameRef, (int)p);
- assignment.sourceStart = (int)(p >> 32); assignment.sourceEnd = assignment.statementEnd = (int)(p >> 32);
+ Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
+ assignment.sourceStart = (int) (p >> 32); assignment.sourceEnd = assignment.statementEnd = (int) (p >> 32);
assigns.add(assignment);
- long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd;
- Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
- Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
- Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
- if (nonNulls.length != 0) {
- Statement nullCheck = generateNullCheck(field, sourceNode);
- if (nullCheck != null) nullChecks.add(nullCheck);
+ if (!allToDefault) {
+ long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
+ Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
+ Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
+ if (nonNulls.length != 0) {
+ Statement nullCheck = generateNullCheck(field, sourceNode);
+ if (nullCheck != null) nullChecks.add(nullCheck);
+ }
+ parameter.annotations = copyAnnotations(source, nonNulls, nullables);
+ params.add(parameter);
}
- parameter.annotations = copyAnnotations(source, nonNulls, nullables);
- params.add(parameter);
}
nullChecks.addAll(assigns);
@@ -343,19 +367,32 @@ public class HandleConstructor {
/* Generate annotations that must be put on the generated method, and attach them. */ {
Annotation[] constructorProperties = null;
- if (!suppressConstructorProperties && level != AccessLevel.PRIVATE && level != AccessLevel.PACKAGE && !isLocalType(type)) {
+ if (!allToDefault && !suppressConstructorProperties && level != AccessLevel.PRIVATE && level != AccessLevel.PACKAGE && !isLocalType(type)) {
constructorProperties = createConstructorProperties(source, fields);
}
constructor.annotations = copyAnnotations(source,
- onConstructor.toArray(new Annotation[0]),
- constructorProperties);
+ onConstructor.toArray(new Annotation[0]),
+ constructorProperties);
}
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
return constructor;
}
+ private static Expression getDefaultExpr(TypeReference type, int s, int e) {
+ char[] lastToken = type.getLastToken();
+ if (Arrays.equals(TypeConstants.BOOLEAN, lastToken)) return new FalseLiteral(s, e);
+ if (Arrays.equals(TypeConstants.CHAR, lastToken)) return new CharLiteral(new char[] {'\'', '\\', '0', '\''}, s, e);
+ if (Arrays.equals(TypeConstants.BYTE, lastToken) || Arrays.equals(TypeConstants.SHORT, lastToken) ||
+ Arrays.equals(TypeConstants.INT, lastToken)) return IntLiteral.buildIntLiteral(new char[] {'0'}, s, e);
+ if (Arrays.equals(TypeConstants.LONG, lastToken)) return LongLiteral.buildLongLiteral(new char[] {'0', 'L'}, s, e);
+ if (Arrays.equals(TypeConstants.FLOAT, lastToken)) return new FloatLiteral(new char[] {'0', 'F'}, s, e);
+ if (Arrays.equals(TypeConstants.DOUBLE, lastToken)) return new DoubleLiteral(new char[] {'0', 'D'}, s, e);
+
+ return new NullLiteral(s, e);
+ }
+
public static boolean isLocalType(EclipseNode type) {
Kind kind = type.up().getKind();
if (kind == Kind.COMPILATION_UNIT) return false;
@@ -365,10 +402,9 @@ public class HandleConstructor {
public MethodDeclaration createStaticConstructor(AccessLevel level, String name, EclipseNode type, Collection<EclipseNode> fields, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
+ long p = (long) pS << 32 | pE;
- MethodDeclaration constructor = new MethodDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ MethodDeclaration constructor = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
constructor.modifiers = toEclipseModifier(level) | ClassFileConstants.AccStatic;
TypeDeclaration typeDecl = (TypeDeclaration) type.get();
@@ -376,7 +412,7 @@ public class HandleConstructor {
constructor.annotations = null;
constructor.selector = name.toCharArray();
constructor.thrownExceptions = null;
- constructor.typeParameters = copyTypeParams(((TypeDeclaration)type.get()).typeParameters, source);
+ constructor.typeParameters = copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source);
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
@@ -389,7 +425,7 @@ public class HandleConstructor {
for (EclipseNode fieldNode : fields) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
- long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd;
+ long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos);
assigns.add(nameRef);
@@ -400,7 +436,7 @@ public class HandleConstructor {
statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]);
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]);
- constructor.statements = new Statement[] { new ReturnStatement(statement, (int)(p >> 32), (int)p) };
+ constructor.statements = new Statement[] { new ReturnStatement(statement, (int) (p >> 32), (int)p) };
constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope);
return constructor;
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index 7ef7b859..066e371e 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -142,7 +142,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
allFields.append(fieldNode);
}
- new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), null, SkipIfConstructorExists.I_AM_BUILDER, null, annotationNode);
+ new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, null, annotationNode);
returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
typeParams = td.typarams;
@@ -255,7 +255,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
- JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), null, annotationNode);
+ JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), false, null, annotationNode);
if (cd != null) injectMethod(builderType, cd);
}
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index c5b309c2..4a4ec49c 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -23,6 +23,8 @@ package lombok.javac.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
+import static lombok.javac.Javac.*;
+
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -41,13 +43,13 @@ import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
-import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
@@ -71,8 +73,9 @@ public class HandleConstructor {
AccessLevel level = ann.access();
if (level == AccessLevel.NONE) return;
String staticName = ann.staticName();
- List<JavacNode> fields = List.nil();
- new HandleConstructor().generateConstructor(typeNode, level, onConstructor, fields, staticName, SkipIfConstructorExists.NO, null, annotationNode);
+ boolean force = ann.force();
+ List<JavacNode> fields = force ? findFinalFields(typeNode) : List.<JavacNode>nil();
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, fields, force, staticName, SkipIfConstructorExists.NO, null, annotationNode);
}
}
@@ -97,11 +100,19 @@ public class HandleConstructor {
suppressConstructorProperties = suppress;
}
- new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findRequiredFields(typeNode), staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode);
}
}
public static List<JavacNode> findRequiredFields(JavacNode typeNode) {
+ return findFields(typeNode, true);
+ }
+
+ public static List<JavacNode> findFinalFields(JavacNode typeNode) {
+ return findFields(typeNode, false);
+ }
+
+ public static List<JavacNode> findFields(JavacNode typeNode, boolean nullMarked) {
ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>();
for (JavacNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD) continue;
@@ -112,7 +123,7 @@ public class HandleConstructor {
//Skip static fields.
if ((fieldFlags & Flags.STATIC) != 0) continue;
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
- boolean isNonNull = !findAnnotations(child, NON_NULL_PATTERN).isEmpty();
+ boolean isNonNull = nullMarked && !findAnnotations(child, NON_NULL_PATTERN).isEmpty();
if ((isFinal || isNonNull) && fieldDecl.init == null) fields.append(child);
}
return fields.toList();
@@ -138,7 +149,7 @@ public class HandleConstructor {
boolean suppress = ann.suppressConstructorProperties();
suppressConstructorProperties = suppress;
}
- new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findAllFields(typeNode), staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode);
+ new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode);
}
}
@@ -174,7 +185,7 @@ public class HandleConstructor {
}
public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
- generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), staticName, skipIfConstructorExists, null, source);
+ generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, null, source);
}
public enum SkipIfConstructorExists {
@@ -182,10 +193,10 @@ public class HandleConstructor {
}
public void generateAllArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
- generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), staticName, skipIfConstructorExists, null, source);
+ generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), false, staticName, skipIfConstructorExists, null, source);
}
- public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, String staticName, SkipIfConstructorExists skipIfConstructorExists, Boolean suppressConstructorProperties, JavacNode source) {
+ public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, Boolean suppressConstructorProperties, JavacNode source) {
boolean staticConstrRequired = staticName != null && !staticName.equals("");
if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return;
@@ -193,8 +204,8 @@ public class HandleConstructor {
for (JavacNode child : typeNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
boolean skipGeneration = annotationTypeMatches(NoArgsConstructor.class, child) ||
- annotationTypeMatches(AllArgsConstructor.class, child) ||
- annotationTypeMatches(RequiredArgsConstructor.class, child);
+ annotationTypeMatches(AllArgsConstructor.class, child) ||
+ annotationTypeMatches(RequiredArgsConstructor.class, child);
if (!skipGeneration && skipIfConstructorExists == SkipIfConstructorExists.YES) {
skipGeneration = annotationTypeMatches(Builder.class, child);
@@ -214,10 +225,10 @@ public class HandleConstructor {
}
}
- JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, suppressConstructorProperties, source);
+ JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, suppressConstructorProperties, source);
injectMethod(typeNode, constr);
if (staticConstrRequired) {
- JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, fields, source.get());
+ JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, allToDefault ? List.<JavacNode>nil() : fields, source.get());
injectMethod(typeNode, staticConstr);
}
}
@@ -236,7 +247,7 @@ public class HandleConstructor {
mods.annotations = mods.annotations.append(annotation);
}
- public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, Boolean suppressConstructorProperties, JavacNode source) {
+ public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, boolean allToDefault, Boolean suppressConstructorProperties, JavacNode source) {
JavacTreeMaker maker = typeNode.getTreeMaker();
boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0;
@@ -259,29 +270,55 @@ public class HandleConstructor {
Name fieldName = removePrefixFromField(fieldNode);
Name rawName = field.name;
List<JCAnnotation> nonNulls = findAnnotations(fieldNode, NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(fieldNode, NULLABLE_PATTERN);
- long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
- JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, nonNulls.appendList(nullables)), fieldName, field.vartype, null);
- params.append(param);
+ if (!allToDefault) {
+ List<JCAnnotation> nullables = findAnnotations(fieldNode, NULLABLE_PATTERN);
+ long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
+ JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, nonNulls.appendList(nullables)), fieldName, field.vartype, null);
+ params.append(param);
+ if (!nonNulls.isEmpty()) {
+ JCStatement nullCheck = generateNullCheck(maker, fieldNode, source);
+ if (nullCheck != null) nullChecks.append(nullCheck);
+ }
+ }
JCFieldAccess thisX = maker.Select(maker.Ident(fieldNode.toName("this")), rawName);
- JCAssign assign = maker.Assign(thisX, maker.Ident(fieldName));
+ JCExpression assign = maker.Assign(thisX, allToDefault ? getDefaultExpr(maker, field.vartype) : maker.Ident(fieldName));
assigns.append(maker.Exec(assign));
-
- if (!nonNulls.isEmpty()) {
- JCStatement nullCheck = generateNullCheck(maker, fieldNode, source);
- if (nullCheck != null) nullChecks.append(nullCheck);
- }
}
JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
- if (!suppressConstructorProperties && level != AccessLevel.PRIVATE && level != AccessLevel.PACKAGE && !isLocalType(typeNode) && LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) {
+ if (!allToDefault && !suppressConstructorProperties && level != AccessLevel.PRIVATE && level != AccessLevel.PACKAGE && !isLocalType(typeNode) && LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) {
addConstructorProperties(mods, typeNode, fields);
}
if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor));
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
- null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
- maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext());
+ null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
+ maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext());
+ }
+
+ private static JCExpression getDefaultExpr(JavacTreeMaker maker, JCExpression type) {
+ if (type instanceof JCPrimitiveTypeTree) {
+ switch (((JCPrimitiveTypeTree) type).getPrimitiveTypeKind()) {
+ case BOOLEAN:
+ return maker.Literal(CTC_BOOLEAN, 0);
+ case CHAR:
+ return maker.Literal(CTC_CHAR, 0);
+ default:
+ case BYTE:
+ case SHORT:
+ case INT:
+ return maker.Literal(CTC_INT, 0);
+ case LONG:
+ return maker.Literal(CTC_LONG, 0L);
+ case FLOAT:
+ return maker.Literal(CTC_FLOAT, 0F);
+ case DOUBLE:
+ return maker.Literal(CTC_DOUBLE, 0D);
+ }
+ }
+
+ return maker.Literal(CTC_BOT, null);
+
}
public static boolean isLocalType(JavacNode type) {