Skip to content

Commit

Permalink
Improve toString generation for enums. Fixes #1916
Browse files Browse the repository at this point in the history
  • Loading branch information
rspilker committed Nov 5, 2018
1 parent dc641cc commit 7e79316
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 31 deletions.
1 change: 1 addition & 0 deletions doc/changelog.markdown
Expand Up @@ -5,6 +5,7 @@ Lombok Changelog
* BUGFIX: Since version 1.18.4, the delombok ant task didn't work and errored with a `NoClassDefFoundError`. [Issue #1932](https://github.com/rzwitserloot/lombok/issues/1932)
* FEATURE: The `@FieldNameConstants` feature now allows you to write the inner type by hand and add whatever you like to it; lombok will add the constants to this class. See the updated [FieldNameConstants feature](https://projectlombok.org/features/experimental/FieldNameConstants) page.
* FEATURE: There is now a `lombok.config` key to configure `@ToString`'s call super behavior; it's just like `@EqualsAndHashCode` which has had it for a while now. [Issue #1918](https://github.com/rzwitserloot/lombok/issues/1918)
* ENHANCEMENT: The toString generation of enums now contains the name of the enum constant. [Issue #1916](https://github.com/rzwitserloot/lombok/issues/1916)

### v1.18.4 (October 30th, 2018)
* PLATFORM: Support for Eclipse Photon. [Issue #1831](https://github.com/rzwitserloot/lombok/issues/1831)
Expand Down
3 changes: 2 additions & 1 deletion src/core/lombok/core/LombokNode.java
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2013 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 @@ -279,6 +279,7 @@ public boolean isStructurallySignificant() {
public abstract boolean isStatic();
public abstract boolean isTransient();
public abstract boolean isEnumMember();
public abstract boolean isEnumType();

public abstract int countMethodParameters();

Expand Down
7 changes: 6 additions & 1 deletion src/core/lombok/eclipse/EclipseNode.java
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2012 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 @@ -250,6 +250,11 @@ private Integer getModifiers() {
return ((FieldDeclaration) node).getKind() == 3;
}

@Override public boolean isEnumType() {
if (getKind() != Kind.TYPE) return false;
return (((TypeDeclaration) node).modifiers & ClassFileConstants.AccEnum) != 0;
}

@Override public int countMethodParameters() {
if (getKind() != Kind.METHOD) return 0;

Expand Down
69 changes: 48 additions & 21 deletions src/core/lombok/eclipse/handlers/HandleToString.java
Expand Up @@ -21,7 +21,7 @@
*/
package lombok.eclipse.handlers;

import static lombok.core.handlers.HandlerUtil.*;
import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;

import java.util.Arrays;
Expand All @@ -31,18 +31,6 @@
import java.util.List;
import java.util.Set;

import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.configuration.CallSuperType;
import lombok.core.handlers.InclusionExclusionUtils;
import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;

import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
Expand All @@ -59,12 +47,26 @@
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.eclipse.jdt.internal.compiler.ast.SuperReference;
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;

import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.configuration.CallSuperType;
import lombok.core.handlers.HandlerUtil.FieldAccess;
import lombok.core.handlers.InclusionExclusionUtils;
import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;

/**
* Handles the {@code ToString} annotation for eclipse.
*/
Expand Down Expand Up @@ -165,38 +167,63 @@ public static MethodDeclaration createToString(EclipseNode type, Collection<Incl
boolean includeNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {

String typeName = getTypeName(type);
boolean isEnum = type.isEnumType();

char[] suffix = ")".toCharArray();
String infixS = ", ";
char[] infix = infixS.toCharArray();
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
final int PLUS = OperatorIds.PLUS;

char[] prefix;
String prefix;

if (callSuper) {
prefix = (typeName + "(super=").toCharArray();
prefix = "(super=";
} else if (members.isEmpty()) {
prefix = (typeName + "()").toCharArray();
prefix = isEnum ? "" : "()";
} else if (includeNames) {
Included<EclipseNode, ToString.Include> firstMember = members.iterator().next();
String name = firstMember.getInc() == null ? "" : firstMember.getInc().name();
if (name.isEmpty()) name = firstMember.getNode().getName();
prefix = (typeName + "(" + name + "=").toCharArray();
prefix = "(" + name + "=";
} else {
prefix = (typeName + "(").toCharArray();
prefix = "(";
}

boolean first = true;
Expression current = new StringLiteral(prefix, pS, pE, 0);
setGeneratedBy(current, source);
Expression current;
if (!isEnum) {
current = new StringLiteral((typeName + prefix).toCharArray(), pS, pE, 0);
setGeneratedBy(current, source);
} else {
current = new StringLiteral((typeName + ".").toCharArray(), pS, pE, 0);
setGeneratedBy(current, source);

MessageSend thisName = new MessageSend();
thisName.sourceStart = pS; thisName.sourceEnd = pE;
setGeneratedBy(thisName, source);
thisName.receiver = new ThisReference(pS, pE);
setGeneratedBy(thisName.receiver, source);
thisName.selector = "name".toCharArray();
current = new BinaryExpression(current, thisName, PLUS);
setGeneratedBy(current, source);

if (!prefix.isEmpty()) {
StringLiteral px = new StringLiteral(prefix.toCharArray(), pS, pE, 0);
setGeneratedBy(px, source);
current = new BinaryExpression(current, px, PLUS);
current.sourceStart = pS; current.sourceEnd = pE;
setGeneratedBy(current, source);
}
}

if (callSuper) {
MessageSend callToSuper = new MessageSend();
callToSuper.sourceStart = pS; callToSuper.sourceEnd = pE;
setGeneratedBy(callToSuper, source);
callToSuper.receiver = new SuperReference(pS, pE);
setGeneratedBy(callToSuper, source);
setGeneratedBy(callToSuper.receiver, source);
callToSuper.selector = "toString".toCharArray();
current = new BinaryExpression(current, callToSuper, PLUS);
setGeneratedBy(current, source);
Expand Down
8 changes: 7 additions & 1 deletion src/core/lombok/javac/JavacNode.java
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2017 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 @@ -317,6 +317,12 @@ private JCModifiers getModifiers() {
return mods != null && (Flags.ENUM & mods.flags) != 0;
}

@Override public boolean isEnumType() {
if (getKind() != Kind.TYPE) return false;
JCModifiers mods = getModifiers();
return mods != null && (Flags.ENUM & mods.flags) != 0;
}

@Override public boolean isTransient() {
if (getKind() != Kind.FIELD) return false;
JCModifiers mods = getModifiers();
Expand Down
21 changes: 16 additions & 5 deletions src/core/lombok/javac/handlers/HandleToString.java
Expand Up @@ -166,23 +166,34 @@ static JCMethodDecl createToString(JavacNode typeNode, Collection<Included<Javac
boolean first = true;

String typeName = getTypeName(typeNode);
boolean isEnum = typeNode.isEnumType();

String infix = ", ";
String suffix = ")";
String prefix;
if (callSuper) {
prefix = typeName + "(super=";
prefix = "(super=";
} else if (members.isEmpty()) {
prefix = typeName + "()";
prefix = isEnum ? "" : "()";
} else if (includeNames) {
Included<JavacNode, ToString.Include> firstMember = members.iterator().next();
String name = firstMember.getInc() == null ? "" : firstMember.getInc().name();
if (name.isEmpty()) name = firstMember.getNode().getName();
prefix = typeName + "(" + name + "=";
prefix = "(" + name + "=";
} else {
prefix = "(";
}

JCExpression current;
if (!isEnum) {
current = maker.Literal(typeName + prefix);
} else {
prefix = typeName + "(";
current = maker.Binary(CTC_PLUS, maker.Literal(typeName + "."), maker.Apply(List.<JCExpression>nil(),
maker.Select(maker.Ident(typeNode.toName("this")), typeNode.toName("name")),
List.<JCExpression>nil()));
if (!prefix.isEmpty()) current = maker.Binary(CTC_PLUS, current, maker.Literal(prefix));
}

JCExpression current = maker.Literal(prefix);

if (callSuper) {
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
Expand Down
2 changes: 1 addition & 1 deletion test/transform/resource/after-delombok/DataOnEnum.java
Expand Up @@ -8,7 +8,7 @@ public String getSomeField() {
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "DataOnEnum(someField=" + this.getSomeField() + ")";
return "DataOnEnum." + this.name() + "(someField=" + this.getSomeField() + ")";
}
@java.lang.SuppressWarnings("all")
private DataOnEnum(final String someField) {
Expand Down
28 changes: 28 additions & 0 deletions test/transform/resource/after-delombok/ToStringEnum.java
@@ -0,0 +1,28 @@
enum ToStringEnum1 {
CONSTANT;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "ToStringEnum1." + this.name();
}
}
enum ToStringEnum2 {
CONSTANT;
int x;
String name;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "ToStringEnum2." + this.name() + "(x=" + this.x + ", name=" + this.name + ")";
}
}
class ToStringEnum3 {
enum MemberEnum {
CONSTANT;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "ToStringEnum3.MemberEnum." + this.name();
}
}
}
2 changes: 1 addition & 1 deletion test/transform/resource/after-ecj/DataOnEnum.java
Expand Up @@ -7,7 +7,7 @@
return this.someField;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (("DataOnEnum(someField=" + this.getSomeField()) + ")");
return (((("DataOnEnum." + this.name()) + "(someField=") + this.getSomeField()) + ")");
}
private @java.lang.SuppressWarnings("all") DataOnEnum(final String someField) {
super();
Expand Down
41 changes: 41 additions & 0 deletions test/transform/resource/after-ecj/ToStringEnum.java
@@ -0,0 +1,41 @@
import lombok.ToString;
@ToString enum ToStringEnum1 {
CONSTANT(),
<clinit>() {
}
ToStringEnum1() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return ("ToStringEnum1." + this.name());
}
}
@ToString enum ToStringEnum2 {
CONSTANT(),
int x;
String name;
<clinit>() {
}
ToStringEnum2() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (((((("ToStringEnum2." + this.name()) + "(x=") + this.x) + ", name=") + this.name) + ")");
}
}
class ToStringEnum3 {
@ToString enum MemberEnum {
CONSTANT(),
<clinit>() {
}
MemberEnum() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return ("ToStringEnum3.MemberEnum." + this.name());
}
}
ToStringEnum3() {
super();
}
}
17 changes: 17 additions & 0 deletions test/transform/resource/before/ToStringEnum.java
@@ -0,0 +1,17 @@
import lombok.ToString;
@ToString
enum ToStringEnum1 {
CONSTANT;
}
@ToString
enum ToStringEnum2 {
CONSTANT();
int x;
String name;
}
class ToStringEnum3 {
@ToString
enum MemberEnum {
CONSTANT;
}
}

0 comments on commit 7e79316

Please sign in to comment.