trying to manually add (parts of) the infrastructure for @Singular @Builder stuff is now flagged as an error.

This commit is contained in:
Reinier Zwitserloot committed 2015-01-20 01:54:25 +01:00
1 parent 519f95c241
commit 857da88e3e
8 files changed
+165 -24

No files matched your search

+1 -1
View File
@@ -195,7 +195,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
</ivy:compile>
<mkdir dir="build/lombok/META-INF" />
<mkdir dir="build/lombok/META-INF/services" />
<echo file="build/lombok/META-INF/services/javax.annotation.processing.Processor">lombok.launch.AnnotationProcessorHider.AnnotationProcessor</echo>
<echo file="build/lombok/META-INF/services/javax.annotation.processing.Processor">lombok.launch.AnnotationProcessorHider$AnnotationProcessor</echo>
</target>
<target name="dist" description="Builds THE lombok.jar file which contains everything." depends="version, compile">
-1
View File
@@ -7,7 +7,6 @@ Lombok Changelog
* Builder __TODO TODO TODO TODO DO NOT SHIP YET__:
* features web page
* warnings / errors when you attempt to handroll some / all of the methods/fields that @Singular would have generated. We are most likely not going to support it.
* The 'I use guava' switch in l.config
* Disable auto-singular in l.config
* Review if there are nay potentially breaking changes in the pipeline for builder BEFORE moving it out of experimental.
@@ -1,9 +1,32 @@
/*
* Copyright (C) 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.eclipse.handlers;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -36,27 +59,6 @@ import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.eclipse.EclipseNode;
/*
* Copyright (C) 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
public class EclipseSingularsRecipes {
private static final EclipseSingularsRecipes INSTANCE = new EclipseSingularsRecipes();
private final Map<String, EclipseSingularizer> singularizers = new HashMap<String, EclipseSingularizer>();
@@ -164,7 +166,51 @@ public class EclipseSingularsRecipes {
protected static final long[] NULL_POSS = {0L};
public abstract LombokImmutableList<String> getSupportedTypes();
public abstract java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType);
/** Checks if any of the to-be-generated nodes (fields, methods) already exist. If so, errors on these (singulars don't support manually writing some of it, and returns true). */
public boolean checkForAlreadyExistingNodesAndGenerateError(EclipseNode builderType, SingularData data) {
for (EclipseNode child : builderType.down()) {
switch (child.getKind()) {
case FIELD: {
FieldDeclaration fd = (FieldDeclaration) child.get();
char[] name = fd.name;
if (name == null) continue;
if (getGeneratedBy(fd) != null) continue;
for (char[] fieldToBeGenerated : listFieldsToBeGenerated(data)) {
if (!Arrays.equals(name, fieldToBeGenerated)) continue;
child.addError("Manually adding a field that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular.");
return true;
}
break;
}
case METHOD: {
AbstractMethodDeclaration method = (AbstractMethodDeclaration) child.get();
char[] name = method.selector;
if (name == null) continue;
if (getGeneratedBy(method) != null) continue;
for (char[] methodToBeGenerated : listMethodsToBeGenerated(data)) {
if (!Arrays.equals(name, methodToBeGenerated)) continue;
child.addError("Manually adding a method that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular.");
return true;
}
break;
}}
}
return false;
}
public List<char[]> listFieldsToBeGenerated(SingularData data) {
return Collections.singletonList(data.pluralName);
}
public List<char[]> listMethodsToBeGenerated(SingularData data) {
char[] p = data.pluralName;
char[] s = data.singularName;
if (Arrays.equals(p, s)) return Collections.singletonList(p);
return Arrays.asList(p, s);
}
public abstract List<EclipseNode> generateFields(SingularData data, EclipseNode builderType);
public abstract void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain);
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName);
@@ -246,6 +246,17 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast);
} else {
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
/* generate errors for @Singular BFDs that have one already defined node. */ {
for (BuilderFieldData bfd : builderFields) {
SingularData sd = bfd.singularData;
if (sd == null) continue;
EclipseSingularizer singularizer = sd.getSingularizer();
if (singularizer == null) continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
bfd.singularData = null;
}
}
}
}
for (BuilderFieldData bfd : builderFields) {
@@ -61,6 +61,26 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap");
}
@Override public List<char[]> listFieldsToBeGenerated(SingularData data) {
char[] p = data.getPluralName();
int len = p.length;
char[] k = new char[len + 4];
char[] v = new char[len + 6];
System.arraycopy(p, 0, k, 0, len);
System.arraycopy(p, 0, v, 0, len);
k[len] = '$';
k[len + 1] = 'k';
k[len + 2] = 'e';
k[len + 3] = 'y';
v[len] = '$';
v[len + 1] = 'v';
v[len + 2] = 'a';
v[len + 3] = 'l';
v[len + 4] = 'u';
v[len + 5] = 'e';
return Arrays.asList(k, v);
}
@Override public java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) {
char[] keyName = (new String(data.getPluralName()) + "$key").toCharArray();
char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
@@ -227,6 +227,18 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast);
} else {
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
/* generate errors for @Singular BFDs that have one already defined node. */ {
for (BuilderFieldData bfd : builderFields) {
SingularData sd = bfd.singularData;
if (sd == null) continue;
JavacSingularizer singularizer = sd.getSingularizer();
if (singularizer == null) continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
bfd.singularData = null;
}
}
}
}
for (BuilderFieldData bfd : builderFields) {
@@ -25,6 +25,8 @@ import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -38,7 +40,9 @@ import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
@@ -137,6 +141,50 @@ public class JavacSingularsRecipes {
public static abstract class JavacSingularizer {
public abstract LombokImmutableList<String> getSupportedTypes();
/** Checks if any of the to-be-generated nodes (fields, methods) already exist. If so, errors on these (singulars don't support manually writing some of it, and returns true). */
public boolean checkForAlreadyExistingNodesAndGenerateError(JavacNode builderType, SingularData data) {
for (JavacNode child : builderType.down()) {
switch (child.getKind()) {
case FIELD: {
JCVariableDecl field = (JCVariableDecl) child.get();
Name name = field.name;
if (name == null) break;
if (getGeneratedBy(field) != null) continue;
for (Name fieldToBeGenerated : listFieldsToBeGenerated(builderType, data)) {
if (!fieldToBeGenerated.equals(name)) continue;
child.addError("Manually adding a field that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular.");
return true;
}
break;
}
case METHOD: {
JCMethodDecl method = (JCMethodDecl) child.get();
Name name = method.name;
if (name == null) break;
if (getGeneratedBy(method) != null) continue;
for (Name methodToBeGenerated : listMethodsToBeGenerated(builderType, data)) {
if (!methodToBeGenerated.equals(name)) continue;
child.addError("Manually adding a method that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular.");
return true;
}
break;
}}
}
return false;
}
public java.util.List<Name> listFieldsToBeGenerated(JavacNode builderType, SingularData data) {
return Collections.singletonList(data.pluralName);
}
public java.util.List<Name> listMethodsToBeGenerated(JavacNode builderType, SingularData data) {
Name p = data.pluralName;
Name s = data.singularName;
if (p.equals(s)) return Collections.singletonList(p);
return Arrays.asList(p, s);
}
public abstract java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source);
public abstract void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain);
public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName);
@@ -55,6 +55,11 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer {
return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap");
}
@Override public java.util.List<Name> listFieldsToBeGenerated(JavacNode builderType, SingularData data) {
String p = data.getPluralName().toString();
return Arrays.asList(builderType.toName(p + "$key"), builderType.toName(p + "$value"));
}
@Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) {
JavacTreeMaker maker = builderType.getTreeMaker();