Skip to content

Commit

Permalink
Generate default no-args constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
rspilker committed May 28, 2018
1 parent 4fb9c6f commit 6045c1b
Show file tree
Hide file tree
Showing 31 changed files with 383 additions and 18 deletions.
7 changes: 7 additions & 0 deletions src/core/lombok/ConfigurationKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ private ConfigurationKeys() {}
*/
public static final ConfigurationKey<FlagUsageType> NO_ARGS_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.noArgsConstructor.flagUsage", "Emit a warning or error if @NoArgsConstructor is used.") {};

/**
* lombok configuration: {@code lombok.noArgsConstructor.extraPrivate} = {@code true} | {@code false}.
*
* If {@code true} (default), @Data and @Value will also generate a private no-args constructor, if there isn't already one, setting all fields to their default values.
*/
public static final ConfigurationKey<Boolean> NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE = new ConfigurationKey<Boolean>("lombok.noArgsConstructor.extraPrivate", "Generate a private no-ars constructor for @Data and @Value (default: true).") {};

/**
* lombok configuration: {@code lombok.requiredArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}.
*
Expand Down
16 changes: 8 additions & 8 deletions src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,12 @@ public static AnnotationValues<Accessors> getAccessorsForField(EclipseNode field

return AnnotationValues.of(Accessors.class, field);
}

public static EclipseNode upToTypeNode(EclipseNode node) {
if (node == null) throw new NullPointerException("node");
while (node != null && !(node.get() instanceof TypeDeclaration)) node = node.up();
return node;
}

/**
* Checks if there is a field with the provided name.
Expand All @@ -1206,10 +1212,7 @@ public static AnnotationValues<Accessors> getAccessorsForField(EclipseNode field
* @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof.
*/
public static MemberExistsResult fieldExists(String fieldName, EclipseNode node) {
while (node != null && !(node.get() instanceof TypeDeclaration)) {
node = node.up();
}

node = upToTypeNode(node);
if (node != null && node.get() instanceof TypeDeclaration) {
TypeDeclaration typeDecl = (TypeDeclaration)node.get();
if (typeDecl.fields != null) for (FieldDeclaration def : typeDecl.fields) {
Expand Down Expand Up @@ -1295,10 +1298,7 @@ public static boolean isTolerate(EclipseNode node, AbstractMethodDeclaration def
* @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof.
*/
public static MemberExistsResult constructorExists(EclipseNode node) {
while (node != null && !(node.get() instanceof TypeDeclaration)) {
node = node.up();
}

node = upToTypeNode(node);
if (node != null && node.get() instanceof TypeDeclaration) {
TypeDeclaration typeDecl = (TypeDeclaration)node.get();
if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
Expand Down
43 changes: 39 additions & 4 deletions src/core/lombok/eclipse/handlers/HandleConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;

import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
Expand Down Expand Up @@ -204,6 +206,18 @@ static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode, String
return true;
}

public enum SkipIfConstructorExists {
YES, NO, I_AM_BUILDER;
}

public void generateExtraNoArgsConstructor(EclipseNode typeNode, EclipseNode sourceNode) {
Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE);
if (v != null && !v) return;

List<EclipseNode> fields = findFinalFields(typeNode);
generate(typeNode, AccessLevel.PRIVATE, fields, true, null, SkipIfConstructorExists.NO, Collections.<Annotation>emptyList(), sourceNode, true);
}

public void generateRequiredArgsConstructor(
EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List<Annotation> onConstructor, EclipseNode sourceNode) {
Expand All @@ -218,14 +232,17 @@ public void generateAllArgsConstructor(
generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode);
}

public enum SkipIfConstructorExists {
YES, NO, I_AM_BUILDER;
}

public void generateConstructor(
EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List<Annotation> onConstructor, EclipseNode sourceNode) {

generate(typeNode, level, fields, allToDefault, staticName, skipIfConstructorExists, onConstructor, sourceNode, false);
}

public void generate(
EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List<Annotation> onConstructor, EclipseNode sourceNode, boolean noArgs) {

ASTNode source = sourceNode.get();
boolean staticConstrRequired = staticName != null && !staticName.equals("");

Expand Down Expand Up @@ -257,6 +274,8 @@ public void generateConstructor(
}
}

if (noArgs && noArgsConstructorExists(typeNode)) return;

ConstructorDeclaration constr = createConstructor(
staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault,
sourceNode, onConstructor);
Expand All @@ -267,6 +286,22 @@ public void generateConstructor(
}
}

private static boolean noArgsConstructorExists(EclipseNode node) {
node = EclipseHandlerUtil.upToTypeNode(node);

if (node != null && node.get() instanceof TypeDeclaration) {
TypeDeclaration typeDecl = (TypeDeclaration)node.get();
if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
if (def instanceof ConstructorDeclaration) {
Argument[] arguments = ((ConstructorDeclaration) def).arguments;
if (arguments == null || arguments.length == 0) return true;
}
}
}
return false;
}


private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
public static Annotation[] createConstructorProperties(ASTNode source, Collection<EclipseNode> fields) {
if (fields.isEmpty()) return null;
Expand Down
1 change: 1 addition & 0 deletions src/core/lombok/eclipse/handlers/HandleData.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@ public class HandleData extends EclipseAnnotationHandler<Data> {
handleConstructor.generateRequiredArgsConstructor(
typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES,
Collections.<Annotation>emptyList(), annotationNode);
handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
}
}
1 change: 1 addition & 0 deletions src/core/lombok/eclipse/handlers/HandleValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,6 @@ public void handle(AnnotationValues<Value> annotation, Annotation ast, EclipseNo
handleToString.generateToStringForType(typeNode, annotationNode);
handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES,
Collections.<Annotation>emptyList(), annotationNode);
handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
}
}
39 changes: 34 additions & 5 deletions src/core/lombok/javac/handlers/HandleConstructor.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2014 The Project Lombok Authors.
* Copyright (C) 2010-2018 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
Expand Down Expand Up @@ -38,6 +38,7 @@
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;

