mirror of
https://github.com/tiennm99/lombok.git
synced 2026-09-04 04:17:59 +00:00
Merge branch 'force'
Conflicts: doc/changelog.markdown src/core/lombok/eclipse/handlers/HandleBuilder.java
This commit is contained in:
@@ -5,6 +5,7 @@ Lombok Changelog
|
||||
* FEATURE: `@Helper` can be placed on method-local inner classes to make all methods in the class accessible to the rest of the method. [Full documentation](https://projectlombok.org/features/experimental/Helper.html).
|
||||
* FEATURE: `@Builder(toBuilder = true)` is now available. It produces an instance method that creates a new builder, initialized with all the values of that instance. For more, read the [Feature page on Builder](https://projectlombok.org/features/Builder.html).
|
||||
* FEATURE: the `hashCode()` method generated by lombok via `@EqualsAndHashCode`, `@Data`, and `@Value` is now smarter about nulls; they are treated as if they hash to a magic prime instead of 0, which reduces hash collisions.
|
||||
* FEATURE: `@NoArgsConstructor(force = true)` can be used to create no args constructors even if final fields are present.
|
||||
* BUGFIX: Parameterized static methods with `@Builder` would produce compiler errors in javac. [Issue #828](https://github.com/rzwitserloot/lombok/issues/828).
|
||||
* PERFORMANCE: the config system caused significant slowdowns in eclipse if the filesystem is very slow (network file system) or has a slow authentication system.
|
||||
* BUGFIX: Various quickfixes in Eclipse Mars were broken. [Issue #861](https://github.com/rzwitserloot/lombok/issues/861) [Issue #866](https://github.com/rzwitserloot/lombok/issues/866) [Issue #870](https://github.com/rzwitserloot/lombok/issues/870).
|
||||
|
||||
@@ -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
|
||||
@@ -60,6 +60,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.
|
||||
|
||||
@@ -187,8 +187,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;
|
||||
@@ -382,7 +382,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
|
||||
ConstructorDeclaration cd = HandleConstructor.createConstructor(
|
||||
AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), null,
|
||||
AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, null,
|
||||
annotationNode, Collections.<Annotation>emptyList());
|
||||
if (cd != null) injectMethod(builderType, cd);
|
||||
}
|
||||
@@ -502,8 +502,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) {
|
||||
MethodDeclaration out = new MethodDeclaration(
|
||||
((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
@@ -572,8 +571,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long) pS << 32 | pE;
|
||||
|
||||
MethodDeclaration out = new MethodDeclaration(
|
||||
((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
out.selector = builderMethodName.toCharArray();
|
||||
out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
@@ -643,7 +641,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName());
|
||||
|
||||
MethodDeclaration setter = HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic,
|
||||
sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
|
||||
sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
|
||||
injectMethod(builderType, setter);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
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);
|
||||
Expression assignmentExpr = allToDefault ? getDefaultExpr(field.type, s, e) : new SingleNameReference(fieldName, p);
|
||||
|
||||
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;
|
||||
|
||||
@@ -152,7 +152,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;
|
||||
@@ -342,7 +342,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
JCFieldAccess thisX = maker.Select(maker.Ident(fieldNode.toName("this")), rawName);
|
||||
JCAssign assign = maker.Assign(thisX, maker.Ident(fieldName));
|
||||
assigns.append(maker.Exec(assign));
|
||||
|
||||
if (!nonNulls.isEmpty()) {
|
||||
JCStatement nullCheck = generateNullCheck(maker, fieldNode, source);
|
||||
if (nullCheck != null) nullChecks.append(nullCheck);
|
||||
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);
|
||||
JCExpression assign = maker.Assign(thisX, allToDefault ? getDefaultExpr(maker, field.vartype) : maker.Ident(fieldName));
|
||||
assigns.append(maker.Exec(assign));
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -124,10 +124,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
|
||||
public void generateMethods(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes,
|
||||
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
|
||||
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
|
||||
|
||||
boolean notAClass = true;
|
||||
if (typeNode.get() instanceof JCClassDecl) {
|
||||
long flags = ((JCClassDecl)typeNode.get()).mods.flags;
|
||||
long flags = ((JCClassDecl) typeNode.get()).mods.flags;
|
||||
notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
boolean implicitCallSuper = callSuper == null;
|
||||
if (callSuper == null) {
|
||||
try {
|
||||
callSuper = ((Boolean)EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
|
||||
callSuper = ((Boolean) EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
|
||||
} catch (Exception ignore) {
|
||||
throw new InternalError("Lombok bug - this cannot happen - can't find callSuper field in EqualsAndHashCode annotation.");
|
||||
}
|
||||
@@ -184,7 +185,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
}
|
||||
|
||||
boolean isFinal = (((JCClassDecl)typeNode.get()).mods.flags & Flags.FINAL) != 0;
|
||||
boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 0;
|
||||
boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject;
|
||||
MemberExistsResult equalsExists = methodExists("equals", typeNode, 1);
|
||||
MemberExistsResult hashCodeExists = methodExists("hashCode", typeNode, 0);
|
||||
@@ -202,8 +203,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
// The user code couldn't possibly (barring really weird subclassing shenanigans) be in a shippable state anyway; the implementations of these 2 methods are
|
||||
// all inter-related and should be written by the same entity.
|
||||
String msg = String.format("Not generating %s: One of equals or hashCode exists. " +
|
||||
"You should either write both of these or none of these (in the latter case, lombok generates them).",
|
||||
equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode");
|
||||
"You should either write both of these or none of these (in the latter case, lombok generates them).",
|
||||
equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode");
|
||||
source.addWarning(msg);
|
||||
}
|
||||
return;
|
||||
@@ -248,8 +249,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
if (callSuper) {
|
||||
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")),
|
||||
List.<JCExpression>nil());
|
||||
maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")),
|
||||
List.<JCExpression>nil());
|
||||
statements.append(createResultCalculation(typeNode, callToSuper));
|
||||
}
|
||||
|
||||
@@ -258,14 +259,14 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
JCExpression fType = getFieldType(fieldNode, fieldAccess);
|
||||
JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
|
||||
if (fType instanceof JCPrimitiveTypeTree) {
|
||||
switch (((JCPrimitiveTypeTree)fType).getPrimitiveTypeKind()) {
|
||||
switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
|
||||
case BOOLEAN:
|
||||
/* this.fieldName ? X : Y */
|
||||
statements.append(createResultCalculation(typeNode, maker.Conditional(fieldAccessor,
|
||||
maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse()))));
|
||||
maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse()))));
|
||||
break;
|
||||
case LONG: {
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name);
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
|
||||
statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor));
|
||||
statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
|
||||
}
|
||||
@@ -273,17 +274,17 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
case FLOAT:
|
||||
/* Float.floatToIntBits(this.fieldName) */
|
||||
statements.append(createResultCalculation(typeNode, maker.Apply(
|
||||
List.<JCExpression>nil(),
|
||||
genJavaLangTypeRef(typeNode, "Float", "floatToIntBits"),
|
||||
List.of(fieldAccessor))));
|
||||
List.<JCExpression>nil(),
|
||||
genJavaLangTypeRef(typeNode, "Float", "floatToIntBits"),
|
||||
List.of(fieldAccessor))));
|
||||
break;
|
||||
case DOUBLE: {
|
||||
/* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name);
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
|
||||
JCExpression init = maker.Apply(
|
||||
List.<JCExpression>nil(),
|
||||
genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"),
|
||||
List.of(fieldAccessor));
|
||||
List.<JCExpression>nil(),
|
||||
genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"),
|
||||
List.of(fieldAccessor));
|
||||
statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), init));
|
||||
statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
|
||||
}
|
||||
@@ -299,8 +300,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
} else if (fType instanceof JCArrayTypeTree) {
|
||||
/* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */
|
||||
boolean multiDim = ((JCArrayTypeTree)fType).elemtype instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = ((JCArrayTypeTree)fType).elemtype instanceof JCPrimitiveTypeTree;
|
||||
boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
|
||||
boolean useDeepHC = multiDim || !primitiveArray;
|
||||
|
||||
JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode");
|
||||
@@ -309,11 +310,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
/* final java.lang.Object $fieldName = this.fieldName; */
|
||||
/* $fieldName == null ? NULL_PRIME : $fieldName.hashCode() */
|
||||
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl)fieldNode.get()).name);
|
||||
Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
|
||||
statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor));
|
||||
|
||||
JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")),
|
||||
List.<JCExpression>nil());
|
||||
List.<JCExpression>nil());
|
||||
JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(dollarFieldName), maker.Literal(CTC_BOT, null));
|
||||
statements.append(createResultCalculation(typeNode, maker.Conditional(thisEqualsNull, maker.Literal(HandlerUtil.primeForNull()), hcCall)));
|
||||
}
|
||||
@@ -325,7 +326,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
JCBlock body = maker.Block(0, statements.toList());
|
||||
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("hashCode"), returnType,
|
||||
List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext());
|
||||
List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext());
|
||||
}
|
||||
|
||||
public JCExpressionStatement createResultCalculation(JavacNode typeNode, JCExpression expr) {
|
||||
@@ -339,7 +340,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
/** The 2 references must be clones of each other. */
|
||||
public JCExpression longToIntForHashCode(JavacTreeMaker maker, JCExpression ref1, JCExpression ref2) {
|
||||
/* (int)(ref >>> 32 ^ ref) */
|
||||
/* (int) (ref >>> 32 ^ ref) */
|
||||
JCExpression shift = maker.Binary(CTC_UNSIGNED_SHIFT_RIGHT, ref1, maker.Literal(32));
|
||||
JCExpression xorBits = maker.Binary(CTC_BITXOR, shift, ref2);
|
||||
return maker.TypeCast(maker.TypeIdent(CTC_INT), xorBits);
|
||||
@@ -385,7 +386,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
/* if (o == this) return true; */ {
|
||||
statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(oName),
|
||||
maker.Ident(thisName)), returnBool(maker, true), null));
|
||||
maker.Ident(thisName)), returnBool(maker, true), null));
|
||||
}
|
||||
|
||||
/* if (!(o instanceof Outer.Inner.MyType) return false; */ {
|
||||
@@ -413,7 +414,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
|
||||
statements.append(
|
||||
maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
|
||||
maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,8 +424,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
JCExpression thisRef = maker.Ident(thisName);
|
||||
JCExpression castThisRef = maker.TypeCast(genJavaLangTypeRef(typeNode, "Object"), thisRef);
|
||||
JCExpression equalityCheck = maker.Apply(exprNil,
|
||||
maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")),
|
||||
List.of(castThisRef));
|
||||
maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")),
|
||||
List.of(castThisRef));
|
||||
statements.append(maker.If(maker.Unary(CTC_NOT, equalityCheck), returnBool(maker, false), null));
|
||||
}
|
||||
}
|
||||
@@ -432,8 +433,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
/* if (!super.equals(o)) return false; */
|
||||
if (callSuper) {
|
||||
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")),
|
||||
List.<JCExpression>of(maker.Ident(oName)));
|
||||
maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")),
|
||||
List.<JCExpression>of(maker.Ident(oName)));
|
||||
JCUnary superNotEqual = maker.Unary(CTC_NOT, callToSuper);
|
||||
statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
|
||||
}
|
||||
@@ -462,19 +463,19 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
} else if (fType instanceof JCArrayTypeTree) {
|
||||
/* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
|
||||
boolean multiDim = ((JCArrayTypeTree)fType).elemtype instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = ((JCArrayTypeTree)fType).elemtype instanceof JCPrimitiveTypeTree;
|
||||
boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
|
||||
boolean useDeepEquals = multiDim || !primitiveArray;
|
||||
|
||||
JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
|
||||
List<JCExpression> args = List.of(thisFieldAccessor, otherFieldAccessor);
|
||||
statements.append(maker.If(maker.Unary(CTC_NOT,
|
||||
maker.Apply(List.<JCExpression>nil(), eqMethod, args)), returnBool(maker, false), null));
|
||||
maker.Apply(List.<JCExpression>nil(), eqMethod, args)), returnBool(maker, false), null));
|
||||
} else /* objects */ {
|
||||
/* final java.lang.Object this$fieldName = this.fieldName; */
|
||||
/* final java.lang.Object other$fieldName = other.fieldName; */
|
||||
/* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */
|
||||
Name fieldName = ((JCVariableDecl)fieldNode.get()).name;
|
||||
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
|
||||
Name thisDollarFieldName = thisDollar.append(fieldName);
|
||||
Name otherDollarFieldName = otherDollar.append(fieldName);
|
||||
|
||||
@@ -484,8 +485,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(thisDollarFieldName), maker.Literal(CTC_BOT, null));
|
||||
JCExpression otherNotEqualsNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(otherDollarFieldName), maker.Literal(CTC_BOT, null));
|
||||
JCExpression thisEqualsThat = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")),
|
||||
List.<JCExpression>of(maker.Ident(otherDollarFieldName)));
|
||||
maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")),
|
||||
List.<JCExpression>of(maker.Ident(otherDollarFieldName)));
|
||||
JCExpression fieldsAreNotEqual = maker.Conditional(thisEqualsNull, otherNotEqualsNull, maker.Unary(CTC_NOT, thisEqualsThat));
|
||||
statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null));
|
||||
}
|
||||
@@ -521,12 +522,13 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
|
||||
public JCStatement generateCompareFloatOrDouble(JCExpression thisDotField, JCExpression otherDotField,
|
||||
JavacTreeMaker maker, JavacNode node, boolean isDouble) {
|
||||
JavacTreeMaker maker, JavacNode node, boolean isDouble) {
|
||||
|
||||
/* if (Float.compare(fieldName, other.fieldName) != 0) return false; */
|
||||
JCExpression clazz = genJavaLangTypeRef(node, isDouble ? "Double" : "Float");
|
||||
List<JCExpression> args = List.of(thisDotField, otherDotField);
|
||||
JCBinary compareCallEquals0 = maker.Binary(CTC_NOT_EQUAL, maker.Apply(
|
||||
List.<JCExpression>nil(), maker.Select(clazz, node.toName("compare")), args), maker.Literal(0));
|
||||
List.<JCExpression>nil(), maker.Select(clazz, node.toName("compare")), args), maker.Literal(0));
|
||||
return maker.If(compareCallEquals0, returnBool(maker, false), null);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,3 +98,22 @@ class AllArgsConstructorPackageAccess {
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
class NoArgsConstructor2 {
|
||||
final int x;
|
||||
final double y;
|
||||
final char c;
|
||||
final boolean b;
|
||||
final float f;
|
||||
final String s;
|
||||
byte z;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@javax.annotation.Generated("lombok")
|
||||
public NoArgsConstructor2() {
|
||||
this.x = 0;
|
||||
this.y = 0.0;
|
||||
this.c = '\000';
|
||||
this.b = false;
|
||||
this.f = 0.0F;
|
||||
this.s = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,4 +77,22 @@
|
||||
super();
|
||||
this.x = x;
|
||||
}
|
||||
}
|
||||
@lombok.NoArgsConstructor(force = true) class NoArgsConstructor2 {
|
||||
final int x;
|
||||
final double y;
|
||||
final char c;
|
||||
final boolean b;
|
||||
final float f;
|
||||
final String s;
|
||||
byte z;
|
||||
public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") NoArgsConstructor2() {
|
||||
super();
|
||||
this.x = 0;
|
||||
this.y = 0D;
|
||||
this.c = '\0';
|
||||
this.b = false;
|
||||
this.f = 0F;
|
||||
this.s = null;
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,13 @@
|
||||
}
|
||||
@lombok.AllArgsConstructor(access=lombok.AccessLevel.PACKAGE) class AllArgsConstructorPackageAccess {
|
||||
final String x;
|
||||
}
|
||||
}
|
||||
@lombok.NoArgsConstructor(force = true) class NoArgsConstructor2 {
|
||||
final int x;
|
||||
final double y;
|
||||
final char c;
|
||||
final boolean b;
|
||||
final float f;
|
||||
final String s;
|
||||
byte z;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
<p>
|
||||
This set of 3 annotations generate a constructor that will accept 1 parameter for certain fields, and simply assigns this parameter to the field.
|
||||
</p><p>
|
||||
<code>@NoArgsConstructor</code> will generate a constructor with no parameters. If this is not possible (because of final fields), a compiler error will result instead.
|
||||
For fields with constraints, such as <code>@NonNull</code> fields, <em>no</em> check or assignment is generated, so be aware that these constraints may then not be
|
||||
<code>@NoArgsConstructor</code> will generate a constructor with no parameters. If this is not possible (because of final fields), a compiler error will result instead, unless <code>@NoArgsConstructor(force = true)</code> is used, then all final fields are initialized with 0 / false / null. For fields with constraints, such as <code>@NonNull</code> fields, <em>no</em> check or assignment is generated, so be aware that these constraints may then not be
|
||||
fulfilled until those fields are properly initialized later. Certain java constructs, such as hibernate and the Service Provider Interface require a no-args constructor.
|
||||
This annotation is useful primarily in combination with either <code>@Data</code> or one of the other constructor generating annotations.
|
||||
</p><p>
|
||||
|
||||
Reference in New Issue
Block a user