aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/lombok/ConfigurationKeys.java36
-rw-r--r--src/core/lombok/EqualsAndHashCode.java29
-rw-r--r--src/core/lombok/ToString.java35
-rw-r--r--src/core/lombok/core/AnnotationProcessor.java46
-rw-r--r--src/core/lombok/core/AnnotationValues.java129
-rw-r--r--src/core/lombok/core/LombokNode.java12
-rw-r--r--src/core/lombok/core/Version.java5
-rw-r--r--src/core/lombok/core/configuration/NullCheckExceptionType.java6
-rw-r--r--src/core/lombok/core/handlers/HandlerUtil.java16
-rw-r--r--src/core/lombok/core/handlers/InclusionExclusionUtils.java227
-rw-r--r--src/core/lombok/eclipse/EclipseNode.java71
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java77
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleConstructor.java53
-rw-r--r--src/core/lombok/eclipse/handlers/HandleData.java5
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java152
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java135
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java14
-rw-r--r--src/core/lombok/eclipse/handlers/HandleLog.java36
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java23
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java140
-rw-r--r--src/core/lombok/eclipse/handlers/HandleValue.java3
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWither.java1
-rw-r--r--src/core/lombok/experimental/FieldNameConstants.java40
-rw-r--r--src/core/lombok/extern/apachecommons/CommonsLog.java1
-rw-r--r--src/core/lombok/extern/flogger/Flogger.java62
-rw-r--r--src/core/lombok/extern/java/Log.java1
-rw-r--r--src/core/lombok/extern/jbosslog/JBossLog.java3
-rw-r--r--src/core/lombok/extern/log4j/Log4j.java1
-rw-r--r--src/core/lombok/extern/log4j/Log4j2.java1
-rw-r--r--src/core/lombok/extern/slf4j/Slf4j.java1
-rw-r--r--src/core/lombok/extern/slf4j/XSlf4j.java1
-rw-r--r--src/core/lombok/javac/JavacAST.java124
-rw-r--r--src/core/lombok/javac/JavacNode.java71
-rw-r--r--src/core/lombok/javac/apt/EmptyLombokFileObject.java2
-rw-r--r--src/core/lombok/javac/apt/LombokProcessor.java94
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java78
-rw-r--r--src/core/lombok/javac/handlers/HandleData.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java145
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldNameConstants.java137
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleLog.java37
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java13
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java11
-rw-r--r--src/core/lombok/javac/handlers/HandleToString.java120
-rw-r--r--src/core/lombok/javac/handlers/HandleValue.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleWither.java1
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java87
-rw-r--r--src/core9/module-info.java1
-rw-r--r--src/delombok/lombok/delombok/Delombok.java15
-rw-r--r--src/delombok/lombok/delombok/DelombokApp.java2
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java29
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchVal.java77
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java19
-rw-r--r--src/eclipseAgent/lombok/launch/PatchFixesHider.java6
-rw-r--r--src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java11
-rw-r--r--src/utils/lombok/core/ClassLiteral.java13
-rw-r--r--src/utils/lombok/core/FieldSelect.java13
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java22
-rw-r--r--src/utils/lombok/javac/Javac.java21
-rw-r--r--src/website/lombok/website/FetchCurrentVersion.java2
63 files changed, 1944 insertions, 622 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index ade86e27..f5134bbd 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -126,6 +126,13 @@ public class 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}.
*
* If set, <em>any</em> usage of {@code @RequiredArgsConstructor} results in a warning / error.
@@ -383,6 +390,13 @@ public class ConfigurationKeys {
public static final ConfigurationKey<FlagUsageType> LOG_JBOSSLOG_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.jbosslog.flagUsage", "Emit a warning or error if @JBossLog is used.") {};
/**
+ * lombok configuration: {@code lombok.log.flogger.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Flogger} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_FLOGGER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.flogger.flagUsage", "Emit a warning or error if @Flogger is used.") {};
+
+ /**
* lombok configuration: {@code lombok.log.fieldName} = &lt;String: aJavaIdentifier&gt; (Default: {@code log}).
*
* If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name.
@@ -499,6 +513,28 @@ public class ConfigurationKeys {
*/
public static final ConfigurationKey<FlagUsageType> UTILITY_CLASS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.utilityClass.flagUsage", "Emit a warning or error if @UtilityClass is used.") {};
+ // ----- FieldNameConstants -----
+ /**
+ * lombok configuration: {@code lombok.fieldNameConstants.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @FieldNameConstants} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> FIELD_NAME_CONSTANTS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.fieldNameConstants.flagUsage", "Emit a warning or error if @FieldNameConstants is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.fieldNameConstants.prefix} = &lt;String: aJavaIdentifierPrefix&gt; (Default: {@code PREFIX_}).
+ *
+ * The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value.
+ */
+ public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_PREFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.prefix", "names of constants generated by @FieldNameConstants will be prefixed with this value. (default: 'PREFIX_').") {};
+
+ /**
+ * lombok configuration: {@code lombok.fieldNameConstants.suffix} = &lt;String: aJavaIdentifierPrefix&gt; (Default: nothing).
+ *
+ * The names of the constants generated by {@code @FieldNameConstants} will be suffixed with this value.
+ */
+ public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_SUFFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.suffix", "names of constants generated by @FieldNameConstants will be suffixed with this value. (default: nothing).") {};
+
// ----- Wither -----
/**
diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java
index 2f88ac50..b2fc672d 100644
--- a/src/core/lombok/EqualsAndHashCode.java
+++ b/src/core/lombok/EqualsAndHashCode.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
@@ -37,6 +37,8 @@ public @interface EqualsAndHashCode {
/**
* Any fields listed here will not be taken into account in the generated {@code equals} and {@code hashCode} implementations.
* Mutually exclusive with {@link #of()}.
+ * <p>
+ * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Exclude} annotation instead.
*
* @return A list of fields to exclude.
*/
@@ -47,6 +49,8 @@ public @interface EqualsAndHashCode {
* Normally, all non-static, non-transient fields are used for identity.
* <p>
* Mutually exclusive with {@link #exclude()}.
+ * <p>
+ * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Include} annotation together with {@code @EqualsAndHashCode(onlyExplicitlyIncluded = true)}.
*
* @return A list of fields to use (<em>default</em>: all of them).
*/
@@ -89,4 +93,27 @@ public @interface EqualsAndHashCode {
@Retention(RetentionPolicy.SOURCE)
@Target({})
@interface AnyAnnotation {}
+
+ /**
+ * Only include fields and methods explicitly marked with {@code @EqualsAndHashCode.Include}.
+ * Normally, all (non-static, non-transient) fields are included by default.
+ */
+ boolean onlyExplicitlyIncluded() default false;
+
+ /**
+ * If present, do not include this field in the generated {@code equals} and {@code hashCode} methods.
+ */
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Exclude {}
+
+ /**
+ * Configure the behaviour of how this member is treated in the {@code equals} and {@code hashCode} implementation; if on a method, include the method's return value as part of calculating hashCode/equality.
+ */
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Include {
+ /** Defaults to the method name of the annotated member. If on a method and the name equals the name of a default-included field, this member takes its place. */
+ String replaces() default "";
+ }
}
diff --git a/src/core/lombok/ToString.java b/src/core/lombok/ToString.java
index 0c43c40b..ae3f071f 100644
--- a/src/core/lombok/ToString.java
+++ b/src/core/lombok/ToString.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
@@ -45,6 +45,8 @@ public @interface ToString {
/**
* Any fields listed here will not be printed in the generated {@code toString} implementation.
* Mutually exclusive with {@link #of()}.
+ * <p>
+ * Will soon be marked {@code @Deprecated}; use the {@code @ToString.Exclude} annotation instead.
*
* @return A list of fields to exclude.
*/
@@ -55,6 +57,8 @@ public @interface ToString {
* Normally, all non-static fields are printed.
* <p>
* Mutually exclusive with {@link #exclude()}.
+ * <p>
+ * Will soon be marked {@code @Deprecated}; use the {@code @ToString.Include} annotation together with {@code @ToString(onlyExplicitlyIncluded = true)}.
*
* @return A list of fields to use (<em>default</em>: all of them).
*/
@@ -75,4 +79,33 @@ public @interface ToString {
* @return If {@code true}, always use direct field access instead of calling the getter method.
*/
boolean doNotUseGetters() default false;
+
+ /**
+ * Only include fields and methods explicitly marked with {@code @ToString.Include}.
+ * Normally, all (non-static) fields are included by default.
+ */
+ boolean onlyExplicitlyIncluded() default false;
+
+ /**
+ * If present, do not include this field in the generated {@code toString}.
+ */
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Exclude {}
+
+ /**
+ * Configure the behaviour of how this member is rendered in the {@code toString}; if on a method, include the method's return value in the output.
+ */
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Include {
+// /** If true and the return value is {@code null}, omit this member entirely from the {@code toString} output. */
+// boolean skipNull() default false; // -- We'll add it later, it requires a complete rework on the toString code we generate.
+
+ /** Higher ranks are printed first. Members of the same rank are printed in the order they appear in the source file. */
+ int rank() default 0;
+
+ /** Defaults to the field / method name of the annotated member. If the name equals the name of a default-included field, this member takes its place. */
+ String name() default "";
+ }
}
diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java
index 5b4ef393..04448ecb 100644
--- a/src/core/lombok/core/AnnotationProcessor.java
+++ b/src/core/lombok/core/AnnotationProcessor.java
@@ -26,6 +26,7 @@ import static lombok.core.Augments.ClassLoader_lombokAlreadyAddedTo;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
@@ -48,6 +49,7 @@ import lombok.patcher.ClassRootFinder;
@SupportedAnnotationTypes("*")
public class AnnotationProcessor extends AbstractProcessor {
+
private static String trace(Throwable t) {
StringWriter w = new StringWriter();
t.printStackTrace(new PrintWriter(w, true));
@@ -63,6 +65,42 @@ public class AnnotationProcessor extends AbstractProcessor {
private final List<ProcessorDescriptor> registered = Arrays.asList(new JavacDescriptor(), new EcjDescriptor());
private final List<ProcessorDescriptor> active = new ArrayList<ProcessorDescriptor>();
private final List<String> delayedWarnings = new ArrayList<String>();
+
+ /**
+ * This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment}
+ * It simply returns the processing environment, but in case of gradle incremental compilation,
+ * the delegate ProcessingEnvironment of the gradle wrapper is returned.
+ */
+ public static ProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
+ ProcessingEnvironment javacProcEnv = tryRecursivelyObtainJavacProcessingEnvironment(procEnv);
+
+ if (javacProcEnv == null) {
+ delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment.");
+ }
+
+ return javacProcEnv;
+ }
+
+ private static ProcessingEnvironment tryRecursivelyObtainJavacProcessingEnvironment(ProcessingEnvironment procEnv) {
+ if (procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) {
+ return procEnv;
+ }
+
+ for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
+ try {
+ Field field = procEnvClass.getDeclaredField("delegate");
+ field.setAccessible(true);
+ Object delegate = field.get(procEnv);
+
+ return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate);
+ } catch (final Exception e) {
+ // no valid delegate, try superclass
+ }
+ }
+
+ return null;
+ }
+
static class JavacDescriptor extends ProcessorDescriptor {
private Processor processor;
@@ -72,10 +110,12 @@ public class AnnotationProcessor extends AbstractProcessor {
}
@Override boolean want(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
- if (!procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) return false;
-
+ ProcessingEnvironment javacProcEnv = getJavacProcessingEnvironment(procEnv, delayedWarnings);
+
+ if (javacProcEnv == null) return false;
+
try {
- ClassLoader classLoader = findAndPatchClassLoader(procEnv);
+ ClassLoader classLoader = findAndPatchClassLoader(javacProcEnv);
processor = (Processor) Class.forName("lombok.javac.apt.LombokProcessor", false, classLoader).newInstance();
} catch (Exception e) {
delayedWarnings.add("You found a bug in lombok; lombok.javac.apt.LombokProcessor is not available. Lombok will not run during this compilation: " + trace(e));
diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java
index d04797cb..a24330fa 100644
--- a/src/core/lombok/core/AnnotationValues.java
+++ b/src/core/lombok/core/AnnotationValues.java
@@ -27,6 +27,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -42,7 +43,7 @@ public class AnnotationValues<A extends Annotation> {
private final Class<A> type;
private final Map<String, AnnotationValue> values;
private final LombokNode<?, ?, ?> ast;
-
+
/**
* Represents a single method on the annotation class. For example, the value() method on the Getter annotation.
*/
@@ -50,8 +51,7 @@ public class AnnotationValues<A extends Annotation> {
/** A list of the raw expressions. List is size 1 unless an array is provided. */
public final List<String> raws;
- /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will
- * likely be right. If not, it'll be wrong. */
+ /** Guesses for each raw expression. It's 'primitive' (String or primitive), an AV.ClassLiteral, an AV.FieldSelect, or an array of one of those. */
public final List<Object> valueGuesses;
/** A list of the actual expressions. List is size 1 unless an array is provided. */
@@ -160,6 +160,62 @@ public class AnnotationValues<A extends Annotation> {
private A cachedInstance = null;
+ public List<String> getAsStringList(String methodName) {
+ AnnotationValue v = values.get(methodName);
+
+ if (v == null) {
+ String[] s = getDefaultIf(methodName, String[].class, new String[0]);
+ return Collections.unmodifiableList(Arrays.asList(s));
+ }
+
+ List<String> out = new ArrayList<String>(v.valueGuesses.size());
+ int idx = 0;
+ for (Object guess : v.valueGuesses) {
+ Object result = guess == null ? null : guessToType(guess, String.class, v, idx);
+ if (result == null) {
+ if (v.valueGuesses.size() == 1) {
+ String[] s = getDefaultIf(methodName, String[].class, new String[0]);
+ return Collections.unmodifiableList(Arrays.asList(s));
+ }
+ throw new AnnotationValueDecodeFail(v,
+ "I can't make sense of this annotation value. Try using a fully qualified literal.", idx);
+ }
+ out.add((String) result);
+ }
+
+ return Collections.unmodifiableList(out);
+ }
+
+ public String getAsString(String methodName) {
+ AnnotationValue v = values.get(methodName);
+ if (v == null || v.valueGuesses.size() != 1) {
+ return getDefaultIf(methodName, String.class, "");
+ }
+
+ Object guess = guessToType(v.valueGuesses.get(0), String.class, v, 0);
+ if (guess instanceof String) return (String) guess;
+ return getDefaultIf(methodName, String.class, "");
+ }
+
+ public boolean getAsBoolean(String methodName) {
+ AnnotationValue v = values.get(methodName);
+ if (v == null || v.valueGuesses.size() != 1) {
+ return getDefaultIf(methodName, boolean.class, false);
+ }
+
+ Object guess = guessToType(v.valueGuesses.get(0), boolean.class, v, 0);
+ if (guess instanceof Boolean) return ((Boolean) guess).booleanValue();
+ return getDefaultIf(methodName, boolean.class, false);
+ }
+
+ public <T> T getDefaultIf(String methodName, Class<T> type, T defaultValue) {
+ try {
+ return type.cast(type.getMethod(methodName).getDefaultValue());
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
/**
* Creates an actual annotation instance. You can use this to query any annotation methods, except for
* those annotation methods with class literals, as those can most likely not be turned into Class objects.
@@ -190,7 +246,7 @@ public class AnnotationValues<A extends Annotation> {
if (!isArray && v.valueGuesses.size() > 1) {
throw new AnnotationValueDecodeFail(v,
- "Expected a single value, but " + method.getName() + " has an array of values", -1);
+ "Expected a single value, but " + method.getName() + " has an array of values", -1);
}
if (v.valueGuesses.size() == 0 && !isArray) {
@@ -217,7 +273,7 @@ public class AnnotationValues<A extends Annotation> {
return defaultValue;
}
throw new AnnotationValueDecodeFail(v,
- "I can't make sense of this annotation value. Try using a fully qualified literal.", idx);
+ "I can't make sense of this annotation value. Try using a fully qualified literal.", idx);
}
Array.set(array, idx++, result);
}
@@ -230,48 +286,48 @@ public class AnnotationValues<A extends Annotation> {
}
private Object guessToType(Object guess, Class<?> expected, AnnotationValue v, int pos) {
- if (expected == int.class) {
+ if (expected == int.class || expected == Integer.class) {
if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) {
- return ((Number)guess).intValue();
+ return ((Number) guess).intValue();
}
}
- if (expected == long.class) {
+ if (expected == long.class || expected == Long.class) {
if (guess instanceof Long || guess instanceof Integer || guess instanceof Short || guess instanceof Byte) {
- return ((Number)guess).longValue();
+ return ((Number) guess).longValue();
}
}
- if (expected == short.class) {
+ if (expected == short.class || expected == Short.class) {
if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) {
- int intVal = ((Number)guess).intValue();
- int shortVal = ((Number)guess).shortValue();
+ int intVal = ((Number) guess).intValue();
+ int shortVal = ((Number) guess).shortValue();
if (shortVal == intVal) return shortVal;
}
}
- if (expected == byte.class) {
+ if (expected == byte.class || expected == Byte.class) {
if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) {
- int intVal = ((Number)guess).intValue();
- int byteVal = ((Number)guess).byteValue();
+ int intVal = ((Number) guess).intValue();
+ int byteVal = ((Number) guess).byteValue();
if (byteVal == intVal) return byteVal;
}
}
- if (expected == double.class) {
- if (guess instanceof Number) return ((Number)guess).doubleValue();
+ if (expected == double.class || expected == Double.class) {
+ if (guess instanceof Number) return ((Number) guess).doubleValue();
}
- if (expected == float.class) {
- if (guess instanceof Number) return ((Number)guess).floatValue();
+ if (expected == float.class || expected == Float.class) {
+ if (guess instanceof Number) return ((Number) guess).floatValue();
}
- if (expected == boolean.class) {
- if (guess instanceof Boolean) return ((Boolean)guess).booleanValue();
+ if (expected == boolean.class || expected == Boolean.class) {
+ if (guess instanceof Boolean) return ((Boolean) guess).booleanValue();
}
- if (expected == char.class) {
- if (guess instanceof Character) return ((Character)guess).charValue();
+ if (expected == char.class || expected == Character.class) {
+ if (guess instanceof Character) return ((Character) guess).charValue();
}
if (expected == String.class) {
@@ -279,27 +335,36 @@ public class AnnotationValues<A extends Annotation> {
}
if (Enum.class.isAssignableFrom(expected) ) {
- if (guess instanceof String) {
+ if (guess instanceof FieldSelect) {
+ String fieldSel = ((FieldSelect) guess).getFinalPart();
for (Object enumConstant : expected.getEnumConstants()) {
- String target = ((Enum<?>)enumConstant).name();
- if (target.equals(guess)) return enumConstant;
+ String target = ((Enum<?>) enumConstant).name();
+ if (target.equals(fieldSel)) return enumConstant;
}
throw new AnnotationValueDecodeFail(v,
- "Can't translate " + guess + " to an enum of type " + expected, pos);
+ "Can't translate " + fieldSel + " to an enum of type " + expected, pos);
}
}
- if (Class.class == expected) {
- if (guess instanceof String) try {
- return Class.forName(toFQ((String)guess));
+ if (expected == Class.class) {
+ if (guess instanceof ClassLiteral) try {
+ String classLit = ((ClassLiteral) guess).getClassName();
+ return Class.forName(toFQ(classLit));
} catch (ClassNotFoundException e) {
throw new AnnotationValueDecodeFail(v,
- "Can't translate " + guess + " to a class object.", pos);
+ "Can't translate " + guess + " to a class object.", pos);
}
}
+ if (guess instanceof AnnotationValues) {
+ return ((AnnotationValues<?>) guess).getInstance();
+ }
+
+ if (guess instanceof FieldSelect) throw new AnnotationValueDecodeFail(v,
+ "You must use constant literals in lombok annotations; they cannot be references to (static) fields.", pos);
+
throw new AnnotationValueDecodeFail(v,
- "Can't translate a " + guess.getClass() + " to the expected " + expected, pos);
+ "Can't translate a " + guess.getClass() + " to the expected " + expected, pos);
}
/**
diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index 07c62151..d6708956 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/src/core/lombok/core/LombokNode.java
@@ -21,6 +21,7 @@
*/
package lombok.core;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -275,4 +276,15 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
public boolean isStructurallySignificant() {
return isStructurallySignificant;
}
+
+ public abstract boolean hasAnnotation(Class<? extends Annotation> type);
+ public abstract <Z extends Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type);
+
+ public abstract boolean isStatic();
+ public abstract boolean isTransient();
+ public abstract boolean isEnumMember();
+
+ public abstract int countMethodParameters();
+
+ public abstract int getStartPos();
}
diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java
index 98f1e575..70af48e0 100644
--- a/src/core/lombok/core/Version.java
+++ b/src/core/lombok/core/Version.java
@@ -30,15 +30,16 @@ public class Version {
// ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries).
// Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example.
// Official builds always end in an even number. (Since 0.10.2).
- private static final String VERSION = "1.16.21";
+ private static final String VERSION = "1.18.1";
private static final String RELEASE_NAME = "Edgy Guinea Pig";
-// private static final String RELEASE_NAME = "Dancing Elephant";
+// private static final String RELEASE_NAME = "Envious Ferret";
// Named version history:
// Angry Butterfly
// Branching Cobra
// Candid Duck
// Dancing Elephant
+ // Envious Ferret
private Version() {
//Prevent instantiation
diff --git a/src/core/lombok/core/configuration/NullCheckExceptionType.java b/src/core/lombok/core/configuration/NullCheckExceptionType.java
index 18a332fd..c4bb71f2 100644
--- a/src/core/lombok/core/configuration/NullCheckExceptionType.java
+++ b/src/core/lombok/core/configuration/NullCheckExceptionType.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Project Lombok Authors.
+ * Copyright (C) 2014-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
@@ -26,7 +26,7 @@ package lombok.core.configuration;
public enum NullCheckExceptionType {
ILLEGAL_ARGUMENT_EXCEPTION {
public String toExceptionMessage(String fieldName) {
- return fieldName + " is null";
+ return fieldName + " is marked @NonNull but is null";
}
@Override public String getExceptionType() {
@@ -35,7 +35,7 @@ public enum NullCheckExceptionType {
},
NULL_POINTER_EXCEPTION {
@Override public String toExceptionMessage(String fieldName) {
- return fieldName;
+ return fieldName + " is marked @NonNull but is null";
}
public String getExceptionType() {
diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java
index 6b516904..0d64c550 100644
--- a/src/core/lombok/core/handlers/HandlerUtil.java
+++ b/src/core/lombok/core/handlers/HandlerUtil.java
@@ -57,6 +57,10 @@ import lombok.experimental.Wither;
public class HandlerUtil {
private HandlerUtil() {}
+ public enum FieldAccess {
+ GETTER, PREFER_FIELD, ALWAYS_FIELD;
+ }
+
public static int primeForHashcode() {
return 59;
}
@@ -441,4 +445,16 @@ public class HandlerUtil {
}
return String.format("%s%s", prefix, suffix);
}
+
+ public static String camelCaseToConstant(String fieldName) {
+ if (fieldName == null || fieldName.isEmpty()) return "";
+ StringBuilder b = new StringBuilder();
+ b.append(Character.toUpperCase(fieldName.charAt(0)));
+ for (int i = 1; i < fieldName.length(); i++) {
+ char c = fieldName.charAt(i);
+ if (Character.isUpperCase(c)) b.append('_');
+ b.append(Character.toUpperCase(c));
+ }
+ return b.toString();
+ }
}
diff --git a/src/core/lombok/core/handlers/InclusionExclusionUtils.java b/src/core/lombok/core/handlers/InclusionExclusionUtils.java
new file mode 100644
index 00000000..8d6c717f
--- /dev/null
+++ b/src/core/lombok/core/handlers/InclusionExclusionUtils.java
@@ -0,0 +1,227 @@
+/*
+ * 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
+ * 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.handlers;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import lombok.core.AST;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.core.LombokNode;
+
+public class InclusionExclusionUtils {
+ private static List<Integer> createListOfNonExistentFields(List<String> list, LombokNode<?, ?, ?> type, boolean excludeStandard, boolean excludeTransient) {
+ boolean[] matched = new boolean[list.size()];
+
+ for (LombokNode<?, ?, ?> child : type.down()) {
+ if (list.isEmpty()) break;
+ if (child.getKind() != Kind.FIELD) continue;
+ if (excludeStandard) {
+ if (child.isStatic()) continue;
+ if (child.getName().startsWith("$")) continue;
+ }
+ if (excludeTransient && child.isTransient()) continue;
+
+ int idx = list.indexOf(child.getName());
+ if (idx > -1) matched[idx] = true;
+ }
+
+ List<Integer> problematic = new ArrayList<Integer>();
+ for (int i = 0 ; i < list.size() ; i++) if (!matched[i]) problematic.add(i);
+
+ return problematic;
+ }
+
+ public static void checkForBogusFieldNames(LombokNode<?, ?, ?> type, AnnotationValues<?> annotation, List<String> excludes, List<String> includes) {
+ if (excludes != null && !excludes.isEmpty()) {
+ for (int i : createListOfNonExistentFields(excludes, type, true, false)) {
+ if (annotation != null) annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
+ }
+ }
+
+ if (includes != null && !includes.isEmpty()) {
+ for (int i : createListOfNonExistentFields(includes, type, false, false)) {
+ if (annotation != null) annotation.setWarning("of", "This field does not exist.", i);
+ }
+ }
+ }
+
+ public static class Included<L, I extends Annotation> {
+ private final L node;
+ private final I inc;
+ private final boolean defaultInclude;
+
+ public Included(L node, I inc, boolean defaultInclude) {
+ this.node = node;
+ this.inc = inc;
+ this.defaultInclude = defaultInclude;
+ }
+
+ public L getNode() {
+ return node;
+ }
+
+ public I getInc() {
+ return inc;
+ }
+
+ public boolean isDefaultInclude() {
+ return defaultInclude;
+ }
+ }
+
+ private static String innerAnnName(Class<? extends Annotation> type) {
+ String name = type.getSimpleName();
+ Class<?> c = type.getEnclosingClass();
+ while (c != null) {
+ name = c.getSimpleName() + "." + name;
+ c = c.getEnclosingClass();
+ }
+ return name;
+ }
+
+ public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N, I extends Annotation> List<Included<L, I>> handleIncludeExcludeMarking(Class<I> inclType, String replaceName, Class<? extends Annotation> exclType, LombokNode<A, L, N> typeNode, AnnotationValues<?> annotation, LombokNode<A, L, N> annotationNode) {
+ List<String> oldExcludes = (annotation != null && annotation.isExplicit("exclude")) ? annotation.getAsStringList("exclude") : null;
+ List<String> oldIncludes = (annotation != null && annotation.isExplicit("of")) ? annotation.getAsStringList("of") : null;
+
+ boolean onlyExplicitlyIncluded = annotation != null ? annotation.getAsBoolean("onlyExplicitlyIncluded") : false;
+ boolean memberAnnotationMode = onlyExplicitlyIncluded;
+ List<Included<L, I>> members = new ArrayList<Included<L, I>>();
+ List<String> namesToAutoExclude = new ArrayList<String>();
+
+ if (typeNode == null || typeNode.getKind() != Kind.TYPE) return null;
+
+ checkForBogusFieldNames(typeNode, annotation, oldExcludes, oldIncludes);
+ String inclTypeName = innerAnnName(inclType);
+ String exclTypeName = innerAnnName(exclType);
+
+ if (oldExcludes != null && oldIncludes != null) {
+ oldExcludes = null;
+ if (annotation != null) annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
+ }
+
+ for (L child : typeNode.down()) {
+ boolean markExclude = child.getKind() == Kind.FIELD && child.hasAnnotation(exclType);
+ AnnotationValues<I> markInclude = null;
+ if (child.getKind() == Kind.FIELD || child.getKind() == Kind.METHOD) markInclude = child.findAnnotation(inclType);
+
+ if (markExclude || markInclude != null) memberAnnotationMode = true;
+
+ if (markInclude != null && markExclude) {
+ child.addError("@" + exclTypeName + " and @" + inclTypeName + " are mutually exclusive; the @Include annotation will be ignored");
+ markInclude = null;
+ }
+
+ String name = child.getName();
+
+ if (markExclude) {
+ if (onlyExplicitlyIncluded) {
+ child.addWarning("The @Exclude annotation is not needed; 'onlyExplicitlyIncluded' is set, so this member would be excluded anyway");
+ } else if (child.isStatic()) {
+ child.addWarning("The @Exclude annotation is not needed; static fields aren't included anyway");
+ } else if (name.startsWith("$")) {
+ child.addWarning("The @Exclude annotation is not needed; fields that start with $ aren't included anyway");
+ }
+ continue;
+ }
+
+ if (oldExcludes != null && oldExcludes.contains(name)) continue;
+
+ if (markInclude != null) {
+ I inc = markInclude.getInstance();
+ if (child.getKind() == Kind.METHOD) {
+ if (child.countMethodParameters() > 0) {
+ child.addError("Methods included with @" + inclTypeName + " must have no arguments; it will not be included");
+ continue;
+ }
+ String n = replaceName != null ? markInclude.getAsString(replaceName) : "";
+ if (n.isEmpty()) n = name;
+ namesToAutoExclude.add(n);
+ }
+ members.add(new Included<L, I>(child, inc, false));
+ continue;
+ }
+
+ if (onlyExplicitlyIncluded) continue;
+ if (oldIncludes != null) {
+ if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included<L, I>(child, null, false));
+ continue;
+ }
+ if (child.getKind() != Kind.FIELD) continue;
+ if (child.isStatic()) continue;
+ if (name.startsWith("$")) continue;
+ if (child.isEnumMember()) continue;
+ members.add(new Included<L, I>(child, null, true));
+ }
+
+ /* delete default-included fields with the same name as an explicit inclusion */ {
+ Iterator<Included<L, I>> it = members.iterator();
+ while (it.hasNext()) {
+ Included<L, I> m = it.next();
+ if (m.isDefaultInclude() && namesToAutoExclude.contains(m.getNode().getName())) it.remove();
+ }
+ }
+
+ if (annotation == null || !annotation.isExplicit("exclude")) oldExcludes = null;
+ if (annotation == null || !annotation.isExplicit("of")) oldIncludes = null;
+
+ if (memberAnnotationMode && (oldExcludes != null || oldIncludes != null)) {
+ annotationNode.addError("The old-style 'exclude/of' parameter cannot be used together with the new-style @Include / @Exclude annotations.");
+ return null;
+ }
+
+ return members;
+ }
+
+ public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> List<Included<L, ToString.Include>> handleToStringMarking(LombokNode<A, L, N> typeNode, AnnotationValues<ToString> annotation, LombokNode<A, L, N> annotationNode) {
+ List<Included<L, ToString.Include>> members = handleIncludeExcludeMarking(ToString.Include.class, "name", ToString.Exclude.class, typeNode, annotation, annotationNode);
+
+ Collections.sort(members, new Comparator<Included<L, ToString.Include>>() {
+ @Override public int compare(Included<L, ToString.Include> a, Included<L, ToString.Include> b) {
+ int ra = a.getInc() == null ? 0 : a.getInc().rank();
+ int rb = b.getInc() == null ? 0 : b.getInc().rank();
+ if (ra < rb) return +1;
+ if (ra > rb) return -1;
+
+ int pa = a.getNode().getStartPos();
+ int pb = b.getNode().getStartPos();
+
+ if (pa < pb) return -1;
+ if (pa > pb) return +1;
+
+ return 0;
+ }
+ });
+ return members;
+ }
+
+ public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> List<Included<L, EqualsAndHashCode.Include>> handleEqualsAndHashCodeMarking(LombokNode<A, L, N> typeNode, AnnotationValues<EqualsAndHashCode> annotation, LombokNode<A, L, N> annotationNode) {
+ return handleIncludeExcludeMarking(EqualsAndHashCode.Include.class, "replaces", EqualsAndHashCode.Exclude.class, typeNode, annotation, annotationNode);
+ }
+}
diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java
index 49867e62..4db1d38d 100644
--- a/src/core/lombok/eclipse/EclipseNode.java
+++ b/src/core/lombok/eclipse/EclipseNode.java
@@ -23,7 +23,9 @@ package lombok.eclipse;
import java.util.List;
+import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.eclipse.handlers.EclipseHandlerUtil;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -36,6 +38,7 @@ import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
/**
* Eclipse specific version of the LombokNode class.
@@ -184,4 +187,72 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode,
public boolean isCompleteParse() {
return ast.isCompleteParse();
}
+
+ @Override public boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type) {
+ return EclipseHandlerUtil.hasAnnotation(type, this);
+ }
+
+ @Override public <Z extends java.lang.annotation.Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type) {
+ EclipseNode annotation = EclipseHandlerUtil.findAnnotation(type, this);
+ if (annotation == null) return null;
+ return EclipseHandlerUtil.createAnnotation(type, annotation);
+ }
+
+ private Integer getModifiers() {
+ if (node instanceof TypeDeclaration) return ((TypeDeclaration) node).modifiers;
+ if (node instanceof FieldDeclaration) return ((FieldDeclaration) node).modifiers;
+ if (node instanceof LocalDeclaration) return ((LocalDeclaration) node).modifiers;
+ if (node instanceof AbstractMethodDeclaration) return ((AbstractMethodDeclaration) node).modifiers;
+
+ return null;
+ }
+
+ @Override public boolean isStatic() {
+ if (node instanceof TypeDeclaration) {
+ EclipseNode directUp = directUp();
+ if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true;
+ if (!(directUp.get() instanceof TypeDeclaration)) return false;
+ TypeDeclaration p = (TypeDeclaration) directUp.get();
+ int f = p.modifiers;
+ if ((ClassFileConstants.AccInterface & f) != 0) return true;
+ if ((ClassFileConstants.AccEnum & f) != 0) return true;
+ }
+
+ if (node instanceof FieldDeclaration) {
+ EclipseNode directUp = directUp();
+ if (directUp != null && directUp.get() instanceof TypeDeclaration) {
+ TypeDeclaration p = (TypeDeclaration) directUp.get();
+ int f = p.modifiers;
+ if ((ClassFileConstants.AccInterface & f) != 0) return true;
+ }
+ }
+
+ Integer i = getModifiers();
+ if (i == null) return false;
+ int f = i.intValue();
+ return (ClassFileConstants.AccStatic & f) != 0;
+ }
+
+ @Override public boolean isTransient() {
+ if (getKind() != Kind.FIELD) return false;
+ Integer i = getModifiers();
+ return i != null && (i.intValue() & ClassFileConstants.AccTransient) != 0;
+ }
+
+ @Override public boolean isEnumMember() {
+ if (getKind() != Kind.FIELD) return false;
+ return ((FieldDeclaration) node).getKind() == 3;
+ }
+
+ @Override public int countMethodParameters() {
+ if (getKind() != Kind.METHOD) return 0;
+
+ Argument[] a = ((AbstractMethodDeclaration) node).arguments;
+ if (a == null) return 0;
+ return a.length;
+ }
+
+ @Override public int getStartPos() {
+ return node.sourceStart;
+ }
}
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 6617d21a..2dce285c 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -746,7 +746,7 @@ public class EclipseHandlerUtil {
* Provides AnnotationValues with the data it needs to do its thing.
*/
public static <A extends java.lang.annotation.Annotation> AnnotationValues<A>
- createAnnotation(Class<A> type, final EclipseNode annotationNode) {
+ createAnnotation(Class<A> type, final EclipseNode annotationNode) {
final Annotation annotation = (Annotation) annotationNode.get();
Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
@@ -763,7 +763,7 @@ public class EclipseHandlerUtil {
String mName = (n == null || n.length == 0) ? "value" : new String(pair.name);
final Expression rhs = pair.value;
if (rhs instanceof ArrayInitializer) {
- expressions = ((ArrayInitializer)rhs).expressions;
+ expressions = ((ArrayInitializer) rhs).expressions;
} else if (rhs != null) {
expressions = new Expression[] { rhs };
}
@@ -920,10 +920,6 @@ public class EclipseHandlerUtil {
return null;
}
- public enum FieldAccess {
- GETTER, PREFER_FIELD, ALWAYS_FIELD;
- }
-
static boolean lookForGetter(EclipseNode field, FieldAccess fieldAccess) {
if (fieldAccess == FieldAccess.GETTER) return true;
if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false;
@@ -940,11 +936,13 @@ public class EclipseHandlerUtil {
}
static TypeReference getFieldType(EclipseNode field, FieldAccess fieldAccess) {
+ if (field.get() instanceof MethodDeclaration) return ((MethodDeclaration) field.get()).returnType;
+
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
- return ((FieldDeclaration)field.get()).type;
+ return ((FieldDeclaration) field.get()).type;
}
return getter.type;
@@ -952,7 +950,7 @@ public class EclipseHandlerUtil {
static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source) {
int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
- long p = (long)pS << 32 | pE;
+ long p = (long) pS << 32 | pE;
boolean lookForGetter = lookForGetter(field, fieldAccess);
@@ -1020,6 +1018,43 @@ public class EclipseHandlerUtil {
return call;
}
+ static Expression createMethodAccessor(EclipseNode method, ASTNode source) {
+ int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ MethodDeclaration methodDecl = (MethodDeclaration) method.get();
+ MessageSend call = new MessageSend();
+ setGeneratedBy(call, source);
+ call.sourceStart = pS; call.statementEnd = call.sourceEnd = pE;
+ if ((methodDecl.modifiers & ClassFileConstants.AccStatic) == 0) {
+ call.receiver = new ThisReference(pS, pE);
+ setGeneratedBy(call.receiver, source);
+ } else {
+ EclipseNode containerNode = method.up();
+ if (containerNode != null && containerNode.get() instanceof TypeDeclaration) {
+ call.receiver = new SingleNameReference(((TypeDeclaration) containerNode.get()).name, p);
+ setGeneratedBy(call.receiver, source);
+ }
+ }
+
+ call.selector = methodDecl.selector;
+ return call;
+ }
+
+ static Expression createMethodAccessor(EclipseNode method, ASTNode source, char[] receiver) {
+ int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ MethodDeclaration methodDecl = (MethodDeclaration) method.get();
+ MessageSend call = new MessageSend();
+ setGeneratedBy(call, source);
+ call.sourceStart = pS; call.statementEnd = call.sourceEnd = pE;
+ call.receiver = new SingleNameReference(receiver, p);
+ setGeneratedBy(call.receiver, source);
+ call.selector = methodDecl.selector;
+ return call;
+ }
+
/** Serves as return value for the methods that check for the existence of fields and methods. */
public enum MemberExistsResult {
NOT_EXISTS, EXISTS_BY_LOMBOK, EXISTS_BY_USER;
@@ -1097,7 +1132,7 @@ public class EclipseHandlerUtil {
public static boolean filterField(FieldDeclaration declaration, boolean skipStatic) {
// Skip the fake fields that represent enum constants.
if (declaration.initialization instanceof AllocationExpression &&
- ((AllocationExpression)declaration.initialization).enumConstant != null) return false;
+ ((AllocationExpression) declaration.initialization).enumConstant != null) return false;
if (declaration.type == null) return false;
@@ -1163,6 +1198,12 @@ public class EclipseHandlerUtil {
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.
@@ -1171,10 +1212,7 @@ public class EclipseHandlerUtil {
* @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) {
@@ -1260,10 +1298,7 @@ public class EclipseHandlerUtil {
* @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) {
@@ -1819,4 +1854,12 @@ public class EclipseHandlerUtil {
private static long[] copy(long[] array) {
return array == null ? null : array.clone();
}
+
+ public static boolean isDirectDescendantOfObject(EclipseNode typeNode) {
+ if (!(typeNode.get() instanceof TypeDeclaration)) throw new IllegalArgumentException("not a type node");
+ TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get();
+ if (typeDecl.superclass == null) return true;
+ String p = typeDecl.superclass.toString();
+ return p.equals("Object") || p.equals("java.lang.Object");
+ }
}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index fe19decd..e1b1af26 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -74,8 +74,10 @@ import lombok.Builder;
import lombok.Builder.ObtainVia;
import lombok.ConfigurationKeys;
import lombok.Singular;
+import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.eclipse.Eclipse;
@@ -449,9 +451,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
- List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>();
+ List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
for (BuilderFieldData bfd : builderFields) {
- fieldNodes.addAll(bfd.createdFields);
+ for (EclipseNode f : bfd.createdFields) {
+ fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true));
+ }
}
MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD);
if (md != null) injectMethod(builderType, md);
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index a2940b88..cab847e6 100644
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -42,8 +42,10 @@ import lombok.core.AST.Kind;
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;
@@ -204,6 +206,20 @@ public class HandleConstructor {
return true;
}
+ public enum SkipIfConstructorExists {
+ YES, NO, I_AM_BUILDER;
+ }
+
+ public void generateExtraNoArgsConstructor(EclipseNode typeNode, EclipseNode sourceNode) {
+ if (!isDirectDescendantOfObject(typeNode)) return;
+
+ 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) {
@@ -218,14 +234,17 @@ public class HandleConstructor {
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("");
@@ -257,6 +276,8 @@ public class HandleConstructor {
}
}
+ if (noArgs && noArgsConstructorExists(typeNode)) return;
+
ConstructorDeclaration constr = createConstructor(
staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault,
sourceNode, onConstructor);
@@ -267,7 +288,29 @@ public class HandleConstructor {
}
}
- public static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
+ 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;
+ }
+ }
+ }
+
+ for (EclipseNode child : node.down()) {
+ if (annotationTypeMatches(NoArgsConstructor.class, child)) return true;
+ if (annotationTypeMatches(RequiredArgsConstructor.class, child) && findRequiredFields(node).isEmpty()) return true;
+ if (annotationTypeMatches(AllArgsConstructor.class, child) && findAllFields(node).isEmpty()) 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;
diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java
index 025ceefd..4011890d 100644
--- a/src/core/lombok/eclipse/handlers/HandleData.java
+++ b/src/core/lombok/eclipse/handlers/HandleData.java
@@ -72,12 +72,13 @@ public class HandleData extends EclipseAnnotationHandler<Data> {
//for whatever reason, though you can find callers of that one by focusing on the class name itself
//and hitting 'find callers'.
- handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
- handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
+ handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList());
+ handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
handleToString.generateToStringForType(typeNode, annotationNode);
handleConstructor.generateRequiredArgsConstructor(
typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES,
Collections.<Annotation>emptyList(), annotationNode);
+ handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index 75339f7c..c99b9b5f 100644
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2015 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
@@ -38,12 +38,13 @@ import lombok.ConfigurationKeys;
import lombok.EqualsAndHashCode;
import lombok.core.AST.Kind;
import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.InclusionExclusionUtils;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.core.AnnotationValues;
import lombok.core.configuration.CallSuperType;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
@@ -57,7 +58,6 @@ import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
@@ -99,62 +99,41 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
public static final Set<String> BUILT_IN_TYPES = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
"byte", "short", "int", "long", "char", "boolean", "double", "float")));
- public void checkForBogusFieldNames(EclipseNode type, AnnotationValues<EqualsAndHashCode> annotation) {
- if (annotation.isExplicit("exclude")) {
- for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().exclude()), type, true, true)) {
- annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
- }
- }
- if (annotation.isExplicit("of")) {
- for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().of()), type, false, false)) {
- annotation.setWarning("of", "This field does not exist.", i);
- }
- }
- }
-
- public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) {
- if (hasAnnotation(EqualsAndHashCode.class, typeNode)) {
- //The annotation will make it happen, so we can skip it.
- return;
- }
-
- Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
- FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
-
- generateMethods(typeNode, errorNode, null, null, null, false, access, new ArrayList<Annotation>());
- }
-
@Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode");
EqualsAndHashCode ann = annotation.getInstance();
- List<String> excludes = Arrays.asList(ann.exclude());
- List<String> includes = Arrays.asList(ann.of());
- EclipseNode typeNode = annotationNode.up();
+ List<Included<EclipseNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode);
+ if (members == null) return;
List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode);
- checkForBogusFieldNames(typeNode, annotation);
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper")) callSuper = null;
- if (!annotation.isExplicit("exclude")) excludes = null;
- if (!annotation.isExplicit("of")) includes = null;
-
- if (excludes != null && includes != null) {
- excludes = null;
- annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
- }
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
- generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess, onParam);
+ generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, fieldAccess, onParam);
+ }
+
+ public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) {
+ if (hasAnnotation(EqualsAndHashCode.class, typeNode)) {
+ //The annotation will make it happen, so we can skip it.
+ return;
+ }
+
+ List<Included<EclipseNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null);
+
+ Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
+ FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
+
+ generateMethods(typeNode, errorNode, members, null, false, access, new ArrayList<Annotation>());
}
- public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes,
- Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
- assert excludes == null || includes == null;
+ public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members,
+ Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
TypeDeclaration typeDecl = null;
@@ -172,18 +151,13 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
if (callSuper == null) {
try {
- callSuper = ((Boolean)EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
+ callSuper = ((Boolean) EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
} catch (Exception ignore) {
throw new InternalError("Lombok bug - this cannot happen - can't find callSuper field in EqualsAndHashCode annotation.");
}
}
- boolean isDirectDescendantOfObject = true;
-
- if (typeDecl.superclass != null) {
- String p = typeDecl.superclass.toString();
- isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
- }
+ boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode);
if (isDirectDescendantOfObject && callSuper) {
errorNode.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless.");
@@ -209,27 +183,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
}
- List<EclipseNode> nodesForEquality = new ArrayList<EclipseNode>();
- if (includes != null) {
- for (EclipseNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
- if (includes.contains(new String(fieldDecl.name))) nodesForEquality.add(child);
- }
- } else {
- for (EclipseNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
- if (!filterField(fieldDecl)) continue;
-
- //Skip transient fields.
- if ((fieldDecl.modifiers & ClassFileConstants.AccTransient) != 0) continue;
- //Skip excluded fields.
- if (excludes != null && excludes.contains(new String(fieldDecl.name))) continue;
- nodesForEquality.add(child);
- }
- }
-
boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0;
boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject;
MemberExistsResult equalsExists = methodExists("equals", typeNode, 1);
@@ -258,7 +211,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
//fallthrough
}
- MethodDeclaration equalsMethod = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam);
+ MethodDeclaration equalsMethod = createEquals(typeNode, members, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam);
equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, equalsMethod);
@@ -268,17 +221,16 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
injectMethod(typeNode, canEqualMethod);
}
- MethodDeclaration hashCodeMethod = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
+ MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, errorNode.get(), fieldAccess);
hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, hashCodeMethod);
}
- public MethodDeclaration createHashCode(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
+ public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
- MethodDeclaration method = new MethodDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
setGeneratedBy(method, source);
method.modifiers = toEclipseModifier(AccessLevel.PUBLIC);
@@ -295,10 +247,10 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
List<Statement> statements = new ArrayList<Statement>();
- final boolean isEmpty = fields.isEmpty();
+ final boolean isEmpty = members.isEmpty();
/* final int PRIME = X; */ {
- /* Without fields, PRIME isn't used, and that would trigger a 'local variable not used' warning. */
+ /* Without members, PRIME isn't used, as that would trigger a 'local variable not used' warning. */
if (!isEmpty) {
LocalDeclaration primeDecl = new LocalDeclaration(PRIME, pS, pE);
setGeneratedBy(primeDecl, source);
@@ -311,7 +263,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
}
- /*int result = ... */{
+ /* int result = ... */ {
LocalDeclaration resultDecl = new LocalDeclaration(RESULT, pS, pE);
setGeneratedBy(resultDecl, source);
final Expression init;
@@ -335,11 +287,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
statements.add(resultDecl);
}
- for (EclipseNode field : fields) {
- TypeReference fType = getFieldType(field, fieldAccess);
- char[] dollarFieldName = ("$" + field.getName()).toCharArray();
+ for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) {
+ EclipseNode memberNode = member.getNode();
+ boolean isMethod = memberNode.getKind() == Kind.METHOD;
+
+ TypeReference fType = getFieldType(memberNode, fieldAccess);
+ char[] dollarFieldName = ((isMethod ? "$$" : "$") + memberNode.getName()).toCharArray();
char[] token = fType.getLastToken();
- Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);
+ Expression fieldAccessor = isMethod ? createMethodAccessor(memberNode, source) : createFieldAccessor(memberNode, fieldAccess, source);
if (fType.dimensions() == 0 && token != null) {
if (Arrays.equals(TypeConstants.BOOLEAN, token)) {
/* booleanField ? X : Y */
@@ -479,14 +434,16 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
list.add(type.getName());
if (addWildcards) genericsCount.add(arraySizeOf(((TypeDeclaration) type.get()).typeParameters));
- boolean staticContext = (((TypeDeclaration) type.get()).modifiers & Modifier.STATIC) != 0;
+ boolean staticContext = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccStatic) != 0;
EclipseNode tNode = type.up();
+ if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true;
while (tNode != null && tNode.getKind() == Kind.TYPE) {
list.add(tNode.getName());
if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(((TypeDeclaration) tNode.get()).typeParameters));
if (!staticContext) staticContext = (((TypeDeclaration) tNode.get()).modifiers & Modifier.STATIC) != 0;
tNode = tNode.up();
+ if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true;
}
Collections.reverse(list);
if (addWildcards) Collections.reverse(genericsCount);
@@ -533,12 +490,11 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
return arr == null ? 0 : arr.length;
}
- public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) {
+ public MethodDeclaration createEquals(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) {
int pS = source.sourceStart; int pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
- MethodDeclaration method = new MethodDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
setGeneratedBy(method, source);
method.modifiers = toEclipseModifier(AccessLevel.PUBLIC);
method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
@@ -605,7 +561,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
char[] otherName = "other".toCharArray();
/* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ {
- if (!fields.isEmpty() || needsCanEqual) {
+ if (!members.isEmpty() || needsCanEqual) {
LocalDeclaration other = new LocalDeclaration(otherName, pS, pE);
other.modifiers |= ClassFileConstants.AccFinal;
setGeneratedBy(other, source);
@@ -674,11 +630,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
statements.add(ifSuperEquals);
}
- for (EclipseNode field : fields) {
- TypeReference fType = getFieldType(field, fieldAccess);
+ for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) {
+ EclipseNode memberNode = member.getNode();
+ boolean isMethod = memberNode.getKind() == Kind.METHOD;
+
+ TypeReference fType = getFieldType(memberNode, fieldAccess);
char[] token = fType.getLastToken();
- Expression thisFieldAccessor = createFieldAccessor(field, fieldAccess, source);
- Expression otherFieldAccessor = createFieldAccessor(field, fieldAccess, source, otherName);
+ Expression thisFieldAccessor = isMethod ? createMethodAccessor(memberNode, source) : createFieldAccessor(memberNode, fieldAccess, source);
+ Expression otherFieldAccessor = isMethod ? createMethodAccessor(memberNode, source, otherName) : createFieldAccessor(memberNode, fieldAccess, source, otherName);
if (fType.dimensions() == 0 && token != null) {
if (Arrays.equals(TypeConstants.FLOAT, token)) {
@@ -699,8 +658,8 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
/* final java.lang.Object this$fieldName = this.fieldName; */
/* final java.lang.Object other$fieldName = other.fieldName; */
/* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */
- char[] thisDollarFieldName = ("this$" + field.getName()).toCharArray();
- char[] otherDollarFieldName = ("other$" + field.getName()).toCharArray();
+ char[] thisDollarFieldName = ("this" + (isMethod ? "$$" : "$") + memberNode.getName()).toCharArray();
+ char[] otherDollarFieldName = ("other" + (isMethod ? "$$" : "$") + memberNode.getName()).toCharArray();
statements.add(createLocalDeclaration(source, thisDollarFieldName, generateQualifiedTypeRef(source, TypeConstants.JAVA_LANG_OBJECT), thisFieldAccessor));
statements.add(createLocalDeclaration(source, otherDollarFieldName, generateQualifiedTypeRef(source, TypeConstants.JAVA_LANG_OBJECT), otherFieldAccessor));
@@ -713,7 +672,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
setGeneratedBy(other1, source);
SingleNameReference other2 = new SingleNameReference(otherDollarFieldName, p);
setGeneratedBy(other2, source);
-
NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, source);
@@ -776,7 +734,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
return method;
}
-
public MethodDeclaration createCanEqual(EclipseNode type, ASTNode source, List<Annotation> onParam) {
/* protected boolean canEqual(final java.lang.Object other) {
* return other instanceof Outer.Inner.MyType;
@@ -787,8 +744,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
char[] otherName = "other".toCharArray();
- MethodDeclaration method = new MethodDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
setGeneratedBy(method, source);
method.modifiers = toEclipseModifier(AccessLevel.PROTECTED);
method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java
new file mode 100644
index 00000000..c3a28f7f
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014-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
+ * 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.core.handlers.HandlerUtil.handleExperimentalFlagUsage;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+
+import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.core.handlers.HandlerUtil;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+import lombok.experimental.FieldNameConstants;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(EclipseAnnotationHandler.class)
+public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldNameConstants> {
+ public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, String prefix, String suffix) {
+ TypeDeclaration typeDecl = null;
+ if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
+
+ int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
+ boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
+
+ if (typeDecl == null || notAClass) {
+ errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field.");
+ return;
+ }
+
+ for (EclipseNode field : typeNode.down()) {
+ if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix);
+ }
+ }
+
+ private void generateFieldNameConstantsForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, String prefix, String suffix) {
+ if (hasAnnotation(FieldNameConstants.class, fieldNode)) return;
+ createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, pos, false);
+ }
+
+ private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field) {
+ if (field.getKind() != Kind.FIELD) return false;
+ FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
+ return filterField(fieldDecl);
+ }
+
+ public void handle(AnnotationValues<FieldNameConstants> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants");
+
+ EclipseNode node = annotationNode.up();
+ FieldNameConstants annotatationInstance = annotation.getInstance();
+ AccessLevel level = annotatationInstance.level();
+ String prefix = annotatationInstance.prefix();
+ String suffix = annotatationInstance.suffix();
+ if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX);
+ if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX);
+ if (prefix == null) prefix = "FIELD_";
+ if (suffix == null) suffix = "";
+ if (node == null) return;
+
+ switch (node.getKind()) {
+ case FIELD:
+ if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true);
+ break;
+ case TYPE:
+ if (level == AccessLevel.NONE) {
+ annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE.");
+ return;
+ }
+ generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix);
+ break;
+ }
+ }
+
+ private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) {
+ for (EclipseNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, source, whineIfExists);
+ }
+
+ private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) {
+ if (fieldNode.getKind() != Kind.FIELD) {
+ errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field");
+ return;
+ }
+
+ FieldDeclaration field = (FieldDeclaration) fieldNode.get();
+ String fieldName = new String(field.name);
+ String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix;
+ if (constantName.equals(fieldName)) {
+ fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field.");
+ return;
+ }
+
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+ FieldDeclaration fieldConstant = new FieldDeclaration(constantName.toCharArray(), pS,pE);
+ fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+ fieldConstant.modifiers = toEclipseModifier(level) | Modifier.STATIC | Modifier.FINAL;
+ fieldConstant.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p,p,p});
+ fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0);
+ injectField(fieldNode.up(), fieldConstant);
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java
index f417aca5..d0c2cc23 100644
--- a/src/core/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleGetter.java
@@ -41,7 +41,6 @@ import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.agent.PatchDelegate;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -80,7 +79,7 @@ import org.mangosdk.spi.ProviderFor;
public class HandleGetter extends EclipseAnnotationHandler<Getter> {
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
- public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter) {
+ public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter, List<Annotation> onMethod) {
if (checkForTypeLevelGetter) {
if (hasAnnotation(Getter.class, typeNode)) {
//The annotation will make it happen, so we can skip it.
@@ -100,7 +99,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
}
for (EclipseNode field : typeNode.down()) {
- if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, false);
+ if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, false, onMethod);
}
return true;
}
@@ -123,13 +122,13 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
* If not, the getter is still generated if it isn't already there, though there will not
* be a warning if its already there. The default access level is used.
*/
- public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean lazy) {
+ public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean lazy, List<Annotation> onMethod) {
if (hasAnnotation(Getter.class, fieldNode)) {
//The annotation will make it happen, so we can skip it.
return;
}
- createGetterForField(level, fieldNode, fieldNode, pos, false, lazy, Collections.<Annotation>emptyList());
+ createGetterForField(level, fieldNode, fieldNode, pos, false, lazy, onMethod);
}
public void handle(AnnotationValues<Getter> annotation, Annotation ast, EclipseNode annotationNode) {
@@ -155,11 +154,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, lazy, onMethod);
break;
case TYPE:
- if (!onMethod.isEmpty()) {
- annotationNode.addError("'onMethod' is not supported for @Getter on a type.");
- }
if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type.");
- generateGetterForType(node, annotationNode, level, false);
+ generateGetterForType(node, annotationNode, level, false, onMethod);
break;
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java
index c49030d8..8c7f7971 100644
--- a/src/core/lombok/eclipse/handlers/HandleLog.java
+++ b/src/core/lombok/eclipse/handlers/HandleLog.java
@@ -109,7 +109,7 @@ public class HandleLog {
private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String logFieldName, boolean useStatic, String loggerTopic) {
int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
+ long p = (long) pS << 32 | pE;
// private static final <loggerType> log = <factoryMethod>(<parameter>);
FieldDeclaration fieldDecl = new FieldDeclaration(logFieldName.toCharArray(), 0, -1);
@@ -126,13 +126,15 @@ public class HandleLog {
factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray();
Expression parameter;
- if (loggerTopic == null || loggerTopic.trim().length() == 0) {
+ if (!framework.passTypeName) {
+ parameter = null;
+ } else if (loggerTopic == null || loggerTopic.trim().length() == 0) {
parameter = framework.createFactoryParameter(loggingType, source);
} else {
parameter = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0);
}
- factoryMethodCall.arguments = new Expression[] { parameter };
+ factoryMethodCall.arguments = parameter != null ? new Expression[] { parameter } : null;
factoryMethodCall.nameSourcePosition = p;
factoryMethodCall.sourceStart = pS;
factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE;
@@ -240,6 +242,17 @@ public class HandleLog {
}
}
+ /**
+ * Handles the {@link lombok.extern.flogger.Flogger} annotation for Eclipse.
+ */
+ @ProviderFor(EclipseAnnotationHandler.class)
+ public static class HandleFloggerLog extends EclipseAnnotationHandler<lombok.extern.flogger.Flogger> {
+ @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
+ processAnnotation(LoggingFramework.FLOGGER, annotation, source, annotationNode, "");
+ }
+ }
+
enum LoggingFramework {
// private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class);
COMMONS("org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog", "@CommonsLog"),
@@ -278,18 +291,31 @@ public class HandleLog {
// private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class);
JBOSSLOG("org.jboss.logging.Logger", "org.jboss.logging.Logger", "getLogger", "@JBossLog"),
+
+ // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
+ FLOGGER("com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger", "forEnclosingClass", "@Flogger", false),
;
private final String loggerTypeName;
private final String loggerFactoryTypeName;
private final String loggerFactoryMethodName;
private final String annotationAsString;
-
+ private final boolean passTypeName;
+
+ LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString, boolean passTypeName) {
+ this.loggerTypeName = loggerTypeName;
+ this.loggerFactoryTypeName = loggerFactoryTypeName;
+ this.loggerFactoryMethodName = loggerFactoryMethodName;
+ this.annotationAsString = annotationAsString;
+ this.passTypeName = passTypeName;
+ }
+
LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString) {
this.loggerTypeName = loggerTypeName;
this.loggerFactoryTypeName = loggerFactoryTypeName;
this.loggerFactoryMethodName = loggerFactoryMethodName;
this.annotationAsString = annotationAsString;
+ this.passTypeName = true;
}
final String getAnnotationAsString() {
@@ -308,7 +334,7 @@ public class HandleLog {
return loggerFactoryMethodName;
}
- Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){
+ Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source) {
TypeReference copy = copyType(loggingType.type, source);
ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy);
setGeneratedBy(result, source);
diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java
index 92489c09..d4df0deb 100644
--- a/src/core/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleSetter.java
@@ -24,11 +24,12 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.toAllSetterNames;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.toSetterName;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
@@ -38,7 +39,6 @@ import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -64,7 +64,7 @@ import org.mangosdk.spi.ProviderFor;
*/
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleSetter extends EclipseAnnotationHandler<Setter> {
- public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter) {
+ public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter, List<Annotation> onMethod, List<Annotation> onParam) {
if (checkForTypeLevelSetter) {
if (hasAnnotation(Setter.class, typeNode)) {
//The annotation will make it happen, so we can skip it.
@@ -91,7 +91,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
//Skip final fields.
if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) continue;
- generateSetterForField(field, pos, level);
+ generateSetterForField(field, pos, level, onMethod, onParam);
}
return true;
}
@@ -108,15 +108,12 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
* If not, the setter is still generated if it isn't already there, though there will not
* be a warning if its already there. The default access level is used.
*/
- public void generateSetterForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level) {
+ public void generateSetterForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level, List<Annotation> onMethod, List<Annotation> onParam) {
if (hasAnnotation(Setter.class, fieldNode)) {
//The annotation will make it happen, so we can skip it.
return;
}
-
- List<Annotation> empty = Collections.emptyList();
-
- createSetterForField(level, fieldNode, sourceNode, false, empty, empty);
+ createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam);
}
@Override public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) {
@@ -134,13 +131,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod, onParam);
break;
case TYPE:
- if (!onMethod.isEmpty()) {
- annotationNode.addError("'onMethod' is not supported for @Setter on a type.");
- }
- if (!onParam.isEmpty()) {
- annotationNode.addError("'onParam' is not supported for @Setter on a type.");
- }
- generateSetterForType(node, annotationNode, level, false);
+ generateSetterForType(node, annotationNode, level, false, onMethod, onParam);
break;
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 12fc4761..6b0275e4 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -74,13 +74,14 @@ import lombok.Builder;
import lombok.Builder.ObtainVia;
import lombok.ConfigurationKeys;
import lombok.Singular;
+import lombok.ToString;
import lombok.core.AST.Kind;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
@@ -307,9 +308,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
// Create the toString() method for the abstract builder.
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
- java.util.List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>();
+ List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
for (BuilderFieldData bfd : builderFields) {
- fieldNodes.addAll(bfd.createdFields);
+ for (EclipseNode f : bfd.createdFields) {
+ fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true));
+ }
}
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD);
diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java
index d8f4c569..02a19f8d 100644
--- a/src/core/lombok/eclipse/handlers/HandleToString.java
+++ b/src/core/lombok/eclipse/handlers/HandleToString.java
@@ -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
@@ -24,7 +24,6 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -37,17 +36,17 @@ import lombok.ConfigurationKeys;
import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
+import lombok.core.handlers.InclusionExclusionUtils;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
@@ -70,17 +69,25 @@ import org.mangosdk.spi.ProviderFor;
*/
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleToString extends EclipseAnnotationHandler<ToString> {
- public void checkForBogusFieldNames(EclipseNode type, AnnotationValues<ToString> annotation) {
- if (annotation.isExplicit("exclude")) {
- for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().exclude()), type, true, false)) {
- annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
- }
- }
- if (annotation.isExplicit("of")) {
- for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().of()), type, false, false)) {
- annotation.setWarning("of", "This field does not exist.", i);
- }
- }
+ public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString");
+
+ ToString ann = annotation.getInstance();
+ List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), annotation, annotationNode);
+ if (members == null) return;
+
+ Boolean callSuper = ann.callSuper();
+
+ if (!annotation.isExplicit("callSuper")) callSuper = null;
+
+ Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
+ boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
+ FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
+
+ Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
+ boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration;
+
+ generateToString(annotationNode.up(), annotationNode, members, includeFieldNames, callSuper, true, fieldAccess);
}
public void generateToStringForType(EclipseNode typeNode, EclipseNode errorNode) {
@@ -98,41 +105,13 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
- generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, access);
+ List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(typeNode, null, null);
+ generateToString(typeNode, errorNode, members, includeFieldNames, null, false, access);
}
- public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) {
- handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString");
-
- ToString ann = annotation.getInstance();
- List<String> excludes = Arrays.asList(ann.exclude());
- List<String> includes = Arrays.asList(ann.of());
- EclipseNode typeNode = annotationNode.up();
- Boolean callSuper = ann.callSuper();
+ public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, ToString.Include>> members,
+ boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
- if (!annotation.isExplicit("callSuper")) callSuper = null;
- if (!annotation.isExplicit("exclude")) excludes = null;
- if (!annotation.isExplicit("of")) includes = null;
-
- if (excludes != null && includes != null) {
- excludes = null;
- annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
- }
-
- checkForBogusFieldNames(typeNode, annotation);
-
- Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
- boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
- FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
-
- Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
- boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration;
-
- generateToString(typeNode, annotationNode, excludes, includes, includeFieldNames, callSuper, true, fieldAccess);
- }
-
- public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes,
- boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
TypeDeclaration typeDecl = null;
if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
@@ -140,39 +119,20 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
boolean notAClass = (modifiers &
(ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
- if (typeDecl == null || notAClass) {
- errorNode.addError("@ToString is only supported on a class or enum.");
- }
-
if (callSuper == null) {
try {
callSuper = ((Boolean)ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
} catch (Exception ignore) {}
}
- List<EclipseNode> nodesForToString = new ArrayList<EclipseNode>();
- if (includes != null) {
- for (EclipseNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
- if (includes.contains(new String(fieldDecl.name))) nodesForToString.add(child);
- }
- } else {
- for (EclipseNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
- if (!filterField(fieldDecl)) continue;
-
- //Skip excluded fields.
- if (excludes != null && excludes.contains(new String(fieldDecl.name))) continue;
-
- nodesForToString.add(child);
- }
+ if (typeDecl == null || notAClass) {
+ errorNode.addError("@ToString is only supported on a class or enum.");
+ return;
}
switch (methodExists("toString", typeNode, 0)) {
case NOT_EXISTS:
- MethodDeclaration toString = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, errorNode.get(), fieldAccess);
+ MethodDeclaration toString = createToString(typeNode, members, includeFieldNames, callSuper, errorNode.get(), fieldAccess);
injectMethod(typeNode, toString);
break;
case EXISTS_BY_LOMBOK:
@@ -185,8 +145,9 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
}
}
- public static MethodDeclaration createToString(EclipseNode type, Collection<EclipseNode> fields,
- boolean includeFieldNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
+ public static MethodDeclaration createToString(EclipseNode type, Collection<Included<EclipseNode, ToString.Include>> members,
+ boolean includeNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
+
String typeName = getTypeName(type);
char[] suffix = ")".toCharArray();
String infixS = ", ";
@@ -199,10 +160,13 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
if (callSuper) {
prefix = (typeName + "(super=").toCharArray();
- } else if (fields.isEmpty()) {
+ } else if (members.isEmpty()) {
prefix = (typeName + "()").toCharArray();
- } else if (includeFieldNames) {
- prefix = (typeName + "(" + new String(((FieldDeclaration)fields.iterator().next().get()).name) + "=").toCharArray();
+ } 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();
} else {
prefix = (typeName + "(").toCharArray();
}
@@ -223,29 +187,35 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
first = false;
}
- for (EclipseNode field : fields) {
- TypeReference fieldType = getFieldType(field, fieldAccess);
- Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);
+ for (Included<EclipseNode, ToString.Include> member : members) {
+ EclipseNode memberNode = member.getNode();
+
+ TypeReference fieldType = getFieldType(memberNode, fieldAccess);
+ Expression memberAccessor;
+ if (memberNode.getKind() == Kind.METHOD) {
+ memberAccessor = createMethodAccessor(memberNode, source);
+ } else {
+ memberAccessor = createFieldAccessor(memberNode, fieldAccess, source);
+ }
// The distinction between primitive and object will be useful if we ever add a 'hideNulls' option.
boolean fieldBaseTypeIsPrimitive = BUILT_IN_TYPES.contains(new String(fieldType.getLastToken()));
+ @SuppressWarnings("unused")
boolean fieldIsPrimitive = fieldType.dimensions() == 0 && fieldBaseTypeIsPrimitive;
boolean fieldIsPrimitiveArray = fieldType.dimensions() == 1 && fieldBaseTypeIsPrimitive;
boolean fieldIsObjectArray = fieldType.dimensions() > 0 && !fieldIsPrimitiveArray;
- @SuppressWarnings("unused")
- boolean fieldIsObject = !fieldIsPrimitive && !fieldIsPrimitiveArray && !fieldIsObjectArray;
Expression ex;
if (fieldIsPrimitiveArray || fieldIsObjectArray) {
MessageSend arrayToString = new MessageSend();
arrayToString.sourceStart = pS; arrayToString.sourceEnd = pE;
arrayToString.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray());
- arrayToString.arguments = new Expression[] { fieldAccessor };
+ arrayToString.arguments = new Expression[] { memberAccessor };
setGeneratedBy(arrayToString.arguments[0], source);
arrayToString.selector = (fieldIsObjectArray ? "deepToString" : "toString").toCharArray();
ex = arrayToString;
} else {
- ex = fieldAccessor;
+ ex = memberAccessor;
}
setGeneratedBy(ex, source);
@@ -258,8 +228,10 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
}
StringLiteral fieldNameLiteral;
- if (includeFieldNames) {
- char[] namePlusEqualsSign = (infixS + field.getName() + "=").toCharArray();
+ if (includeNames) {
+ String n = member.getInc() == null ? "" : member.getInc().name();
+ if (n.isEmpty()) n = memberNode.getName();
+ char[] namePlusEqualsSign = (infixS + n + "=").toCharArray();
fieldNameLiteral = new StringLiteral(namePlusEqualsSign, pS, pE, 0);
} else {
fieldNameLiteral = new StringLiteral(infix, pS, pE, 0);
diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java
index a61ca6c3..2e0338a8 100644
--- a/src/core/lombok/eclipse/handlers/HandleValue.java
+++ b/src/core/lombok/eclipse/handlers/HandleValue.java
@@ -86,10 +86,11 @@ public class HandleValue extends EclipseAnnotationHandler<Value> {
//for whatever reason, though you can find callers of that one by focusing on the class name itself
//and hitting 'find callers'.
- handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
+ handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList());
handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
handleToString.generateToStringForType(typeNode, annotationNode);
handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES,
Collections.<Annotation>emptyList(), annotationNode);
+ handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java
index 200ebde7..c035fc26 100644
--- a/src/core/lombok/eclipse/handlers/HandleWither.java
+++ b/src/core/lombok/eclipse/handlers/HandleWither.java
@@ -36,7 +36,6 @@ import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
-import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import lombok.experimental.Wither;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
diff --git a/src/core/lombok/experimental/FieldNameConstants.java b/src/core/lombok/experimental/FieldNameConstants.java
new file mode 100644
index 00000000..31c2970c
--- /dev/null
+++ b/src/core/lombok/experimental/FieldNameConstants.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014-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
+ * 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.experimental;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import lombok.AccessLevel;
+
+/**
+ * Generates String constants containing the field name for each field.
+ */
+@Target({ElementType.TYPE, ElementType.FIELD})
+@Retention(RetentionPolicy.SOURCE)
+public @interface FieldNameConstants {
+ lombok.AccessLevel level() default AccessLevel.PUBLIC;
+ String prefix() default " CONFIG DEFAULT ";
+ String suffix() default " CONFIG DEFAULT ";
+}
diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java
index 04d5ef93..fa3d6f09 100644
--- a/src/core/lombok/extern/apachecommons/CommonsLog.java
+++ b/src/core/lombok/extern/apachecommons/CommonsLog.java
@@ -56,6 +56,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/flogger/Flogger.java b/src/core/lombok/extern/flogger/Flogger.java
new file mode 100644
index 00000000..ecbfd28c
--- /dev/null
+++ b/src/core/lombok/extern/flogger/Flogger.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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
+ * 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.extern.flogger;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Causes lombok to generate a logger field.
+ * <p>
+ * Complete documentation is found at <a href="https://projectlombok.org/features/Log">the project lombok features page for lombok log annotations</a>.
+ * <p>
+ * Example:
+ * <pre>
+ * &#64;Flogger
+ * public class LogExample {
+ * }
+ * </pre>
+ *
+ * will generate:
+ *
+ * <pre>
+ * public class LogExample {
+ * private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
+ * }
+ * </pre>
+ *
+ * This annotation is valid for classes and enumerations.<br>
+ * @see <a href="https://google.github.io/flogger/">com.google.common.flogger</a>
+ * @see lombok.extern.apachecommons.CommonsLog &#64;CommonsLog
+ * @see lombok.extern.java.Log &#64;Log
+ * @see lombok.extern.log4j.Log4j &#64;Log4j
+ * @see lombok.extern.log4j.Log4j2 &#64;Log4j2
+ * @see lombok.extern.slf4j.Slf4j &#64;Slf4j
+ * @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
+ * @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.TYPE)
+public @interface Flogger {
+}
diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java
index 553b7c4a..9a1ee412 100644
--- a/src/core/lombok/extern/java/Log.java
+++ b/src/core/lombok/extern/java/Log.java
@@ -55,6 +55,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/jbosslog/JBossLog.java b/src/core/lombok/extern/jbosslog/JBossLog.java
index ea520aea..684585e0 100644
--- a/src/core/lombok/extern/jbosslog/JBossLog.java
+++ b/src/core/lombok/extern/jbosslog/JBossLog.java
@@ -53,8 +53,9 @@ import java.lang.annotation.Target;
* @see lombok.extern.java.Log &#64;Log
* @see lombok.extern.log4j.Log4j &#64;Log4j
* @see lombok.extern.log4j.Log4j2 &#64;Log4j2
+ * @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
- * @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
* */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java
index ee719407..249ef71a 100644
--- a/src/core/lombok/extern/log4j/Log4j.java
+++ b/src/core/lombok/extern/log4j/Log4j.java
@@ -56,6 +56,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java
index 4a5b166c..a6aa90c0 100644
--- a/src/core/lombok/extern/log4j/Log4j2.java
+++ b/src/core/lombok/extern/log4j/Log4j2.java
@@ -56,6 +56,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java
index 24586d43..347d81d2 100644
--- a/src/core/lombok/extern/slf4j/Slf4j.java
+++ b/src/core/lombok/extern/slf4j/Slf4j.java
@@ -55,6 +55,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.log4j.Log4j2 &#64;Log4j2
* @see lombok.extern.slf4j.XSlf4j &#64;XSlf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java
index 85a0fdd8..4d53a1eb 100644
--- a/src/core/lombok/extern/slf4j/XSlf4j.java
+++ b/src/core/lombok/extern/slf4j/XSlf4j.java
@@ -55,6 +55,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.log4j.Log4j2 &#64;Log4j2
* @see lombok.extern.slf4j.Slf4j &#64;Slf4j
* @see lombok.extern.jbosslog.JBossLog &#64;JBossLog
+ * @see lombok.extern.flogger.Flogger &#64;Flogger
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 45679fd3..4ca2c050 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -35,6 +35,7 @@ import javax.annotation.processing.Messager;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
+import com.sun.tools.javac.util.JCDiagnostic;
import lombok.core.AST;
import com.sun.tools.javac.code.Source;
@@ -395,7 +396,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
oldSource = log.useSource(newSource);
if (pos == null) pos = astObject.pos();
}
- if (pos != null && attemptToRemoveErrorsInRange) {
+ if (pos != null && node != null && attemptToRemoveErrorsInRange) {
removeFromDeferredDiagnostics(pos.getStartPosition(), node.getEndPosition(pos));
}
try {
@@ -470,22 +471,21 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
increment(errorCount);
error1(pos, message);
}
-
+
final void warning(DiagnosticPosition pos, String message) {
increment(warningCount);
- log.warning(pos, "proc.messager", message);
+ warning1(pos, message);
}
-
+
final void mandatoryWarning(DiagnosticPosition pos, String message) {
increment(warningCount);
- log.mandatoryWarning(pos, "proc.messager", message);
+ mandatoryWarning1(pos, message);
}
-
- final void note(DiagnosticPosition pos, String message) {
- log.note(pos, "proc.messager", message);
- }
-
+
abstract void error1(DiagnosticPosition pos, String message);
+ abstract void warning1(DiagnosticPosition pos, String message);
+ abstract void mandatoryWarning1(DiagnosticPosition pos, String message);
+ abstract void note(DiagnosticPosition pos, String message);
private void increment(Field field) {
if (field == null) return;
@@ -520,18 +520,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
warningCount = f;
} catch (Throwable t) {}
-
- Method logMethod = null;
- Object multiple = null;
- try {
- Class<?> df = Class.forName("com.sun.tools.javac.util.JCDiagnostic$DiagnosticFlag");
- for (Object constant : df.getEnumConstants()) {
- if (constant.toString().equals("MULTIPLE")) multiple = constant;
- }
- logMethod = log.getClass().getMethod("error", new Class<?>[] {df, DiagnosticPosition.class, String.class, Object[].class});
- } catch (Throwable t) {}
-
- return new Jdk9Plus(log, messager, errorCount, warningCount, logMethod, multiple);
+ return new Jdk9Plus(log, messager, errorCount, warningCount);
}
}
@@ -549,22 +538,99 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
log.multipleErrors = prev;
}
}
+
+ @Override void warning1(DiagnosticPosition pos, String message) {
+ log.warning(pos, "proc.messager", message);
+ }
+
+ @Override void mandatoryWarning1(DiagnosticPosition pos, String message) {
+ log.mandatoryWarning(pos, "proc.messager", message);
+ }
+
+ @Override void note(DiagnosticPosition pos, String message) {
+ log.note(pos, "proc.messager", message);
+ }
}
static class Jdk9Plus extends ErrorLog {
- private final Object multiple;
- private final Method logMethod;
+ private static final String PROC_MESSAGER = "proc.messager";
+ private Object multiple;
+ private Method errorMethod, warningMethod, mandatoryWarningMethod, noteMethod;
+ private Method errorKey, warningKey, noteKey;
+ private JCDiagnostic.Factory diags;
- private Jdk9Plus(Log log, Messager messager, Field errorCount, Field warningCount, Method logMethod, Object multiple) {
+ private Jdk9Plus(Log log, Messager messager, Field errorCount, Field warningCount) {
super(log, messager, errorCount, warningCount);
- this.logMethod = logMethod;
- this.multiple = multiple;
+
+ try {
+ final String jcd = "com.sun.tools.javac.util.JCDiagnostic";
+ Class<?> df = Class.forName(jcd + "$DiagnosticFlag");
+ for (Object constant : df.getEnumConstants()) {
+ if (constant.toString().equals("MULTIPLE")) this.multiple = constant;
+ }
+
+ Class<?> errorCls = Class.forName(jcd + "$Error");
+ Class<?> warningCls = Class.forName(jcd + "$Warning");
+ Class<?> noteCls = Class.forName(jcd + "$Note");
+
+ Class<?> lc = log.getClass();
+ this.errorMethod = lc.getMethod("error", df, DiagnosticPosition.class, errorCls);
+ this.warningMethod = lc.getMethod("warning", DiagnosticPosition.class, warningCls);
+ this.mandatoryWarningMethod = lc.getMethod("mandatoryWarning", DiagnosticPosition.class, warningCls);
+ this.noteMethod = lc.getMethod("note", DiagnosticPosition.class, noteCls);
+
+ Field diagsField = lc.getSuperclass().getDeclaredField("diags");
+ diagsField.setAccessible(true);
+ this.diags = (JCDiagnostic.Factory)diagsField.get(log);
+
+ Class<?> dc = this.diags.getClass();
+ this.errorKey = dc.getMethod("errorKey", String.class, Object[].class);
+ this.warningKey = dc.getDeclaredMethod("warningKey", String.class, Object[].class);
+ this.warningKey.setAccessible(true);
+ this.noteKey = dc.getDeclaredMethod("noteKey", String.class, Object[].class);
+ this.noteKey.setAccessible(true);
+ } catch (Throwable t) {
+ //t.printStackTrace();
+ }
}
@Override void error1(DiagnosticPosition pos, String message) {
try {
- logMethod.invoke(log, multiple, pos, "proc.messager", new Object[] { message });
- } catch (Throwable t) {}
+ Object error = this.errorKey.invoke(diags, PROC_MESSAGER, new Object[] { message });
+ errorMethod.invoke(log, multiple, pos, error);
+ } catch (Throwable t) {
+ //t.printStackTrace();
+ }
+ }
+
+ @Override
+ void warning1(DiagnosticPosition pos, String message) {
+ try {
+ Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message });
+ warningMethod.invoke(log, pos, warning);
+ } catch (Throwable t) {
+ //t.printStackTrace();
+ }
+ }
+
+ @Override
+ void mandatoryWarning1(DiagnosticPosition pos, String message) {
+ try {
+ Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message });
+ mandatoryWarningMethod.invoke(log, pos, warning);
+ } catch (Throwable t) {
+ //t.printStackTrace();
+ }
+ }
+
+ @Override
+ void note(DiagnosticPosition pos, String message) {
+ try {
+ Object note = this.noteKey.invoke(diags, PROC_MESSAGER, new Object[] { message });
+ noteMethod.invoke(log, pos, note);
+ } catch (Throwable t) {
+ //t.printStackTrace();
+ }
}
}
}
diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java
index fa24c2f9..2bce6e3a 100644
--- a/src/core/lombok/javac/JavacNode.java
+++ b/src/core/lombok/javac/JavacNode.java
@@ -21,13 +21,17 @@
*/
package lombok.javac;
+import java.lang.annotation.Annotation;
import java.util.List;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
+import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.javac.handlers.JavacHandlerUtil;
+import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.model.JavacTypes;
import com.sun.tools.javac.tree.JCTree;
@@ -36,6 +40,7 @@ import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Name;
@@ -256,4 +261,70 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre
public void addWarning(String message, DiagnosticPosition pos) {
ast.printMessage(Diagnostic.Kind.WARNING, message, null, pos, false);
}
+
+ @Override public boolean hasAnnotation(Class<? extends Annotation> type) {
+ return JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(type, this);
+ }
+
+ @Override public <Z extends Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type) {
+ JavacNode annotation = JavacHandlerUtil.findAnnotation(type, this, true);
+ if (annotation == null) return null;
+ return JavacHandlerUtil.createAnnotation(type, annotation);
+ }
+
+ private JCModifiers getModifiers() {
+ if (node instanceof JCClassDecl) return ((JCClassDecl) node).getModifiers();
+ if (node instanceof JCMethodDecl) return ((JCMethodDecl) node).getModifiers();
+ if (node instanceof JCVariableDecl) return ((JCVariableDecl) node).getModifiers();
+ return null;
+ }
+
+ @Override public boolean isStatic() {
+ if (node instanceof JCClassDecl) {
+ JavacNode directUp = directUp();
+ if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true;
+ if (!(directUp.get() instanceof JCClassDecl)) return false;
+ JCClassDecl p = (JCClassDecl) directUp.get();
+ long f = p.mods.flags;
+ if ((Flags.INTERFACE & f) != 0) return true;
+ if ((Flags.ENUM & f) != 0) return true;
+ }
+
+ if (node instanceof JCVariableDecl) {
+ JavacNode directUp = directUp();
+ if (directUp != null && directUp.get() instanceof JCClassDecl) {
+ JCClassDecl p = (JCClassDecl) directUp.get();
+ long f = p.mods.flags;
+ if ((Flags.INTERFACE & f) != 0) return true;
+ }
+ }
+
+ JCModifiers mods = getModifiers();
+ if (mods == null) return false;
+ return (mods.flags & Flags.STATIC) != 0;
+ }
+
+ @Override public boolean isEnumMember() {
+ if (getKind() != Kind.FIELD) 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();
+ return mods != null && (Flags.TRANSIENT & mods.flags) != 0;
+ }
+
+ @Override public int countMethodParameters() {
+ if (getKind() != Kind.METHOD) return 0;
+
+ com.sun.tools.javac.util.List<JCVariableDecl> params = ((JCMethodDecl) node).params;
+ if (params == null) return 0;
+ return params.size();
+ }
+
+ @Override public int getStartPos() {
+ return node.getPreferredPosition();
+ }
}
diff --git a/src/core/lombok/javac/apt/EmptyLombokFileObject.java b/src/core/lombok/javac/apt/EmptyLombokFileObject.java
index 5a3a7def..84bb00e4 100644
--- a/src/core/lombok/javac/apt/EmptyLombokFileObject.java
+++ b/src/core/lombok/javac/apt/EmptyLombokFileObject.java
@@ -57,7 +57,7 @@ class EmptyLombokFileObject implements LombokFileObject {
}
@Override public URI toUri() {
- return URI.create(name);
+ return URI.create("file:///" + (name.startsWith("/") ? name.substring(1) : name));
}
@Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java
index 9c0a2dfa..04b494bf 100644
--- a/src/core/lombok/javac/apt/LombokProcessor.java
+++ b/src/core/lombok/javac/apt/LombokProcessor.java
@@ -69,7 +69,10 @@ import com.sun.tools.javac.util.Context;
*/
@SupportedAnnotationTypes("*")
public class LombokProcessor extends AbstractProcessor {
- private JavacProcessingEnvironment processingEnv;
+
+ private ProcessingEnvironment processingEnv;
+ private JavacProcessingEnvironment javacProcessingEnv;
+ private JavacFiler javacFiler;
private JavacTransformer transformer;
private Trees trees;
private boolean lombokDisabled = false;
@@ -81,11 +84,13 @@ public class LombokProcessor extends AbstractProcessor {
lombokDisabled = true;
return;
}
-
- this.processingEnv = (JavacProcessingEnvironment) procEnv;
-
+
+ this.processingEnv = procEnv;
+ this.javacProcessingEnv = getJavacProcessingEnvironment(procEnv);
+ this.javacFiler = getJavacFiler(procEnv.getFiler());
+
placePostCompileAndDontMakeForceRoundDummiesHook();
- trees = Trees.instance(procEnv);
+ trees = Trees.instance(javacProcessingEnv);
transformer = new JavacTransformer(procEnv.getMessager(), trees);
SortedSet<Long> p = transformer.getPriorities();
if (p.isEmpty()) {
@@ -124,7 +129,7 @@ public class LombokProcessor extends AbstractProcessor {
@SuppressWarnings("unused")
private String listAnnotationProcessorsBeforeOurs() {
try {
- Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.processingEnv);
+ Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.javacProcessingEnv);
ArrayList<?> states = (ArrayList<?>) discoveredProcessors_procStateList.get(discoveredProcessors);
if (states == null || states.isEmpty()) return null;
if (states.size() == 1) return processorState_processor.get(states.get(0)).getClass().getName();
@@ -147,7 +152,7 @@ public class LombokProcessor extends AbstractProcessor {
stopJavacProcessingEnvironmentFromClosingOurClassloader();
forceMultipleRoundsInNetBeansEditor();
- Context context = processingEnv.getContext();
+ Context context = javacProcessingEnv.getContext();
disablePartialReparseInNetBeansEditor(context);
try {
Method keyMethod = Context.class.getDeclaredMethod("key", Class.class);
@@ -161,14 +166,14 @@ public class LombokProcessor extends AbstractProcessor {
if (!(originalFiler instanceof InterceptingJavaFileManager)) {
final Messager messager = processingEnv.getMessager();
DiagnosticsReceiver receiver = new MessagerDiagnosticsReceiver(messager);
-
- JavaFileManager newFiler = new InterceptingJavaFileManager(originalFiler, receiver);
- ht.put(key, newFiler);
+
+ JavaFileManager newFilerManager = new InterceptingJavaFileManager(originalFiler, receiver);
+ ht.put(key, newFilerManager);
Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
filerFileManagerField.setAccessible(true);
- filerFileManagerField.set(processingEnv.getFiler(), newFiler);
-
- replaceFileManagerJdk9(context, newFiler);
+ filerFileManagerField.set(javacFiler, newFilerManager);
+
+ replaceFileManagerJdk9(context, newFilerManager);
}
} catch (Exception e) {
throw Lombok.sneakyThrow(e);
@@ -203,7 +208,7 @@ public class LombokProcessor extends AbstractProcessor {
try {
Field f = JavacProcessingEnvironment.class.getDeclaredField("isBackgroundCompilation");
f.setAccessible(true);
- f.set(processingEnv, true);
+ f.set(javacProcessingEnv, true);
} catch (NoSuchFieldException e) {
// only NetBeans has it
} catch (Throwable t) {
@@ -277,10 +282,10 @@ public class LombokProcessor extends AbstractProcessor {
try {
Field f = JavacProcessingEnvironment.class.getDeclaredField("processorClassLoader");
f.setAccessible(true);
- ClassLoader unwrapped = (ClassLoader) f.get(processingEnv);
+ ClassLoader unwrapped = (ClassLoader) f.get(javacProcessingEnv);
if (unwrapped == null) return;
ClassLoader wrapped = wrapClassLoader(unwrapped);
- f.set(processingEnv, wrapped);
+ f.set(javacProcessingEnv, wrapped);
} catch (NoSuchFieldException e) {
// Some versions of javac have this (and call close on it), some don't. I guess this one doesn't have it.
} catch (Throwable t) {
@@ -321,7 +326,7 @@ public class LombokProcessor extends AbstractProcessor {
if (prioOfCu == null || prioOfCu != prio) continue;
cusForThisRound.add(entry.getKey());
}
- transformer.transform(prio, processingEnv.getContext(), cusForThisRound);
+ transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound);
}
// Step 3: Push up all CUs to the next level. Set level to null if there is no next level.
@@ -349,7 +354,7 @@ public class LombokProcessor extends AbstractProcessor {
newLevels.retainAll(priorityLevelsRequiringResolutionReset);
if (!newLevels.isEmpty()) {
// Force a new round to reset resolution. The next round will cause this method (process) to be called again.
- forceNewRound(randomModuleName, (JavacFiler) processingEnv.getFiler());
+ forceNewRound(randomModuleName, javacFiler);
return false;
}
// None of the new levels need resolution, so just keep going.
@@ -399,4 +404,57 @@ public class LombokProcessor extends AbstractProcessor {
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
+
+ /**
+ * This class casts the given processing environment to a JavacProcessingEnvironment. In case of
+ * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned.
+ */
+ public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) {
+ if (procEnv instanceof JavacProcessingEnvironment) {
+ return (JavacProcessingEnvironment) procEnv;
+ }
+
+ // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment
+ for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
+ try {
+ return getJavacProcessingEnvironment(tryGetDelegateField(procEnvClass, procEnv));
+ } catch (final Exception e) {
+ // delegate field was not found, try on superclass
+ }
+ }
+
+ processingEnv.getMessager().printMessage(Kind.WARNING,
+ "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work.");
+ return null;
+ }
+
+ /**
+ * This class returns the given filer as a JavacFiler. In case the case that the filer is no
+ * JavacFiler (e.g. the Gradle IncrementalFiler), its "delegate" field is used to get the JavacFiler
+ * (directly or through a delegate field again)
+ */
+ public JavacFiler getJavacFiler(Object filer) {
+ if (filer instanceof JavacFiler) {
+ return (JavacFiler) filer;
+ }
+
+ // try to find a "delegate" field in the object, and use this to check for a JavacFiler
+ for (Class<?> filerClass = filer.getClass(); filerClass != null; filerClass = filerClass.getSuperclass()) {
+ try {
+ return getJavacFiler(tryGetDelegateField(filerClass, filer));
+ } catch (final Exception e) {
+ // delegate field was not found, try on superclass
+ }
+ }
+
+ processingEnv.getMessager().printMessage(Kind.WARNING,
+ "Can't get a JavacFiler from " + filer.getClass().getName() + ". Lombok won't work.");
+ return null;
+ }
+
+ private Object tryGetDelegateField(Class<?> delegateClass, Object instance) throws Exception {
+ Field field = delegateClass.getDeclaredField("delegate");
+ field.setAccessible(true);
+ return field.get(instance);
+ }
}
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index fec999ba..d56d6ac2 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -54,10 +54,12 @@ import lombok.Builder;
import lombok.Builder.ObtainVia;
import lombok.ConfigurationKeys;
import lombok.Singular;
+import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.experimental.NonFinal;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
@@ -398,10 +400,13 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
- java.util.List<JavacNode> fieldNodes = new ArrayList<JavacNode>();
+ java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>();
for (BuilderFieldData bfd : builderFields) {
- fieldNodes.addAll(bfd.createdFields);
+ for (JavacNode f : bfd.createdFields) {
+ fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true));
+ }
}
+
JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast);
if (md != null) injectMethod(builderType, md);
}
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index dca25ee7..32eb43b2 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -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
@@ -22,22 +22,8 @@
package lombok.javac.handlers;
import static lombok.core.handlers.HandlerUtil.*;
-import static lombok.javac.handlers.JavacHandlerUtil.*;
import static lombok.javac.Javac.*;
-
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.ConfigurationKeys;
-import lombok.NoArgsConstructor;
-import lombok.RequiredArgsConstructor;
-import lombok.core.AnnotationValues;
-import lombok.core.AST.Kind;
-import lombok.delombok.LombokOptionsFactory;
-import lombok.javac.Javac;
-import lombok.javac.JavacAnnotationHandler;
-import lombok.javac.JavacNode;
-import lombok.javac.JavacTreeMaker;
+import static lombok.javac.handlers.JavacHandlerUtil.*;
import org.mangosdk.spi.ProviderFor;
@@ -61,6 +47,21 @@ import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.ConfigurationKeys;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.delombok.LombokOptionsFactory;
+import lombok.javac.Javac;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+import lombok.javac.JavacTreeMaker;
+import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
+
public class HandleConstructor {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleNoArgsConstructor extends JavacAnnotationHandler<NoArgsConstructor> {
@@ -191,19 +192,33 @@ public class HandleConstructor {
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) {
+ if (!isDirectDescendantOfObject(typeNode)) return;
+
+ 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;
@@ -232,6 +247,8 @@ public class HandleConstructor {
}
}
+ 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) {
@@ -252,6 +269,27 @@ public class HandleConstructor {
}
}
+ 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;
+ }
+ }
+ }
+
+ for (JavacNode child : node.down()) {
+ if (annotationTypeMatches(NoArgsConstructor.class, child)) return true;
+ if (annotationTypeMatches(RequiredArgsConstructor.class, child) && findRequiredFields(node).isEmpty()) return true;
+ if (annotationTypeMatches(AllArgsConstructor.class, child) && findAllFields(node).isEmpty()) return true;
+ }
+
+ return false;
+ }
+
public static void addConstructorProperties(JCModifiers mods, JavacNode node, List<JavacNode> fields) {
if (fields.isEmpty()) return;
JavacTreeMaker maker = node.getTreeMaker();
diff --git a/src/core/lombok/javac/handlers/HandleData.java b/src/core/lombok/javac/handlers/HandleData.java
index 15f1fd83..15c9c9e7 100644
--- a/src/core/lombok/javac/handlers/HandleData.java
+++ b/src/core/lombok/javac/handlers/HandleData.java
@@ -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
@@ -34,6 +34,7 @@ import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.util.List;
/**
* Handles the {@code lombok.Data} annotation for javac.
@@ -60,9 +61,11 @@ 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);
- handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
- handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
+ 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);
handleToString.generateToStringForType(typeNode, annotationNode);
}
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index d8bfd154..aa0fe633 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -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
@@ -21,7 +21,7 @@
*/
package lombok.javac.handlers;
-import static lombok.core.handlers.HandlerUtil.*;
+import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
@@ -29,19 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import lombok.ConfigurationKeys;
-import lombok.EqualsAndHashCode;
-import lombok.core.AST.Kind;
-import lombok.core.configuration.CallSuperType;
-import lombok.core.AnnotationValues;
-import lombok.core.handlers.HandlerUtil;
-import lombok.javac.Javac;
-import lombok.javac.JavacAnnotationHandler;
-import lombok.javac.JavacNode;
-import lombok.javac.JavacTreeMaker;
-import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
-import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
-
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.BoundKind;
@@ -66,6 +53,20 @@ import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
+import lombok.ConfigurationKeys;
+import lombok.EqualsAndHashCode;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.core.configuration.CallSuperType;
+import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.HandlerUtil.FieldAccess;
+import lombok.core.handlers.InclusionExclusionUtils;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+import lombok.javac.JavacTreeMaker;
+import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
+
/**
* Handles the {@code lombok.EqualsAndHashCode} annotation for javac.
*/
@@ -74,45 +75,23 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
private static final String RESULT_NAME = "result";
private static final String PRIME_NAME = "PRIME";
- public void checkForBogusFieldNames(JavacNode type, AnnotationValues<EqualsAndHashCode> annotation) {
- if (annotation.isExplicit("exclude")) {
- for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().exclude()), type, true, true)) {
- annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
- }
- }
- if (annotation.isExplicit("of")) {
- for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().of()), type, false, false)) {
- annotation.setWarning("of", "This field does not exist.", i);
- }
- }
- }
-
@Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode");
deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class);
EqualsAndHashCode ann = annotation.getInstance();
- List<String> excludes = List.from(ann.exclude());
- List<String> includes = List.from(ann.of());
+ java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode);
JavacNode typeNode = annotationNode.up();
List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode);
- checkForBogusFieldNames(typeNode, annotation);
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper")) callSuper = null;
- if (!annotation.isExplicit("exclude")) excludes = null;
- if (!annotation.isExplicit("of")) includes = null;
-
- if (excludes != null && includes != null) {
- excludes = null;
- annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
- }
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
- generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess, onParam);
+ generateMethods(typeNode, annotationNode, members, callSuper, true, fieldAccess, onParam);
}
public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode source) {
@@ -124,10 +103,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
- generateMethods(typeNode, source, null, null, null, false, access, List.<JCAnnotation>nil());
+ java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null);
+
+ generateMethods(typeNode, source, members, null, false, access, List.<JCAnnotation>nil());
}
- public void generateMethods(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes,
+ public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members,
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
boolean notAClass = true;
@@ -141,7 +122,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
return;
}
- boolean isDirectDescendantOfObject = true;
boolean implicitCallSuper = callSuper == null;
if (callSuper == null) {
try {
@@ -151,11 +131,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
}
}
- JCTree extending = Javac.getExtendsClause((JCClassDecl)typeNode.get());
- if (extending != null) {
- String p = extending.toString();
- isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
- }
+ boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode);
if (isDirectDescendantOfObject && callSuper) {
source.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless.");
@@ -181,29 +157,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
}
}
- ListBuffer<JavacNode> nodesForEquality = new ListBuffer<JavacNode>();
- if (includes != null) {
- for (JavacNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
- if (includes.contains(fieldDecl.name.toString())) nodesForEquality.append(child);
- }
- } else {
- for (JavacNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
- //Skip static fields.
- if ((fieldDecl.mods.flags & Flags.STATIC) != 0) continue;
- //Skip transient fields.
- if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0) continue;
- //Skip excluded fields.
- if (excludes != null && excludes.contains(fieldDecl.name.toString())) continue;
- //Skip fields that start with $
- if (fieldDecl.name.toString().startsWith("$")) continue;
- nodesForEquality.append(child);
- }
- }
-
boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 0;
boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject;
MemberExistsResult equalsExists = methodExists("equals", typeNode, 1);
@@ -232,7 +185,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
//fallthrough
}
- JCMethodDecl equalsMethod = createEquals(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, needsCanEqual, source.get(), onParam);
+ JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source.get(), onParam);
injectMethod(typeNode, equalsMethod);
@@ -241,11 +194,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
injectMethod(typeNode, canEqualMethod);
}
- JCMethodDecl hashCodeMethod = createHashCode(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, source.get());
+ JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, fieldAccess, source.get());
injectMethod(typeNode, hashCodeMethod);
}
- public JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
+ public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
JavacTreeMaker maker = typeNode.getTreeMaker();
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
@@ -258,7 +211,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());
/* final int PRIME = X; */ {
- if (!fields.isEmpty()) {
+ if (!members.isEmpty()) {
statements.append(maker.VarDef(maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode())));
}
}
@@ -268,8 +221,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
if (callSuper) {
/* ... super.hashCode(); */
init = maker.Apply(List.<JCExpression>nil(),
- maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")),
- List.<JCExpression>nil());
+ maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")),
+ List.<JCExpression>nil());
} else {
/* ... 1; */
init = maker.Literal(1);
@@ -277,10 +230,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
statements.append(maker.VarDef(maker.Modifiers(0), resultName, maker.TypeIdent(CTC_INT), init));
}
- Name dollar = typeNode.toName("$");
- for (JavacNode fieldNode : fields) {
- JCExpression fType = getFieldType(fieldNode, fieldAccess);
- JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
+ for (Included<JavacNode, EqualsAndHashCode.Include> member : members) {
+ JavacNode memberNode = member.getNode();
+ JCExpression fType = getFieldType(memberNode, fieldAccess);
+ boolean isMethod = memberNode.getKind() == Kind.METHOD;
+
+ JCExpression fieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
if (fType instanceof JCPrimitiveTypeTree) {
switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
case BOOLEAN:
@@ -289,7 +244,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse())))));
break;
case LONG: {
- Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
+ Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName());
statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor));
statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
}
@@ -303,7 +258,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
break;
case DOUBLE: {
/* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */
- Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
+ Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName());
JCExpression init = maker.Apply(
List.<JCExpression>nil(),
genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"),
@@ -333,7 +288,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
/* final java.lang.Object $fieldName = this.fieldName; */
/* ($fieldName == null ? NULL_PRIME : $fieldName.hashCode()) */
- Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
+ Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName());
statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor));
JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")),
@@ -411,7 +366,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
return maker.TypeApply(expr, wildcards.toList());
}
- public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
+ public JCMethodDecl createEquals(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
JavacTreeMaker maker = typeNode.getTreeMaker();
Name oName = typeNode.toName("o");
@@ -440,7 +395,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
}
/* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ {
- if (!fields.isEmpty() || needsCanEqual) {
+ if (!members.isEmpty() || needsCanEqual) {
final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true);
statements.append(
@@ -469,12 +424,13 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
}
- Name thisDollar = typeNode.toName("this$");
- Name otherDollar = typeNode.toName("other$");
- for (JavacNode fieldNode : fields) {
- JCExpression fType = getFieldType(fieldNode, fieldAccess);
- JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
- JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName));
+ for (Included<JavacNode, EqualsAndHashCode.Include> member : members) {
+ JavacNode memberNode = member.getNode();
+ boolean isMethod = memberNode.getKind() == Kind.METHOD;
+
+ JCExpression fType = getFieldType(memberNode, fieldAccess);
+ JCExpression thisFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
+ JCExpression otherFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode, maker.Ident(otherName)) : createFieldAccessor(maker, memberNode, fieldAccess, maker.Ident(otherName));
if (fType instanceof JCPrimitiveTypeTree) {
switch (((JCPrimitiveTypeTree)fType).getPrimitiveTypeKind()) {
case FLOAT:
@@ -505,9 +461,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
/* final java.lang.Object this$fieldName = this.fieldName; */
/* final java.lang.Object other$fieldName = other.fieldName; */
/* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */
- Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
- Name thisDollarFieldName = thisDollar.append(fieldName);
- Name otherDollarFieldName = otherDollar.append(fieldName);
+ Name thisDollarFieldName = memberNode.toName("this" + (isMethod ? "$$" : "$") + memberNode.getName());
+ Name otherDollarFieldName = memberNode.toName("other" + (isMethod ? "$$" : "$") + memberNode.getName());
statements.append(maker.VarDef(maker.Modifiers(finalFlag), thisDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), thisFieldAccessor));
statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), otherFieldAccessor));
@@ -546,7 +501,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null));
JCBlock body = maker.Block(0, List.<JCStatement>of(
- maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false)))));
+ maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false)))));
return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext());
}
diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java
new file mode 100644
index 00000000..8ff136fc
--- /dev/null
+++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014-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
+ * 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.javac.handlers;
+
+import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage;
+import static lombok.javac.handlers.JavacHandlerUtil.*;
+
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+
+import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
+import lombok.core.AST.Kind;
+import lombok.core.handlers.HandlerUtil;
+import lombok.core.AnnotationValues;
+import lombok.experimental.FieldNameConstants;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+import lombok.javac.JavacTreeMaker;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+@ProviderFor(JavacAnnotationHandler.class)
+public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameConstants> {
+ public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, String prefix, String suffix) {
+ JCClassDecl typeDecl = null;
+ if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
+
+ long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
+ boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
+
+ if (typeDecl == null || notAClass) {
+ errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field.");
+ return;
+ }
+
+ for (JavacNode field : typeNode.down()) {
+ if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix);
+ }
+ }
+
+ private void generateFieldNameConstantsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, String prefix, String suffix) {
+ if (hasAnnotation(FieldNameConstants.class, fieldNode)) return;
+ createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, false);
+ }
+
+ private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field) {
+ if (field.getKind() != Kind.FIELD) return false;
+ JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
+ if (fieldDecl.name.toString().startsWith("$")) return false;
+ if ((fieldDecl.mods.flags & Flags.STATIC) != 0) return false;
+ return true;
+ }
+
+ public void handle(AnnotationValues<FieldNameConstants> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants");
+
+ Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
+ deleteAnnotationIfNeccessary(annotationNode, FieldNameConstants.class);
+ deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
+ JavacNode node = annotationNode.up();
+ FieldNameConstants annotatationInstance = annotation.getInstance();
+ AccessLevel level = annotatationInstance.level();
+ String prefix = annotatationInstance.prefix();
+ String suffix = annotatationInstance.suffix();
+ if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX);
+ if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX);
+ if (prefix == null) prefix = "FIELD_";
+ if (suffix == null) suffix = "";
+ if (node == null) return;
+ switch (node.getKind()) {
+ case FIELD:
+ if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, fields, annotationNode, annotationNode, true);
+ break;
+ case TYPE:
+ if (level == AccessLevel.NONE) {
+ annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE.");
+ return;
+ }
+ generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix);
+ break;
+ }
+ }
+
+ private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<JavacNode> fieldNodes, JavacNode annotationNode, JavacNode errorNode, boolean whineIfExists) {
+ for (JavacNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, whineIfExists);
+ }
+
+ private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, JavacNode fieldNode, JavacNode source, boolean whineIfExists) {
+ if (fieldNode.getKind() != Kind.FIELD) {
+ source.addError("@FieldNameConstants is only supported on a class, an enum, or a field");
+ return;
+ }
+
+ JCVariableDecl field = (JCVariableDecl) fieldNode.get();
+ String fieldName = field.name.toString();
+ String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix;
+ if (constantName.equals(fieldName)) {
+ fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field.");
+ return;
+ }
+
+ JavacTreeMaker treeMaker = fieldNode.getTreeMaker();
+ JCModifiers modifiers = treeMaker.Modifiers(toJavacModifier(level) | Modifier.STATIC | Modifier.FINAL);
+ JCExpression returnType = chainDots(fieldNode, "java", "lang", "String");
+ JCExpression init = treeMaker.Literal(fieldNode.getName());
+ JCVariableDecl fieldConstant = treeMaker.VarDef(modifiers, fieldNode.toName(constantName), returnType, init);
+ injectField(fieldNode.up(), fieldConstant);
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 0540465d..4fc6155c 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -41,7 +41,6 @@ import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
import lombok.javac.JavacTreeMaker.TypeTag;
-import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
@@ -72,7 +71,7 @@ import com.sun.tools.javac.util.Name;
*/
@ProviderFor(JavacAnnotationHandler.class)
public class HandleGetter extends JavacAnnotationHandler<Getter> {
- public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter) {
+ public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter, List<JCAnnotation> onMethod) {
if (checkForTypeLevelGetter) {
if (hasAnnotation(Getter.class, typeNode)) {
//The annotation will make it happen, so we can skip it.
@@ -91,7 +90,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
}
for (JavacNode field : typeNode.down()) {
- if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, false);
+ if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, false, onMethod);
}
}
@@ -120,12 +119,12 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
* @param fieldNode The node representing the field you want a getter for.
* @param pos The node responsible for generating the getter (the {@code @Data} or {@code @Getter} annotation).
*/
- public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean lazy) {
+ public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean lazy, List<JCAnnotation> onMethod) {
if (hasAnnotation(Getter.class, fieldNode)) {
//The annotation will make it happen, so we can skip it.
return;
}
- createGetterForField(level, fieldNode, fieldNode, false, lazy, List.<JCAnnotation>nil());
+ createGetterForField(level, fieldNode, fieldNode, false, lazy, onMethod);
}
@Override public void handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -154,11 +153,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
createGetterForFields(level, fields, annotationNode, true, lazy, onMethod);
break;
case TYPE:
- if (!onMethod.isEmpty()) {
- annotationNode.addError("'onMethod' is not supported for @Getter on a type.");
- }
if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type.");
- generateGetterForType(node, annotationNode, level, false);
+ generateGetterForType(node, annotationNode, level, false, onMethod);
break;
}
}
diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java
index d0d709e3..6d742e76 100644
--- a/src/core/lombok/javac/handlers/HandleLog.java
+++ b/src/core/lombok/javac/handlers/HandleLog.java
@@ -91,16 +91,18 @@ public class HandleLog {
// private static final <loggerType> log = <factoryMethod>(<parameter>);
JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName());
JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName());
-
+
JCExpression loggerName;
- if (loggerTopic == null || loggerTopic.trim().length() == 0) {
+ if (!framework.passTypeName) {
+ loggerName = null;
+ } else if (loggerTopic == null || loggerTopic.trim().length() == 0) {
loggerName = framework.createFactoryParameter(typeNode, loggingType);
} else {
loggerName = maker.Literal(loggerTopic);
}
-
- JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName));
-
+
+ JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, loggerName != null ? List.<JCExpression>of(loggerName) : List.<JCExpression>nil());
+
JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef(
maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)),
typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext());
@@ -186,6 +188,17 @@ public class HandleLog {
}
}
+ /**
+ * Handles the {@link lombok.extern.flogger.Flogger} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleFloggerLog extends JavacAnnotationHandler<lombok.extern.flogger.Flogger> {
+ @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
+ processAnnotation(LoggingFramework.FLOGGER, annotation, annotationNode, "");
+ }
+ }
+
enum LoggingFramework {
// private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class);
COMMONS(lombok.extern.apachecommons.CommonsLog.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"),
@@ -212,17 +225,29 @@ public class HandleLog {
XSLF4J(lombok.extern.slf4j.XSlf4j.class, "org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory.getXLogger"),
// private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class);
- JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger")
+ JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger"),
+
+ // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
+ FLOGGER(lombok.extern.flogger.Flogger.class, "com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger.forEnclosingClass", false),
;
private final Class<? extends Annotation> annotationClass;
private final String loggerTypeName;
private final String loggerFactoryName;
+ private final boolean passTypeName;
+
+ LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName, boolean passTypeName) {
+ this.annotationClass = annotationClass;
+ this.loggerTypeName = loggerTypeName;
+ this.loggerFactoryName = loggerFactoryName;
+ this.passTypeName = passTypeName;
+ }
LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) {
this.annotationClass = annotationClass;
this.loggerTypeName = loggerTypeName;
this.loggerFactoryName = loggerFactoryName;
+ this.passTypeName = true;
}
final Class<? extends Annotation> getAnnotationClass() {
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index be3337db..0ddaa7d7 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -36,7 +36,6 @@ import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
-import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
@@ -62,7 +61,7 @@ import com.sun.tools.javac.util.Name;
*/
@ProviderFor(JavacAnnotationHandler.class)
public class HandleSetter extends JavacAnnotationHandler<Setter> {
- public void generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter) {
+ public void generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (checkForTypeLevelSetter) {
if (hasAnnotation(Setter.class, typeNode)) {
//The annotation will make it happen, so we can skip it.
@@ -90,7 +89,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
//Skip final fields.
if ((fieldDecl.mods.flags & Flags.FINAL) != 0) continue;
- generateSetterForField(field, errorNode, level);
+ generateSetterForField(field, errorNode, level, onMethod, onParam);
}
}
@@ -109,13 +108,13 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
* @param fieldNode The node representing the field you want a setter for.
* @param pos The node responsible for generating the setter (the {@code @Data} or {@code @Setter} annotation).
*/
- public void generateSetterForField(JavacNode fieldNode, JavacNode sourceNode, AccessLevel level) {
+ public void generateSetterForField(JavacNode fieldNode, JavacNode sourceNode, AccessLevel level, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (hasAnnotation(Setter.class, fieldNode)) {
//The annotation will make it happen, so we can skip it.
return;
}
- createSetterForField(level, fieldNode, sourceNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
+ createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam);
}
@Override public void handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -137,9 +136,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
createSetterForFields(level, fields, annotationNode, true, onMethod, onParam);
break;
case TYPE:
- if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Setter on a type.");
- if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @Setter on a type.");
- generateSetterForType(node, annotationNode, level, false);
+ generateSetterForType(node, annotationNode, level, false, onMethod, onParam);
break;
}
}
diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
index 1707fb0e..38fec2f6 100644
--- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
@@ -56,17 +56,18 @@ import lombok.Builder;
import lombok.Builder.ObtainVia;
import lombok.ConfigurationKeys;
import lombok.Singular;
+import lombok.ToString;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.experimental.NonFinal;
import lombok.experimental.SuperBuilder;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
-import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker;
import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
@@ -255,8 +256,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
}
// Create the toString() method for the abstract builder.
- java.util.List<JavacNode> fieldNodes = new ArrayList<JavacNode>();
- for (BuilderFieldData bfd : builderFields) fieldNodes.addAll(bfd.createdFields);
+ java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>();
+ for (BuilderFieldData bfd : builderFields) {
+ for (JavacNode f : bfd.createdFields) {
+ fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true));
+ }
+ }
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
JCMethodDecl toStringMethod = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClassExpression != null, FieldAccess.ALWAYS_FIELD, ast);
diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java
index 897d5f2c..28d18357 100644
--- a/src/core/lombok/javac/handlers/HandleToString.java
+++ b/src/core/lombok/javac/handlers/HandleToString.java
@@ -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
@@ -31,6 +31,8 @@ import lombok.ConfigurationKeys;
import lombok.ToString;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.core.handlers.InclusionExclusionUtils;
+import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
@@ -52,57 +54,33 @@ import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.ListBuffer;
/**
* Handles the {@code ToString} annotation for javac.
*/
@ProviderFor(JavacAnnotationHandler.class)
public class HandleToString extends JavacAnnotationHandler<ToString> {
- public void checkForBogusFieldNames(JavacNode type, AnnotationValues<ToString> annotation) {
- if (annotation.isExplicit("exclude")) {
- for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().exclude()), type, true, false)) {
- annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i);
- }
- }
- if (annotation.isExplicit("of")) {
- for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().of()), type, false, false)) {
- annotation.setWarning("of", "This field does not exist.", i);
- }
- }
- }
-
@Override public void handle(AnnotationValues<ToString> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString");
deleteAnnotationIfNeccessary(annotationNode, ToString.class);
ToString ann = annotation.getInstance();
- List<String> excludes = List.from(ann.exclude());
- List<String> includes = List.from(ann.of());
- JavacNode typeNode = annotationNode.up();
-
- checkForBogusFieldNames(typeNode, annotation);
+ java.util.List<Included<JavacNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), annotation, annotationNode);
+ if (members == null) return;
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper")) callSuper = null;
- if (!annotation.isExplicit("exclude")) excludes = null;
- if (!annotation.isExplicit("of")) includes = null;
-
- if (excludes != null && includes != null) {
- excludes = null;
- annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
- }
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
- boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration;
+ boolean includeNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration;
- generateToString(typeNode, annotationNode, excludes, includes, includeFieldNames, callSuper, true, fieldAccess);
+ generateToString(annotationNode.up(), annotationNode, members, includeNames, callSuper, true, fieldAccess);
}
public void generateToStringForType(JavacNode typeNode, JavacNode errorNode) {
@@ -111,7 +89,6 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
return;
}
-
boolean includeFieldNames = true;
try {
Boolean configuration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
@@ -121,20 +98,22 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
- generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, access);
+ java.util.List<Included<JavacNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(typeNode, null, null);
+ generateToString(typeNode, errorNode, members, includeFieldNames, null, false, access);
}
- public void generateToString(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes,
- boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
+ public void generateToString(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, ToString.Include>> members,
+ boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
+
boolean notAClass = true;
if (typeNode.get() instanceof JCClassDecl) {
- long flags = ((JCClassDecl)typeNode.get()).mods.flags;
+ long flags = ((JCClassDecl) typeNode.get()).mods.flags;
notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
}
if (callSuper == null) {
try {
- callSuper = ((Boolean)ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
+ callSuper = ((Boolean) ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
} catch (Exception ignore) {}
}
@@ -143,30 +122,9 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
return;
}
- ListBuffer<JavacNode> nodesForToString = new ListBuffer<JavacNode>();
- if (includes != null) {
- for (JavacNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
- if (includes.contains(fieldDecl.name.toString())) nodesForToString.append(child);
- }
- } else {
- for (JavacNode child : typeNode.down()) {
- if (child.getKind() != Kind.FIELD) continue;
- JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
- //Skip static fields.
- if ((fieldDecl.mods.flags & Flags.STATIC) != 0) continue;
- //Skip excluded fields.
- if (excludes != null && excludes.contains(fieldDecl.name.toString())) continue;
- //Skip fields that start with $.
- if (fieldDecl.name.toString().startsWith("$")) continue;
- nodesForToString.append(child);
- }
- }
-
switch (methodExists("toString", typeNode, 0)) {
case NOT_EXISTS:
- JCMethodDecl method = createToString(typeNode, nodesForToString.toList(), includeFieldNames, callSuper, fieldAccess, source.get());
+ JCMethodDecl method = createToString(typeNode, members, includeFieldNames, callSuper, fieldAccess, source.get());
injectMethod(typeNode, method);
break;
case EXISTS_BY_LOMBOK:
@@ -180,7 +138,9 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
}
}
- static JCMethodDecl createToString(JavacNode typeNode, Collection<JavacNode> fields, boolean includeFieldNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
+ static JCMethodDecl createToString(JavacNode typeNode, Collection<Included<JavacNode, ToString.Include>> members,
+ boolean includeNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
+
JavacTreeMaker maker = typeNode.getTreeMaker();
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
@@ -195,10 +155,13 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
String prefix;
if (callSuper) {
prefix = typeName + "(super=";
- } else if (fields.isEmpty()) {
+ } else if (members.isEmpty()) {
prefix = typeName + "()";
- } else if (includeFieldNames) {
- prefix = typeName + "(" + ((JCVariableDecl)fields.iterator().next().get()).name.toString() + "=";
+ } 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 + "=";
} else {
prefix = typeName + "(";
}
@@ -207,30 +170,35 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
if (callSuper) {
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
- maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("toString")),
- List.<JCExpression>nil());
+ maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("toString")),
+ List.<JCExpression>nil());
current = maker.Binary(CTC_PLUS, current, callToSuper);
first = false;
}
- for (JavacNode fieldNode : fields) {
+ for (Included<JavacNode, ToString.Include> member : members) {
JCExpression expr;
- JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
+ JCExpression memberAccessor;
+ JavacNode memberNode = member.getNode();
+ if (memberNode.getKind() == Kind.METHOD) {
+ memberAccessor = createMethodAccessor(maker, memberNode);
+ } else {
+ memberAccessor = createFieldAccessor(maker, memberNode, fieldAccess);
+ }
- JCExpression fieldType = getFieldType(fieldNode, fieldAccess);
+ JCExpression memberType = getFieldType(memberNode, fieldAccess);
// The distinction between primitive and object will be useful if we ever add a 'hideNulls' option.
- boolean fieldIsPrimitive = fieldType instanceof JCPrimitiveTypeTree;
- boolean fieldIsPrimitiveArray = fieldType instanceof JCArrayTypeTree && ((JCArrayTypeTree) fieldType).elemtype instanceof JCPrimitiveTypeTree;
- boolean fieldIsObjectArray = !fieldIsPrimitiveArray && fieldType instanceof JCArrayTypeTree;
@SuppressWarnings("unused")
- boolean fieldIsObject = !fieldIsPrimitive && !fieldIsPrimitiveArray && !fieldIsObjectArray;
+ boolean fieldIsPrimitive = memberType instanceof JCPrimitiveTypeTree;
+ boolean fieldIsPrimitiveArray = memberType instanceof JCArrayTypeTree && ((JCArrayTypeTree) memberType).elemtype instanceof JCPrimitiveTypeTree;
+ boolean fieldIsObjectArray = !fieldIsPrimitiveArray && memberType instanceof JCArrayTypeTree;
if (fieldIsPrimitiveArray || fieldIsObjectArray) {
JCExpression tsMethod = chainDots(typeNode, "java", "util", "Arrays", fieldIsObjectArray ? "deepToString" : "toString");
- expr = maker.Apply(List.<JCExpression>nil(), tsMethod, List.<JCExpression>of(fieldAccessor));
- } else expr = fieldAccessor;
+ expr = maker.Apply(List.<JCExpression>nil(), tsMethod, List.<JCExpression>of(memberAccessor));
+ } else expr = memberAccessor;
if (first) {
current = maker.Binary(CTC_PLUS, current, expr);
@@ -238,8 +206,10 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
continue;
}
- if (includeFieldNames) {
- current = maker.Binary(CTC_PLUS, current, maker.Literal(infix + fieldNode.getName() + "="));
+ if (includeNames) {
+ String n = member.getInc() == null ? "" : member.getInc().name();
+ if (n.isEmpty()) n = memberNode.getName();
+ current = maker.Binary(CTC_PLUS, current, maker.Literal(infix + n + "="));
} else {
current = maker.Binary(CTC_PLUS, current, maker.Literal(infix));
}
@@ -254,7 +224,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
JCBlock body = maker.Block(0, List.of(returnStatement));
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("toString"), returnType,
- List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext());
+ List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext());
}
public static String getTypeName(JavacNode typeNode) {
diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java
index d1af4168..abc5a5ca 100644
--- a/src/core/lombok/javac/handlers/HandleValue.java
+++ b/src/core/lombok/javac/handlers/HandleValue.java
@@ -40,6 +40,7 @@ import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.util.List;
/**
* Handles the {@code lombok.Value} annotation for javac.
@@ -76,7 +77,8 @@ public class HandleValue extends JavacAnnotationHandler<Value> {
}
handleFieldDefaults.generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
- handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
+ handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode);
+ handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil());
handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
handleToString.generateToStringForType(typeNode, annotationNode);
}
diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java
index 987a3d34..87f3c16a 100644
--- a/src/core/lombok/javac/handlers/HandleWither.java
+++ b/src/core/lombok/javac/handlers/HandleWither.java
@@ -36,7 +36,6 @@ import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc;
-import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 65d09a9a..f335cf94 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -216,7 +216,11 @@ public class JavacHandlerUtil {
}
}
- static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) {
+ public static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node) {
+ return findAnnotation(type, node, false);
+ }
+
+ public static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) {
if (node == null) return null;
if (type == null) return null;
switch (node.getKind()) {
@@ -321,8 +325,19 @@ public class JavacHandlerUtil {
* @param node A Lombok AST node representing an annotation in source code.
*/
public static <A extends Annotation> AnnotationValues<A> createAnnotation(Class<A> type, final JavacNode node) {
+ return createAnnotation(type, (JCAnnotation) node.get(), node);
+ }
+
+ /**
+ * Creates an instance of {@code AnnotationValues} for the provided AST Node
+ * and Annotation expression.
+ *
+ * @param type An annotation class type, such as {@code lombok.Getter.class}.
+ * @param anno the annotation expression
+ * @param node A Lombok AST node representing an annotation in source code.
+ */
+ public static <A extends Annotation> AnnotationValues<A> createAnnotation(Class<A> type, JCAnnotation anno, final JavacNode node) {
Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
- JCAnnotation anno = (JCAnnotation) node.get();
List<JCExpression> arguments = anno.getArguments();
for (JCExpression arg : arguments) {
@@ -343,17 +358,39 @@ public class JavacHandlerUtil {
}
if (rhs instanceof JCNewArray) {
- List<JCExpression> elems = ((JCNewArray)rhs).elems;
+ List<JCExpression> elems = ((JCNewArray) rhs).elems;
for (JCExpression inner : elems) {
raws.add(inner.toString());
expressions.add(inner);
- guesses.add(calculateGuess(inner));
+ if (inner instanceof JCAnnotation) {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<A> innerClass = (Class<A>) Class.forName(inner.type.toString());
+
+ guesses.add(createAnnotation(innerClass, (JCAnnotation) inner, node));
+ } catch (ClassNotFoundException ex) {
+ guesses.add(calculateGuess(inner));
+ }
+ } else {
+ guesses.add(calculateGuess(inner));
+ }
positions.add(inner.pos());
}
} else {
raws.add(rhs.toString());
expressions.add(rhs);
- guesses.add(calculateGuess(rhs));
+ if (rhs instanceof JCAnnotation) {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<A> innerClass = (Class<A>) Class.forName(rhs.type.toString());
+
+ guesses.add(createAnnotation(innerClass, (JCAnnotation) rhs, node));
+ } catch (ClassNotFoundException ex) {
+ guesses.add(calculateGuess(rhs));
+ }
+ } else {
+ guesses.add(calculateGuess(rhs));
+ }
positions.add(rhs.pos());
}
@@ -841,10 +878,6 @@ public class JavacHandlerUtil {
return null;
}
- public enum FieldAccess {
- GETTER, PREFER_FIELD, ALWAYS_FIELD;
- }
-
static boolean lookForGetter(JavacNode field, FieldAccess fieldAccess) {
if (fieldAccess == FieldAccess.GETTER) return true;
if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false;
@@ -866,12 +899,14 @@ public class JavacHandlerUtil {
* @see #createFieldAccessor(TreeMaker, JavacNode, FieldAccess)
*/
static JCExpression getFieldType(JavacNode field, FieldAccess fieldAccess) {
+ if (field.getKind() == Kind.METHOD) return ((JCMethodDecl) field.get()).restype;
+
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
- return ((JCVariableDecl)field.get()).vartype;
+ return ((JCVariableDecl) field.get()).vartype;
}
return getter.type;
@@ -908,7 +943,29 @@ public class JavacHandlerUtil {
if (receiver == null) receiver = maker.Ident(field.toName("this"));
JCMethodInvocation call = maker.Apply(List.<JCExpression>nil(),
- maker.Select(receiver, getter.name), List.<JCExpression>nil());
+ maker.Select(receiver, getter.name), List.<JCExpression>nil());
+ return call;
+ }
+
+ static JCExpression createMethodAccessor(JavacTreeMaker maker, JavacNode method) {
+ return createMethodAccessor(maker, method, null);
+ }
+
+ static JCExpression createMethodAccessor(JavacTreeMaker maker, JavacNode method, JCExpression receiver) {
+ JCMethodDecl methodDecl = (JCMethodDecl) method.get();
+
+ if (receiver == null && (methodDecl.mods.flags & Flags.STATIC) == 0) {
+ receiver = maker.Ident(method.toName("this"));
+ } else if (receiver == null) {
+ JavacNode containerNode = method.up();
+ if (containerNode != null && containerNode.get() instanceof JCClassDecl) {
+ JCClassDecl container = (JCClassDecl) method.up().get();
+ receiver = maker.Ident(container.name);
+ }
+ }
+
+ JCMethodInvocation call = maker.Apply(List.<JCExpression>nil(),
+ receiver == null ? maker.Ident(methodDecl.name) : maker.Select(receiver, methodDecl.name), List.<JCExpression>nil());
return call;
}
@@ -1756,4 +1813,12 @@ public class JavacHandlerUtil {
docComments.put(from.get(), filtered[1]);
}
}
+
+ public static boolean isDirectDescendantOfObject(JavacNode typeNode) {
+ if (!(typeNode.get() instanceof JCClassDecl)) throw new IllegalArgumentException("not a type node");
+ JCTree extending = Javac.getExtendsClause((JCClassDecl)typeNode.get());
+ if (extending == null) return true;
+ String p = extending.toString();
+ return p.equals("Object") || p.equals("java.lang.Object");
+ }
}
diff --git a/src/core9/module-info.java b/src/core9/module-info.java
index 87f819e2..f4d5815f 100644
--- a/src/core9/module-info.java
+++ b/src/core9/module-info.java
@@ -31,6 +31,7 @@ module lombok {
exports lombok.extern.jbosslog;
exports lombok.extern.log4j;
exports lombok.extern.slf4j;
+ exports lombok.extern.flogger;
provides javax.annotation.processing.Processor with lombok.launch.AnnotationProcessorHider.AnnotationProcessor;
provides org.mapstruct.ap.spi.AstModifyingAnnotationProcessor with lombok.launch.AnnotationProcessorHider.AstModificationNotifier;
diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java
index 0d887cb9..f5372fbb 100644
--- a/src/delombok/lombok/delombok/Delombok.java
+++ b/src/delombok/lombok/delombok/Delombok.java
@@ -86,6 +86,7 @@ public class Delombok {
private PrintStream feedback = System.err;
private boolean verbose;
private boolean noCopy;
+ private boolean onlyChanged;
private boolean force = false;
private String classpath, sourcepath, bootclasspath;
private LinkedHashMap<File, File> fileToBase = new LinkedHashMap<File, File>();
@@ -145,6 +146,9 @@ public class Delombok {
@Shorthand("n")
private boolean nocopy;
+ @Description("Output only changed files (implies -n)")
+ private boolean onlyChanged;
+
private boolean help;
}
@@ -238,7 +242,8 @@ public class Delombok {
}
if (args.verbose) delombok.setVerbose(true);
- if (args.nocopy) delombok.setNoCopy(true);
+ if (args.nocopy || args.onlyChanged) delombok.setNoCopy(true);
+ if (args.onlyChanged) delombok.setOnlyChanged(true);
if (args.print) {
delombok.setOutputToStandardOut();
} else {
@@ -364,6 +369,10 @@ public class Delombok {
this.noCopy = noCopy;
}
+ public void setOnlyChanged(boolean onlyChanged) {
+ this.onlyChanged = onlyChanged;
+ }
+
public void setOutput(File dir) {
if (dir.isFile() || (!dir.isDirectory() && dir.getName().endsWith(".java"))) throw new IllegalArgumentException(
"DELOMBOK: delombok will only write to a directory. " +
@@ -585,6 +594,10 @@ public class Delombok {
FormatPreferences fps = new FormatPreferences(formatPrefs);
for (JCCompilationUnit unit : roots) {
DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit), fps);
+ if (onlyChanged && !result.isChanged() && !options.isChanged(unit)) {
+ if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), "unchanged (skipped)");
+ continue;
+ }
if (verbose) feedback.printf("File: %s [%s%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged", force && !options.isChanged(unit) ? " (forced)" : "");
Writer rawWriter;
if (presetWriter != null) rawWriter = createUnicodeEscapeWriter(presetWriter);
diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java
index aa753fc8..2ba4c6ed 100644
--- a/src/delombok/lombok/delombok/DelombokApp.java
+++ b/src/delombok/lombok/delombok/DelombokApp.java
@@ -79,7 +79,7 @@ public class DelombokApp extends LombokApp {
}
}
- System.err.printf("Can't find tools.jar. Rerun delombok as: java -cp lombok.jar%1$s%2$s lombok.core.Main delombok %3$s\n",
+ System.err.printf("Can't find tools.jar. Rerun delombok as: java -cp lombok.jar%1$s%2$s lombok.launch.Main delombok %3$s\n",
File.pathSeparator, examplePath, sb.toString());
return null;
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
index 33d7a496..a6d745b6 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
@@ -106,7 +106,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
patchHideGeneratedNodes(sm);
patchPostCompileHookEclipse(sm);
patchFixSourceTypeConverter(sm);
- patchDisableLombokForCodeFormatterAndCleanup(sm);
+ patchDisableLombokForCodeCleanup(sm);
patchListRewriteHandleGeneratedMethods(sm);
patchSyntaxAndOccurrencesHighlighting(sm);
patchSortMembersOperation(sm);
@@ -224,13 +224,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.build());
}
- private static void patchDisableLombokForCodeFormatterAndCleanup(ScriptManager sm) {
- sm.addScript(ScriptBuilder.setSymbolDuringMethodCall()
- .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit"))
- .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean"))
- .symbol("lombok.disable")
- .build());
-
+ private static void patchDisableLombokForCodeCleanup(ScriptManager sm) {
sm.addScript(ScriptBuilder.exitEarly()
.target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.DoStatement"))
.target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.EnhancedForStatement"))
@@ -349,18 +343,19 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
}
private static void patchFormatters(ScriptManager sm) {
+ // before Eclipse Mars
sm.addScript(ScriptBuilder.setSymbolDuringMethodCall()
- .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.java.JavaFormattingStrategy", "format", "void"))
- .callToWrap(new Hook("org.eclipse.jdt.internal.corext.util.CodeFormatterUtil", "reformat", "org.eclipse.text.edits.TextEdit",
- "int", "java.lang.String", "int", "int", "int", "java.lang.String", "java.util.Map"))
- .symbol("lombok.disable").build());
+ .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit"))
+ .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean"))
+ .symbol("lombok.disable")
+ .build());
+ // Eclipse Mars and beyond
sm.addScript(ScriptBuilder.setSymbolDuringMethodCall()
- .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.CodeFormatFix", "createCleanUp", "org.eclipse.jdt.ui.cleanup.ICleanUpFix",
- "org.eclipse.jdt.core.ICompilationUnit", "org.eclipse.jface.text.IRegion[]", "boolean", "boolean", "boolean", "boolean"))
- .callToWrap(new Hook("org.eclipse.jdt.internal.corext.util.CodeFormatterUtil", "reformat", "org.eclipse.text.edits.TextEdit",
- "int", "java.lang.String", "int", "java.lang.String", "java.util.Map"))
- .symbol("lombok.disable").build());
+ .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "parseSourceCode"))
+ .callToWrap(new Hook("org.eclipse.jdt.core.dom.ASTParser", "createAST", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.core.runtime.IProgressMonitor"))
+ .symbol("lombok.disable")
+ .build());
}
private static void patchRefactorScripts(ScriptManager sm) {
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
index 3da37869..c2a362bd 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
@@ -21,9 +21,11 @@
*/
package lombok.eclipse.agent;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
@@ -32,8 +34,11 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.ImportBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
@@ -84,11 +89,28 @@ public class PatchVal {
return true;
}
- public static boolean couldBe(String key, TypeReference ref) {
+ public static boolean couldBe(ImportBinding[] imports, String key, TypeReference ref) {
String[] keyParts = key.split("\\.");
if (ref instanceof SingleTypeReference) {
char[] token = ((SingleTypeReference)ref).token;
- return matches(keyParts[keyParts.length - 1], token);
+ if (!matches(keyParts[keyParts.length - 1], token)) return false;
+ if (imports == null) return true;
+ top:
+ for (ImportBinding ib : imports) {
+ ImportReference ir = ib.reference;
+ if (ir == null) continue;
+ if (ir.isStatic()) continue;
+ boolean star = ((ir.bits & ASTNode.OnDemand) != 0);
+ int len = keyParts.length - (star ? 1 : 0);
+ char[][] t = ir.tokens;
+ if (len != t.length) continue;
+ for (int i = 0; i < len; i++) {
+ if (keyParts[i].length() != t[i].length) continue top;
+ for (int j = 0; j < t[i].length; j++) if (keyParts[i].charAt(j) != t[i][j]) continue top;
+ }
+ return true;
+ }
+ return false;
}
if (ref instanceof QualifiedTypeReference) {
@@ -104,10 +126,53 @@ public class PatchVal {
return false;
}
-
+
+ public static boolean couldBe(ImportReference[] imports, String key, TypeReference ref) {
+ String[] keyParts = key.split("\\.");
+ if (ref instanceof SingleTypeReference) {
+ char[] token = ((SingleTypeReference)ref).token;
+ if (!matches(keyParts[keyParts.length - 1], token)) return false;
+ if (imports == null) return true;
+ top:
+ for (ImportReference ir : imports) {
+ if (ir.isStatic()) continue;
+ boolean star = ((ir.bits & ASTNode.OnDemand) != 0);
+ int len = keyParts.length - (star ? 1 : 0);
+ char[][] t = ir.tokens;
+ if (len != t.length) continue;
+ for (int i = 0; i < len; i++) {
+ if (keyParts[i].length() != t[i].length) continue top;
+ for (int j = 0; j < t[i].length; j++) if (keyParts[i].charAt(j) != t[i][j]) continue top;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ if (ref instanceof QualifiedTypeReference) {
+ char[][] tokens = ((QualifiedTypeReference)ref).tokens;
+ if (keyParts.length != tokens.length) return false;
+ for(int i = 0; i < tokens.length; ++i) {
+ String part = keyParts[i];
+ char[] token = tokens[i];
+ if (!matches(part, token)) return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
private static boolean is(TypeReference ref, BlockScope scope, String key) {
- if (!couldBe(key, ref)) return false;
-
+ Scope s = scope.parent;
+ while (s != null && !(s instanceof CompilationUnitScope)) {
+ Scope ns = s.parent;
+ s = ns == s ? null : ns;
+ }
+ ImportBinding[] imports = null;
+ if (s instanceof CompilationUnitScope) imports = ((CompilationUnitScope) s).imports;
+ if (!couldBe(imports, key, ref)) return false;
+
TypeBinding resolvedType = ref.resolvedType;
if (resolvedType == null) resolvedType = ref.resolveType(scope, false);
if (resolvedType == null) return false;
@@ -224,7 +289,7 @@ public class PatchVal {
boolean val = isVal(forEach.elementVariable, scope);
boolean var = isVar(forEach.elementVariable, scope);
- if (!(val || var)) return false;
+ if (!(val || var)) return false;
TypeBinding component = getForEachComponentType(forEach.collection, scope);
if (component == null) return false;
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
index 46237dcf..d59b6a2e 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
@@ -45,6 +45,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
@@ -66,8 +67,8 @@ public class PatchValEclipse {
ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr];
ASTNode init = foreachDecl.collection;
if (init == null) return;
- boolean val = couldBeVal(foreachDecl.elementVariable.type);
- boolean var = couldBeVar(foreachDecl.elementVariable.type);
+ boolean val = couldBeVal(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, foreachDecl.elementVariable.type);
+ boolean var = couldBeVar(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, foreachDecl.elementVariable.type);
if (foreachDecl.elementVariable == null || !(val || var)) return;
try {
@@ -91,8 +92,8 @@ public class PatchValEclipse {
if (!(variableDecl instanceof LocalDeclaration)) return;
ASTNode init = variableDecl.initialization;
if (init == null) return;
- boolean val = couldBeVal(variableDecl.type);
- boolean var = couldBeVar(variableDecl.type);
+ boolean val = couldBeVal(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, variableDecl.type);
+ boolean var = couldBeVar(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, variableDecl.type);
if (!(val || var)) return;
try {
@@ -102,8 +103,8 @@ public class PatchValEclipse {
}
}
- private static boolean couldBeVar(TypeReference type) {
- return PatchVal.couldBe("lombok.experimental.var", type) || PatchVal.couldBe("lombok.var", type);
+ private static boolean couldBeVar(ImportReference[] imports, TypeReference type) {
+ return PatchVal.couldBe(imports, "lombok.experimental.var", type) || PatchVal.couldBe(imports, "lombok.var", type);
}
public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) {
@@ -124,7 +125,7 @@ public class PatchValEclipse {
Annotation valAnnotation = null;
for (Annotation ann : in.annotations) {
- if (couldBeVal(ann.type)) {
+ if (couldBeVal(null, ann.type)) {
found = true;
valAnnotation = ann;
break;
@@ -176,8 +177,8 @@ public class PatchValEclipse {
}
}
- private static boolean couldBeVal(TypeReference type) {
- return PatchVal.couldBe("lombok.val", type);
+ private static boolean couldBeVal(ImportReference[] imports, TypeReference type) {
+ return PatchVal.couldBe(imports, "lombok.val", type);
}
public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) {
diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
index b1d73352..317b06a4 100644
--- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java
+++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
@@ -148,7 +148,11 @@ final class PatchFixesHider {
}
public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) {
- return (String) Util.invokeMethod(LombokDeps.ADD_LOMBOK_NOTES, origReturnValue, key);
+ try {
+ return (String) Util.invokeMethod(LombokDeps.ADD_LOMBOK_NOTES, origReturnValue, key);
+ } catch (Throwable t) {
+ return origReturnValue;
+ }
}
public static byte[] runPostCompiler(byte[] bytes, String fileName) {
diff --git a/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java
index b807f02b..917091c0 100644
--- a/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java
+++ b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java
@@ -43,18 +43,19 @@ public class EclipseProductLocationProvider implements IdeLocationProvider {
this.descriptor = descriptor;
}
- @Override public final IdeLocation create(String path) throws CorruptedIdeLocationException {
- return create0(path);
- }
-
/**
* Create a new EclipseLocation by pointing at either the directory contains the Eclipse executable, or the executable itself,
* or an eclipse.ini file.
*
- * @throws NotAnIdeLocationException
+ * @throws CorruptedIdeLocationException
* If this isn't an Eclipse executable or a directory with an
* Eclipse executable.
+ * @throws NullPointerException if {@code path} is {@code null}.
*/
+ @Override public final IdeLocation create(String path) throws CorruptedIdeLocationException {
+ return create0(path);
+ }
+
private IdeLocation create0(String path) throws CorruptedIdeLocationException {
if (path == null) throw new NullPointerException("path");
String iniName = descriptor.getIniFileName();
diff --git a/src/utils/lombok/core/ClassLiteral.java b/src/utils/lombok/core/ClassLiteral.java
new file mode 100644
index 00000000..077ead31
--- /dev/null
+++ b/src/utils/lombok/core/ClassLiteral.java
@@ -0,0 +1,13 @@
+package lombok.core;
+
+public class ClassLiteral {
+ private final String className;
+
+ public ClassLiteral(String className) {
+ this.className = className;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+}
diff --git a/src/utils/lombok/core/FieldSelect.java b/src/utils/lombok/core/FieldSelect.java
new file mode 100644
index 00000000..ab784401
--- /dev/null
+++ b/src/utils/lombok/core/FieldSelect.java
@@ -0,0 +1,13 @@
+package lombok.core;
+
+public class FieldSelect {
+ private final String finalPart;
+
+ public FieldSelect(String finalPart) {
+ this.finalPart = finalPart;
+ }
+
+ public String getFinalPart() {
+ return finalPart;
+ }
+}
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index 18b22256..5ef33086 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -27,6 +27,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
+import lombok.core.ClassLiteral;
+import lombok.core.FieldSelect;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -40,6 +42,7 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TryStatement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
@@ -161,7 +164,7 @@ public class Eclipse {
*/
public static Object calculateValue(Expression e) {
if (e instanceof Literal) {
- ((Literal)e).computeConstant();
+ ((Literal) e).computeConstant();
switch (e.constant.typeID()) {
case TypeIds.T_int: return e.constant.intValue();
case TypeIds.T_byte: return e.constant.byteValue();
@@ -175,13 +178,24 @@ public class Eclipse {
default: return null;
}
} else if (e instanceof ClassLiteralAccess) {
- return Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName());
+ return new ClassLiteral(Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName()));
} else if (e instanceof SingleNameReference) {
- return new String(((SingleNameReference)e).token);
+ return new FieldSelect(new String(((SingleNameReference)e).token));
} else if (e instanceof QualifiedNameReference) {
String qName = Eclipse.toQualifiedName(((QualifiedNameReference)e).tokens);
int idx = qName.lastIndexOf('.');
- return idx == -1 ? qName : qName.substring(idx+1);
+ return new FieldSelect(idx == -1 ? qName : qName.substring(idx+1));
+ } else if (e instanceof UnaryExpression) {
+ if ("-".equals(((UnaryExpression) e).operatorToString())) {
+ Object inner = calculateValue(((UnaryExpression) e).expression);
+ if (inner instanceof Integer) return - ((Integer) inner).intValue();
+ if (inner instanceof Byte) return - ((Byte) inner).byteValue();
+ if (inner instanceof Short) return - ((Short) inner).shortValue();
+ if (inner instanceof Long) return - ((Long) inner).longValue();
+ if (inner instanceof Float) return - ((Float) inner).floatValue();
+ if (inner instanceof Double) return - ((Double) inner).doubleValue();
+ return null;
+ }
}
return null;
diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java
index 9ff4d22f..92961726 100644
--- a/src/utils/lombok/javac/Javac.java
+++ b/src/utils/lombok/javac/Javac.java
@@ -36,6 +36,8 @@ import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeVisitor;
+import lombok.core.ClassLiteral;
+import lombok.core.FieldSelect;
import lombok.javac.JavacTreeMaker.TreeTag;
import lombok.javac.JavacTreeMaker.TypeTag;
@@ -143,16 +145,17 @@ public class Javac {
return ((Number) lit.value).intValue() == 0 ? false : true;
}
return lit.value;
- } else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) {
+ }
+
+ if (expr instanceof JCIdent || expr instanceof JCFieldAccess) {
String x = expr.toString();
- if (x.endsWith(".class")) x = x.substring(0, x.length() - 6);
- else {
- int idx = x.lastIndexOf('.');
- if (idx > -1) x = x.substring(idx + 1);
- }
- return x;
- } else
- return null;
+ if (x.endsWith(".class")) return new ClassLiteral(x.substring(0, x.length() - 6));
+ int idx = x.lastIndexOf('.');
+ if (idx > -1) x = x.substring(idx + 1);
+ return new FieldSelect(x);
+ }
+
+ return null;
}
public static final TypeTag CTC_BOOLEAN = typeTag("BOOLEAN");
diff --git a/src/website/lombok/website/FetchCurrentVersion.java b/src/website/lombok/website/FetchCurrentVersion.java
index 6c1ca639..0d789256 100644
--- a/src/website/lombok/website/FetchCurrentVersion.java
+++ b/src/website/lombok/website/FetchCurrentVersion.java
@@ -23,7 +23,7 @@ public class FetchCurrentVersion {
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
for (String line = br.readLine(); line != null; line = br.readLine()) {
Matcher m = VERSION_PATTERN.matcher(line);
- if (m.matches() && m.group(1).equals("currentVersionFull") == fetchFull) return m.group(2);
+ if (m.matches() && m.group(1).equals("currentVersionFull") == fetchFull) return m.group(2).replace("&quot;", "\"");
}
throw new IOException("Expected a span with id 'currentVersion'");
} finally {