import org.mangosdk.spi.ProviderFor;

Expand Down Expand Up @@ -191,19 +192,31 @@ public static boolean checkLegality(JavacNode typeNode, JavacNode errorNode, Str
return true;
}

public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, source);
}

public enum SkipIfConstructorExists {
YES, NO, I_AM_BUILDER;
}

public void generateExtraNoArgsConstructor(JavacNode typeNode, JavacNode source) {
Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE);
if (v != null && !v) return;

List<JavacNode> fields = findFinalFields(typeNode);
generate(typeNode, AccessLevel.PRIVATE, List.<JCAnnotation>nil(), fields, true, null, SkipIfConstructorExists.NO, source, true);
}

public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, source);
}

public void generateAllArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), false, staticName, skipIfConstructorExists, source);
}

public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) {
generate(typeNode, level, onConstructor, fields, allToDefault, staticName, skipIfConstructorExists, source, false);
}

private void generate(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source, boolean noArgs) {
boolean staticConstrRequired = staticName != null && !staticName.equals("");

if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return;
Expand Down Expand Up @@ -232,6 +245,8 @@ public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAn
}
}

if (noArgs && noArgsConstructorExists(typeNode)) return;

JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, source);
ListBuffer<Type> argTypes = new ListBuffer<Type>();
for (JavacNode fieldNode : fields) {
Expand All @@ -252,6 +267,20 @@ public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAn
}
}

private static boolean noArgsConstructorExists(JavacNode node) {
node = upToTypeNode(node);

if (node != null && node.get() instanceof JCClassDecl) {
for (JCTree def : ((JCClassDecl) node.get()).defs) {
if (def instanceof JCMethodDecl) {
JCMethodDecl md = (JCMethodDecl) def;
if (md.name.contentEquals("<init>") && md.params.size() == 0) return true;
}
}
}
return false;
}

