From 7e79316a1f28d1eb1ef8569119b97a70387fd6c6 Mon Sep 17 00:00:00 2001
From: Roel Spilker <r.spilker@gmail.com>
Date: Tue, 6 Nov 2018 00:27:02 +0100
Subject: Improve toString generation for enums. Fixes #1916

---
 src/core/lombok/core/LombokNode.java               |  3 +-
 src/core/lombok/eclipse/EclipseNode.java           |  7 ++-
 .../lombok/eclipse/handlers/HandleToString.java    | 69 +++++++++++++++-------
 src/core/lombok/javac/JavacNode.java               |  8 ++-
 src/core/lombok/javac/handlers/HandleToString.java | 21 +++++--
 5 files changed, 79 insertions(+), 29 deletions(-)

(limited to 'src')

diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index 5a0842bc..ae8fd325 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/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
@@ -279,6 +279,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
 	public abstract boolean isStatic();
 	public abstract boolean isTransient();
 	public abstract boolean isEnumMember();
+	public abstract boolean isEnumType();
 	
 	public abstract int countMethodParameters();
 	
diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java
index 1738c770..a0580c51 100644
--- a/src/core/lombok/eclipse/EclipseNode.java
+++ b/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
@@ -250,6 +250,11 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode,
 		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;
 		
diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java
index 303e5bea..bb52feb5 100644
--- a/src/core/lombok/eclipse/handlers/HandleToString.java
+++ b/src/core/lombok/eclipse/handlers/HandleToString.java
@@ -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;
@@ -31,18 +31,6 @@ import java.util.HashSet;
 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;
@@ -59,12 +47,26 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
 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.
  */
@@ -165,6 +167,8 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
 		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();
@@ -172,31 +176,54 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
 		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);
diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java
index 3963c892..f119f1f9 100644
--- a/src/core/lombok/javac/JavacNode.java
+++ b/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
@@ -317,6 +317,12 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre
 		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();
diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java
index eb6e56f3..3780da79 100644
--- a/src/core/lombok/javac/handlers/HandleToString.java
+++ b/src/core/lombok/javac/handlers/HandleToString.java
@@ -166,23 +166,34 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
 		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(),
-- 
cgit