aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok')
-rw-r--r--src/core/lombok/ConfigurationKeys.java10
-rw-r--r--src/core/lombok/core/configuration/CheckerFrameworkVersion.java86
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java33
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java17
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleBuilder.java93
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleConstructor.java17
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java18
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java13
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java7
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleSuperBuilder.java106
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java10
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWither.java13
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java21
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java23
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java23
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java69
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java22
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java11
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java95
-rw-r--r--src/core/lombok/javac/handlers/HandleToString.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleWither.java10
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java8
-rw-r--r--src/core/lombok/javac/handlers/JavacSingularsRecipes.java40
-rw-r--r--src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java5
-rw-r--r--src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java5
-rw-r--r--src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java5
28 files changed, 586 insertions, 201 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index dda0b54b..d46889d6 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -24,6 +24,7 @@ package lombok;
import java.util.List;
import lombok.core.configuration.CallSuperType;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.core.configuration.ConfigurationKey;
import lombok.core.configuration.LogDeclaration;
import lombok.core.configuration.FlagUsageType;
@@ -627,5 +628,14 @@ public class ConfigurationKeys {
* Copy these annotations to getters, setters, withers, builder-setters, etc.
*/
public static final ConfigurationKey<List<TypeName>> COPYABLE_ANNOTATIONS = new ConfigurationKey<List<TypeName>>("lombok.copyableAnnotations", "Copy these annotations to getters, setters, withers, builder-setters, etc.") {};
+
+ /**
+ * lombok configuration: {@code checkerframework} = {@code true} | {@code false} | &lt;String: MajorVer.MinorVer&gt; (Default: false).
+ *
+ * If set, lombok will generate appropriate annotations from checkerframework.org on generated code. If set to {@code true}, all relevant annotations from the most recent version of
+ * checkerframework.org that lombok supports will be generated. If set to a specific major/minor version number, only checkerframework annotations introduced on or before the stated
+ * checkerframework.org version will be generated.
+ */
+ public static final ConfigurationKey<CheckerFrameworkVersion> CHECKER_FRAMEWORK = new ConfigurationKey<CheckerFrameworkVersion>("checkerframework", "If set with the version of checkerframework.org (in major.minor, or just 'true' for the latest supported version), create relevant checkerframework.org annotations for code lombok generates (default: false).") {};
}
diff --git a/src/core/lombok/core/configuration/CheckerFrameworkVersion.java b/src/core/lombok/core/configuration/CheckerFrameworkVersion.java
new file mode 100644
index 00000000..68fc05a7
--- /dev/null
+++ b/src/core/lombok/core/configuration/CheckerFrameworkVersion.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.core.configuration;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class CheckerFrameworkVersion implements ConfigurationValueType {
+ private final int version;
+ private static final int MAX_SUPPORTED = 3000;
+
+ public static final String NAME__SIDE_EFFECT_FREE = "org.checkerframework.dataflow.qual.SideEffectFree";
+ public static final String NAME__UNIQUE = "org.checkerframework.common.aliasing.qual.Unique";
+ public static final String NAME__RETURNS_RECEIVER = "org.checkerframework.checker.builder.qual.ReturnsReceiver";
+ public static final String NAME__NOT_CALLED = "org.checkerframework.checker.builder.qual.NotCalledMethods";
+ public static final String NAME__CALLED = "org.checkerframework.checker.builder.qual.CalledMethods";
+
+ public static final CheckerFrameworkVersion NONE = new CheckerFrameworkVersion(0);
+
+ private CheckerFrameworkVersion(int v) {
+ this.version = v;
+ }
+
+ private static final Pattern VERSION = Pattern.compile("^(\\d+)(?:\\.(\\d+))?(?:\\.\\d+)*$");
+
+ public boolean generateSideEffectFree() {
+ return version > 0;
+ }
+
+ public boolean generateUnique() {
+ return version > 0;
+ }
+
+ public boolean generateReturnsReceiver() {
+ return version > 2999;
+ }
+
+ public boolean generateCalledMethods() {
+ return version > 2999;
+ }
+
+ public static CheckerFrameworkVersion valueOf(String versionString) {
+ if (versionString != null) versionString = versionString.trim();
+ if (versionString == null || versionString.equalsIgnoreCase("false") || versionString.equals("0")) return new CheckerFrameworkVersion(0);
+ if (versionString.equalsIgnoreCase("true")) return new CheckerFrameworkVersion(MAX_SUPPORTED);
+ Matcher m = VERSION.matcher(versionString);
+ if (!m.matches()) throw new IllegalArgumentException("Expected 'true' or 'false' or a major/minor version, such as '2.9'");
+ int major = Integer.parseInt(m.group(1));
+ int minor = (m.group(2) != null && !m.group(2).isEmpty()) ? Integer.parseInt(m.group(2)) : 0;
+ if (minor > 999) throw new IllegalArgumentException("Minor version must be between 0 and 999");
+ int v = major * 1000 + minor;
+ if (v > MAX_SUPPORTED) {
+ String s = (v / 1000) + "." + (v % 1000);
+ throw new IllegalArgumentException("Lombok supports at most v" + s + "; reduce the value of key 'checkerframework' to " + s);
+ }
+ return new CheckerFrameworkVersion(v);
+ }
+
+ public static String description() {
+ return "checkerframework-version";
+ }
+
+ public static String exampleValue() {
+ String s = (MAX_SUPPORTED / 1000) + "." + (MAX_SUPPORTED % 1000);
+ return "major.minor (example: 2.9 - and no higher than " + s + ") or true or false";
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 11a2b9bd..782c6a29 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -111,6 +111,7 @@ import lombok.core.AnnotationValues;
import lombok.core.AnnotationValues.AnnotationValue;
import lombok.core.LombokImmutableList;
import lombok.core.TypeResolver;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.core.configuration.NullCheckExceptionType;
import lombok.core.configuration.TypeName;
import lombok.core.debug.ProblemReporter;
@@ -184,6 +185,23 @@ public class EclipseHandlerUtil {
return ma;
}
+ public static MarkerAnnotation generateNamedAnnotation(ASTNode source, String typeName) {
+ char[][] cc = fromQualifiedName(typeName);
+ QualifiedTypeReference qtr = new QualifiedTypeReference(cc, poss(source, cc.length));
+ setGeneratedBy(qtr, source);
+ MarkerAnnotation ma = new MarkerAnnotation(qtr, source.sourceStart);
+ // No matter what value you input for sourceEnd, the AST->DOM converter of eclipse will reparse to find the end, and will fail as
+ // it can't find code that isn't really there. This results in the end position being set to 2 or 0 or some weird magic value, and thus,
+ // length, as calculated by end-start, is all screwed up, resulting in IllegalArgumentException during a setSourceRange call MUCH later in the process.
+ // We solve it by going with a voodoo magic source start value such that the calculated length so happens to exactly be 0. 0 lengths are accepted
+ // by eclipse. For some reason.
+ // TL;DR: Don't change 1. 1 is sacred. Trust the 1.
+ // issue: #408.
+ ma.sourceStart = 1;
+ setGeneratedBy(ma, source);
+ return ma;
+ }
+
public static boolean isFieldDeprecated(EclipseNode fieldNode) {
if (!(fieldNode.get() instanceof FieldDeclaration)) return false;
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
@@ -199,6 +217,11 @@ public class EclipseHandlerUtil {
return false;
}
+ public static CheckerFrameworkVersion getCheckerFrameworkVersion(EclipseNode node) {
+ CheckerFrameworkVersion cfv = node.getAst().readConfiguration(ConfigurationKeys.CHECKER_FRAMEWORK);
+ return cfv != null ? cfv : CheckerFrameworkVersion.NONE;
+ }
+
/**
* Checks if the given TypeReference node is likely to be a reference to the provided class.
*
@@ -1908,11 +1931,13 @@ public class EclipseHandlerUtil {
* Create an annotation of the given name, and is marked as being generated by the given source.
*/
public static MarkerAnnotation makeMarkerAnnotation(char[][] name, ASTNode source) {
- long pos = (long)source.sourceStart << 32 | source.sourceEnd;
- TypeReference typeRef = new QualifiedTypeReference(name, new long[] {pos, pos, pos});
+ long pos = (long) source.sourceStart << 32 | source.sourceEnd;
+ long[] poss = new long[name.length];
+ Arrays.fill(poss, pos);
+ TypeReference typeRef = new QualifiedTypeReference(name, poss);
setGeneratedBy(typeRef, source);
- MarkerAnnotation ann = new MarkerAnnotation(typeRef, (int)(pos >> 32));
- ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = (int)pos;
+ MarkerAnnotation ann = new MarkerAnnotation(typeRef, (int) (pos >> 32));
+ ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = (int) pos;
setGeneratedBy(ann, source);
return ann;
}
diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
index a8a780d6..da0bf471 100755
--- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
+++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
@@ -33,6 +33,7 @@ import java.util.Map;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
@@ -62,6 +63,7 @@ import lombok.AccessLevel;
import lombok.core.LombokImmutableList;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.eclipse.EclipseNode;
public class EclipseSingularsRecipes {
@@ -235,7 +237,7 @@ public class EclipseSingularsRecipes {
* If you need more control over the return type and value, use
* {@link #generateMethods(SingularData, boolean, EclipseNode, boolean, TypeReferenceMaker, StatementMaker)}.
*/
- public void generateMethods(SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain, AccessLevel access) {
+ public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain, AccessLevel access) {
TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() {
@Override public TypeReference make() {
return chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
@@ -248,14 +250,14 @@ public class EclipseSingularsRecipes {
}
};
- generateMethods(data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker, access);
+ generateMethods(cfv, data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker, access);
}
/**
* Generates the singular, plural, and clear methods for the given {@link SingularData}.
* Uses the given {@code returnTypeMaker} and {@code returnStatementMaker} for the generated methods.
*/
- public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access);
+ public abstract void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access);
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable);
@@ -272,6 +274,15 @@ public class EclipseSingularsRecipes {
// -- Utility methods --
+ protected Annotation[] generateSelfReturnAnnotations(boolean deprecate, CheckerFrameworkVersion cfv, ASTNode source) {
+ Annotation deprecated = deprecate ? generateDeprecatedAnnotation(source) : null;
+ Annotation returnsReceiver = cfv.generateReturnsReceiver() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null;
+ if (deprecated == null && returnsReceiver == null) return null;
+ if (deprecated == null) return new Annotation[] {returnsReceiver};
+ if (returnsReceiver == null) return new Annotation[] {deprecated};
+ return new Annotation[] {deprecated, returnsReceiver};
+ }
+
/**
* Adds the requested number of type arguments to the provided type, copying each argument in {@code typeArgs}. If typeArgs is too long, the extra elements are ignored.
* If {@code typeArgs} is null or too short, {@code java.lang.Object} will be substituted for each missing type argument.
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index d2b1b823..8bfdeb65 100755
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -37,6 +37,7 @@ import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
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.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
@@ -57,9 +58,11 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
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.TrueLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
@@ -84,6 +87,7 @@ import lombok.core.handlers.HandlerUtil;
import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
@@ -155,7 +159,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
-
+ CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode);
+
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
Builder builderInstance = annotation.getInstance();
@@ -487,14 +492,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
for (BuilderFieldData bfd : builderFields) {
- makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode);
+ makeSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode);
}
{
MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1);
if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0);
if (methodExists == MemberExistsResult.NOT_EXISTS) {
- MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, accessForInners);
+ MethodDeclaration md = generateBuildMethod(cfv, tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, accessForInners);
if (md != null) injectMethod(builderType, md);
}
}
@@ -517,7 +522,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false;
if (generateBuilderMethod) {
- MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast, accessForOuters);
+ MethodDeclaration md = generateBuilderMethod(cfv, isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast, accessForOuters);
if (md != null) injectMethod(tdParent, md);
}
@@ -534,7 +539,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
tps[i].name = typeArgsForToBuilder.get(i);
}
}
- MethodDeclaration md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters);
+ MethodDeclaration md = generateToBuilderMethod(cfv, toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters);
if (md != null) injectMethod(tdParent, md);
}
@@ -547,7 +552,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'};
- private MethodDeclaration generateToBuilderMethod(String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source, AccessLevel access) {
+ private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source, AccessLevel access) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
@@ -623,6 +628,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
out.statements = new Statement[] {new ReturnStatement(receiver, pS, pE)};
}
+ if (cfv.generateUnique()) {
+ out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)};
+ }
+
out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope);
return out;
@@ -650,7 +659,35 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
return decl;
}
- public MethodDeclaration generateBuildMethod(EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) {
+ static Argument[] generateBuildArgs(CheckerFrameworkVersion cfv, EclipseNode type, List<BuilderFieldData> builderFields, ASTNode source) {
+ if (!cfv.generateCalledMethods()) return null;
+
+ List<char[]> mandatories = new ArrayList<char[]>();
+ for (BuilderFieldData bfd : builderFields) {
+ if (bfd.singularData == null && bfd.nameOfSetFlag == null) mandatories.add(bfd.name);
+ }
+
+ if (mandatories.size() == 0) return null;
+ char[][] nameCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__CALLED);
+ SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameCalled, poss(source, nameCalled.length)), source.sourceStart);
+ if (mandatories.size() == 1) {
+ ann.memberValue = new StringLiteral(mandatories.get(0), 0, 0, 0);
+ } else {
+ ArrayInitializer arr = new ArrayInitializer();
+ arr.sourceStart = source.sourceStart;
+ arr.sourceEnd = source.sourceEnd;
+ arr.expressions = new Expression[mandatories.size()];
+ for (int i = 0; i < arr.expressions.length; i++) {
+ arr.expressions[i] = new StringLiteral(mandatories.get(i), source.sourceStart, source.sourceEnd, 0);
+ }
+ ann.memberValue = arr;
+ }
+ Argument arg = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, new SingleTypeReference(type.getName().toCharArray(), source.sourceStart), Modifier.FINAL);
+ arg.annotations = new Annotation[] {ann};
+ return new Argument[] {arg};
+ }
+
+ public MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) {
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
List<Statement> statements = new ArrayList<Statement>();
@@ -723,6 +760,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
}
out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]);
+ if (cfv.generateSideEffectFree()) {
+ out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)};
+ }
+ out.arguments = generateBuildArgs(cfv, type, builderFields, source);
out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
return out;
}
@@ -754,7 +795,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
return out;
}
- public MethodDeclaration generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source, AccessLevel access) {
+ public MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source, AccessLevel access) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
@@ -768,7 +809,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
AllocationExpression invoke = new AllocationExpression();
invoke.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p);
out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)};
-
+ Annotation uniqueAnn = cfv.generateUnique() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) : null;
+ Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) : null;
+ if (uniqueAnn != null && sefAnn != null) {
+ out.annotations = new Annotation[] {uniqueAnn, sefAnn};
+ } else if (uniqueAnn != null) {
+ out.annotations = new Annotation[] {uniqueAnn};
+ } else if (sefAnn != null) {
+ out.annotations = new Annotation[] {sefAnn};
+ }
out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope);
return out;
}
@@ -813,18 +862,19 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
private static final AbstractMethodDeclaration[] EMPTY = {};
- public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode) {
+ public void makeSetterMethodsForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode) {
boolean deprecate = isFieldDeprecated(bfd.originalFieldNode);
if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) {
- makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode);
+ makeSimpleSetterMethodForBuilder(cfv, builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode);
} else {
- bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, fluent, chain, access);
+ bfd.singularData.getSingularizer().generateMethods(cfv, bfd.singularData, deprecate, builderType, fluent, chain, access);
}
}
- private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode) {
+ private void makeSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode) {
TypeDeclaration td = (TypeDeclaration) builderType.get();
AbstractMethodDeclaration[] existing = td.methods;
+ ASTNode source = sourceNode.get();
if (existing == null) existing = EMPTY;
int len = existing.length;
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
@@ -838,11 +888,20 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
String setterName = fluent ? new String(paramName) : HandlerUtil.buildAccessorName("set", new String(paramName));
- List<Annotation> methodAnnsList = Collections.<Annotation>emptyList();
- Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode);
- if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns);
+ List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode));
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, chain, toEclipseModifier(access),
- sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList());
+ sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(source, annotations)) : Collections.<Annotation>emptyList());
+ if (cfv.generateCalledMethods()) {
+ Argument[] arr = setter.arguments == null ? new Argument[0] : setter.arguments;
+ Argument[] newArr = new Argument[arr.length + 1];
+ System.arraycopy(arr, 0, newArr, 1, arr.length);
+ newArr[0] = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, new SingleTypeReference(builderType.getName().toCharArray(), 0), Modifier.FINAL);
+ char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED);
+ SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart);
+ ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0);
+ newArr[0].annotations = new Annotation[] {ann};
+ setter.arguments = newArr;
+ }
injectMethod(builderType, setter);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index c6b51042..8f981c1a 100755
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2018 The Project Lombok Authors.
+ * Copyright (C) 2010-2019 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
@@ -39,6 +39,7 @@ import lombok.ConfigurationKeys;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.core.AST.Kind;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
@@ -456,14 +457,14 @@ public class HandleConstructor {
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]);
/* Generate annotations that must be put on the generated method, and attach them. */ {
- Annotation[] constructorProperties = null;
- if (addConstructorProperties && !isLocalType(type)) {
- constructorProperties = createConstructorProperties(source, fieldsToParam);
- }
+ Annotation[] constructorProperties = null, checkerFramework = null;
+ if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, fieldsToParam);
+ if (getCheckerFrameworkVersion(type).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) };
constructor.annotations = copyAnnotations(source,
onConstructor.toArray(new Annotation[0]),
- constructorProperties);
+ constructorProperties,
+ checkerFramework);
}
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
@@ -551,7 +552,9 @@ public class HandleConstructor {
assigns.add(nameRef);
Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL);
- parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode));
+ Annotation[] checkerFramework = null;
+ if (getCheckerFrameworkVersion(fieldNode).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) };
+ parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode), checkerFramework);
params.add(parameter);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index 046b197f..1bca4767 100755
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2018 The Project Lombok Authors.
+ * Copyright (C) 2009-2019 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
@@ -42,6 +42,7 @@ import lombok.core.handlers.InclusionExclusionUtils;
import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.core.AnnotationValues;
import lombok.core.configuration.CallSuperType;
+import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
@@ -235,7 +236,12 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
method.modifiers = toEclipseModifier(AccessLevel.PUBLIC);
method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0);
setGeneratedBy(method.returnType, source);
- method.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
+ Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source);
+ if (getCheckerFrameworkVersion(type).generateSideEffectFree()) {