public static void addConstructorProperties(JCModifiers mods, JavacNode node, List<JavacNode> fields) {
if (fields.isEmpty()) return;
JavacTreeMaker maker = node.getTreeMaker();
Expand Down
4 changes: 3 additions & 1 deletion src/core/lombok/javac/handlers/HandleData.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014 The Project Lombok Authors.
* Copyright (C) 2009-2018 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
Expand Down Expand Up @@ -61,7 +61,9 @@ public class HandleData extends JavacAnnotationHandler<Data> {

String staticConstructorName = annotation.getInstance().staticConstructor();

// TODO move this to the end OR move it to the top in eclipse.
handleConstructor.generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil());
handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
Expand Down
1 change: 1 addition & 0 deletions src/core/lombok/javac/handlers/HandleValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class HandleValue extends JavacAnnotationHandler<Value> {
}
handleFieldDefaults.generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil());
handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
handleToString.generateToStringForType(typeNode, annotationNode);
Expand Down
6 changes: 6 additions & 0 deletions test/transform/resource/after-delombok/BuilderDefaults.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ public static BuilderDefaultsBuilder builder() {
return new BuilderDefaultsBuilder();
}
@java.lang.SuppressWarnings("all")
private BuilderDefaults() {
this.x = 0;
this.name = null;
this.z = 0L;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public static <Foo, Bar extends Set<Foo>, Quz extends Inter<Bar, Quz>> TestBuild
return new TestBuilder<Foo, Bar, Quz>();
}
@java.lang.SuppressWarnings("all")
private Test() {
this.foo = null;
this.bar = null;
}
@java.lang.SuppressWarnings("all")
public Foo getFoo() {
return this.foo;
}
Expand Down
4 changes: 4 additions & 0 deletions test/transform/resource/after-delombok/DataConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ public DataConfiguration(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private DataConfiguration() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down
4 changes: 4 additions & 0 deletions test/transform/resource/after-delombok/DataIgnore.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public DataIgnore(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private DataIgnore() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down
11 changes: 11 additions & 0 deletions test/transform/resource/after-delombok/DataOnLocalClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public Local(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private Local() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down Expand Up @@ -68,6 +72,9 @@ public InnerLocal(@lombok.NonNull final String name) {
}
this.name = name;
}
@java.lang.SuppressWarnings("all")
private InnerLocal() {
}
@lombok.NonNull
@java.lang.SuppressWarnings("all")
public String getName() {
Expand Down Expand Up @@ -116,6 +123,10 @@ public Local(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private Local() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down
12 changes: 12 additions & 0 deletions test/transform/resource/after-delombok/DataPlain.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public Data1(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private Data1() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down Expand Up @@ -58,6 +62,10 @@ public Data2(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private Data2() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down Expand Up @@ -110,6 +118,10 @@ public Data3(final int x) {
this.x = x;
}
@java.lang.SuppressWarnings("all")
private Data3() {
this.x = 0;
}
@java.lang.SuppressWarnings("all")
public int getX() {
return this.x;
}
Expand Down
4 changes: 4 additions & 0 deletions test/transform/resource/after-delombok/DataWithGetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ public DataWithGetter(final String z) {
this.z = z;
}
@java.lang.SuppressWarnings("all")
private DataWithGetter() {
this.z = null;
}
@java.lang.SuppressWarnings("all")
public void setX(final int x) {
this.x = x;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ public DataWithGetterNone(final String z) {
this.z = z;
}
@java.lang.SuppressWarnings("all")
private DataWithGetterNone() {
this.z = null;
}
@java.lang.SuppressWarnings("all")
public void setX(final int x) {
this.x = x;
}
Expand Down
4 changes: 4 additions & 0 deletions test/transform/resource/after-delombok/InnerClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public D(final A a) {
this.a = a;
}
@java.lang.SuppressWarnings("all")
private D() {
this.a = null;
}
@java.lang.SuppressWarnings("all")
public A getA() {
return this.a;
}
Expand Down
Loading

0 comments on commit 6045c1b

Please sign in to comment.