aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml11
-rw-r--r--buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml14
-rw-r--r--buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml14
-rw-r--r--buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml14
-rw-r--r--buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml14
-rw-r--r--buildScripts/ivy.xml2
-rw-r--r--src/core/lombok/Cleanup.java2
-rw-r--r--src/core/lombok/ConfigurationKeys.java350
-rw-r--r--src/core/lombok/Delegate.java2
-rw-r--r--src/core/lombok/EqualsAndHashCode.java2
-rw-r--r--src/core/lombok/NonNull.java3
-rw-r--r--src/core/lombok/SneakyThrows.java2
-rw-r--r--src/core/lombok/Synchronized.java2
-rw-r--r--src/core/lombok/ToString.java2
-rw-r--r--src/core/lombok/core/AST.java14
-rw-r--r--src/core/lombok/core/FlagUsageType.java6
-rw-r--r--src/core/lombok/core/LombokConfiguration.java54
-rw-r--r--src/core/lombok/core/TransformationsUtil.java306
-rw-r--r--src/core/lombok/core/configuration/BubblingConfigurationResolver.java78
-rw-r--r--src/core/lombok/core/configuration/ConfigurationApp.java376
-rw-r--r--src/core/lombok/core/configuration/ConfigurationDataType.java182
-rw-r--r--src/core/lombok/core/configuration/ConfigurationKey.java96
-rw-r--r--src/core/lombok/core/configuration/ConfigurationKeysLoader.java57
-rw-r--r--src/core/lombok/core/configuration/ConfigurationParser.java109
-rw-r--r--src/core/lombok/core/configuration/ConfigurationProblemReporter.java32
-rw-r--r--src/core/lombok/core/configuration/ConfigurationResolver.java26
-rw-r--r--src/core/lombok/core/configuration/ConfigurationResolverFactory.java28
-rw-r--r--src/core/lombok/core/configuration/ConfigurationSource.java67
-rw-r--r--src/core/lombok/core/configuration/ConfigurationValueParser.java28
-rw-r--r--src/core/lombok/core/configuration/FileSystemSourceCache.java184
-rw-r--r--src/core/lombok/core/configuration/StringConfigurationSource.java90
-rw-r--r--src/core/lombok/core/configuration/TypeName.java47
-rw-r--r--src/core/lombok/core/handlers/HandlerUtil.java361
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java27
-rw-r--r--src/core/lombok/eclipse/HandlerLibrary.java5
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java36
-rw-r--r--src/core/lombok/eclipse/handlers/HandleAccessors.java43
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleCleanup.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandleConstructor.java17
-rw-r--r--src/core/lombok/eclipse/handlers/HandleData.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java7
-rw-r--r--src/core/lombok/eclipse/handlers/HandleExtensionMethod.java7
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleLog.java36
-rw-r--r--src/core/lombok/eclipse/handlers/HandleNonNull.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandlePrintAST.java17
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSneakyThrows.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSynchronized.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java19
-rw-r--r--src/core/lombok/eclipse/handlers/HandleVal.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleValue.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWither.java11
-rw-r--r--src/core/lombok/experimental/Accessors.java2
-rw-r--r--src/core/lombok/experimental/ExtensionMethod.java2
-rw-r--r--src/core/lombok/experimental/FieldDefaults.java2
-rw-r--r--src/core/lombok/extern/apachecommons/CommonsLog.java2
-rw-r--r--src/core/lombok/extern/java/Log.java2
-rw-r--r--src/core/lombok/extern/log4j/Log4j.java2
-rw-r--r--src/core/lombok/extern/log4j/Log4j2.java2
-rw-r--r--src/core/lombok/extern/slf4j/Slf4j.java2
-rw-r--r--src/core/lombok/extern/slf4j/XSlf4j.java1
-rw-r--r--src/core/lombok/javac/HandlerLibrary.java2
-rw-r--r--src/core/lombok/javac/JavacAST.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleAccessors.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java6
-rw-r--r--src/core/lombok/javac/handlers/HandleCleanup.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java19
-rw-r--r--src/core/lombok/javac/handlers/HandleData.java6
-rw-r--r--src/core/lombok/javac/handlers/HandleDelegate.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleExtensionMethod.java6
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldDefaults.java6
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleLog.java34
-rw-r--r--src/core/lombok/javac/handlers/HandleNonNull.java4
-rw-r--r--src/core/lombok/javac/handlers/HandlePrintAST.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleSneakyThrows.java4
-rw-r--r--src/core/lombok/javac/handlers/HandleSynchronized.java6
-rw-r--r--src/core/lombok/javac/handlers/HandleToString.java16
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleValue.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleWither.java9
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java62
-rw-r--r--src/core/lombok/val.java5
-rw-r--r--src/delombok/lombok/delombok/PrettyCommentsPrinter.java9
-rw-r--r--test/configuration/resource/configurationRoot/d1/d11/d111/f1.txt0
-rw-r--r--test/configuration/resource/configurationRoot/d1/d11/d111/lombok.config2
-rw-r--r--test/configuration/resource/configurationRoot/d1/d11/lombok.config5
-rw-r--r--test/configuration/resource/configurationRoot/d1/d12/lombok.config3
-rw-r--r--test/configuration/resource/configurationRoot/d1/lombok.config3
-rw-r--r--test/configuration/resource/configurationRoot/err.txt0
-rw-r--r--test/configuration/resource/configurationRoot/out.txt90
-rw-r--r--test/configuration/src/lombok/core/configuration/RunConfigurationTests.java31
-rw-r--r--test/configuration/src/lombok/core/configuration/TestConfiguration.java95
-rw-r--r--test/core/src/lombok/AbstractRunTests.java95
-rw-r--r--test/core/src/lombok/DirectoryRunner.java59
-rw-r--r--test/core/src/lombok/LombokTestSource.java239
-rw-r--r--test/core/src/lombok/RunAllTests.java4
-rw-r--r--test/core/src/lombok/RunTestsViaDelombok.java2
-rw-r--r--test/core/src/lombok/RunTestsViaEcj.java2
-rw-r--r--test/transform/resource/after-delombok/AccessorsConfiguration.java26
-rw-r--r--test/transform/resource/after-delombok/LoggerConfig.java4
-rw-r--r--test/transform/resource/after-delombok/ToStringConfiguration.java32
-rw-r--r--test/transform/resource/after-ecj/AccessorsConfiguration.java31
-rw-r--r--test/transform/resource/after-ecj/LoggerConfig.java6
-rw-r--r--test/transform/resource/after-ecj/ToStringConfiguration.java35
-rw-r--r--test/transform/resource/before/AccessorsConfiguration.java20
-rw-r--r--test/transform/resource/before/BuilderInvalidUse.java1
-rw-r--r--test/transform/resource/before/DelegateOnStatic.java1
-rw-r--r--test/transform/resource/before/FlagUsages.java11
-rw-r--r--test/transform/resource/before/LoggerConfig.java5
-rw-r--r--test/transform/resource/before/ToStringConfiguration.java13
-rw-r--r--test/transform/resource/messages-delombok/BuilderInvalidUse.java.messages4
-rw-r--r--test/transform/resource/messages-delombok/DelegateOnStatic.java.messages4
-rw-r--r--test/transform/resource/messages-delombok/FlagUsages.java.messages2
-rw-r--r--test/transform/resource/messages-ecj/BuilderInvalidUse.java.messages4
-rw-r--r--test/transform/resource/messages-ecj/DelegateOnStatic.java.messages4
-rw-r--r--test/transform/resource/messages-ecj/FlagUsages.java.messages2
122 files changed, 3420 insertions, 572 deletions
diff --git a/build.xml b/build.xml
index 847d9056..d640acc8 100644
--- a/build.xml
+++ b/build.xml
@@ -247,6 +247,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<srcdir dir="test/transform/src" test="true" />
<srcdir dir="test/core/src" test="true" />
<srcdir dir="test/bytecode/src" test="true" />
+ <srcdir dir="test/configuration/src" test="true" />
</module>
<settings>
<url url="http://projectlombok.org/downloads/lombok.intellij.settings" />
@@ -275,9 +276,10 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<srcdir dir="test/transform/src" />
<srcdir dir="test/core/src" />
<srcdir dir="test/bytecode/src" />
- <local org="org.projectlombok" name="lombok.patcher" dir="../lombok.patcher" />
+ <srcdir dir="test/configuration/src" />
<conf name="${eclipse.build.configname}" sources="contrib" />
<conf name="test" sources="contrib" />
+ <local org="org.projectlombok" name="lombok.patcher" dir="../lombok.patcher" />
<settings>
<url url="http://projectlombok.org/downloads/lombok.eclipse.settings" />
</settings>
@@ -320,6 +322,8 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.osgi" /></antcall>
<antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.jdt.core" /></antcall>
<antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.jdt.ui" /></antcall>
+ <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.core.resources" /></antcall>
+ <antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.core.jobs" /></antcall>
<!-- These are merely useful -->
<antcall target="-augmentClasspath"><param name="pluginName" value="org.eclipse.text" /></antcall>
@@ -387,10 +391,12 @@ ${sourceWarning}</echo>
<src path="test/core/src" />
<src path="test/transform/src" />
<src path="test/bytecode/src" />
+ <src path="test/configuration/src" />
</ivy:compile>
<copy todir="build/tests">
<fileset dir="test/pretty/resource" />
<fileset dir="test/transform/resource" />
+ <fileset dir="test/configuration/resource" />
</copy>
</target>
@@ -521,6 +527,9 @@ You can also create your own by writing a 'testenvironment.properties' file. The
<fileset dir="test/bytecode/src">
<include name="**/Test*.java" />
</fileset>
+ <fileset dir="test/configuration/src">
+ <include name="**/Test*.java" />
+ </fileset>
</batchtest>
</junit>
<echo level="info">All tests successful.</echo>
diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml
new file mode 100644
index 00000000..ed4f5fd5
--- /dev/null
+++ b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.200.xml
@@ -0,0 +1,14 @@
+<ivy-module version="2.0">
+ <info organisation="org.eclipse.custom" module="core.jobs" revision="3.5.200" publication="20120521234600">
+ <license name="Eclipse Public Licence v1.0" url="http://www.eclipse.org/org/documents/epl-v10.php" />
+ <description homepage="http://www.eclipse.org/eclipse/" />
+ </info>
+ <configurations>
+ <conf name="default" />
+ <conf name="sources" />
+ </configurations>
+ <publications>
+ <artifact conf="default" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.jobs_3.5.200.v20120521-2346.jar" />
+ <artifact type="zip" conf="sources" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.jobs_3.5.200.v20120521-2346-sources.jar" />
+ </publications>
+</ivy-module>
diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml
new file mode 100644
index 00000000..4ac11822
--- /dev/null
+++ b/buildScripts/ivy-repo/org.eclipse.custom-core.jobs-3.5.300.xml
@@ -0,0 +1,14 @@
+<ivy-module version="2.0">
+ <info organisation="org.eclipse.custom" module="core.jobs" revision="3.5.300" publication="20130429181300">
+ <license name="Eclipse Public Licence v1.0" url="http://www.eclipse.org/org/documents/epl-v10.php" />
+ <description homepage="http://www.eclipse.org/eclipse/" />
+ </info>
+ <configurations>
+ <conf name="default" />
+ <conf name="sources" />
+ </configurations>
+ <publications>
+ <artifact conf="default" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.jobs_3.5.300.v20130429-1813.jar" />
+ <artifact type="zip" conf="sources" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.jobs_3.5.300.v20130429-1813-sources.jar" />
+ </publications>
+</ivy-module>
diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml
new file mode 100644
index 00000000..9fe7836e
--- /dev/null
+++ b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.7.0.xml
@@ -0,0 +1,14 @@
+<ivy-module version="2.0">
+ <info organisation="org.eclipse.custom" module="core.resources" revision="3.7.0" publication="20110510071200">
+ <license name="Eclipse Public Licence v1.0" url="http://www.eclipse.org/org/documents/epl-v10.php" />
+ <description homepage="http://www.eclipse.org/eclipse/" />
+ </info>
+ <configurations>
+ <conf name="default" />
+ <conf name="sources" />
+ </configurations>
+ <publications>
+ <artifact conf="default" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.resources_3.7.100.v20110510-0712.jar" />
+ <artifact type="zip" conf="sources" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.resources_3.7.100.v20110510-0712-sources.jar" />
+ </publications>
+</ivy-module>
diff --git a/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml
new file mode 100644
index 00000000..c76dba24
--- /dev/null
+++ b/buildScripts/ivy-repo/org.eclipse.custom-core.resources-3.8.100.xml
@@ -0,0 +1,14 @@
+<ivy-module version="2.0">
+ <info organisation="org.eclipse.custom" module="core.resources" revision="3.8.100" publication="20130521202600">
+ <license name="Eclipse Public Licence v1.0" url="http://www.eclipse.org/org/documents/epl-v10.php" />
+ <description homepage="http://www.eclipse.org/eclipse/" />
+ </info>
+ <configurations>
+ <conf name="default" />
+ <conf name="sources" />
+ </configurations>
+ <publications>
+ <artifact conf="default" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.resources_3.8.100.v20130521-2026.jar" />
+ <artifact type="zip" conf="sources" url="http://projectlombok.org/ivyrepo/eclipse/org.eclipse.core.resources_3.8.100.v20130521-2026-sources.jar" />
+ </publications>
+</ivy-module>
diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml
index 32f8d790..b2d3ab21 100644
--- a/buildScripts/ivy.xml
+++ b/buildScripts/ivy.xml
@@ -47,5 +47,7 @@
<dependency org="org.eclipse.custom" name="jdt.ui" rev="3.9.1" conf="eclipseBuild->default; contrib->sources" />
<dependency org="org.eclipse.custom" name="equinox.common" rev="3.6.200" conf="eclipseBuild->default; contrib->sources" />
<dependency org="org.eclipse.custom" name="osgi" rev="3.9.0" conf="eclipseBuild->default; contrib->sources" />
+ <dependency org="org.eclipse.custom" name="core.resources" rev="3.8.100" conf="eclipseBuild->default; contrib->sources" />
+ <dependency org="org.eclipse.custom" name="core.jobs" rev="3.5.300" conf="eclipseBuild->default; contrib->sources" />
</dependencies>
</ivy-module>
diff --git a/src/core/lombok/Cleanup.java b/src/core/lombok/Cleanup.java
index eb223958..4b5c6fc2 100644
--- a/src/core/lombok/Cleanup.java
+++ b/src/core/lombok/Cleanup.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
new file mode 100644
index 00000000..9d9d17b4
--- /dev/null
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2013-2014 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;
+
+import java.util.List;
+
+import lombok.core.FlagUsageType;
+import lombok.core.configuration.ConfigurationKey;
+
+/**
+ * A container class containing all lombok configuration keys that do not belong to a specific annotation.
+ */
+public class ConfigurationKeys {
+ private ConfigurationKeys() {}
+
+ // ##### main package features #####
+
+ // ----- *ArgsConstructor -----
+
+ /**
+ * lombok configuration: {@code lombok.AnyConstructor.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @AllArgsConstructor}, {@code @RequiredArgsConstructor}, or {@code @NoArgsConstructor} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> ANY_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.AnyConstructor.flagUsage", "Emit a warning or error if any of the XxxArgsConstructor annotations are used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.AllArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @AllArgsConstructor} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> ALL_ARGS_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.AllArgsConstructor.flagUsage", "Emit a warning or error if @AllArgsConstructor is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.NoArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @NoArgsConstructor} results in a warning / error.
+ */
+ 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.RequiredArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @RequiredArgsConstructor} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> REQUIRED_ARGS_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.RequiredArgsConstructor.flagUsage", "Emit a warning or error if @RequiredArgsConstructor is used.") {};
+
+ // ##### Beanies #####
+
+ // ----- Data -----
+
+ /**
+ * lombok configuration: {@code lombok.Data.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Data} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> DATA_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Data.flagUsage", "Emit a warning or error if @Data is used.") {};
+
+ // ----- Value -----
+
+ /**
+ * lombok configuration: {@code lombok.Value.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Value} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> VALUE_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Value.flagUsage", "Emit a warning or error if @Value is used.") {};
+
+ // ----- Getter -----
+
+ /**
+ * lombok configuration: {@code lombok.Getter.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Getter} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> GETTER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Getter.flagUsage", "Emit a warning or error if @Getter is used.") {};
+
+ // ----- Setter -----
+
+ /**
+ * lombok configuration: {@code lombok.Setter.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Setter} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> SETTER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Setter.flagUsage", "Emit a warning or error if @Setter is used.") {};
+
+ // ----- EqualsAndHashCode -----
+
+ /**
+ * lombok configuration: {@code lombok.EqualsAndHashCode.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @EqualsAndHashCode} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> EQUALS_AND_HASH_CODE_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.EqualsAndHashCode.flagUsage", "Emit a warning or error if @EqualsAndHashCode is used.") {};
+
+ // ----- ToString -----
+
+ /**
+ * lombok configuration: {@code lombok.ToString.doNotUseGetters} = {@code true} | {@code false}.
+ *
+ * For any class without an {@code @ToString} that explicitly defines the {@code doNotUseGetters} option, this value is used.
+ */
+ public static final ConfigurationKey<Boolean> TO_STRING_DO_NOT_USE_GETTERS = new ConfigurationKey<Boolean>("lombok.ToString.doNotUseGetters", "Don't call the getters but use the fields directly in the generated toString method.") {};
+
+ /**
+ * lombok configuration: {@code lombok.ToString.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @ToString} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> TO_STRING_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.ToString.flagUsage", "Emit a warning or error if @ToString is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.ToString.includeFieldNames} = {@code true} | {@code false}.
+ *
+ * For any class without an {@code @ToString} that explicitly defines the {@code includeFieldNames} option, this value is used.
+ */
+ public static final ConfigurationKey<Boolean> TO_STRING_INCLUDE_FIELD_NAMES = new ConfigurationKey<Boolean>("lombok.ToString.includeFieldNames", "Include the field names in the generated toString method.") {};
+
+ // ##### Standalones #####
+
+ // ----- Cleanup -----
+
+ /**
+ * lombok configuration: {@code lombok.Cleanup.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Cleanup} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> CLEANUP_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Cleanup.flagUsage", "Emit a warning or error if @Cleanup is used.") {};
+
+ // ----- Delegate -----
+
+ /**
+ * lombok configuration: {@code lombok.Delegate.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Delegate} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> DELEGATE_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Delegate.flagUsage", "Emit a warning or error if @Delegate is used.") {};
+
+ // ----- NonNull -----
+
+ /**
+ * lombok configuration: {@code lombok.NonNull.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * <em>Implementation note: This field is supposed to be lombok.NonNull itself, but jdk6 and 7 have bugs where fields in annotations don't work well.</em>
+ *
+ * If set, <em>any</em> usage of {@code @NonNull} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> NON_NULL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.NonNull.flagUsage", "Emit a warning or error if @NonNull is used.") {};
+
+ // ----- SneakyThrows -----
+
+ /**
+ * lombok configuration: {@code lombok.SneakyThrows.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @SneakyThrows} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> SNEAKY_THROWS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.SneakyThrows.flagUsage", "Emit a warning or error if @SneakyThrows is used.") {};
+
+ // ----- Synchronized -----
+
+ /**
+ * lombok configuration: {@code lombok.Synchronized.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Synchronized} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> SYNCHRONIZED_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Synchronized.flagUsage", "Emit a warning or error if @Synchronized is used.") {};
+
+ // ----- val -----
+
+ /**
+ * lombok configuration: {@code lombok.val.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code val} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> VAL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.val.flagUsage", "Emit a warning or error if 'val' is used.") {};
+
+ // ##### Extern #####
+
+ // ----- Logging -----
+ /**
+ * lombok configuration: {@code lombok.log.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of any of the log annotations in {@code lombok.extern}{@code @Slf4j} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_ANY_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.flagUsage", "Emit a warning or error if any of the log annotations is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.apacheCommons.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @CommonsLog} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_COMMONS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.apacheCommons.flagUsage", "Emit a warning or error if @CommonsLog is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.javaUtilLogging.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Log} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_JUL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.javaUtilLogging.flagUsage", "Emit a warning or error if @Log is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.log4j.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Log4j} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_LOG4J_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.log4j.flagUsage", "Emit a warning or error if @Log4j is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.log4j2.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Log4j2} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_LOG4J2_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.log4j2.flagUsage", "Emit a warning or error if @Log4j2 is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.slf4j.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Slf4j} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_SLF4J_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.slf4j.flagUsage", "Emit a warning or error if @Slf4j is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.xslf4j.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @XSlf4j} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> LOG_XSLF4J_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.xslf4j.flagUsage", "Emit a warning or error if @XSlf4j is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.fieldName} = "aJavaIdentifier".
+ *
+ * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name.
+ */
+ public static final ConfigurationKey<String> LOG_ANY_FIELD_NAME = new ConfigurationKey<String>("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log')") {};
+
+ /**
+ * lombok configuration: {@code lombok.log.fieldIsStatic} = {@code true} | {@code false}.
+ *
+ * If not set, or set to {@code true}, the log field generated by the various log annotations will be {@code static}.
+ *
+ * If set to {@code false}, these will be generated as instance fields instead.
+ */
+ public static final ConfigurationKey<Boolean> LOG_ANY_FIELD_IS_STATIC = new ConfigurationKey<Boolean>("lombok.log.fieldIsStatic", "Make the generated logger fields static (default: true).") {};
+
+ // ##### Experimental #####
+
+ /**
+ * lombok configuration: {@code lombok.experimental.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of any experimental features (from package {@code lombok.experimental}) that haven't been
+ * promoted to a main feature results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> EXPERIMENTAL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.experimental.flagUsage", "Emit a warning or error if an experimental feature is used.") {};
+
+ // ----- Accessors -----
+
+ /**
+ * lombok configuration: {@code lombok.Accessors.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Accessors} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> ACCESSORS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Accessors.flagUsage", "Emit a warning or error if @Accessors is used.") {};
+
+ /**
+ * lombok configuration: {@code lombok.Accessors.prefix} += &lt;String: prefix&gt;.
+ *
+ * For any class without an {@code @Accessors} that explicitly defines the {@code prefix} option, this list of prefixes is used.
+ */
+ public static final ConfigurationKey<List<String>> ACCESSORS_PREFIX = new ConfigurationKey<List<String>>("lombok.Accessors.prefix", "Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters.") {};
+
+ /**
+ * lombok configuration: {@code lombok.Accessors.chain} = {@code true} | {@code false}.
+ *
+ * For any class without an {@code @Accessors} that explicitly defines the {@code chain} option, this value is used.
+ */
+ public static final ConfigurationKey<Boolean> ACCESSORS_CHAIN = new ConfigurationKey<Boolean>("lombok.Accessors.chain", "Generate setters that return 'this' instead of 'void'.") {};
+
+ /**
+ * lombok configuration: {@code lombok.Accessors.fluent} = {@code true} | {@code false}.
+ *
+ * For any class without an {@code @Accessors} that explicitly defines the {@code fluent} option, this value is used.
+ */
+ public static final ConfigurationKey<Boolean> ACCESSORS_FLUENT = new ConfigurationKey<Boolean>("lombok.Accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix).") {};
+
+ // ----- Builder -----
+
+ /**
+ * lombok configuration: {@code lombok.Builder.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Builder} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> BUILDER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Builder.flagUsage", "Emit a warning or error if @Builder is used.") {};
+
+ // ----- ExtensionMethod -----
+
+ /**
+ * lombok configuration: {@code lombok.ExtensionMethod.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @ExtensionMethod} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> EXTENSION_METHOD_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.ExtensionMethod.flagUsage", "Emit a warning or error if @ExtensionMethod is used.") {};
+
+ // ----- FieldDefaults -----
+
+ /**
+ * lombok configuration: {@code lombok.FieldDefaults.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @FieldDefaults} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> FIELD_DEFAULTS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.FieldDefaults.flagUsage", "Emit a warning or error if @FieldDefaults is used.") {};
+
+ // ----- Wither -----
+
+ /**
+ * lombok configuration: {@code lombok.Wither.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @Value} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> WITHER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.Wither.flagUsage", "Emit a warning or error if @Wither is used.") {};
+
+
+ // ----- Configuration System -----
+
+ /**
+ * lombok configuration: {@code stop-bubbling} = {@code true} | {@code false}.
+ *
+ * If not set, or set to {@code false}, the configuration system will look for {@code lombok.config} files in the parent directory.
+ *
+ * If set to {@code true}, no futher {@code lombok.config} files will be checked.
+ */
+ public static final ConfigurationKey<Boolean> STOP_BUBBLING = new ConfigurationKey<Boolean>("stop-bubbling", "Tell the configuration system it should stop looking for other configuration files (default: false).") {};
+}
diff --git a/src/core/lombok/Delegate.java b/src/core/lombok/Delegate.java
index b599e4f0..534cfb3d 100644
--- a/src/core/lombok/Delegate.java
+++ b/src/core/lombok/Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-2013 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
diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java
index 8b809c4b..60ed9e7a 100644
--- a/src/core/lombok/EqualsAndHashCode.java
+++ b/src/core/lombok/EqualsAndHashCode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
diff --git a/src/core/lombok/NonNull.java b/src/core/lombok/NonNull.java
index 96813170..58538583 100644
--- a/src/core/lombok/NonNull.java
+++ b/src/core/lombok/NonNull.java
@@ -44,4 +44,5 @@ import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.CLASS)
@Documented
-public @interface NonNull {}
+public @interface NonNull {
+}
diff --git a/src/core/lombok/SneakyThrows.java b/src/core/lombok/SneakyThrows.java
index 4bd79065..929b4578 100644
--- a/src/core/lombok/SneakyThrows.java
+++ b/src/core/lombok/SneakyThrows.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
diff --git a/src/core/lombok/Synchronized.java b/src/core/lombok/Synchronized.java
index fadea89a..c5601a0c 100644
--- a/src/core/lombok/Synchronized.java
+++ b/src/core/lombok/Synchronized.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
diff --git a/src/core/lombok/ToString.java b/src/core/lombok/ToString.java
index e39b9858..e87c71e7 100644
--- a/src/core/lombok/ToString.java
+++ b/src/core/lombok/ToString.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java
index 6fed0252..50eeb399 100644
--- a/src/core/lombok/core/AST.java
+++ b/src/core/lombok/core/AST.java
@@ -28,6 +28,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -35,6 +36,8 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import lombok.core.configuration.ConfigurationKey;
+
/**
* Lombok wraps the AST produced by a target platform into its own AST system, mostly because both Eclipse and javac
* do not allow upward traversal (from a method to its owning type, for example).
@@ -64,6 +67,13 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
this.imports = imports;
}
+ /**
+ * Attempts to find the absolute path (in URI form) to the source file represented by this AST.
+ *
+ * May return {@code null} if this cannot be done. We don't yet know under which conditions this will happen.
+ */
+ public abstract URI getAbsoluteFileLocation();
+
public void setChanged() {
this.changed = true;
}
@@ -407,4 +417,8 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
buildWithCollection(nodeType, v, list, dim-1);
}
}
+
+ public final <T> T readConfiguration(ConfigurationKey<T> key) {
+ return LombokConfiguration.read(key, this);
+ }
}
diff --git a/src/core/lombok/core/FlagUsageType.java b/src/core/lombok/core/FlagUsageType.java
new file mode 100644
index 00000000..42770ef1
--- /dev/null
+++ b/src/core/lombok/core/FlagUsageType.java
@@ -0,0 +1,6 @@
+package lombok.core;
+
+/** Used for lombok configuration to flag usages of certain lombok feature. */
+public enum FlagUsageType {
+ WARNING, ERROR;
+}
diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java
new file mode 100644
index 00000000..137a8a83
--- /dev/null
+++ b/src/core/lombok/core/LombokConfiguration.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013-2014 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;
+
+import lombok.core.configuration.BubblingConfigurationResolver;
+import lombok.core.configuration.ConfigurationKey;
+import lombok.core.configuration.ConfigurationProblemReporter;
+import lombok.core.configuration.ConfigurationResolver;
+import lombok.core.configuration.ConfigurationResolverFactory;
+import lombok.core.configuration.FileSystemSourceCache;
+
+public class LombokConfiguration {
+ private static FileSystemSourceCache cache = new FileSystemSourceCache();
+ private static ConfigurationResolverFactory configurationResolverFactory = createFileSystemBubblingResolverFactory();
+
+ private LombokConfiguration() {
+ // prevent instantiation
+ }
+
+ public static void overrideConfigurationResolverFactory(ConfigurationResolverFactory crf) {
+ configurationResolverFactory = crf == null ? createFileSystemBubblingResolverFactory() : crf;
+ }
+
+ static <T> T read(ConfigurationKey<T> key, AST<?, ?, ?> ast) {
+ return configurationResolverFactory.createResolver(ast).resolve(key);
+ }
+
+ private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() {
+ return new ConfigurationResolverFactory() {
+ @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) {
+ return new BubblingConfigurationResolver(cache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), ConfigurationProblemReporter.CONSOLE));
+ }
+ };
+ }
+}
diff --git a/src/core/lombok/core/TransformationsUtil.java b/src/core/lombok/core/TransformationsUtil.java
deleted file mode 100644
index 8c7fbd3f..00000000
--- a/src/core/lombok/core/TransformationsUtil.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2009-2012 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;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.RequiredArgsConstructor;
-import lombok.Setter;
-import lombok.ToString;
-import lombok.Value;
-import lombok.experimental.Accessors;
-import lombok.experimental.FieldDefaults;
-import lombok.experimental.Wither;
-
-/**
- * Container for static utility methods useful for some of the standard lombok transformations, regardless of
- * target platform (e.g. useful for both javac and Eclipse lombok implementations).
- */
-public class TransformationsUtil {
- private TransformationsUtil() {
- //Prevent instantiation
- }
-
- @SuppressWarnings({"all", "unchecked", "deprecation"})
- public static final List<Class<? extends java.lang.annotation.Annotation>> INVALID_ON_BUILDERS = Collections.unmodifiableList(
- Arrays.<Class<? extends java.lang.annotation.Annotation>>asList(
- Getter.class, Setter.class, Wither.class, ToString.class, EqualsAndHashCode.class,
- RequiredArgsConstructor.class, AllArgsConstructor.class, NoArgsConstructor.class,
- Data.class, Value.class, lombok.experimental.Value.class, FieldDefaults.class));
-
- /**
- * Given the name of a field, return the 'base name' of that field. For example, {@code fFoobar} becomes {@code foobar} if {@code f} is in the prefix list.
- * For prefixes that end in a letter character, the next character must be a non-lowercase character (i.e. {@code hashCode} is not {@code ashCode} even if
- * {@code h} is in the prefix list, but {@code hAshcode} would become {@code ashCode}). The first prefix that matches is used. If the prefix list is empty,
- * or the empty string is in the prefix list and no prefix before it matches, the fieldName will be returned verbatim.
- *
- * If no prefix matches and the empty string is not in the prefix list and the prefix list is not empty, {@code null} is returned.
- *
- * @param fieldName The full name of a field.
- * @param prefixes A list of prefixes, usually provided by the {@code Accessors} settings annotation, listing field prefixes.
- * @return The base name of the field.
- */
- public static CharSequence removePrefix(CharSequence fieldName, String[] prefixes) {
- if (prefixes == null || prefixes.length == 0) return fieldName;
-
- fieldName = fieldName.toString();
-
- outer:
- for (String prefix : prefixes) {
- if (prefix.length() == 0) return fieldName;
- if (fieldName.length() <= prefix.length()) continue outer;
- for (int i = 0; i < prefix.length(); i++) {
- if (fieldName.charAt(i) != prefix.charAt(i)) continue outer;
- }
- char followupChar = fieldName.charAt(prefix.length());
- // if prefix is a letter then follow up letter needs to not be lowercase, i.e. 'foo' is not a match
- // as field named 'oo' with prefix 'f', but 'fOo' would be.
- if (Character.isLetter(prefix.charAt(prefix.length() - 1)) &&
- Character.isLowerCase(followupChar)) continue outer;
- return "" + Character.toLowerCase(followupChar) + fieldName.subSequence(prefix.length() + 1, fieldName.length());
- }
-
- return null;
- }
-
- /* NB: 'notnull' is not part of the pattern because there are lots of @NotNull annotations out there that are crappily named and actually mean
- something else, such as 'this field must not be null _when saved to the db_ but its perfectly okay to start out as such, and a no-args
- constructor and the implied starts-out-as-null state that goes with it is in fact mandatory' which happens with javax.validation.constraints.NotNull.
- Various problems with spring have also been reported. See issue #287, issue #271, and issue #43. */
-
- /** Matches the simple part of any annotation that lombok considers as indicative of NonNull status. */
- public static final Pattern NON_NULL_PATTERN = Pattern.compile("^(?:nonnull)$", Pattern.CASE_INSENSITIVE);
-
- /** Matches the simple part of any annotation that lombok considers as indicative of Nullable status. */
- public static final Pattern NULLABLE_PATTERN = Pattern.compile("^(?:nullable|checkfornull)$", Pattern.CASE_INSENSITIVE);
-
- /**
- * Generates a getter name from a given field name.
- *
- * Strategy:
- * <ul>
- * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
- * the prefix list, this method immediately returns {@code null}.</li>
- * <li>If {@code Accessors} has {@code fluent=true}, then return the basename.</li>
- * <li>Pick a prefix. 'get' normally, but 'is' if {@code isBoolean} is true.</li>
- * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character. If so, return the field name verbatim.</li>
- * <li>Check if the first character of the field is lowercase. If so, check if the second character
- * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
- * <li>Return the prefix plus the possibly title/uppercased first character, and the rest of the field name.</li>
- * </ul>
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
- * @return The getter name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
- */
- public static String toGetterName(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAccessorName(accessors, fieldName, isBoolean, "is", "get", true);
- }
-
- /**
- * Generates a setter name from a given field name.
- *
- * Strategy:
- * <ul>
- * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
- * the prefix list, this method immediately returns {@code null}.</li>
- * <li>If {@code Accessors} has {@code fluent=true}, then return the basename.</li>
- * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character.
- * If so, replace {@code is} with {@code set} and return that.</li>
- * <li>Check if the first character of the field is lowercase. If so, check if the second character
- * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
- * <li>Return {@code "set"} plus the possibly title/uppercased first character, and the rest of the field name.</li>
- * </ul>
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
- * @return The setter name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
- */
- public static String toSetterName(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAccessorName(accessors, fieldName, isBoolean, "set", "set", true);
- }
-
- /**
- * Generates a wither name from a given field name.
- *
- * Strategy:
- * <ul>
- * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
- * the prefix list, this method immediately returns {@code null}.</li>
- * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character.
- * If so, replace {@code is} with {@code with} and return that.</li>
- * <li>Check if the first character of the field is lowercase. If so, check if the second character
- * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
- * <li>Return {@code "with"} plus the possibly title/uppercased first character, and the rest of the field name.</li>
- * </ul>
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
- * @return The wither name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
- */
- public static String toWitherName(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAccessorName(accessors, fieldName, isBoolean, "with", "with", false);
- }
-
- private static String toAccessorName(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean,
- String booleanPrefix, String normalPrefix, boolean adhereToFluent) {
-
- fieldName = fieldName.toString();
- if (fieldName.length() == 0) return null;
-
- Accessors ac = accessors == null ? null : accessors.getInstance();
- fieldName = removePrefix(fieldName, ac == null ? new String[0] : ac.prefix());
- if (fieldName == null) return null;
-
- String fName = fieldName.toString();
- if (adhereToFluent && ac != null && ac.fluent()) return fName;
-
- if (isBoolean && fName.startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) {
- // The field is for example named 'isRunning'.
- return booleanPrefix + fName.substring(2);
- }
-
- return buildName(isBoolean ? booleanPrefix : normalPrefix, fName);
- }
-
- /**
- * Returns all names of methods that would represent the getter for a field with the provided name.
- *
- * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
- * {@code [isRunning, getRunning, isIsRunning, getIsRunning]}
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
- */
- public static List<String> toAllGetterNames(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAllAccessorNames(accessors, fieldName, isBoolean, "is", "get", true);
- }
-
- /**
- * Returns all names of methods that would represent the setter for a field with the provided name.
- *
- * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
- * {@code [setRunning, setIsRunning]}
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
- */
- public static List<String> toAllSetterNames(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAllAccessorNames(accessors, fieldName, isBoolean, "set", "set", true);
- }
-
- /**
- * Returns all names of methods that would represent the wither for a field with the provided name.
- *
- * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
- * {@code [withRunning, withIsRunning]}
- *
- * @param accessors Accessors configuration.
- * @param fieldName the name of the field.
- * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
- */
- public static List<String> toAllWitherNames(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
- return toAllAccessorNames(accessors, fieldName, isBoolean, "with", "with", false);
- }
-
- private static List<String> toAllAccessorNames(AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean,
- String booleanPrefix, String normalPrefix, boolean adhereToFluent) {
-
- if (!isBoolean) {
- String accessorName = toAccessorName(accessors, fieldName, false, booleanPrefix, normalPrefix, adhereToFluent);
- return (accessorName == null) ? Collections.<String>emptyList() : Collections.singletonList(accessorName);
- }
-
- Accessors acc = accessors.getInstance();
- fieldName = removePrefix(fieldName, acc.prefix());
- if (fieldName == null) return Collections.emptyList();
-
- List<String> baseNames = toBaseNames(fieldName, isBoolean, acc.fluent());
-
- Set<String> names = new HashSet<String>();
- for (String baseName : baseNames) {
- if (adhereToFluent && acc.fluent()) {
- names.add(baseName);
- } else {
- names.add(buildName(normalPrefix, baseName));
- if (!normalPrefix.equals(booleanPrefix)) names.add(buildName(booleanPrefix, baseName));
- }
- }
-
- return new ArrayList<String>(names);
-
- }
-
- private static List<String> toBaseNames(CharSequence fieldName, boolean isBoolean, boolean fluent) {
- List<String> baseNames = new ArrayList<String>();
- baseNames.add(fieldName.toString());
-
- // isPrefix = field is called something like 'isRunning', so 'running' could also be the fieldname.
- String fName = fieldName.toString();
- if (fName.startsWith("is") && fName.length() > 2 && !Character.isLowerCase(fName.charAt(2))) {
- String baseName = fName.substring(2);
- if (fluent) {
- baseNames.add("" + Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1));
- } else {
- baseNames.add(baseName);
- }
- }
-
- return baseNames;
- }
-
- /**
- * @param prefix Something like {@code get} or {@code set} or {@code is}.
- * @param suffix Something like {@code running}.
- * @return prefix + smartly title-cased suffix. For example, {@code setRunning}.
- */
- private static String buildName(String prefix, String suffix) {
- if (suffix.length() == 0) return prefix;
- if (prefix.length() == 0) return suffix;
-
- char first = suffix.charAt(0);
- if (Character.isLowerCase(first)) {
- boolean useUpperCase = suffix.length() > 2 &&
- (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1)));
- suffix = String.format("%s%s",
- useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first),
- suffix.subSequence(1, suffix.length()));
- }
- return String.format("%s%s", prefix, suffix);
- }
-}
diff --git a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java
new file mode 100644
index 00000000..f96b4468
--- /dev/null
+++ b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import lombok.core.configuration.ConfigurationSource.ListModification;
+import lombok.core.configuration.ConfigurationSource.Result;
+
+public class BubblingConfigurationResolver implements ConfigurationResolver {
+
+ private final Iterable<ConfigurationSource> sources;
+
+ public BubblingConfigurationResolver(Iterable<ConfigurationSource> sources) {
+ this.sources = sources;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T resolve(ConfigurationKey<T> key) {
+ boolean isList = key.getType().isList();
+ List<List<ListModification>> listModificationsList = null;
+ for (ConfigurationSource source : sources) {
+ Result result = source.resolve(key);
+ if (result == null) continue;
+ if (isList) {
+ if (listModificationsList == null) {
+ listModificationsList = new ArrayList<List<ListModification>>();
+ }
+ listModificationsList.add((List<ListModification>)result.getValue());
+ }
+ if (result.isAuthoritative()) {
+ if (isList) {
+ break;
+ }
+ return (T) result.getValue();
+ }
+ }
+ if (!isList) {
+ return null;
+ }
+ if (listModificationsList == null) {
+ return (T) Collections.emptyList();
+ }
+ List<Object> listValues = new ArrayList<Object>();
+ Collections.reverse(listModificationsList);
+ for (List<ListModification> listModifications : listModificationsList) {
+ if (listModifications != null) for (ListModification modification : listModifications) {
+ listValues.remove(modification.getValue());
+ if (modification.isAdded()) {
+ listValues.add(modification.getValue());
+ }
+ }
+ }
+ return (T) listValues;
+ }
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java
new file mode 100644
index 00000000..e441b4de
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationApp.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import static lombok.core.configuration.FileSystemSourceCache.fileToString;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import lombok.ConfigurationKeys;
+import lombok.core.LombokApp;
+import lombok.core.configuration.ConfigurationParser.Collector;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.zwitserloot.cmdreader.CmdReader;
+import com.zwitserloot.cmdreader.Description;
+import com.zwitserloot.cmdreader.Excludes;
+import com.zwitserloot.cmdreader.InvalidCommandLineException;
+import com.zwitserloot.cmdreader.Mandatory;
+import com.zwitserloot.cmdreader.Sequential;
+import com.zwitserloot.cmdreader.Shorthand;
+
+@ProviderFor(LombokApp.class)
+public class ConfigurationApp extends LombokApp {
+ private static final URI NO_CONFIG = URI.create("");
+
+ private PrintStream out = System.out;
+ private PrintStream err = System.err;
+
+ @Override public String getAppName() {
+ return "config";
+ }
+
+ @Override public String getAppDescription() {
+ return "Prints the configurations for the provided paths to standard out.";
+ }
+
+ @Override public List<String> getAppAliases() {
+ return Arrays.asList("configuration", "config", "conf", "settings");
+ }
+
+ public static class CmdArgs {
+ @Sequential
+ @Mandatory(onlyIfNot={"help", "generate"})
+ @Description("Paths to java files or directories the configuration is to be printed for.")
+ private List<String> paths = new ArrayList<String>();
+
+ @Shorthand("g")
+ @Excludes("paths")
+ @Description("Generates a list containing all the available configuration parameters. Add --verbose to print more information.")
+ boolean generate = false;
+
+ @Shorthand("v")
+ @Description("Displays more information.")
+ boolean verbose = false;
+
+ @Shorthand("k")
+ @Description("Limit the result to these keys.")
+ private List<String> key = new ArrayList<String>();
+
+ @Shorthand({"h", "?"})
+ @Description("Shows this help text.")
+ boolean help = false;
+ }
+
+ @Override public int runApp(List<String> raw) throws Exception {
+ CmdReader<CmdArgs> reader = CmdReader.of(CmdArgs.class);
+ CmdArgs args;
+ try {
+ args = reader.make(raw.toArray(new String[0]));
+ if (args.help) {
+ out.println(reader.generateCommandLineHelp("java -jar lombok.jar configuration"));
+ return 0;
+ }
+ } catch (InvalidCommandLineException e) {
+ err.println(e.getMessage());
+ err.println(reader.generateCommandLineHelp("java -jar lombok.jar configuration"));
+ return 1;
+ }
+
+ ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys();
+ Collection<ConfigurationKey<?>> keys = checkKeys(args.key);
+ if (keys == null) return 1;
+
+ boolean verbose = args.verbose;
+ if (args.generate) {
+ return generate(keys, verbose);
+ }
+
+ return display(keys, verbose, args.paths, !args.key.isEmpty());
+ }
+
+ public ConfigurationApp redirectOutput(PrintStream out, PrintStream err) {
+ if (out != null) this.out = out;
+ if (err != null) this.err = err;
+ return this;
+ }
+
+ public int generate(Collection<ConfigurationKey<?>> keys, boolean verbose) {
+ for (ConfigurationKey<?> key : keys) {
+ String keyName = key.getKeyName();
+ ConfigurationDataType type = key.getType();
+ String description = key.getDescription();
+ boolean hasDescription = description != null && !description.isEmpty();
+ if (!verbose) {
+ out.println(keyName);
+ if (hasDescription) {
+ out.print(" ");
+ out.println(description);
+ }
+ out.println();
+ continue;
+ }
+ out.printf("##%n## Key : %s%n## Type: %s%n", keyName, type);
+ if (hasDescription) {
+ out.printf("##%n## %s%n", description);
+ }
+ out.printf("##%n## Examples:%n#%n");
+ out.printf("# clear %s%n", keyName);
+ String exampleValue = type.getParser().exampleValue();
+ if (type.isList()) {
+ out.printf("# %s += %s%n", keyName, exampleValue);
+ out.printf("# %s -= %s%n", keyName, exampleValue);
+ } else {
+ out.printf("# %s = %s%n", keyName, exampleValue);
+ }
+ out.printf("#%n%n");
+ }
+ if (!verbose) {
+ out.println("Use --verbose for more information.");
+ }
+ return 0;
+ }
+
+ public int display(Collection<ConfigurationKey<?>> keys, boolean verbose, Collection<String> argsPaths, boolean explicitKeys) throws Exception {
+ TreeMap<URI, Set<String>> sharedDirectories = findSharedDirectories(argsPaths);
+
+ if (sharedDirectories == null) return 1;
+
+ Set<String> none = sharedDirectories.remove(NO_CONFIG);
+ if (none != null) {
+ if (none.size() == 1) {
+ out.printf("No 'lombok.config' found for '%s'.%n", none.iterator().next());
+ } else {
+ out.println("No 'lombok.config' found for: ");
+ for (String path : none) out.printf("- %s%n", path);
+ }
+ }
+
+ final List<String> problems = new ArrayList<String>();
+ ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() {
+ @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {
+ problems.add(String.format("%s: %s (%s:%d)", problem, line, sourceDescription, lineNumber));
+ }
+ };
+
+ FileSystemSourceCache cache = new FileSystemSourceCache();
+ boolean first = true;
+ for (Entry<URI, Set<String>> entry : sharedDirectories.entrySet()) {
+ if (!first) {
+ out.printf("%n%n");
+ }
+ Set<String> paths = entry.getValue();
+ if (paths.size() == 1) {
+ if (!(argsPaths.size() == 1)) out.printf("Configuration for '%s'.%n%n", paths.iterator().next());
+ } else {
+ out.printf("Configuration for:%n", paths.iterator().next());
+ for (String path : paths) out.printf("- %s%n", path);
+ out.println();
+ }
+ URI directory = entry.getKey();
+ ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, reporter));
+ Map<ConfigurationKey<?>, ? extends Collection<String>> traces = trace(keys, directory);
+ boolean printed = false;
+ for (ConfigurationKey<?> key : keys) {
+ Object value = resolver.resolve(key);
+ Collection<String> modifications = traces.get(key);
+ if (!modifications.isEmpty() || explicitKeys) {
+ if (printed && verbose) out.println();
+ printValue(key, value, verbose, modifications);
+ printed = true;
+ }
+ }
+ if (!printed) out.println("<default>");
+ first = false;
+ }
+
+ if (!problems.isEmpty()) {
+ out.printf("%nProblems in the configuration files: %n");
+ for (String problem : problems) out.printf("- %s%n", problem);
+ }
+
+ return 0;
+ }
+
+ private void printValue(ConfigurationKey<?> key, Object value, boolean verbose, Collection<String> history) {
+ if (verbose) out.printf("# %s%n", key.getDescription());
+ if (value == null) {
+ out.printf("clear %s%n", key.getKeyName());
+ } else if (value instanceof List<?>) {
+ List<?> list = (List<?>)value;
+ if (list.isEmpty()) out.printf("clear %s%n", key.getKeyName());
+ for (Object element : list) out.printf("%s += %s%n", key.getKeyName(), element);
+ } else {
+ out.printf("%s = %s%n", key.getKeyName(), value);
+ }
+ if (!verbose) return;
+ for (String modification : history) out.printf("# %s%n", modification);
+ }
+
+ private static final ConfigurationProblemReporter VOID = new ConfigurationProblemReporter() {
+ @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {}
+ };
+
+ private Map<ConfigurationKey<?>, ? extends Collection<String>> trace(Collection<ConfigurationKey<?>> keys, URI directory) throws Exception {
+ Map<ConfigurationKey<?>, List<String>> result = new HashMap<ConfigurationKey<?>, List<String>>();
+ for (ConfigurationKey<?> key : keys) result.put(key, new ArrayList<String>());
+ Set<ConfigurationKey<?>> used = new HashSet<ConfigurationKey<?>>();
+
+ boolean stopBubbling = false;
+ String previousFileName = null;
+ for (File currentDirectory = new File(directory); currentDirectory != null && !stopBubbling; currentDirectory = currentDirectory.getParentFile()) {
+ File configFile = new File(currentDirectory, "lombok.config");
+ if (!configFile.exists() || !configFile.isFile()) continue;
+
+ Map<ConfigurationKey<?>, List<String>> traces = trace(fileToString(configFile), configFile.getAbsolutePath(), keys);
+
+ stopBubbling = stopBubbling(traces.get(ConfigurationKeys.STOP_BUBBLING));
+ for (ConfigurationKey<?> key : keys) {
+ List<String> modifications = traces.get(key);
+ if (modifications == null) {
+ modifications = new ArrayList<String>();
+ modifications.add(" <'" + key.getKeyName() + "' not mentioned>");
+ } else {
+ used.add(key);
+ }
+ if (previousFileName != null) {
+ modifications.add("");
+ modifications.add(previousFileName + ":");
+ }
+ result.get(key).addAll(0, modifications);
+ }
+ previousFileName = configFile.getAbsolutePath();
+ }
+ for (ConfigurationKey<?> key : keys) {
+ if (used.contains(key)) {
+ result.get(key).add(0, previousFileName + (stopBubbling ? " (stopped bubbling):" : ":"));
+ } else {
+ result.put(key, Collections.<String>emptyList());
+ }
+ }
+ return result;
+ }
+
+ private Map<ConfigurationKey<?>, List<String>> trace(String content, String contentDescription, final Collection<ConfigurationKey<?>> keys) {
+ final Map<ConfigurationKey<?>, List<String>> result = new HashMap<ConfigurationKey<?>, List<String>>();
+
+ Collector collector = new Collector() {
+ @Override public void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber) {
+ trace(key, "clear " + key.getKeyName(), lineNumber);
+ }
+
+ @Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ trace(key, key.getKeyName() + " = " + value, lineNumber);
+ }
+
+ @Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ trace(key, key.getKeyName() + " += " + value, lineNumber);
+ }
+
+ @Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ trace(key, key.getKeyName() + " -= " + value, lineNumber);
+ }
+
+ private void trace(ConfigurationKey<?> key, String message, int lineNumber) {
+ if (!keys.contains(key)) return;
+ List<String> traces = result.get(key);
+ if (traces == null) {
+ traces = new ArrayList<String>();
+ result.put(key, traces);
+ }
+ traces.add(String.format("%4d: %s", lineNumber, message));
+ }
+ };
+ new ConfigurationParser(VOID).parse(content, contentDescription, collector);
+ return result;
+ }
+
+ private boolean stopBubbling(List<String> stops) {
+ return stops != null && !stops.isEmpty() && stops.get(stops.size() -1).endsWith("true");
+ }
+
+ private Collection<ConfigurationKey<?>> checkKeys(List<String> keyList) {
+ Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys();
+ if (keyList.isEmpty()) return registeredKeys.values();
+
+ Collection<ConfigurationKey<?>> keys = new ArrayList<ConfigurationKey<?>>();
+ for (String keyName : keyList) {
+ ConfigurationKey<?> key = registeredKeys.get(keyName);
+ if (key == null) {
+ err.printf("Unknown key '%s'%n", keyName);
+ return null;
+ }
+ keys.remove(key);
+ keys.add(key);
+ }
+ return keys;
+ }
+
+ private TreeMap<URI, Set<String>> findSharedDirectories(Collection<String> paths) {
+ TreeMap<URI,Set<String>> sharedDirectories = new TreeMap<URI, Set<String>>(new Comparator<URI>() {
+ @Override public int compare(URI o1, URI o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ });
+ for (String path : paths) {
+ File file = new File(path);
+ if (!file.exists()) {
+ err.printf("File not found: '%s'%n", path);
+ return null;
+ }
+ URI first = findFirstLombokDirectory(file);
+ Set<String> sharedBy = sharedDirectories.get(first);
+ if (sharedBy == null) {
+ sharedBy = new TreeSet<String>();
+ sharedDirectories.put(first, sharedBy);
+ }
+ sharedBy.add(path);
+ }
+ return sharedDirectories;
+ }
+
+ private URI findFirstLombokDirectory(File file) {
+ File current = new File(file.toURI().normalize());
+ if (file.isFile()) current = current.getParentFile();
+ while (current != null) {
+ if (new File(current, "lombok.config").exists()) return current.toURI();
+ current = current.getParentFile();
+ }
+ return NO_CONFIG;
+ }
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationDataType.java b/src/core/lombok/core/configuration/ConfigurationDataType.java
new file mode 100644
index 00000000..ca0302ff
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationDataType.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public final class ConfigurationDataType {
+ private static final Map<Class<?>, ConfigurationValueParser> SIMPLE_TYPES;
+ static {
+ Map<Class<?>, ConfigurationValueParser> map = new HashMap<Class<?>, ConfigurationValueParser>();
+ map.put(String.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return value;
+ }
+ @Override public String description() {
+ return "string";
+ }
+ @Override public String exampleValue() {
+ return "<text>";
+ }
+ });
+ map.put(Integer.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return Integer.parseInt(value);
+ }
+ @Override public String description() {
+ return "int";
+ }
+ @Override public String exampleValue() {
+ return "<int>";
+ }
+ });
+ map.put(Long.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return Long.parseLong(value);
+ }
+ @Override public String description() {
+ return "long";
+ }
+ @Override public String exampleValue() {
+ return "<long>";
+ }
+ });
+ map.put(Double.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return Double.parseDouble(value);
+ }
+ @Override public String description() {
+ return "double";
+ }
+ @Override public String exampleValue() {
+ return "<double>";
+ }
+ });
+ map.put(Boolean.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return Boolean.parseBoolean(value);
+ }
+ @Override public String description() {
+ return "boolean";
+ }
+ @Override public String exampleValue() {
+ return "[false | true]";
+ }
+ });
+ map.put(TypeName.class, new ConfigurationValueParser() {
+ @Override public Object parse(String value) {
+ return TypeName.valueOf(value);
+ }
+ @Override public String description() {
+ return "type-name";
+ }
+ @Override public String exampleValue() {
+ return "<fully.qualified.Type>";
+ }
+ });
+ SIMPLE_TYPES = map;
+ }
+
+ private static ConfigurationValueParser enumParser(Object enumType) {
+ @SuppressWarnings("rawtypes") final Class rawType = (Class)enumType;
+ return new ConfigurationValueParser(){
+ @SuppressWarnings("unchecked")
+ @Override public Object parse(String value) {
+ try {
+ return Enum.valueOf(rawType, value);
+ } catch (Exception e) {
+ return Enum.valueOf(rawType, value.toUpperCase());
+ }
+ }
+ @Override public String description() {
+ return "enum (" + rawType.getName() + ")";
+ }
+ @Override public String exampleValue() {
+ return Arrays.toString(rawType.getEnumConstants()).replace(",", " |");
+ }
+ };
+ }
+
+ private final boolean isList;
+ private final ConfigurationValueParser parser;
+
+ public static ConfigurationDataType toDataType(Class<? extends ConfigurationKey<?>> keyClass) {
+ if (keyClass.getSuperclass() != ConfigurationKey.class) {
+ throw new IllegalArgumentException("No direct subclass of ConfigurationKey: " + keyClass.getName());
+ }
+
+ Type type = keyClass.getGenericSuperclass();
+ if (!(type instanceof ParameterizedType)) {
+ throw new IllegalArgumentException("Missing type parameter in "+ type);
+ }
+
+ ParameterizedType parameterized = (ParameterizedType) type;
+ Type argumentType = parameterized.getActualTypeArguments()[0];
+
+ boolean isList = false;
+ if (argumentType instanceof ParameterizedType) {
+ ParameterizedType parameterizedArgument = (ParameterizedType) argumentType;
+ if (parameterizedArgument.getRawType() == List.class) {
+ isList = true;
+ argumentType = parameterizedArgument.getActualTypeArguments()[0];
+ }
+ }
+
+ if (SIMPLE_TYPES.containsKey(argumentType)) {
+ return new ConfigurationDataType(isList, SIMPLE_TYPES.get(argumentType));
+ }
+
+ if (isEnum(argumentType)) {
+ return new ConfigurationDataType(isList, enumParser(argumentType));
+ }
+
+ throw new IllegalArgumentException("Unsupported type parameter in " + type);
+ }
+
+ private ConfigurationDataType(boolean isList, ConfigurationValueParser parser) {
+ this.isList = isList;
+ this.parser = parser;
+ }
+
+ boolean isList() {
+ return isList;
+ }
+
+ ConfigurationValueParser getParser() {
+ return parser;
+ }
+
+ @Override
+ public String toString() {
+ if (isList) return "list of " + parser.description();
+ return parser.description();
+ }
+
+ private static boolean isEnum(Type argumentType) {
+ return argumentType instanceof Class && ((Class<?>) argumentType).isEnum();
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/core/configuration/ConfigurationKey.java b/src/core/lombok/core/configuration/ConfigurationKey.java
new file mode 100644
index 00000000..d46a70b0
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationKey.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013-2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+/**
+ * Describes a configuration key and its type.
+ * <p>
+ * The recommended usage is to create a type token:
+ * <pre>
+ * private static ConfigurationKey&lt;String> KEY = new ConfigurationKey&lt;String>("keyName", "description") {};
+ * </pre>
+ */
+public abstract class ConfigurationKey<T> {
+ private static final Pattern VALID_NAMES = Pattern.compile("[-_a-zA-Z][-.\\w]*(?<![-.])");
+
+ private static final TreeMap<String, ConfigurationKey<?>> registeredKeys = new TreeMap<String, ConfigurationKey<?>>(String.CASE_INSENSITIVE_ORDER);
+ private static Map<String, ConfigurationKey<?>> copy;
+
+ private final String keyName;
+ private final String description;
+ private final ConfigurationDataType type;
+
+ public ConfigurationKey(String keyName, String description) {
+ this.keyName = checkName(keyName);
+ @SuppressWarnings("unchecked")
+ ConfigurationDataType type = ConfigurationDataType.toDataType((Class<? extends ConfigurationKey<?>>)getClass());
+ this.type = type;
+ this.description = description;
+ registerKey(keyName, this);
+ }
+
+ public final String getKeyName() {
+ return keyName;
+ }
+
+ public final String getDescription() {
+ return description;
+ }
+
+ public final ConfigurationDataType getType() {
+ return type;
+ }
+
+ @Override public String toString() {
+ return keyName + " (" + type + "): " + description;
+ }
+
+ private static String checkName(String keyName) {
+ if (keyName == null) throw new NullPointerException("keyName");
+ if (!VALID_NAMES.matcher(keyName).matches()) throw new IllegalArgumentException("Invalid keyName: " + keyName);
+ return keyName;
+ }
+
+ /**
+ * Returns a copy of the currently registered keys.
+ */
+ @SuppressWarnings("unchecked")
+ public static Map<String, ConfigurationKey<?>> registeredKeys() {
+ synchronized (registeredKeys) {
+ if (copy == null) copy = Collections.unmodifiableMap((Map<String, ConfigurationKey<?>>) registeredKeys.clone());
+ return copy;
+ }
+ }
+
+ private static void registerKey(String keyName, ConfigurationKey<?> key) {
+ synchronized (registeredKeys) {
+ if (registeredKeys.containsKey(keyName)) throw new IllegalArgumentException("Key '" + keyName + "' already registered");
+ registeredKeys.put(keyName, key);
+ copy = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/core/configuration/ConfigurationKeysLoader.java b/src/core/lombok/core/configuration/ConfigurationKeysLoader.java
new file mode 100644
index 00000000..4e6e4fb1
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationKeysLoader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import lombok.ConfigurationKeys;
+import lombok.core.SpiLoadUtil;
+
+public interface ConfigurationKeysLoader {
+ public class LoaderLoader {
+ private static final AtomicBoolean alreadyLoaded = new AtomicBoolean(false);
+ private LoaderLoader() {}
+
+ public static void loadAllConfigurationKeys() {
+ if (alreadyLoaded.get()) return;
+
+ try {
+ Class.forName(ConfigurationKeys.class.getName());
+ } catch (Throwable ignore) {}
+
+ try {
+ Iterator<ConfigurationKeysLoader> iterator = SpiLoadUtil.findServices(ConfigurationKeysLoader.class, ConfigurationKeysLoader.class.getClassLoader()).iterator();
+ while (iterator.hasNext()) {
+ try {
+ iterator.next();
+ } catch (Exception ignore) {}
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Can't load config keys; services file issue.", e);
+ } finally {
+ alreadyLoaded.set(true);
+ }
+ }
+ }
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationParser.java b/src/core/lombok/core/configuration/ConfigurationParser.java
new file mode 100644
index 00000000..f0a9e142
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationParser.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ConfigurationParser {
+ private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))");
+ private static final Pattern NEWLINE_FINDER = Pattern.compile("^\\s*(.*?)\\s*$", Pattern.MULTILINE);
+
+ private ConfigurationProblemReporter reporter;
+
+ public ConfigurationParser(ConfigurationProblemReporter reporter) {
+ if (reporter == null) throw new NullPointerException("reporter");
+ this.reporter = reporter;
+ }
+
+ public void parse(CharSequence content, String contentDescription, Collector collector) {
+ Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys();
+ int lineNumber = 0;
+ Matcher lineMatcher = NEWLINE_FINDER.matcher(content);
+ while (lineMatcher.find()) {
+ CharSequence line = content.subSequence(lineMatcher.start(1), lineMatcher.end(1));
+ lineNumber++;
+ if (line.length() == 0 || line.charAt(0) == '#') continue;
+
+ Matcher matcher = LINE.matcher(line);
+ if (!matcher.matches()) {
+ reporter.report(contentDescription, "Invalid line", lineNumber, line);
+ continue;
+ }
+
+ String operator = null;
+ String keyName = null;
+ String stringValue;
+ if (matcher.group(1) == null) {
+ keyName = matcher.group(2);
+ operator = matcher.group(3);
+ stringValue = matcher.group(4);
+ } else {
+ keyName = matcher.group(1);
+ operator = "clear";
+ stringValue = null;
+ }
+ ConfigurationKey<?> key = registeredKeys.get(keyName);
+ if (key == null) {
+ reporter.report(contentDescription, "Unknown key '" + keyName + "'", lineNumber, line);
+ continue;
+ }
+
+ ConfigurationDataType type = key.getType();
+ boolean listOperator = operator.equals("+=") || operator.equals("-=");
+ if (listOperator && !type.isList()) {
+ reporter.report(contentDescription, "'" + keyName + "' is not a list and doesn't support " + operator + " (only = and clear)", lineNumber, line);
+ continue;
+ }
+ if (operator.equals("=") && type.isList()) {
+ reporter.report(contentDescription, "'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line);
+ continue;
+ }
+
+ Object value = null;
+ if (stringValue != null) try {
+ value = type.getParser().parse(stringValue);
+ } catch (Exception e) {
+ reporter.report(contentDescription, "Error while parsing the value for '" + keyName + "' value '" + stringValue + "' (should be " + type.getParser().exampleValue() + ")", lineNumber, line);
+ continue;
+ }
+
+ if (operator.equals("clear")) {
+ collector.clear(key, contentDescription, lineNumber);
+ } else if (operator.equals("=")) {
+ collector.set(key, value, contentDescription, lineNumber);
+ } else if (operator.equals("+=")) {
+ collector.add(key, value, contentDescription, lineNumber);
+ } else {
+ collector.remove(key, value, contentDescription, lineNumber);
+ }
+ }
+ }
+
+ public interface Collector {
+ void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber);
+ void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
+ void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
+ void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
+ }
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationProblemReporter.java b/src/core/lombok/core/configuration/ConfigurationProblemReporter.java
new file mode 100644
index 00000000..5dbf99a8
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationProblemReporter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+public interface ConfigurationProblemReporter {
+ void report(String sourceDescription, String problem, int lineNumber, CharSequence line);
+
+ ConfigurationProblemReporter CONSOLE = new ConfigurationProblemReporter() {
+ @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {
+ System.err.printf("%s (%s:%d)\n", problem, sourceDescription, lineNumber);
+ }
+ };
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationResolver.java b/src/core/lombok/core/configuration/ConfigurationResolver.java
new file mode 100644
index 00000000..6f52fc6e
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationResolver.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+public interface ConfigurationResolver {
+ <T> T resolve(ConfigurationKey<T> key);
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationResolverFactory.java b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java
new file mode 100644
index 00000000..83b58c2f
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationResolverFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import lombok.core.AST;
+
+public interface ConfigurationResolverFactory {
+ ConfigurationResolver createResolver(AST<?, ?, ?> ast);
+}
diff --git a/src/core/lombok/core/configuration/ConfigurationSource.java b/src/core/lombok/core/configuration/ConfigurationSource.java
new file mode 100644
index 00000000..4a2b5808
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationSource.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+public interface ConfigurationSource {
+
+ Result resolve(ConfigurationKey<?> key);
+
+ public static final class Result {
+ private final Object value;
+ private final boolean authoritative;
+
+ public Result(Object value, boolean authoritative) {
+ this.value = value;
+ this.authoritative = authoritative;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public boolean isAuthoritative() {
+ return authoritative;
+ }
+
+ @Override public String toString() {
+ return String.valueOf(value) + (authoritative ? " (set)" : " (delta)");
+ }
+ }
+
+ public static class ListModification {
+ private final Object value;
+ private final boolean added;
+
+ public ListModification(Object value, boolean added) {
+ this.value = value;
+ this.added = added;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public boolean isAdded() {
+ return added;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/core/configuration/ConfigurationValueParser.java b/src/core/lombok/core/configuration/ConfigurationValueParser.java
new file mode 100644
index 00000000..cf3bd5ab
--- /dev/null
+++ b/src/core/lombok/core/configuration/ConfigurationValueParser.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+interface ConfigurationValueParser {
+ Object parse(String value);
+ String description();
+ String exampleValue();
+} \ No newline at end of file
diff --git a/src/core/lombok/core/configuration/FileSystemSourceCache.java b/src/core/lombok/core/configuration/FileSystemSourceCache.java
new file mode 100644
index 00000000..03e6d338
--- /dev/null
+++ b/src/core/lombok/core/configuration/FileSystemSourceCache.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+import lombok.ConfigurationKeys;
+import lombok.core.configuration.ConfigurationSource.Result;
+
+public class FileSystemSourceCache {
+ private static String LOMBOK_CONFIG_FILENAME = "lombok.config";
+ private static final long RECHECK_FILESYSTEM = TimeUnit.SECONDS.toMillis(2);
+ private static final long MISSING = -1;
+
+ private final ConcurrentMap<File, Content> cache = new ConcurrentHashMap<File, Content>();
+
+ public Iterable<ConfigurationSource> sourcesForJavaFile(URI javaFile, ConfigurationProblemReporter reporter) {
+ if (javaFile == null) return Collections.emptyList();
+ return sourcesForDirectory(new File(javaFile.normalize()).getParentFile(), reporter);
+ }
+
+ public Iterable<ConfigurationSource> sourcesForDirectory(URI directory, ConfigurationProblemReporter reporter) {
+ if (directory == null) return Collections.emptyList();
+ return sourcesForDirectory(new File(directory.normalize()), reporter);
+ }
+
+ private Iterable<ConfigurationSource> sourcesForDirectory(final File directory, final ConfigurationProblemReporter reporter) {
+ return new Iterable<ConfigurationSource>() {
+ @Override
+ public Iterator<ConfigurationSource> iterator() {
+ return new Iterator<ConfigurationSource>() {
+ File currentDirectory = directory;
+ ConfigurationSource next;
+ boolean stopBubbling = false;
+
+ @Override
+ public boolean hasNext() {
+ if (next != null) return true;
+ if (stopBubbling) return false;
+ next = findNext();
+ return next != null;
+ }
+
+ @Override
+ public ConfigurationSource next() {
+ if (!hasNext()) throw new NoSuchElementException();
+ ConfigurationSource result = next;
+ next = null;
+ return result;
+ }
+
+ private ConfigurationSource findNext() {
+ while (currentDirectory != null && next == null) {
+ next = getSourceForDirectory(currentDirectory, reporter);
+ currentDirectory = currentDirectory.getParentFile();
+ }
+ if (next != null) {
+ Result stop = next.resolve(ConfigurationKeys.STOP_BUBBLING);
+ stopBubbling = (stop != null && Boolean.TRUE.equals(stop.getValue()));
+ }
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ ConfigurationSource getSourceForDirectory(File directory, ConfigurationProblemReporter reporter) {
+ if (!directory.exists() && !directory.isDirectory()) throw new IllegalArgumentException("Not a directory: " + directory);
+ long now = System.currentTimeMillis();
+ File configFile = new File(directory, LOMBOK_CONFIG_FILENAME);
+
+ Content content = ensureContent(directory);
+ synchronized (content) {
+ if (content.lastChecked != MISSING && now - content.lastChecked < RECHECK_FILESYSTEM && getLastModified(configFile) == content.lastModified) {
+ return content.source;
+ }
+ content.lastChecked = now;
+ long previouslyModified = content.lastModified;
+ content.lastModified = getLastModified(configFile);
+ if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : parse(configFile, reporter);
+ return content.source;
+ }
+ }
+
+ private Content ensureContent(File directory) {
+ Content content = cache.get(directory);
+ if (content != null) {
+ return content;
+ }
+ cache.putIfAbsent(directory, Content.empty());
+ return cache.get(directory);
+ }
+
+ private ConfigurationSource parse(File configFile, ConfigurationProblemReporter reporter) {
+ String contentDescription = configFile.getAbsolutePath();
+ try {
+ return StringConfigurationSource.forString(fileToString(configFile), reporter, contentDescription);
+ } catch (Exception e) {
+ reporter.report(contentDescription, "Exception while reading file: " + e.getMessage(), 0, null);
+ return null;
+ }
+ }
+
+ private static final ThreadLocal<byte[]> buffers = new ThreadLocal<byte[]>() {
+ protected byte[] initialValue() {
+ return new byte[65536];
+ }
+ };
+
+ static String fileToString(File configFile) throws Exception {
+ byte[] b = buffers.get();
+ FileInputStream fis = new FileInputStream(configFile);
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while (true) {
+ int r = fis.read(b);
+ if (r == -1) break;
+ out.write(b, 0, r);
+ }
+ return new String(out.toByteArray(), "UTF-8");
+ } finally {
+ fis.close();
+ }
+ }
+
+ private static final long getLastModified(File file) {
+ if (!file.exists() || !file.isFile()) return MISSING;
+ return file.lastModified();
+ }
+
+ private static class Content {
+ ConfigurationSource source;
+ long lastModified;
+ long lastChecked;
+
+ private Content(ConfigurationSource source, long lastModified, long lastChecked) {
+ this.source = source;
+ this.lastModified = lastModified;
+ this.lastChecked = lastChecked;
+ }
+
+ static Content empty() {
+ return new Content(null, MISSING, MISSING);
+ }
+ }
+
+ public void reset() {
+ cache.clear();
+ }
+} \ No newline at end of file
diff --git a/src/core/lombok/core/configuration/StringConfigurationSource.java b/src/core/lombok/core/configuration/StringConfigurationSource.java
new file mode 100644
index 00000000..dd2f0319
--- /dev/null
+++ b/src/core/lombok/core/configuration/StringConfigurationSource.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import lombok.core.configuration.ConfigurationParser.Collector;
+
+public class StringConfigurationSource implements ConfigurationSource {
+ private final Map<ConfigurationKey<?>, Result> values;
+
+ public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, String contentDescription) {
+
+ final Map<ConfigurationKey<?>, Result> values = new HashMap<ConfigurationKey<?>, Result>();
+
+ new ConfigurationParser(reporter).parse(content, contentDescription, new Collector() {
+ @Override public void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber) {
+ values.put(key, new Result(null, true));
+ }
+
+ @Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ values.put(key, new Result(value, true));
+ }
+
+ @Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ modifyList(key, value, true);
+ }
+
+ @Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
+ modifyList(key, value, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void modifyList(ConfigurationKey<?> key, Object value, boolean add) {
+ Result result = values.get(key);
+ List<ListModification> list;
+ if (result == null || result.getValue() == null) {
+ list = new ArrayList<ConfigurationSource.ListModification>();
+ values.put(key, new Result(list, result != null));
+ } else {
+ list = (List<ListModification>) result.getValue();
+ }
+ list.add(new ListModification(value, add));
+ }
+ });
+
+ return new StringConfigurationSource(values);
+ }
+
+ private StringConfigurationSource(Map<ConfigurationKey<?>, Result> values) {
+ this.values = new HashMap<ConfigurationKey<?>, Result>();
+ for (Entry<ConfigurationKey<?>, Result> entry : values.entrySet()) {
+ Result result = entry.getValue();
+ if (result.getValue() instanceof List<?>) {
+ this.values.put(entry.getKey(), new Result(Collections.unmodifiableList((List<?>) result.getValue()), result.isAuthoritative()));
+ } else {
+ this.values.put(entry.getKey(), result);
+ }
+ }
+ }
+
+ @Override
+ public Result resolve(ConfigurationKey<?> key) {
+ return values.get(key);
+ }
+}
diff --git a/src/core/lombok/core/configuration/TypeName.java b/src/core/lombok/core/configuration/TypeName.java
new file mode 100644
index 00000000..989e1b97
--- /dev/null
+++ b/src/core/lombok/core/configuration/TypeName.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+public final class TypeName {
+ private final String name;
+
+ private TypeName(String name) {
+ this.name = name;
+ }
+
+ public static TypeName valueOf(String name) {
+ return new TypeName(name);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (!(obj instanceof TypeName)) return false;
+ return name.equals(((TypeName) obj).name);
+ }
+
+ @Override public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override public String toString() {
+ return name;
+ }
+}
diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java
index 23b8ccc7..fe2f3406 100644
--- a/src/core/lombok/core/handlers/HandlerUtil.java
+++ b/src/core/lombok/core/handlers/HandlerUtil.java
@@ -21,9 +21,38 @@
*/
package lombok.core.handlers;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import lombok.AllArgsConstructor;
+import lombok.ConfigurationKeys;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.Value;
+import lombok.core.AST;
+import lombok.core.AnnotationValues;
+import lombok.core.FlagUsageType;
import lombok.core.JavaIdentifiers;
import lombok.core.LombokNode;
+import lombok.core.configuration.ConfigurationKey;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import lombok.experimental.Wither;
+/**
+ * Container for static utility methods useful for some of the standard lombok handlers, regardless of
+ * target platform (e.g. useful for both javac and Eclipse lombok implementations).
+ */
public class HandlerUtil {
private HandlerUtil() {}
@@ -57,4 +86,336 @@ public class HandlerUtil {
return true;
}
+
+ public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) {
+ FlagUsageType fut = node.getAst().readConfiguration(key);
+
+ if (fut != null) {
+ String msg = "Use of " + featureName + " is flagged according to lombok configuration.";
+ if (fut == FlagUsageType.WARNING) node.addWarning(msg);
+ else node.addError(msg);
+ }
+ }
+
+ public static void handleExperimentalFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) {
+ handleFlagUsage(node, key, featureName, ConfigurationKeys.EXPERIMENTAL_FLAG_USAGE, "any lombok.experimental feature");
+ }
+
+ public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key1, String featureName1, ConfigurationKey<FlagUsageType> key2, String featureName2) {
+ FlagUsageType fut1 = node.getAst().readConfiguration(key1);
+ FlagUsageType fut2 = node.getAst().readConfiguration(key2);
+
+ FlagUsageType fut = null;
+ String featureName = null;
+ if (fut1 == FlagUsageType.ERROR) {
+ fut = fut1;
+ featureName = featureName1;
+ } else if (fut2 == FlagUsageType.ERROR) {
+ fut = fut2;
+ featureName = featureName2;
+ } else if (fut1 == FlagUsageType.WARNING) {
+ fut = fut1;
+ featureName = featureName1;
+ } else {
+ fut = fut2;
+ featureName = featureName2;
+ }
+
+ if (fut != null) {
+ String msg = "Use of " + featureName + " is flagged according to lombok configuration.";
+ if (fut == FlagUsageType.WARNING) node.addWarning(msg);
+ else node.addError(msg);
+ }
+ }
+
+ public static boolean shouldReturnThis0(AnnotationValues<Accessors> accessors, AST<?, ?, ?> ast) {
+ boolean chainForced = accessors.isExplicit("chain");
+ boolean fluentForced = accessors.isExplicit("fluent");
+ Accessors instance = accessors.getInstance();
+
+ boolean chain = instance.chain();
+ boolean fluent = instance.fluent();
+
+ if (chainForced) return chain;
+
+ if (!chainForced) {
+ Boolean chainConfig = ast.readConfiguration(ConfigurationKeys.ACCESSORS_CHAIN);
+ if (chainConfig != null) return chainConfig;
+ }
+
+ if (!fluentForced) {
+ Boolean fluentConfig = ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT);
+ if (fluentConfig != null) fluent = fluentConfig;
+ }
+
+ return chain || fluent;
+ }
+
+ @SuppressWarnings({"all", "unchecked", "deprecation"})
+ public static final List<Class<? extends java.lang.annotation.Annotation>> INVALID_ON_BUILDERS = Collections.unmodifiableList(
+ Arrays.<Class<? extends java.lang.annotation.Annotation>>asList(
+ Getter.class, Setter.class, Wither.class, ToString.class, EqualsAndHashCode.class,
+ RequiredArgsConstructor.class, AllArgsConstructor.class, NoArgsConstructor.class,
+ Data.class, Value.class, lombok.experimental.Value.class, FieldDefaults.class));
+
+ /**
+ * Given the name of a field, return the 'base name' of that field. For example, {@code fFoobar} becomes {@code foobar} if {@code f} is in the prefix list.
+ * For prefixes that end in a letter character, the next character must be a non-lowercase character (i.e. {@code hashCode} is not {@code ashCode} even if
+ * {@code h} is in the prefix list, but {@code hAshcode} would become {@code ashCode}). The first prefix that matches is used. If the prefix list is empty,
+ * or the empty string is in the prefix list and no prefix before it matches, the fieldName will be returned verbatim.
+ *
+ * If no prefix matches and the empty string is not in the prefix list and the prefix list is not empty, {@code null} is returned.
+ *
+ * @param fieldName The full name of a field.
+ * @param prefixes A list of prefixes, usually provided by the {@code Accessors} settings annotation, listing field prefixes.
+ * @return The base name of the field.
+ */
+ public static CharSequence removePrefix(CharSequence fieldName, List<String> prefixes) {
+ if (prefixes == null || prefixes.isEmpty()) return fieldName;
+
+ fieldName = fieldName.toString();
+
+ outer:
+ for (String prefix : prefixes) {
+ if (prefix.length() == 0) return fieldName;
+ if (fieldName.length() <= prefix.length()) continue outer;
+ for (int i = 0; i < prefix.length(); i++) {
+ if (fieldName.charAt(i) != prefix.charAt(i)) continue outer;
+ }
+ char followupChar = fieldName.charAt(prefix.length());
+ // if prefix is a letter then follow up letter needs to not be lowercase, i.e. 'foo' is not a match
+ // as field named 'oo' with prefix 'f', but 'fOo' would be.
+ if (Character.isLetter(prefix.charAt(prefix.length() - 1)) &&
+ Character.isLowerCase(followupChar)) continue outer;
+ return "" + Character.toLowerCase(followupChar) + fieldName.subSequence(prefix.length() + 1, fieldName.length());
+ }
+
+ return null;
+ }
+
+ /* NB: 'notnull' is not part of the pattern because there are lots of @NotNull annotations out there that are crappily named and actually mean
+ something else, such as 'this field must not be null _when saved to the db_ but its perfectly okay to start out as such, and a no-args
+ constructor and the implied starts-out-as-null state that goes with it is in fact mandatory' which happens with javax.validation.constraints.NotNull.
+ Various problems with spring have also been reported. See issue #287, issue #271, and issue #43. */
+
+ /** Matches the simple part of any annotation that lombok considers as indicative of NonNull status. */
+ public static final Pattern NON_NULL_PATTERN = Pattern.compile("^(?:nonnull)$", Pattern.CASE_INSENSITIVE);
+
+ /** Matches the simple part of any annotation that lombok considers as indicative of Nullable status. */
+ public static final Pattern NULLABLE_PATTERN = Pattern.compile("^(?:nullable|checkfornull)$", Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Generates a getter name from a given field name.
+ *
+ * Strategy:
+ * <ul>
+ * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
+ * the prefix list, this method immediately returns {@code null}.</li>
+ * <li>If {@code Accessors} has {@code fluent=true}, then return the basename.</li>
+ * <li>Pick a prefix. 'get' normally, but 'is' if {@code isBoolean} is true.</li>
+ * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character. If so, return the field name verbatim.</li>
+ * <li>Check if the first character of the field is lowercase. If so, check if the second character
+ * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
+ * <li>Return the prefix plus the possibly title/uppercased first character, and the rest of the field name.</li>
+ * </ul>
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
+ * @return The getter name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
+ */
+ public static String toGetterName(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAccessorName(ast, accessors, fieldName, isBoolean, "is", "get", true);
+ }
+
+ /**
+ * Generates a setter name from a given field name.
+ *
+ * Strategy:
+ * <ul>
+ * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
+ * the prefix list, this method immediately returns {@code null}.</li>
+ * <li>If {@code Accessors} has {@code fluent=true}, then return the basename.</li>
+ * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character.
+ * If so, replace {@code is} with {@code set} and return that.</li>
+ * <li>Check if the first character of the field is lowercase. If so, check if the second character
+ * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
+ * <li>Return {@code "set"} plus the possibly title/uppercased first character, and the rest of the field name.</li>
+ * </ul>
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
+ * @return The setter name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
+ */
+ public static String toSetterName(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAccessorName(ast, accessors, fieldName, isBoolean, "set", "set", true);
+ }
+
+ /**
+ * Generates a wither name from a given field name.
+ *
+ * Strategy:
+ * <ul>
+ * <li>Reduce the field's name to its base name by stripping off any prefix (from {@code Accessors}). If the field name does not fit
+ * the prefix list, this method immediately returns {@code null}.</li>
+ * <li>Only if {@code isBoolean} is true: Check if the field starts with {@code is} followed by a non-lowercase character.
+ * If so, replace {@code is} with {@code with} and return that.</li>
+ * <li>Check if the first character of the field is lowercase. If so, check if the second character
+ * exists and is title or upper case. If so, uppercase the first character. If not, titlecase the first character.</li>
+ * <li>Return {@code "with"} plus the possibly title/uppercased first character, and the rest of the field name.</li>
+ * </ul>
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type {@code java.lang.Boolean}, you should provide {@code false}.
+ * @return The wither name for this field, or {@code null} if this field does not fit expected patterns and therefore cannot be turned into a getter name.
+ */
+ public static String toWitherName(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAccessorName(ast, accessors, fieldName, isBoolean, "with", "with", false);
+ }
+
+ private static String toAccessorName(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean,
+ String booleanPrefix, String normalPrefix, boolean adhereToFluent) {
+
+ fieldName = fieldName.toString();
+ if (fieldName.length() == 0) return null;
+
+ boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix");
+// System.out.printf("accessors: %s actual expr: %s val: %s\n", accessors, accessors != null ? accessors.getActualExpression("prefix") : "(null)", accessors == null ? "(null)" : Arrays.toString(accessors.getInstance().prefix()));
+ boolean explicitFluent = accessors != null && accessors.isExplicit("fluent");
+
+ Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null;
+
+ List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX);
+ boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT));
+
+ fieldName = removePrefix(fieldName, prefix);
+ if (fieldName == null) return null;
+
+ String fName = fieldName.toString();
+ if (adhereToFluent && fluent) return fName;
+
+ if (isBoolean && fName.startsWith("is") && fieldName.length() > 2 && !Character.isLowerCase(fieldName.charAt(2))) {
+ // The field is for example named 'isRunning'.
+ return booleanPrefix + fName.substring(2);
+ }
+
+ return buildName(isBoolean ? booleanPrefix : normalPrefix, fName);
+ }
+
+ /**
+ * Returns all names of methods that would represent the getter for a field with the provided name.
+ *
+ * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
+ * {@code [isRunning, getRunning, isIsRunning, getIsRunning]}
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
+ */
+ public static List<String> toAllGetterNames(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAllAccessorNames(ast, accessors, fieldName, isBoolean, "is", "get", true);
+ }
+
+ /**
+ * Returns all names of methods that would represent the setter for a field with the provided name.
+ *
+ * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
+ * {@code [setRunning, setIsRunning]}
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
+ */
+ public static List<String> toAllSetterNames(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAllAccessorNames(ast, accessors, fieldName, isBoolean, "set", "set", true);
+ }
+
+ /**
+ * Returns all names of methods that would represent the wither for a field with the provided name.
+ *
+ * For example if {@code isBoolean} is true, then a field named {@code isRunning} would produce:<br />
+ * {@code [withRunning, withIsRunning]}
+ *
+ * @param accessors Accessors configuration.
+ * @param fieldName the name of the field.
+ * @param isBoolean if the field is of type 'boolean'. For fields of type 'java.lang.Boolean', you should provide {@code false}.
+ */
+ public static List<String> toAllWitherNames(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean) {
+ return toAllAccessorNames(ast, accessors, fieldName, isBoolean, "with", "with", false);
+ }
+
+ private static List<String> toAllAccessorNames(AST<?, ?, ?> ast, AnnotationValues<Accessors> accessors, CharSequence fieldName, boolean isBoolean,
+ String booleanPrefix, String normalPrefix, boolean adhereToFluent) {
+
+ if (!isBoolean) {
+ String accessorName = toAccessorName(ast, accessors, fieldName, false, booleanPrefix, normalPrefix, adhereToFluent);
+ return (accessorName == null) ? Collections.<String>emptyList() : Collections.singletonList(accessorName);
+ }
+
+ boolean explicitPrefix = accessors != null && accessors.isExplicit("prefix");
+ boolean explicitFluent = accessors != null && accessors.isExplicit("fluent");
+
+ Accessors ac = (explicitPrefix || explicitFluent) ? accessors.getInstance() : null;
+
+ List<String> prefix = explicitPrefix ? Arrays.asList(ac.prefix()) : ast.readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX);
+ boolean fluent = explicitFluent ? ac.fluent() : Boolean.TRUE.equals(ast.readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT));
+
+ fieldName = removePrefix(fieldName, prefix);
+ if (fieldName == null) return Collections.emptyList();
+
+ List<String> baseNames = toBaseNames(fieldName, isBoolean, fluent);
+
+ Set<String> names = new HashSet<String>();
+ for (String baseName : baseNames) {
+ if (adhereToFluent && fluent) {
+ names.add(baseName);
+ } else {
+ names.add(buildName(normalPrefix, baseName));
+ if (!normalPrefix.equals(booleanPrefix)) names.add(buildName(booleanPrefix, baseName));
+ }
+ }
+
+ return new ArrayList<String>(names);
+
+ }
+
+ private static List<String> toBaseNames(CharSequence fieldName, boolean isBoolean, boolean fluent) {
+ List<String> baseNames = new ArrayList<String>();
+ baseNames.add(fieldName.toString());
+
+ // isPrefix = field is called something like 'isRunning', so 'running' could also be the fieldname.
+ String fName = fieldName.toString();
+ if (fName.startsWith("is") && fName.length() > 2 && !Character.isLowerCase(fName.charAt(2))) {
+ String baseName = fName.substring(2);
+ if (fluent) {
+ baseNames.add("" + Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1));
+ } else {
+ baseNames.add(baseName);
+ }
+ }
+
+ return baseNames;
+ }
+
+ /**
+ * @param prefix Something like {@code get} or {@code set} or {@code is}.
+ * @param suffix Something like {@code running}.
+ * @return prefix + smartly title-cased suffix. For example, {@code setRunning}.
+ */
+ private static String buildName(String prefix, String suffix) {
+ if (suffix.length() == 0) return prefix;
+ if (prefix.length() == 0) return suffix;
+
+ char first = suffix.charAt(0);
+ if (Character.isLowerCase(first)) {
+ boolean useUpperCase = suffix.length() > 2 &&
+ (Character.isTitleCase(suffix.charAt(1)) || Character.isUpperCase(suffix.charAt(1)));
+ suffix = String.format("%s%s",
+ useUpperCase ? Character.toUpperCase(first) : Character.toTitleCase(first),
+ suffix.subSequence(1, suffix.length()));
+ }
+ return String.format("%s%s", prefix, suffix);
+ }
}
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 370b40fc..45551d1c 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -21,10 +21,11 @@
*/
package lombok.eclipse;
+import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.URI;
import java.util.ArrayList;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -33,6 +34,9 @@ import lombok.Lombok;
import lombok.core.AST;
import lombok.core.LombokImmutableList;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -64,6 +68,27 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
clearChanged();
}
+ private static volatile boolean skipEclipseWorkspaceBasedFileResolver = false;
+ public URI getAbsoluteFileLocation() {
+ if (!skipEclipseWorkspaceBasedFileResolver) {
+ try {
+ return EclipseWorkspaceBasedFileResolver.resolve(getFileName());
+ } catch (NoClassDefFoundError e) {
+ skipEclipseWorkspaceBasedFileResolver = true;
+ }
+ }
+
+ // Our fancy workspace based source file to absolute disk location algorithm only works in a fully fledged eclipse.
+ // This fallback works when using 'ecj', which has a much simpler project/path system. For example, no 'linked' resources.
+ return new File(getFileName()).getAbsoluteFile().toURI();
+ }
+
+ private static class EclipseWorkspaceBasedFileResolver {
+ public static URI resolve(String path) {
+ return ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path)).getLocationURI();
+ }
+ }
+
private static String packageDeclaration(CompilationUnitDeclaration cud) {
ImportReference pkg = cud.currentPackage;
return pkg == null ? null : Eclipse.toQualifiedName(pkg.getImportName());
diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java
index 242e923c..ad9c87b9 100644
--- a/src/core/lombok/eclipse/HandlerLibrary.java
+++ b/src/core/lombok/eclipse/HandlerLibrary.java
@@ -38,6 +38,7 @@ import java.util.WeakHashMap;
import lombok.Lombok;
import lombok.core.AnnotationValues;
import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
+import lombok.core.configuration.ConfigurationKeysLoader;
import lombok.core.HandlerPriority;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
@@ -58,7 +59,9 @@ public class HandlerLibrary {
* Creates a new HandlerLibrary. Errors will be reported to the Eclipse Error log.
* You probably want to use {@link #load()} instead.
*/
- public HandlerLibrary() {}
+ public HandlerLibrary() {
+ ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys();
+ }
private TypeLibrary typeLibrary = new TypeLibrary();
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index fbad53d4..94fdffad 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -22,7 +22,7 @@
package lombok.eclipse.handlers;
import static lombok.eclipse.Eclipse.*;
-import static lombok.core.TransformationsUtil.*;
+import static lombok.core.handlers.HandlerUtil.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -38,14 +38,15 @@ import java.util.Map;
import java.util.WeakHashMap;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Data;
import lombok.Getter;
import lombok.Lombok;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.AnnotationValues.AnnotationValue;
-import lombok.core.TransformationsUtil;
import lombok.core.TypeResolver;
+import lombok.core.handlers.HandlerUtil;
import lombok.eclipse.EclipseAST;
import lombok.eclipse.EclipseNode;
import lombok.experimental.Accessors;
@@ -1043,7 +1044,7 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllGetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static List<String> toAllGetterNames(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toAllGetterNames(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toAllGetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
@@ -1052,7 +1053,7 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toGetterName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toGetterName(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toGetterName(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toGetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
@@ -1060,7 +1061,7 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static java.util.List<String> toAllSetterNames(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toAllSetterNames(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toAllSetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
@@ -1069,7 +1070,7 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toSetterName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toSetterName(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toSetterName(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toSetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
@@ -1077,7 +1078,7 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllWitherNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static java.util.List<String> toAllWitherNames(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toAllWitherNames(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toAllWitherNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
@@ -1086,19 +1087,17 @@ public class EclipseHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toWitherName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toWitherName(EclipseNode field, boolean isBoolean) {
- return TransformationsUtil.toWitherName(getAccessorsForField(field), field.getName(), isBoolean);
+ return HandlerUtil.toWitherName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean);
}
/**
* When generating a setter, the setter either returns void (beanspec) or Self (fluent).
- * This method scans for the {@code Accessors} annotation to figure that out.
+ * This method scans for the {@code Accessors} annotation and associated config properties to figure that out.
*/
public static boolean shouldReturnThis(EclipseNode field) {
if ((((FieldDeclaration) field.get()).modifiers & ClassFileConstants.AccStatic) != 0) return false;
AnnotationValues<Accessors> accessors = EclipseHandlerUtil.getAccessorsForField(field);
- boolean forced = (accessors.getActualExpression("chain") != null);
- Accessors instance = accessors.getInstance();
- return instance.chain() || (instance.fluent() && !forced);
+ return shouldReturnThis0(accessors, field.getAst());
}
/**
@@ -1126,10 +1125,11 @@ public class EclipseHandlerUtil {
}
public static char[] removePrefixFromField(EclipseNode field) {
- String[] prefixes = null;
+ List<String> prefixes = null;
for (EclipseNode node : field.down()) {
if (annotationTypeMatches(Accessors.class, node)) {
- prefixes = createAnnotation(Accessors.class, node).getInstance().prefix();
+ AnnotationValues<Accessors> ann = createAnnotation(Accessors.class, node);
+ if (ann.isExplicit("prefix")) prefixes = Arrays.asList(ann.getInstance().prefix());
break;
}
}
@@ -1140,7 +1140,8 @@ public class EclipseHandlerUtil {
while (current != null) {
for (EclipseNode node : current.down()) {
if (annotationTypeMatches(Accessors.class, node)) {
- prefixes = createAnnotation(Accessors.class, node).getInstance().prefix();
+ AnnotationValues<Accessors> ann = createAnnotation(Accessors.class, node);
+ if (ann.isExplicit("prefix")) prefixes = Arrays.asList(ann.getInstance().prefix());
break outer;
}
}
@@ -1148,8 +1149,9 @@ public class EclipseHandlerUtil {
}
}
- if (prefixes != null && prefixes.length > 0) {
- CharSequence newName = TransformationsUtil.removePrefix(field.getName(), prefixes);
+ if (prefixes == null) prefixes = field.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX);
+ if (!prefixes.isEmpty()) {
+ CharSequence newName = removePrefix(field.getName(), prefixes);
if (newName != null) return newName.toString().toCharArray();
}
diff --git a/src/core/lombok/eclipse/handlers/HandleAccessors.java b/src/core/lombok/eclipse/handlers/HandleAccessors.java
new file mode 100644
index 00000000..864ff50b
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleAccessors.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 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 lombok.ConfigurationKeys;
+import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+import lombok.experimental.Accessors;
+
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(65536)
+public class HandleAccessors extends EclipseAnnotationHandler<Accessors> {
+ @Override public void handle(AnnotationValues<Accessors> annotation, Annotation ast, EclipseNode annotationNode) {
+ // Accessors itself is handled by HandleGetter/Setter; this is just to ensure that usages are flagged if requested.
+
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.ACCESSORS_FLAG_USAGE, "@Accessors");
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index ea282b3b..12b16934 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -56,10 +56,10 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.mangosdk.spi.ProviderFor;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
-import lombok.core.TransformationsUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
@@ -71,6 +71,8 @@ import lombok.experimental.NonFinal;
@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
+
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
Builder builderInstance = annotation.getInstance();
@@ -347,7 +349,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
boolean isBoolean = isBoolean(fd.type);
- String setterName = fluent ? fieldNode.getName() : TransformationsUtil.toSetterName(null, fieldNode.getName(), isBoolean);
+ String setterName = fluent ? fieldNode.getName() : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean);
return HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic,
source, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java
index b8ea1669..dde7cd08 100644
--- a/src/core/lombok/eclipse/handlers/HandleCleanup.java
+++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java
@@ -21,11 +21,13 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Arrays;
import lombok.Cleanup;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
import lombok.eclipse.EclipseAnnotationHandler;
@@ -58,6 +60,8 @@ import org.mangosdk.spi.ProviderFor;
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleCleanup extends EclipseAnnotationHandler<Cleanup> {
public void handle(AnnotationValues<Cleanup> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup");
+
String cleanupName = annotation.getInstance().value();
if (cleanupName.length() == 0) {
annotationNode.addError("cleanupName cannot be the empty string.");
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index d86aadee..6b7df349 100644
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
@@ -32,11 +33,11 @@ import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
+import lombok.ConfigurationKeys;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.experimental.Builder;
@@ -69,6 +70,8 @@ public class HandleConstructor {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleNoArgsConstructor extends EclipseAnnotationHandler<NoArgsConstructor> {
@Override public void handle(AnnotationValues<NoArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.NO_ARGS_CONSTRUCTOR_FLAG_USAGE, "@NoArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return;
NoArgsConstructor ann = annotation.getInstance();
@@ -86,6 +89,8 @@ public class HandleConstructor {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleRequiredArgsConstructor extends EclipseAnnotationHandler<RequiredArgsConstructor> {
@Override public void handle(AnnotationValues<RequiredArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.REQUIRED_ARGS_CONSTRUCTOR_FLAG_USAGE, "@RequiredArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return;
RequiredArgsConstructor ann = annotation.getInstance();
@@ -108,7 +113,7 @@ public class HandleConstructor {
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (!filterField(fieldDecl)) continue;
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
- boolean isNonNull = findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0;
+ boolean isNonNull = findAnnotations(fieldDecl, NON_NULL_PATTERN).length != 0;
if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child);
}
return fields;
@@ -132,6 +137,8 @@ public class HandleConstructor {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleAllArgsConstructor extends EclipseAnnotationHandler<AllArgsConstructor> {
@Override public void handle(AnnotationValues<AllArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.ALL_ARGS_CONSTRUCTOR_FLAG_USAGE, "@AllArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return;
AllArgsConstructor ann = annotation.getInstance();
@@ -285,8 +292,8 @@ public class HandleConstructor {
assigns.add(assignment);
long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd;
Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
- Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
if (nonNulls.length != 0) {
Statement nullCheck = generateNullCheck(field, source);
if (nullCheck != null) nullChecks.add(nullCheck);
@@ -355,7 +362,7 @@ public class HandleConstructor {
Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL);
- Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN));
+ Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, NON_NULL_PATTERN), findAnnotations(field, NULLABLE_PATTERN));
if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations;
params.add(parameter);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java
index aa309489..a6a8842d 100644
--- a/src/core/lombok/eclipse/handlers/HandleData.java
+++ b/src/core/lombok/eclipse/handlers/HandleData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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,9 +21,12 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
+
import java.util.Collections;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Data;
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
@@ -40,7 +43,9 @@ import org.mangosdk.spi.ProviderFor;
*/
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleData extends EclipseAnnotationHandler<Data> {
- public void handle(AnnotationValues<Data> annotation, Annotation ast, EclipseNode annotationNode) {
+ @Override public void handle(AnnotationValues<Data> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.DATA_FLAG_USAGE, "@Data");
+
Data ann = annotation.getInstance();
EclipseNode typeNode = annotationNode.up();
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index 0cc0836e..2ae7aba4 100644
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Modifier;
@@ -33,6 +34,7 @@ import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.EqualsAndHashCode;
import lombok.core.AST.Kind;
import lombok.core.handlers.HandlerUtil;
@@ -117,8 +119,9 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
generateMethods(typeNode, errorNode, null, null, null, false, FieldAccess.GETTER);
}
- @Override public void handle(AnnotationValues<EqualsAndHashCode> annotation,
- Annotation ast, EclipseNode annotationNode) {
+ @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());
diff --git a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
index 3d30e8fe..8e53d873 100644
--- a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
+++ b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,6 +21,8 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
+
import java.util.List;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -28,6 +30,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.mangosdk.spi.ProviderFor;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.eclipse.EclipseAnnotationHandler;
@@ -39,6 +42,8 @@ import lombok.experimental.ExtensionMethod;
@HandlerPriority(66560) // 2^16 + 2^10; we must run AFTER HandleVal which is at 2^16
public class HandleExtensionMethod extends EclipseAnnotationHandler<ExtensionMethod> {
@Override public void handle(AnnotationValues<ExtensionMethod> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.EXTENSION_METHOD_FLAG_USAGE, "@ExtensionMethod");
+
TypeDeclaration typeDecl = null;
EclipseNode owner = annotationNode.up();
if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get();
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index d6d839cc..7d0702db 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,8 +21,10 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -102,6 +104,8 @@ public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults>
}
public void handle(AnnotationValues<FieldDefaults> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
EclipseNode node = annotationNode.up();
FieldDefaults instance = annotation.getInstance();
AccessLevel level = instance.level();
diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java
index 188dfce2..8cffaa2c 100644
--- a/src/core/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleGetter.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
@@ -32,11 +33,11 @@ import java.util.List;
import java.util.Map;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Delegate;
import lombok.Getter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.agent.PatchDelegate;
@@ -132,6 +133,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
}
public void handle(AnnotationValues<Getter> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.GETTER_FLAG_USAGE, "@Getter");
+
EclipseNode node = annotationNode.up();
Getter annotationInstance = annotation.getInstance();
AccessLevel level = annotationInstance.value();
@@ -269,8 +272,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
Annotation[] copiedAnnotations = copyAnnotations(source,
onMethod.toArray(new Annotation[0]),
- findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN),
- findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN),
+ findAnnotations(field, NON_NULL_PATTERN),
+ findAnnotations(field, NULLABLE_PATTERN),
findDelegatesAndMarkAsHandled(fieldNode),
deprecated);
diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java
index cf1e8018..830190a2 100644
--- a/src/core/lombok/eclipse/handlers/HandleLog.java
+++ b/src/core/lombok/eclipse/handlers/HandleLog.java
@@ -21,15 +21,18 @@
*/
package lombok.eclipse.handlers;
-import static lombok.eclipse.Eclipse.*;
+import static lombok.core.handlers.HandlerUtil.*;
+import static lombok.eclipse.Eclipse.fromQualifiedName;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Modifier;
import java.util.Arrays;
+import lombok.ConfigurationKeys;
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.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
@@ -49,10 +52,16 @@ public class HandleLog {
throw new UnsupportedOperationException();
}
- public static void processAnnotation(LoggingFramework framework, AnnotationValues<? extends java.lang.annotation.Annotation> annotation, Annotation source, EclipseNode annotationNode, String loggerCategory) {
+ public static void processAnnotation(LoggingFramework framework, AnnotationValues<? extends java.lang.annotation.Annotation> annotation, Annotation source, EclipseNode annotationNode, String loggerTopic) {
EclipseNode owner = annotationNode.up();
+
switch (owner.getKind()) {
case TYPE:
+ String logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME);
+ if (logFieldName == null) logFieldName = "log";
+
+ boolean useStatic = !Boolean.FALSE.equals(annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_IS_STATIC));
+
TypeDeclaration typeDecl = null;
if (owner.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) owner.get();
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
@@ -65,14 +74,14 @@ public class HandleLog {
return;
}
- if (fieldExists("log", owner) != MemberExistsResult.NOT_EXISTS) {
- annotationNode.addWarning("Field 'log' already exists.");
+ if (fieldExists(logFieldName, owner) != MemberExistsResult.NOT_EXISTS) {
+ annotationNode.addWarning("Field '" + logFieldName + "' already exists.");
return;
}
ClassLiteralAccess loggingType = selfType(owner, source);
- FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, loggerCategory);
+ FieldDeclaration fieldDeclaration = createField(framework, source, loggingType, logFieldName, useStatic, loggerTopic);
fieldDeclaration.traverse(new SetGeneratedByVisitor(source), typeDecl.staticInitializerScope);
// TODO temporary workaround for issue 217. http://code.google.com/p/projectlombok/issues/detail?id=217
// injectFieldSuppressWarnings(owner, fieldDeclaration);
@@ -98,16 +107,15 @@ public class HandleLog {
return result;
}
- public static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String loggerCategory) {
+ 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;
// private static final <loggerType> log = <factoryMethod>(<parameter>);
-
- FieldDeclaration fieldDecl = new FieldDeclaration("log".toCharArray(), 0, -1);
+ FieldDeclaration fieldDecl = new FieldDeclaration(logFieldName.toCharArray(), 0, -1);
setGeneratedBy(fieldDecl, source);
fieldDecl.declarationSourceEnd = -1;
- fieldDecl.modifiers = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+ fieldDecl.modifiers = Modifier.PRIVATE | (useStatic ? Modifier.STATIC : 0) | Modifier.FINAL;
fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source);
@@ -118,10 +126,10 @@ public class HandleLog {
factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray();
Expression parameter;
- if (loggerCategory == null || loggerCategory.trim().length() == 0) {
+ if (loggerTopic == null || loggerTopic.trim().length() == 0) {
parameter = framework.createFactoryParameter(loggingType, source);
} else {
- parameter = new StringLiteral(loggerCategory.toCharArray(), pS, pE, 0);
+ parameter = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0);
}
factoryMethodCall.arguments = new Expression[] { parameter };
@@ -161,6 +169,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleCommonsLog extends EclipseAnnotationHandler<lombok.extern.apachecommons.CommonsLog> {
@Override public void handle(AnnotationValues<lombok.extern.apachecommons.CommonsLog> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.COMMONS, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
@@ -171,6 +180,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleJulLog extends EclipseAnnotationHandler<lombok.extern.java.Log> {
@Override public void handle(AnnotationValues<lombok.extern.java.Log> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.JUL, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
@@ -181,6 +191,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleLog4jLog extends EclipseAnnotationHandler<lombok.extern.log4j.Log4j> {
@Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.LOG4J, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
@@ -191,6 +202,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleLog4j2Log extends EclipseAnnotationHandler<lombok.extern.log4j.Log4j2> {
@Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j2> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.LOG4J2, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
@@ -201,6 +213,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleSlf4jLog extends EclipseAnnotationHandler<lombok.extern.slf4j.Slf4j> {
@Override public void handle(AnnotationValues<lombok.extern.slf4j.Slf4j> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.SLF4J, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
@@ -211,6 +224,7 @@ public class HandleLog {
@ProviderFor(EclipseAnnotationHandler.class)
public static class HandleXSlf4jLog extends EclipseAnnotationHandler<lombok.extern.slf4j.XSlf4j> {
@Override public void handle(AnnotationValues<lombok.extern.slf4j.XSlf4j> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.XSLF4J, annotation, source, annotationNode, annotation.getInstance().topic());
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java
index 7fd12ca3..79bb7a08 100644
--- a/src/core/lombok/eclipse/handlers/HandleNonNull.java
+++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java
@@ -21,11 +21,13 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.isPrimitive;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Arrays;
+import lombok.ConfigurationKeys;
import lombok.NonNull;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
@@ -57,6 +59,8 @@ import org.mangosdk.spi.ProviderFor;
@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first.
public class HandleNonNull extends EclipseAnnotationHandler<NonNull> {
@Override public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
+
if (annotationNode.up().getKind() == Kind.FIELD) {
// This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc),
// but in that case those handlers will take care of it. However, we DO check if the annotation is applied to
diff --git a/src/core/lombok/eclipse/handlers/HandlePrintAST.java b/src/core/lombok/eclipse/handlers/HandlePrintAST.java
index da6fa2a2..65cda98a 100644
--- a/src/core/lombok/eclipse/handlers/HandlePrintAST.java
+++ b/src/core/lombok/eclipse/handlers/HandlePrintAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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
@@ -52,7 +52,16 @@ public class HandlePrintAST extends EclipseAnnotationHandler<PrintAST> {
} catch (FileNotFoundException e) {
Lombok.sneakyThrow(e);
}
-
- annotationNode.up().traverse(new EclipseASTVisitor.Printer(annotation.getInstance().printContent(), stream, annotation.getInstance().printPositions()));
+ try {
+ annotationNode.up().traverse(new EclipseASTVisitor.Printer(annotation.getInstance().printContent(), stream, annotation.getInstance().printPositions()));
+ } finally {
+ if (stream != System.out) {
+ try {
+ stream.close();
+ } catch (Exception e) {
+ Lombok.sneakyThrow(e);
+ }
+ }
+ }
}
-}
+} \ No newline at end of file
diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java
index caa5329a..74ef07b5 100644
--- a/src/core/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleSetter.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
@@ -31,10 +32,10 @@ import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Setter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
@@ -118,6 +119,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
}
public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SETTER_FLAG_USAGE, "@Setter");
+
EclipseNode node = annotationNode.up();
AccessLevel level = annotation.getInstance().value();
if (level == AccessLevel.NONE || node == null) return;
@@ -230,8 +233,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
- Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
List<Statement> statements = new ArrayList<Statement>(5);
if (nonNulls.length == 0) {
statements.add(assignment);
diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
index d8261326..481dbcde 100644
--- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
+++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Modifier;
@@ -28,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import lombok.ConfigurationKeys;
import lombok.SneakyThrows;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -75,6 +77,8 @@ public class HandleSneakyThrows extends EclipseAnnotationHandler<SneakyThrows> {
}
@Override public void handle(AnnotationValues<SneakyThrows> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SNEAKY_THROWS_FLAG_USAGE, "@SneakyThrows");
+
List<String> exceptionNames = annotation.getRawExpressions("value");
List<DeclaredException> exceptions = new ArrayList<DeclaredException>();
diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java
index b3e51da0..a45a499c 100644
--- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java
+++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java
@@ -21,10 +21,12 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Modifier;
+import lombok.ConfigurationKeys;
import lombok.Synchronized;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -105,6 +107,8 @@ public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> {
}
@Override public void handle(AnnotationValues<Synchronized> annotation, Annotation source, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SYNCHRONIZED_FLAG_USAGE, "@Synchronized");
+
int p1 = source.sourceStart -1;
int p2 = source.sourceStart -2;
long pos = (((long)p1) << 32) | p2;
diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java
index 31ff3021..a4ed254a 100644
--- a/src/core/lombok/eclipse/handlers/HandleToString.java
+++ b/src/core/lombok/eclipse/handlers/HandleToString.java
@@ -21,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.ArrayList;
@@ -32,12 +33,14 @@ import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.ToString;
-import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
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;
@@ -88,12 +91,15 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
boolean includeFieldNames = true;
try {
- includeFieldNames = ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue();
+ Boolean configuration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
+ includeFieldNames = configuration != null ? configuration : ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue();
} catch (Exception ignore) {}
generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, FieldAccess.GETTER);
}
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());
@@ -111,9 +117,14 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
checkForBogusFieldNames(typeNode, annotation);
- FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
+ 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;
- generateToString(typeNode, annotationNode, excludes, includes, ann.includeFieldNames(), callSuper, true, fieldAccess);
+ 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,
diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java
index c8339f35..d4ae417c 100644
--- a/src/core/lombok/eclipse/handlers/HandleVal.java
+++ b/src/core/lombok/eclipse/handlers/HandleVal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-2014 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,6 +21,8 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
+import lombok.ConfigurationKeys;
import lombok.val;
import lombok.core.HandlerPriority;
import lombok.eclipse.DeferUntilPostDiet;
@@ -43,6 +45,8 @@ import org.mangosdk.spi.ProviderFor;
public class HandleVal extends EclipseASTAdapter {
@Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) {
if (!EclipseHandlerUtil.typeMatches(val.class, localNode, local.type)) return;
+ handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val");
+
boolean variableOfForEach = false;
if (localNode.directUp().get() instanceof ForeachStatement) {
diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java
index 0607137b..211b337a 100644
--- a/src/core/lombok/eclipse/handlers/HandleValue.java
+++ b/src/core/lombok/eclipse/handlers/HandleValue.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,11 +21,13 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Collections;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.eclipse.EclipseAnnotationHandler;
@@ -46,6 +48,8 @@ import org.mangosdk.spi.ProviderFor;
@HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier.
public class HandleValue extends EclipseAnnotationHandler<Value> {
public void handle(AnnotationValues<Value> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.VALUE_FLAG_USAGE, "@Value");
+
Value ann = annotation.getInstance();
EclipseNode typeNode = annotationNode.up();
diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java
index 305e0a16..30306b72 100644
--- a/src/core/lombok/eclipse/handlers/HandleWither.java
+++ b/src/core/lombok/eclipse/handlers/HandleWither.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,6 +21,7 @@
*/
package lombok.eclipse.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
@@ -31,9 +32,9 @@ import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
@@ -120,6 +121,8 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> {
}
@Override public void handle(AnnotationValues<Wither> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.WITHER_FLAG_USAGE, "@Wither");
+
EclipseNode node = annotationNode.up();
AccessLevel level = annotation.getInstance().value();
if (level == AccessLevel.NONE || node == null) return;
@@ -266,8 +269,8 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> {
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
- Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
List<Statement> statements = new ArrayList<Statement>(5);
if (nonNulls.length > 0) {
Statement nullCheck = generateNullCheck(field, source);
diff --git a/src/core/lombok/experimental/Accessors.java b/src/core/lombok/experimental/Accessors.java
index 2748bfa9..c2a0ca16 100644
--- a/src/core/lombok/experimental/Accessors.java
+++ b/src/core/lombok/experimental/Accessors.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2013 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
diff --git a/src/core/lombok/experimental/ExtensionMethod.java b/src/core/lombok/experimental/ExtensionMethod.java
index 44f28d04..7de8a136 100644
--- a/src/core/lombok/experimental/ExtensionMethod.java
+++ b/src/core/lombok/experimental/ExtensionMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2013 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
diff --git a/src/core/lombok/experimental/FieldDefaults.java b/src/core/lombok/experimental/FieldDefaults.java
index 8a3fb534..1c621f3c 100644
--- a/src/core/lombok/experimental/FieldDefaults.java
+++ b/src/core/lombok/experimental/FieldDefaults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2013 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
diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java
index 2e31edf7..45345098 100644
--- a/src/core/lombok/extern/apachecommons/CommonsLog.java
+++ b/src/core/lombok/extern/apachecommons/CommonsLog.java
@@ -63,4 +63,4 @@ public @interface CommonsLog {
* Sets the category of the constructed Logger. By default, it will use the type where the annotation is placed.
*/
String topic() default "";
-} \ No newline at end of file
+}
diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java
index f8cbf03f..bac2742e 100644
--- a/src/core/lombok/extern/java/Log.java
+++ b/src/core/lombok/extern/java/Log.java
@@ -62,4 +62,4 @@ public @interface Log {
* Sets the category of the constructed Logger. By default, it will use the type where the annotation is placed.
*/
String topic() default "";
-} \ No newline at end of file
+}
diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java
index d3164047..9490acb8 100644
--- a/src/core/lombok/extern/log4j/Log4j.java
+++ b/src/core/lombok/extern/log4j/Log4j.java
@@ -63,4 +63,4 @@ public @interface Log4j {
* Sets the category of the constructed Logger. By default, it will use the type where the annotation is placed.
*/
String topic() default "";
-} \ No newline at end of file
+}
diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java
index 0267d98c..43125e6b 100644
--- a/src/core/lombok/extern/log4j/Log4j2.java
+++ b/src/core/lombok/extern/log4j/Log4j2.java
@@ -63,4 +63,4 @@ public @interface Log4j2 {
* Sets the category of the constructed Logger. By default, it will use the type where the annotation is placed.
*/
String topic() default "";
-} \ No newline at end of file
+}
diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java
index 5d6e7d8c..04df6498 100644
--- a/src/core/lombok/extern/slf4j/Slf4j.java
+++ b/src/core/lombok/extern/slf4j/Slf4j.java
@@ -25,6 +25,7 @@ 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>
@@ -62,3 +63,4 @@ public @interface Slf4j {
*/
String topic() default "";
}
+
diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java
index 0f2efe26..8a311c79 100644
--- a/src/core/lombok/extern/slf4j/XSlf4j.java
+++ b/src/core/lombok/extern/slf4j/XSlf4j.java
@@ -25,6 +25,7 @@ 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>
diff --git a/src/core/lombok/javac/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java
index 4306b5f2..0905170b 100644
--- a/src/core/lombok/javac/HandlerLibrary.java
+++ b/src/core/lombok/javac/HandlerLibrary.java
@@ -40,6 +40,7 @@ import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.core.TypeResolver;
import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
+import lombok.core.configuration.ConfigurationKeysLoader;
import lombok.javac.handlers.JavacHandlerUtil;
import com.sun.tools.javac.tree.JCTree;
@@ -63,6 +64,7 @@ public class HandlerLibrary {
* You probably want to use {@link #load(Messager)} instead.
*/
public HandlerLibrary(Messager messager) {
+ ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys();
this.messager = messager;
}
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 31bdc3a6..4e553063 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -22,6 +22,7 @@
package lombok.javac;
import java.lang.reflect.Field;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -88,7 +89,16 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
this.javacTypes = JavacTypes.instance(context);
clearChanged();
}
-
+
+ @Override public URI getAbsoluteFileLocation() {
+ try {
+ JCCompilationUnit cu = (JCCompilationUnit) top().get();
+ return cu.sourcefile.toUri();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
private static String sourceName(JCCompilationUnit cu) {
return cu.sourcefile == null ? null : cu.sourcefile.toString();
}
@@ -385,7 +395,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
}
}
- private void removeFromDeferredDiagnostics(int startPos, int endPos) {
+ public void removeFromDeferredDiagnostics(int startPos, int endPos) {
JCCompilationUnit self = (JCCompilationUnit) top().get();
new CompilerMessageSuppressor(getContext()).removeAllBetween(self.sourcefile, startPos, endPos);
}
diff --git a/src/core/lombok/javac/handlers/HandleAccessors.java b/src/core/lombok/javac/handlers/HandleAccessors.java
index e2489bda..46fe1cd2 100644
--- a/src/core/lombok/javac/handlers/HandleAccessors.java
+++ b/src/core/lombok/javac/handlers/HandleAccessors.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,12 +21,14 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.experimental.Accessors;
@@ -39,6 +41,9 @@ public class HandleAccessors extends JavacAnnotationHandler<Accessors> {
@Override public void handle(AnnotationValues<Accessors> annotation, JCAnnotation ast, JavacNode annotationNode) {
// Accessors itself is handled by HandleGetter/Setter; this is just to ensure that the annotation is removed
// from the AST when delomboking.
+
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.ACCESSORS_FLAG_USAGE, "@Accessors");
+
deleteAnnotationIfNeccessary(annotationNode, Accessors.class);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index 1fc2941e..b382395e 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -46,10 +46,10 @@ import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
-import lombok.core.TransformationsUtil;
import lombok.experimental.Builder;
import lombok.experimental.NonFinal;
import lombok.javac.JavacAnnotationHandler;
@@ -65,6 +65,8 @@ import static lombok.javac.JavacTreeMaker.TypeTag.*;
@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
public class HandleBuilder extends JavacAnnotationHandler<Builder> {
@Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
+
Builder builderInstance = annotation.getInstance();
String builderMethodName = builderInstance.builderMethodName();
String buildMethodName = builderInstance.buildMethodName();
@@ -307,7 +309,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
boolean isBoolean = isBoolean(fieldNode);
- String setterName = fluent ? fieldNode.getName() : TransformationsUtil.toSetterName(null, fieldNode.getName(), isBoolean);
+ String setterName = fluent ? fieldNode.getName() : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean);
JavacTreeMaker maker = builderType.getTreeMaker();
return HandleSetter.createSetter(Flags.PUBLIC, fieldNode, maker, setterName, chain, source, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java
index 12e7227d..4aa61764 100644
--- a/src/core/lombok/javac/handlers/HandleCleanup.java
+++ b/src/core/lombok/javac/handlers/HandleCleanup.java
@@ -21,9 +21,11 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import static lombok.javac.Javac.*;
import lombok.Cleanup;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.delombok.LombokOptionsFactory;
@@ -61,6 +63,8 @@ import com.sun.tools.javac.util.Name;
@ProviderFor(JavacAnnotationHandler.class)
public class HandleCleanup extends JavacAnnotationHandler<Cleanup> {
@Override public void handle(AnnotationValues<Cleanup> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup");
+
if (inNetbeansEditor(annotationNode)) return;
deleteAnnotationIfNeccessary(annotationNode, Cleanup.class);
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index b8762ed8..adfa253f 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -21,13 +21,14 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
+import lombok.ConfigurationKeys;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.core.AST.Kind;
import lombok.delombok.LombokOptionsFactory;
import lombok.experimental.Builder;
@@ -59,6 +60,8 @@ public class HandleConstructor {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleNoArgsConstructor extends JavacAnnotationHandler<NoArgsConstructor> {
@Override public void handle(AnnotationValues<NoArgsConstructor> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.NO_ARGS_CONSTRUCTOR_FLAG_USAGE, "@NoArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
deleteAnnotationIfNeccessary(annotationNode, NoArgsConstructor.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
@@ -76,6 +79,8 @@ public class HandleConstructor {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleRequiredArgsConstructor extends JavacAnnotationHandler<RequiredArgsConstructor> {
@Override public void handle(AnnotationValues<RequiredArgsConstructor> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.REQUIRED_ARGS_CONSTRUCTOR_FLAG_USAGE, "@RequiredArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
deleteAnnotationIfNeccessary(annotationNode, RequiredArgsConstructor.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
@@ -102,7 +107,7 @@ public class HandleConstructor {
//Skip static fields.
if ((fieldFlags & Flags.STATIC) != 0) continue;
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
- boolean isNonNull = !findAnnotations(child, TransformationsUtil.NON_NULL_PATTERN).isEmpty();
+ boolean isNonNull = !findAnnotations(child, NON_NULL_PATTERN).isEmpty();
if ((isFinal || isNonNull) && fieldDecl.init == null) fields.append(child);
}
return fields.toList();
@@ -111,6 +116,8 @@ public class HandleConstructor {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleAllArgsConstructor extends JavacAnnotationHandler<AllArgsConstructor> {
@Override public void handle(AnnotationValues<AllArgsConstructor> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.ALL_ARGS_CONSTRUCTOR_FLAG_USAGE, "@AllArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
+
deleteAnnotationIfNeccessary(annotationNode, AllArgsConstructor.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode typeNode = annotationNode.up();
@@ -234,8 +241,8 @@ public class HandleConstructor {
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
Name fieldName = removePrefixFromField(fieldNode);
Name rawName = field.name;
- List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN);
+ List<JCAnnotation> nonNulls = findAnnotations(fieldNode, NON_NULL_PATTERN);
+ List<JCAnnotation> nullables = findAnnotations(fieldNode, NULLABLE_PATTERN);
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, nonNulls.appendList(nullables)), fieldName, field.vartype, null);
params.append(param);
@@ -297,8 +304,8 @@ public class HandleConstructor {
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
Name fieldName = removePrefixFromField(fieldNode);
JCExpression pType = cloneType(maker, field.vartype, source, typeNode.getContext());
- List<JCAnnotation> nonNulls = findAnnotations(fieldNode, TransformationsUtil.NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(fieldNode, TransformationsUtil.NULLABLE_PATTERN);
+ List<JCAnnotation> nonNulls = findAnnotations(fieldNode, NON_NULL_PATTERN);
+ List<JCAnnotation> nullables = findAnnotations(fieldNode, NULLABLE_PATTERN);
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, nonNulls.appendList(nullables)), fieldName, pType, null);
params.append(param);
diff --git a/src/core/lombok/javac/handlers/HandleData.java b/src/core/lombok/javac/handlers/HandleData.java
index 858fb543..9ecf8754 100644
--- a/src/core/lombok/javac/handlers/HandleData.java
+++ b/src/core/lombok/javac/handlers/HandleData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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,8 +21,10 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Data;
import lombok.core.AnnotationValues;
import lombok.javac.JavacAnnotationHandler;
@@ -39,6 +41,8 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation;
@ProviderFor(JavacAnnotationHandler.class)
public class HandleData extends JavacAnnotationHandler<Data> {
@Override public void handle(AnnotationValues<Data> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.DATA_FLAG_USAGE, "@Data");
+
deleteAnnotationIfNeccessary(annotationNode, Data.class);
JavacNode typeNode = annotationNode.up();
boolean notAClass = !isClass(typeNode);
diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java
index 5e603777..ec6ea20c 100644
--- a/src/core/lombok/javac/handlers/HandleDelegate.java
+++ b/src/core/lombok/javac/handlers/HandleDelegate.java
@@ -21,6 +21,7 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import static com.sun.tools.javac.code.Flags.*;
@@ -40,6 +41,7 @@ import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
+import lombok.ConfigurationKeys;
import lombok.Delegate;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
@@ -97,6 +99,8 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
private static final String LEGALITY_OF_DELEGATE = "@Delegate is legal only on instance fields or no-argument instance methods.";
@Override public void handle(AnnotationValues<Delegate> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.DELEGATE_FLAG_USAGE, "@Delegate");
+
deleteAnnotationIfNeccessary(annotationNode, Delegate.class);
Type delegateType;
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index 05c07c7a..2c998f48 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -21,6 +21,7 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
@@ -28,6 +29,7 @@ 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.AnnotationValues;
@@ -85,6 +87,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
}
@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());
diff --git a/src/core/lombok/javac/handlers/HandleExtensionMethod.java b/src/core/lombok/javac/handlers/HandleExtensionMethod.java
index 3aee2f51..345c5f8e 100644
--- a/src/core/lombok/javac/handlers/HandleExtensionMethod.java
+++ b/src/core/lombok/javac/handlers/HandleExtensionMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,6 +22,7 @@
package lombok.javac.handlers;
import static com.sun.tools.javac.code.Flags.*;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import static lombok.javac.handlers.JavacResolver.*;
@@ -30,6 +31,7 @@ import java.util.List;
import javax.lang.model.element.ElementKind;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.experimental.ExtensionMethod;
@@ -64,6 +66,8 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMethod> {
@Override
public void handle(final AnnotationValues<ExtensionMethod> annotation, final JCAnnotation source, final JavacNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.EXTENSION_METHOD_FLAG_USAGE, "@ExtensionMethod");
+
deleteAnnotationIfNeccessary(annotationNode, ExtensionMethod.class);
JavacNode typeNode = annotationNode.up();
boolean isClassOrEnum = isClassOrEnum(typeNode);
diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
index 038f3e3f..335ab1fe 100644
--- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,8 +21,10 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -96,6 +98,8 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
}
@Override public void handle(AnnotationValues<FieldDefaults> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
deleteAnnotationIfNeccessary(annotationNode, FieldDefaults.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode node = annotationNode.up();
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 6b055193..48a13bde 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -21,6 +21,7 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import static lombok.javac.JavacTreeMaker.TypeTag.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
@@ -31,11 +32,11 @@ import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Delegate;
import lombok.Getter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
@@ -127,6 +128,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
}
@Override public void handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.GETTER_FLAG_USAGE, "@Getter");
+
Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
deleteAnnotationIfNeccessary(annotationNode, Getter.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
@@ -239,8 +242,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;
- List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ List<JCAnnotation> nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ List<JCAnnotation> nullables = findAnnotations(field, NULLABLE_PATTERN);
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java
index 36f3bbb5..ee7268f7 100644
--- a/src/core/lombok/javac/handlers/HandleLog.java
+++ b/src/core/lombok/javac/handlers/HandleLog.java
@@ -21,10 +21,12 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.lang.annotation.Annotation;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
@@ -48,24 +50,28 @@ public class HandleLog {
throw new UnsupportedOperationException();
}
- public static void processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode, String loggerCategory) {
+ public static void processAnnotation(LoggingFramework framework, AnnotationValues<?> annotation, JavacNode annotationNode, String loggerTopic) {
deleteAnnotationIfNeccessary(annotationNode, framework.getAnnotationClass());
JavacNode typeNode = annotationNode.up();
switch (typeNode.getKind()) {
case TYPE:
- if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE)!= 0) {
+ String logFieldName = annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_NAME);
+ if (logFieldName == null) logFieldName = "log";
+
+ boolean useStatic = !Boolean.FALSE.equals(annotationNode.getAst().readConfiguration(ConfigurationKeys.LOG_ANY_FIELD_IS_STATIC));
+
+ if ((((JCClassDecl)typeNode.get()).mods.flags & Flags.INTERFACE) != 0) {
annotationNode.addError("@Log is legal only on classes and enums.");
return;
}
-
- if (fieldExists("log", typeNode)!= MemberExistsResult.NOT_EXISTS) {
- annotationNode.addWarning("Field 'log' already exists.");
+ if (fieldExists(logFieldName, typeNode) != MemberExistsResult.NOT_EXISTS) {
+ annotationNode.addWarning("Field '" + logFieldName + "' already exists.");
return;
}
JCFieldAccess loggingType = selfType(typeNode);
- createField(framework, typeNode, loggingType, annotationNode.get(), loggerCategory);
+ createField(framework, typeNode, loggingType, annotationNode.get(), logFieldName, useStatic, loggerTopic);
break;
default:
annotationNode.addError("@Log is legal only on types.");
@@ -79,7 +85,7 @@ public class HandleLog {
return maker.Select(maker.Ident(name), typeNode.toName("class"));
}
- public static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String loggerCategory) {
+ private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, String loggerTopic) {
JavacTreeMaker maker = typeNode.getTreeMaker();
// private static final <loggerType> log = <factoryMethod>(<parameter>);
@@ -87,17 +93,17 @@ public class HandleLog {
JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName());
JCExpression loggerName;
- if (loggerCategory == null || loggerCategory.trim().length() == 0) {
+ if (loggerTopic == null || loggerTopic.trim().length() == 0) {
loggerName = framework.createFactoryParameter(typeNode, loggingType);
} else {
- loggerName = maker.Literal(loggerCategory);
+ loggerName = maker.Literal(loggerTopic);
}
JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName));
JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef(
- maker.Modifiers(Flags.PRIVATE | Flags.FINAL | Flags.STATIC),
- typeNode.toName("log"), loggerType, factoryMethodCall), source, typeNode.getContext());
+ maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)),
+ typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext());
injectFieldSuppressWarnings(typeNode, fieldDecl);
return true;
@@ -109,6 +115,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleCommonsLog extends JavacAnnotationHandler<lombok.extern.apachecommons.CommonsLog> {
@Override public void handle(AnnotationValues<lombok.extern.apachecommons.CommonsLog> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.COMMONS, annotation, annotationNode, annotation.getInstance().topic());
}
}
@@ -119,6 +126,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleJulLog extends JavacAnnotationHandler<lombok.extern.java.Log> {
@Override public void handle(AnnotationValues<lombok.extern.java.Log> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.JUL, annotation, annotationNode, annotation.getInstance().topic());
}
}
@@ -129,6 +137,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleLog4jLog extends JavacAnnotationHandler<lombok.extern.log4j.Log4j> {
@Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.LOG4J, annotation, annotationNode, annotation.getInstance().topic());
}
}
@@ -139,6 +148,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleLog4j2Log extends JavacAnnotationHandler<lombok.extern.log4j.Log4j2> {
@Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j2> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.LOG4J2, annotation, annotationNode, annotation.getInstance().topic());
}
}
@@ -149,6 +159,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleSlf4jLog extends JavacAnnotationHandler<lombok.extern.slf4j.Slf4j> {
@Override public void handle(AnnotationValues<lombok.extern.slf4j.Slf4j> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.SLF4J, annotation, annotationNode, annotation.getInstance().topic());
}
}
@@ -159,6 +170,7 @@ public class HandleLog {
@ProviderFor(JavacAnnotationHandler.class)
public static class HandleXSlf4jLog extends JavacAnnotationHandler<lombok.extern.slf4j.XSlf4j> {
@Override public void handle(AnnotationValues<lombok.extern.slf4j.XSlf4j> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log");
processAnnotation(LoggingFramework.XSLF4J, annotation, annotationNode, annotation.getInstance().topic());
}
}
diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java
index 4cab48cf..172e70b3 100644
--- a/src/core/lombok/javac/handlers/HandleNonNull.java
+++ b/src/core/lombok/javac/handlers/HandleNonNull.java
@@ -21,6 +21,7 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
@@ -42,6 +43,7 @@ import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
+import lombok.ConfigurationKeys;
import lombok.NonNull;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -55,6 +57,8 @@ import static lombok.javac.JavacTreeMaker.TreeTag.*;
@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first.
public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
@Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
+
if (annotationNode.up().getKind() == Kind.FIELD) {
// This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc),
// but in that case those handlers will take care of it. However, we DO check if the annotation is applied to
diff --git a/src/core/lombok/javac/handlers/HandlePrintAST.java b/src/core/lombok/javac/handlers/HandlePrintAST.java
index 7b6d942c..2c229f2b 100644
--- a/src/core/lombok/javac/handlers/HandlePrintAST.java
+++ b/src/core/lombok/javac/handlers/HandlePrintAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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
@@ -52,6 +52,16 @@ public class HandlePrintAST extends JavacAnnotationHandler<PrintAST> {
Lombok.sneakyThrow(e);
}
- annotationNode.up().traverse(new JavacASTVisitor.Printer(annotation.getInstance().printContent(), stream));
+ try {
+ annotationNode.up().traverse(new JavacASTVisitor.Printer(annotation.getInstance().printContent(), stream));
+ } finally {
+ if (stream != System.out) {
+ try {
+ stream.close();
+ } catch (Exception e) {
+ Lombok.sneakyThrow(e);
+ }
+ }
+ }
}
}
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index ae8741de..fbc9ef46 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -22,15 +22,16 @@
package lombok.javac.handlers;
import static lombok.javac.Javac.*;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.Collection;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Setter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
@@ -118,6 +119,8 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
}
@Override public void handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SETTER_FLAG_USAGE, "@Setter");
+
Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
deleteAnnotationIfNeccessary(annotationNode, Setter.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
@@ -205,8 +208,8 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
JCAssign assign = treeMaker.Assign(fieldRef, treeMaker.Ident(fieldDecl.name));
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
- List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ List<JCAnnotation> nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ List<JCAnnotation> nullables = findAnnotations(field, NULLABLE_PATTERN);
Name methodName = field.toName(setterName);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables);
diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
index aa0c3c7e..ffe37a4c 100644
--- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java
+++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
@@ -21,12 +21,14 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import lombok.ConfigurationKeys;
import lombok.SneakyThrows;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
@@ -57,6 +59,8 @@ import lombok.javac.Javac;
@HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it.
public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> {
@Override public void handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SNEAKY_THROWS_FLAG_USAGE, "@SneakyThrows");
+
deleteAnnotationIfNeccessary(annotationNode, SneakyThrows.class);
Collection<String> exceptionNames = annotation.getRawExpressions("value");
if (exceptionNames.isEmpty()) {
diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java
index 13b8ffcb..fb6678e6 100644
--- a/src/core/lombok/javac/handlers/HandleSynchronized.java
+++ b/src/core/lombok/javac/handlers/HandleSynchronized.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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,8 +21,10 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
+import lombok.ConfigurationKeys;
import lombok.Synchronized;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
@@ -54,6 +56,8 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> {
private static final String STATIC_LOCK_NAME = "$LOCK";
@Override public void handle(AnnotationValues<Synchronized> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.SYNCHRONIZED_FLAG_USAGE, "@Synchronized");
+
if (inNetbeansEditor(annotationNode)) return;
deleteAnnotationIfNeccessary(annotationNode, Synchronized.class);
diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java
index f1edae0c..743e7b26 100644
--- a/src/core/lombok/javac/handlers/HandleToString.java
+++ b/src/core/lombok/javac/handlers/HandleToString.java
@@ -21,11 +21,13 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import static lombok.javac.Javac.*;
import java.util.Collection;
+import lombok.ConfigurationKeys;
import lombok.ToString;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
@@ -71,6 +73,8 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
}
@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();
@@ -91,9 +95,14 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
}
- FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
+ 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, ann.includeFieldNames(), callSuper, true, fieldAccess);
+ generateToString(typeNode, annotationNode, excludes, includes, includeFieldNames, callSuper, true, fieldAccess);
}
public void generateToStringForType(JavacNode typeNode, JavacNode errorNode) {
@@ -105,7 +114,8 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
boolean includeFieldNames = true;
try {
- includeFieldNames = ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue();
+ Boolean configuration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
+ includeFieldNames = configuration != null ? configuration : ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue();
} catch (Exception ignore) {}
generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, FieldAccess.GETTER);
}
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
index 8dc8e865..75464195 100644
--- a/src/core/lombok/javac/handlers/HandleVal.java
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-2014 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,8 +21,9 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
-
+import lombok.ConfigurationKeys;
import lombok.val;
import lombok.core.HandlerPriority;
import lombok.javac.JavacASTAdapter;
@@ -55,6 +56,8 @@ public class HandleVal extends JavacASTAdapter {
if (!typeMatches(val.class, localNode, local.vartype)) return;
+ handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val");
+
JCTree parentRaw = localNode.directUp().get();
if (parentRaw instanceof JCForLoop) {
localNode.addError("'val' is not allowed in old-style for loops");
diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java
index 15fb4781..90f6a98d 100644
--- a/src/core/lombok/javac/handlers/HandleValue.java
+++ b/src/core/lombok/javac/handlers/HandleValue.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 The Project Lombok Authors.
+ * Copyright (C) 2012-2014 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,11 +21,13 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.lang.annotation.Annotation;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.experimental.NonFinal;
@@ -50,6 +52,9 @@ public class HandleValue extends JavacAnnotationHandler<Value> {
@Override public void handle(AnnotationValues<Value> annotation, JCAnnotation ast, JavacNode annotationNode) {
@SuppressWarnings("deprecation")
Class<? extends Annotation> oldExperimentalValue = lombok.experimental.Value.class;
+
+ handleFlagUsage(annotationNode, ConfigurationKeys.VALUE_FLAG_USAGE, "@Value");
+
deleteAnnotationIfNeccessary(annotationNode, Value.class, oldExperimentalValue);
JavacNode typeNode = annotationNode.up();
boolean notAClass = !isClass(typeNode);
diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java
index f6277bc3..7b55b671 100644
--- a/src/core/lombok/javac/handlers/HandleWither.java
+++ b/src/core/lombok/javac/handlers/HandleWither.java
@@ -21,15 +21,16 @@
*/
package lombok.javac.handlers;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.Collection;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
-import lombok.core.TransformationsUtil;
import lombok.experimental.Wither;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
@@ -119,6 +120,8 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
}
@Override public void handle(AnnotationValues<Wither> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.WITHER_FLAG_USAGE, "@Wither");
+
Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
deleteAnnotationIfNeccessary(annotationNode, Wither.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
@@ -208,8 +211,8 @@ public class HandleWither extends JavacAnnotationHandler<Wither> {
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
- List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
- List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
+ List<JCAnnotation> nonNulls = findAnnotations(field, NON_NULL_PATTERN);
+ List<JCAnnotation> nullables = findAnnotations(field, NULLABLE_PATTERN);
Name methodName = field.toName(witherName);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(nonNulls).appendList(nullables);
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index bc4dda8e..37164a6c 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -21,7 +21,7 @@
*/
package lombok.javac.handlers;
-import static lombok.core.TransformationsUtil.INVALID_ON_BUILDERS;
+import static lombok.core.handlers.HandlerUtil.*;
import static lombok.javac.Javac.*;
import java.lang.annotation.Annotation;
@@ -29,6 +29,7 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
@@ -36,12 +37,13 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
import lombok.Data;
import lombok.Getter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.AnnotationValues.AnnotationValue;
-import lombok.core.TransformationsUtil;
+import lombok.core.handlers.HandlerUtil;
import lombok.core.TypeResolver;
import lombok.delombok.LombokOptionsFactory;
import lombok.experimental.Accessors;
@@ -391,7 +393,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllGetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static java.util.List<String> toAllGetterNames(JavacNode field) {
- return TransformationsUtil.toAllGetterNames(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toAllGetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -400,7 +402,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toGetterName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toGetterName(JavacNode field) {
- return TransformationsUtil.toGetterName(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toGetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -408,7 +410,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static java.util.List<String> toAllSetterNames(JavacNode field) {
- return TransformationsUtil.toAllSetterNames(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toAllSetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -417,7 +419,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toSetterName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toSetterName(JavacNode field) {
- return TransformationsUtil.toSetterName(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toSetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -425,7 +427,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toAllWitherNames(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static java.util.List<String> toAllWitherNames(JavacNode field) {
- return TransformationsUtil.toAllWitherNames(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toAllWitherNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -434,7 +436,7 @@ public class JavacHandlerUtil {
* Convenient wrapper around {@link TransformationsUtil#toWitherName(lombok.core.AnnotationValues, CharSequence, boolean)}.
*/
public static String toWitherName(JavacNode field) {
- return TransformationsUtil.toWitherName(getAccessorsForField(field), field.getName(), isBoolean(field));
+ return HandlerUtil.toWitherName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field));
}
/**
@@ -446,9 +448,7 @@ public class JavacHandlerUtil {
AnnotationValues<Accessors> accessors = JavacHandlerUtil.getAccessorsForField(field);
- boolean forced = (accessors.getActualExpression("chain") != null);
- Accessors instance = accessors.getInstance();
- return instance.chain() || (instance.fluent() && !forced);
+ return HandlerUtil.shouldReturnThis0(accessors, field.getAst());
}
public static JCExpression cloneSelfType(JavacNode field) {
@@ -481,10 +481,11 @@ public class JavacHandlerUtil {
}
public static Name removePrefixFromField(JavacNode field) {
- String[] prefixes = null;
+ java.util.List<String> prefixes = null;
for (JavacNode node : field.down()) {
if (annotationTypeMatches(Accessors.class, node)) {
- prefixes = createAnnotation(Accessors.class, node).getInstance().prefix();
+ AnnotationValues<Accessors> ann = createAnnotation(Accessors.class, node);
+ if (ann.isExplicit("prefix")) prefixes = Arrays.asList(ann.getInstance().prefix());
break;
}
}
@@ -495,7 +496,8 @@ public class JavacHandlerUtil {
while (current != null) {
for (JavacNode node : current.down()) {
if (annotationTypeMatches(Accessors.class, node)) {
- prefixes = createAnnotation(Accessors.class, node).getInstance().prefix();
+ AnnotationValues<Accessors> ann = createAnnotation(Accessors.class, node);
+ if (ann.isExplicit("prefix")) prefixes = Arrays.asList(ann.getInstance().prefix());
break outer;
}
}
@@ -503,8 +505,10 @@ public class JavacHandlerUtil {
}
}
- if (prefixes != null && prefixes.length > 0) {
- CharSequence newName = TransformationsUtil.removePrefix(field.getName(), prefixes);
+ if (prefixes == null) prefixes = field.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_PREFIX);
+
+ if (!prefixes.isEmpty()) {
+ CharSequence newName = removePrefix(field.getName(), prefixes);
if (newName != null) return field.toName(newName.toString());
}
@@ -1073,11 +1077,20 @@ public class JavacHandlerUtil {
return problematic.toList();
}
- static List<JCAnnotation> unboxAndRemoveAnnotationParameter(JCAnnotation ast, String parameterName, String errorName, JavacNode errorNode) {
+ static List<JCAnnotation> unboxAndRemoveAnnotationParameter(JCAnnotation ast, String parameterName, String errorName, JavacNode annotationNode) {
ListBuffer<JCExpression> params = new ListBuffer<JCExpression>();
ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>();
- errorNode.removeDeferredErrors();
+ try {
+ for (JCExpression arg : ast.args) {
+ String argName = "value";
+ if (arg instanceof JCAssign) {
+ JCAssign as = (JCAssign) arg;
+ argName = as.lhs.toString();
+ }
+ if (!argName.equals(parameterName)) continue;
+ }
+ } catch (Exception ignore) {}
outer:
for (JCExpression param : ast.args) {
@@ -1097,11 +1110,14 @@ public class JavacHandlerUtil {
continue outer;
}
+ int endPos = Javac.getEndPosition(param.pos(), (JCCompilationUnit) annotationNode.top().get());
+ annotationNode.getAst().removeFromDeferredDiagnostics(param.pos, endPos);
+
if (valueOfParam instanceof JCAnnotation) {
String dummyAnnotationName = ((JCAnnotation) valueOfParam).annotationType.toString();
dummyAnnotationName = dummyAnnotationName.replace("_", "").replace("$", "").replace("x", "").replace("X", "");
if (dummyAnnotationName.length() > 0) {
- errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
+ annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
continue outer;
}
for (JCExpression expr : ((JCAnnotation) valueOfParam).args) {
@@ -1110,7 +1126,7 @@ public class JavacHandlerUtil {
if ("value".equals(id.name.toString())) {
expr = ((JCAssign) expr).rhs;
} else {
- errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
+ annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
continue outer;
}
}
@@ -1122,12 +1138,12 @@ public class JavacHandlerUtil {
if (expr2 instanceof JCAnnotation) {
result.append((JCAnnotation) expr2);
} else {
- errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
+ annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
continue outer;
}
}
} else {
- errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
+ annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
continue outer;
}
}
@@ -1135,7 +1151,7 @@ public class JavacHandlerUtil {
if (valueOfParam instanceof JCNewArray && ((JCNewArray) valueOfParam).elems.isEmpty()) {
// Then we just remove it and move on (it's onMethod={} for example).
} else {
- errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
+ annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))");
}
}
}
diff --git a/src/core/lombok/val.java b/src/core/lombok/val.java
index 7e495c8d..cd8652d6 100644
--- a/src/core/lombok/val.java
+++ b/src/core/lombok/val.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-2013 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
@@ -30,4 +30,5 @@ package lombok;
* <p>
* Complete documentation is found at <a href="http://projectlombok.org/features/val.html">the project lombok features page for &#64;val</a>.
*/
-public @interface val {}
+public @interface val {
+}
diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java
index 9309e05d..1657d2a1 100644
--- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java
+++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java
@@ -632,8 +632,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
*/
public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
Object dc = getDocComments(tree);
- if (dc instanceof Map) this.docComments = (Map) dc;
- else if (dc instanceof DocCommentTable) this.docTable = (DocCommentTable) dc;
+ loadDocCommentsTable(dc);
printDocComment(tree);
if (tree.pid != null) {
consumeComments(tree.pos, tree);
@@ -668,6 +667,12 @@ public class PrettyCommentsPrinter extends JCTree.Visitor {
}
}
// where
+ @SuppressWarnings("unchecked")
+ private void loadDocCommentsTable(Object dc) {
+ if (dc instanceof Map<?, ?>) this.docComments = (Map) dc;
+ else if (dc instanceof DocCommentTable) this.docTable = (DocCommentTable) dc;
+ }
+
boolean isUsed(final Symbol t, JCTree cdef) {
class UsedVisitor extends TreeScanner {
public void scan(JCTree tree) {
diff --git a/test/configuration/resource/configurationRoot/d1/d11/d111/f1.txt b/test/configuration/resource/configurationRoot/d1/d11/d111/f1.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/d1/d11/d111/f1.txt
diff --git a/test/configuration/resource/configurationRoot/d1/d11/d111/lombok.config b/test/configuration/resource/configurationRoot/d1/d11/d111/lombok.config
new file mode 100644
index 00000000..bcea2a72
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/d1/d11/d111/lombok.config
@@ -0,0 +1,2 @@
+clear lombok.Accessors.chain
+lombok.Accessors.prefix += m_ \ No newline at end of file
diff --git a/test/configuration/resource/configurationRoot/d1/d11/lombok.config b/test/configuration/resource/configurationRoot/d1/d11/lombok.config
new file mode 100644
index 00000000..fcdc4823
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/d1/d11/lombok.config
@@ -0,0 +1,5 @@
+stop-bubbling=true
+
+lombok.Accessors.chain = false
+lombok.Accessors.flagUsage = ERROR
+lombok.Accessors.prefix += f \ No newline at end of file
diff --git a/test/configuration/resource/configurationRoot/d1/d12/lombok.config b/test/configuration/resource/configurationRoot/d1/d12/lombok.config
new file mode 100644
index 00000000..a18a4756
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/d1/d12/lombok.config
@@ -0,0 +1,3 @@
+stop-bubbling=true
+
+lombok.Accessors.chain = true \ No newline at end of file
diff --git a/test/configuration/resource/configurationRoot/d1/lombok.config b/test/configuration/resource/configurationRoot/d1/lombok.config
new file mode 100644
index 00000000..dec482e6
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/d1/lombok.config
@@ -0,0 +1,3 @@
+stop-bubbling=true
+# this file shouldn't be read
+no error expected \ No newline at end of file
diff --git a/test/configuration/resource/configurationRoot/err.txt b/test/configuration/resource/configurationRoot/err.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/err.txt
diff --git a/test/configuration/resource/configurationRoot/out.txt b/test/configuration/resource/configurationRoot/out.txt
new file mode 100644
index 00000000..54e91094
--- /dev/null
+++ b/test/configuration/resource/configurationRoot/out.txt
@@ -0,0 +1,90 @@
+Configuration for 'BASE/d1/d11'.
+
+# Emit a warning or error if @Accessors is used.
+lombok.Accessors.flagUsage = ERROR
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.flagUsage' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 3: lombok.Accessors.flagUsage = ERROR
+
+# Generate setters that return 'this' instead of 'void'.
+lombok.Accessors.chain = false
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.chain' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 2: lombok.Accessors.chain = false
+
+# Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters.
+lombok.Accessors.prefix += f
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.prefix' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 4: lombok.Accessors.prefix += f
+
+# Use this name for the generated logger fields (default: 'log')
+clear lombok.log.fieldName
+
+
+Configuration for:
+- BASE/d1/d11/d111
+- BASE/d1/d11/d111/f1.txt
+
+# Emit a warning or error if @Accessors is used.
+lombok.Accessors.flagUsage = ERROR
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.flagUsage' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 3: lombok.Accessors.flagUsage = ERROR
+#
+# BASE/d1/d11/d111/lombok.config:
+# <'lombok.Accessors.flagUsage' not mentioned>
+
+# Generate setters that return 'this' instead of 'void'.
+clear lombok.Accessors.chain
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.chain' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 2: lombok.Accessors.chain = false
+#
+# BASE/d1/d11/d111/lombok.config:
+# 1: clear lombok.Accessors.chain
+
+# Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters.
+lombok.Accessors.prefix += f
+lombok.Accessors.prefix += m_
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.prefix' not mentioned>
+#
+# BASE/d1/d11/lombok.config:
+# 4: lombok.Accessors.prefix += f
+#
+# BASE/d1/d11/d111/lombok.config:
+# 2: lombok.Accessors.prefix += m_
+
+# Use this name for the generated logger fields (default: 'log')
+clear lombok.log.fieldName
+
+
+Configuration for 'BASE/d1/d12'.
+
+# Emit a warning or error if @Accessors is used.
+clear lombok.Accessors.flagUsage
+
+# Generate setters that return 'this' instead of 'void'.
+lombok.Accessors.chain = true
+# BASE/d1/lombok.config:
+# <'lombok.Accessors.chain' not mentioned>
+#
+# BASE/d1/d12/lombok.config:
+# 2: lombok.Accessors.chain = true
+
+# Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters.
+clear lombok.Accessors.prefix
+
+# Use this name for the generated logger fields (default: 'log')
+clear lombok.log.fieldName \ No newline at end of file
diff --git a/test/configuration/src/lombok/core/configuration/RunConfigurationTests.java b/test/configuration/src/lombok/core/configuration/RunConfigurationTests.java
new file mode 100644
index 00000000..40e0a7f4
--- /dev/null
+++ b/test/configuration/src/lombok/core/configuration/RunConfigurationTests.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({TestConfiguration.class})
+public class RunConfigurationTests {
+}
diff --git a/test/configuration/src/lombok/core/configuration/TestConfiguration.java b/test/configuration/src/lombok/core/configuration/TestConfiguration.java
new file mode 100644
index 00000000..d2599334
--- /dev/null
+++ b/test/configuration/src/lombok/core/configuration/TestConfiguration.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.core.configuration;
+
+import static lombok.ConfigurationKeys.*;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+public class TestConfiguration {
+
+ @Test
+ public void testDisplayVerbose() throws Exception {
+
+ @SuppressWarnings("unchecked")
+ Collection<ConfigurationKey<?>> keys = Arrays.asList(ACCESSORS_FLAG_USAGE, ACCESSORS_CHAIN, ACCESSORS_PREFIX, LOG_ANY_FIELD_NAME);
+
+ String baseName = "test/configuration/resource/configurationRoot/";
+ File directory = new File(baseName);
+ String normalizedName = new File(directory.getAbsoluteFile().toURI().normalize()).toString().replace('\\', '/') + "/";
+ Collection<String> paths = Arrays.asList(normalizedName + "d1/d11", normalizedName + "d1/d12", normalizedName + "d1/d11/d111", normalizedName + "d1/d11/d111/f1.txt");
+
+ ByteArrayOutputStream rawOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream rawErr = new ByteArrayOutputStream();
+ PrintStream outStream = new PrintStream(rawOut);
+ PrintStream errStream = new PrintStream(rawErr);
+
+ int result = new ConfigurationApp().redirectOutput(outStream, errStream).display(keys, true, paths, true);
+
+ outStream.flush();
+ errStream.flush();
+
+ String out = new String(rawOut.toByteArray()).replace("\r\n", "\n").replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim();
+ String err = new String(rawErr.toByteArray()).replace("\r\n", "\n").replace('\\', '/').replaceAll(Pattern.quote(normalizedName) + "|" + Pattern.quote(baseName), "BASE/").trim();
+
+ checkContent(directory, out, "out");
+ checkContent(directory, err, "err");
+ assertEquals(0, result);
+ }
+
+ private void checkContent(File dir, String actual, String type) throws Exception {
+ String expected = fileToString(new File(dir, type + ".txt")).trim();
+ if (!expected.equals(actual)) {
+ System.out.printf("**** Expected %s:\n", type);
+ System.out.println(expected);
+ System.out.printf("**** Actual %s:\n", type);
+ System.out.println(actual);
+ System.out.println("****");
+ }
+ assertEquals(expected, actual);
+ }
+
+ static String fileToString(File configFile) throws Exception {
+ byte[] b = new byte[65536];
+ FileInputStream fis = new FileInputStream(configFile);
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ while (true) {
+ int r = fis.read(b);
+ if (r == -1) break;
+ out.write(b, 0, r);
+ }
+ return new String(out.toByteArray(), "UTF-8");
+ } finally {
+ fis.close();
+ }
+ }
+}
diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java
index e84aec0d..34f6cbf4 100644
--- a/test/core/src/lombok/AbstractRunTests.java
+++ b/test/core/src/lombok/AbstractRunTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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
@@ -25,21 +25,25 @@ import static org.junit.Assert.*;
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import org.junit.Assert;
+
+import lombok.core.AST;
+import lombok.core.LombokConfiguration;
+import lombok.core.LombokImmutableList;
+import lombok.core.configuration.ConfigurationKeysLoader;
+import lombok.core.configuration.ConfigurationResolver;
+import lombok.core.configuration.ConfigurationResolverFactory;
import lombok.javac.CapturingDiagnosticListener.CompilerMessage;
public abstract class AbstractRunTests {
@@ -50,39 +54,27 @@ public abstract class AbstractRunTests {
}
public boolean compareFile(DirectoryRunner.TestParams params, File file) throws Throwable {
+ ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys();
+ final LombokTestSource sourceDirectives = LombokTestSource.readDirectives(file);
+ if (sourceDirectives.isIgnore() || !sourceDirectives.versionWithinLimit(params.getVersion())) return false;
+
+ String fileName = file.getName();
+ LombokTestSource expected = LombokTestSource.read(params.getAfterDirectory(), params.getMessagesDirectory(), fileName);
+
+ if (expected.isIgnore() || !expected.versionWithinLimit(params.getVersion())) return false;
+
LinkedHashSet<CompilerMessage> messages = new LinkedHashSet<CompilerMessage>();
StringWriter writer = new StringWriter();
- transformCode(messages, writer, file);
- String expectedFile = readFile(params.getAfterDirectory(), file, false);
- List<CompilerMessageMatcher> expectedMessages = Collections.emptyList();
- if (params.getMessagesDirectory() != null) {
- try {
- InputStream in = new FileInputStream(new File(params.getMessagesDirectory(), file.getName() + ".messages"));
- try {
- expectedMessages = CompilerMessageMatcher.readAll(in);
- } finally {
- in.close();
- }
- } catch (FileNotFoundException ex) {
- // That's okay - then we expect no messages, and expectedMessages already gets initialized to the empty list.
- }
- }
- if (expectedFile != null) {
- StringReader r = new StringReader(expectedFile);
- BufferedReader br = new BufferedReader(r);
- String firstLine = br.readLine();
- if (firstLine != null && (firstLine.startsWith("//ignore") || params.shouldIgnoreBasedOnVersion(firstLine))) return false;
- }
+ LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() {
+ @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) {
+ return sourceDirectives.getConfiguration();
+ }
+ });
- compare(
- file.getName(),
- expectedFile,
- writer.toString(),
- expectedMessages,
- messages,
- params.printErrors());
+ transformCode(messages, writer, file);
+ compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives.isSkipCompareContent() || expected.isSkipCompareContent());
return true;
}
@@ -105,11 +97,6 @@ public abstract class AbstractRunTests {
return result.toString();
}
- private String readFile(File dir, File file, boolean messages) throws IOException {
- if (dir == null) return null;
- return readFile(new File(dir, file.getName() + (messages ? ".messages" : "")));
- }
-
private static File findPlaceToDumpActualFiles() {
String location = System.getProperty("lombok.tests.dump_actual_files");
if (location != null) {
@@ -141,17 +128,15 @@ public abstract class AbstractRunTests {
}
}
- private void compare(String name, String expectedFile, String actualFile, List<CompilerMessageMatcher> expectedMessages, LinkedHashSet<CompilerMessage> actualMessages, boolean printErrors) throws Throwable {
- if (expectedFile == null && expectedMessages.isEmpty()) expectedFile = "";
-
- if (expectedFile != null) try {
- compareContent(name, expectedFile, actualFile);
+ private void compare(String name, LombokTestSource expected, String actualFile, LinkedHashSet<CompilerMessage> actualMessages, boolean printErrors, boolean skipCompareContent) throws Throwable {
+ if (!skipCompareContent) try {
+ compareContent(name, expected.getContent(), actualFile);
} catch (Throwable e) {
if (printErrors) {
System.out.println("***** " + name + " *****");
System.out.println(e.getMessage());
System.out.println("**** Expected ******");
- System.out.println(expectedFile);
+ System.out.println(expected.getContent());
System.out.println("**** Actual ******");
System.out.println(actualFile);
if (actualMessages != null && !actualMessages.isEmpty()) {
@@ -169,13 +154,13 @@ public abstract class AbstractRunTests {
}
try {
- compareMessages(name, expectedMessages, actualMessages);
+ compareMessages(name, expected.getMessages(), actualMessages);
} catch (Throwable e) {
if (printErrors) {
System.out.println("***** " + name + " *****");
System.out.println(e.getMessage());
System.out.println("**** Expected ******");
- for (CompilerMessageMatcher expectedMessage : expectedMessages) {
+ for (CompilerMessageMatcher expectedMessage : expected.getMessages()) {
System.out.println(expectedMessage);
}
System.out.println("**** Actual ******");
@@ -191,7 +176,7 @@ public abstract class AbstractRunTests {
}
}
- private static void compareMessages(String name, List<CompilerMessageMatcher> expected, LinkedHashSet<CompilerMessage> actual) {
+ private static void compareMessages(String name, LombokImmutableList<CompilerMessageMatcher> expected, LinkedHashSet<CompilerMessage> actual) {
Iterator<CompilerMessageMatcher> expectedIterator = expected.iterator();
Iterator<CompilerMessage> actualIterator = actual.iterator();
@@ -215,15 +200,23 @@ public abstract class AbstractRunTests {
private static void compareContent(String name, String expectedFile, String actualFile) {
String[] expectedLines = expectedFile.split("(\\r?\\n)");
String[] actualLines = actualFile.split("(\\r?\\n)");
- if (expectedLines[0].startsWith("// Generated by delombok at ")) {
- expectedLines[0] = "";
+
+ for (int i = 0; i < expectedLines.length; i++) {
+ if (expectedLines[i].isEmpty() || expectedLines[i].startsWith("//")) expectedLines[i] = "";
+ else break;
}
- if (actualLines[0].startsWith("// Generated by delombok at ")) {
- actualLines[0] = "";
+ for (int i = 0; i < actualLines.length; i++) {
+ if (actualLines[i].isEmpty() || actualLines[i].startsWith("//")) actualLines[i] = "";
+ else break;
}
expectedLines = removeBlanks(expectedLines);
actualLines = removeBlanks(actualLines);
+
int size = Math.min(expectedLines.length, actualLines.length);
+ if (size == 0 && expectedLines.length + actualLines.length > 0) {
+ Assert.fail("Missing / empty expected file.");
+ }
+
for (int i = 0; i < size; i++) {
String expected = trimRight(expectedLines[i]);
String actual = trimRight(actualLines[i]);
diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java
index 5325c1e3..9062f523 100644
--- a/test/core/src/lombok/DirectoryRunner.java
+++ b/test/core/src/lombok/DirectoryRunner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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,16 +21,10 @@
*/
package lombok;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import lombok.eclipse.Eclipse;
import lombok.javac.Javac;
@@ -75,46 +69,8 @@ public class DirectoryRunner extends Runner {
public boolean accept(File file) {
return true;
}
-
- private static final Pattern P1 = Pattern.compile("^(\\d+)$");
- private static final Pattern P2 = Pattern.compile("^\\:(\\d+)$");
- private static final Pattern P3 = Pattern.compile("^(\\d+):$");
- private static final Pattern P4 = Pattern.compile("^(\\d+):(\\d+)$");
-
- public boolean shouldIgnoreBasedOnVersion(String firstLine) {
- int thisVersion = getVersion();
- if (!firstLine.startsWith("//version ")) return false;
-
- String spec = firstLine.substring("//version ".length());
-
- /* Single version: '5' */ {
- Matcher m = P1.matcher(spec);
- if (m.matches()) return Integer.parseInt(m.group(1)) != thisVersion;
- }
-
- /* Upper bound: ':5' (inclusive) */ {
- Matcher m = P2.matcher(spec);
- if (m.matches()) return Integer.parseInt(m.group(1)) < thisVersion;
- }
-
- /* Lower bound '5:' (inclusive) */ {
- Matcher m = P3.matcher(spec);
- if (m.matches()) return Integer.parseInt(m.group(1)) > thisVersion;
- }
-
- /* Range '7:8' (inclusive) */ {
- Matcher m = P4.matcher(spec);
- if (m.matches()) {
- if (Integer.parseInt(m.group(1)) < thisVersion) return true;
- if (Integer.parseInt(m.group(2)) > thisVersion) return true;
- return false;
- }
- }
-
- throw new IllegalArgumentException("Version validity spec not valid: " + spec);
- }
}
-
+
private static final FileFilter JAVA_FILE_FILTER = new FileFilter() {
@Override public boolean accept(File file) {
return file.isFile() && file.getName().endsWith(".java");
@@ -180,9 +136,7 @@ public class DirectoryRunner extends Runner {
private boolean runTest(String fileName) throws Throwable {
File file = new File(params.getBeforeDirectory(), fileName);
- if (mustIgnore(file)) {
- return false;
- }
+
switch (params.getCompiler()) {
case DELOMBOK:
return new RunTestsViaDelombok().compareFile(params, file);
@@ -193,11 +147,4 @@ public class DirectoryRunner extends Runner {
throw new UnsupportedOperationException();
}
}
-
- private boolean mustIgnore(File file) throws FileNotFoundException, IOException {
- BufferedReader reader = new BufferedReader(new FileReader(file));
- String line = reader.readLine();
- reader.close();
- return line != null && (line.startsWith("//ignore") || params.shouldIgnoreBasedOnVersion(line));
- }
}
diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java
new file mode 100644
index 00000000..318c5885
--- /dev/null
+++ b/test/core/src/lombok/LombokTestSource.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2014 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;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+
+import lombok.core.LombokImmutableList;
+import lombok.core.configuration.BubblingConfigurationResolver;
+import lombok.core.configuration.ConfigurationProblemReporter;
+import lombok.core.configuration.ConfigurationResolver;
+import lombok.core.configuration.StringConfigurationSource;
+
+public class LombokTestSource {
+ private final File file;
+ private final String content;
+ private final LombokImmutableList<CompilerMessageMatcher> messages;
+ private final boolean ignore;
+ private final boolean skipCompareContent;
+ private final int versionLowerLimit, versionUpperLimit;
+ private final ConfigurationResolver configuration;
+
+ public boolean versionWithinLimit(int version) {
+ return version >= versionLowerLimit && version <= versionUpperLimit;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public LombokImmutableList<CompilerMessageMatcher> getMessages() {
+ return messages;
+ }
+
+ public boolean isIgnore() {
+ return ignore;
+ }
+
+ public boolean isSkipCompareContent() {
+ return skipCompareContent;
+ }
+
+ public ConfigurationResolver getConfiguration() {
+ return configuration;
+ }
+
+ private static final Pattern VERSION_STYLE_1 = Pattern.compile("^(\\d+)$");
+ private static final Pattern VERSION_STYLE_2 = Pattern.compile("^\\:(\\d+)$");
+ private static final Pattern VERSION_STYLE_3 = Pattern.compile("^(\\d+):$");
+ private static final Pattern VERSION_STYLE_4 = Pattern.compile("^(\\d+):(\\d+)$");
+
+ private int[] parseVersionLimit(String spec) {
+ /* Single version: '5' */ {
+ Matcher m = VERSION_STYLE_1.matcher(spec);
+ if (m.matches()) {
+ int v = Integer.parseInt(m.group(1));
+ return new int[] {v, v};
+ }
+ }
+
+ /* Upper bound: ':5' (inclusive) */ {
+ Matcher m = VERSION_STYLE_2.matcher(spec);
+ if (m.matches()) return new int[] {0, Integer.parseInt(m.group(1))};
+ }
+
+ /* Lower bound '5:' (inclusive) */ {
+ Matcher m = VERSION_STYLE_3.matcher(spec);
+ if (m.matches()) return new int[] {Integer.parseInt(m.group(1)), 0};
+ }
+
+ /* Range '7:8' (inclusive) */ {
+ Matcher m = VERSION_STYLE_4.matcher(spec);
+ if (m.matches()) return new int[] {Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2))};
+ }
+
+ return null;
+ }
+
+ private static final Pattern IGNORE_PATTERN = Pattern.compile("^\\s*ignore\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?content\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE);
+
+ private LombokTestSource(File file, String content, List<CompilerMessageMatcher> messages, List<String> directives) {
+ this.file = file;
+ this.content = content;
+ this.messages = messages == null ? LombokImmutableList.<CompilerMessageMatcher>of() : LombokImmutableList.copyOf(messages);
+
+ StringBuilder conf = new StringBuilder();
+ int versionLower = 0;
+ int versionUpper = Integer.MAX_VALUE;
+ boolean ignore = false;
+ boolean skipCompareContent = false;
+
+ for (String directive : directives) {
+ directive = directive.trim();
+ String lc = directive.toLowerCase();
+ if (IGNORE_PATTERN.matcher(directive).matches()) {
+ ignore = true;
+ continue;
+ }
+
+ if (SKIP_COMPARE_CONTENT_PATTERN.matcher(directive).matches()) {
+ skipCompareContent = true;
+ continue;
+ }
+
+ if (lc.startsWith("version ")) {
+ int[] limits = parseVersionLimit(lc.substring(7).trim());
+ if (limits == null) {
+ Assert.fail("Directive line \"" + directive + "\" in '" + file.getAbsolutePath() + "' invalid: version must be followed by a single integer.");
+ throw new RuntimeException();
+ }
+ versionLower = limits[0];
+ versionUpper = limits[1];
+ continue;
+ }
+
+ if (lc.startsWith("conf:")) {
+ String confLine = directive.substring(5).trim();
+ conf.append(confLine).append("\n");
+ continue;
+ }
+
+ Assert.fail("Directive line \"" + directive + "\" in '" + file.getAbsolutePath() + "' invalid: unrecognized directive.");
+ throw new RuntimeException();
+ }
+
+ this.versionLowerLimit = versionLower;
+ this.versionUpperLimit = versionUpper;
+ this.ignore = ignore;
+ this.skipCompareContent = skipCompareContent;
+ ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() {
+ @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {
+ Assert.fail("Problem on directive line: " + problem + " at conf line #" + lineNumber + " (" + line + ")");
+ }
+ };
+
+ this.configuration = new BubblingConfigurationResolver(Collections.singleton(StringConfigurationSource.forString(conf, reporter, file.getAbsolutePath())));
+ }
+
+ public static LombokTestSource readDirectives(File file) throws IOException {
+ List<String> directives = new ArrayList<String>();
+
+ {
+ @Cleanup val rawIn = new FileInputStream(file);
+ BufferedReader in = new BufferedReader(new InputStreamReader(rawIn, "UTF-8"));
+ for (String i = in.readLine(); i != null; i = in.readLine()) {
+ if (i.isEmpty()) continue;
+
+ if (i.startsWith("//")) {
+ directives.add(i.substring(2));
+ } else {
+ break;
+ }
+ }
+ in.close();
+ rawIn.close();
+ }
+
+ return new LombokTestSource(file, "", null, directives);
+ }
+
+ public static LombokTestSource read(File sourceFolder, File messagesFolder, String fileName) throws IOException {
+ StringBuilder content = null;
+ List<String> directives = new ArrayList<String>();
+
+ File sourceFile = new File(sourceFolder, fileName);
+ if (sourceFile.exists()) {
+ @Cleanup val rawIn = new FileInputStream(sourceFile);
+ BufferedReader in = new BufferedReader(new InputStreamReader(rawIn, "UTF-8"));
+ for (String i = in.readLine(); i != null; i = in.readLine()) {
+ if (content != null) {
+ content.append(i).append("\n");
+ continue;
+ }
+
+ if (i.isEmpty()) continue;
+
+ if (i.startsWith("//")) {
+ directives.add(i.substring(2));
+ } else {
+ content = new StringBuilder();
+ content.append(i).append("\n");
+ }
+ }
+ in.close();
+ rawIn.close();
+ }
+
+ if (content == null) content = new StringBuilder();
+
+ List<CompilerMessageMatcher> messages = null;
+ if (messagesFolder != null) {
+ File messagesFile = new File(messagesFolder, fileName + ".messages");
+ try {
+ @Cleanup val rawIn = new FileInputStream(messagesFile);
+ messages = CompilerMessageMatcher.readAll(rawIn);
+ rawIn.close();
+ } catch (FileNotFoundException e) {
+ messages = null;
+ }
+ }
+
+ return new LombokTestSource(sourceFile, content.toString(), messages, directives);
+ }
+}
diff --git a/test/core/src/lombok/RunAllTests.java b/test/core/src/lombok/RunAllTests.java
index 0076e662..9f56b45b 100644
--- a/test/core/src/lombok/RunAllTests.java
+++ b/test/core/src/lombok/RunAllTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Project Lombok Authors.
+ * Copyright (C) 2011-2014 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,6 +26,6 @@ import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
-@SuiteClasses({lombok.transform.RunTransformTests.class, lombok.bytecode.RunBytecodeTests.class})
+@SuiteClasses({lombok.transform.RunTransformTests.class, lombok.bytecode.RunBytecodeTests.class, lombok.core.configuration.RunConfigurationTests.class})
public class RunAllTests {
}
diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java
index 17665173..6a08642b 100644
--- a/test/core/src/lombok/RunTestsViaDelombok.java
+++ b/test/core/src/lombok/RunTestsViaDelombok.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 The Project Lombok Authors.
+ * Copyright (C) 2009-2014 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
diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java
index 4f3e2794..2734eb43 100644
--- a/test/core/src/lombok/RunTestsViaEcj.java
+++ b/test/core/src/lombok/RunTestsViaEcj.java
@@ -107,6 +107,8 @@ public class RunTestsViaEcj extends AbstractRunTests {
}
};
+ // TODO: Create a configuration based on confLines and set this up so that this compile run will use them.
+
ecjCompiler.compile(new ICompilationUnit[] {sourceUnit});
CompilationResult compilationResult = compilationResult_.get();
diff --git a/test/transform/resource/after-delombok/AccessorsConfiguration.java b/test/transform/resource/after-delombok/AccessorsConfiguration.java
new file mode 100644
index 00000000..fd60b152
--- /dev/null
+++ b/test/transform/resource/after-delombok/AccessorsConfiguration.java
@@ -0,0 +1,26 @@
+class AccessorsConfiguration {
+ private String m_FieldName = "";
+ @java.lang.SuppressWarnings("all")
+ public String fieldName() {
+ return this.m_FieldName;
+ }
+ @java.lang.SuppressWarnings("all")
+ public void fieldName(final String m_FieldName) {
+ this.m_FieldName = m_FieldName;
+ }
+}
+class AccessorsConfiguration2 {
+ private String m_FieldName = "";
+ @java.lang.SuppressWarnings("all")
+ public void setM_FieldName(final String m_FieldName) {
+ this.m_FieldName = m_FieldName;
+ }
+}
+class AccessorsConfiguration3 {
+ private String fFieldName = "";
+ @java.lang.SuppressWarnings("all")
+ public AccessorsConfiguration3 setFieldName(final String fFieldName) {
+ this.fFieldName = fFieldName;
+ return this;
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/after-delombok/LoggerConfig.java b/test/transform/resource/after-delombok/LoggerConfig.java
new file mode 100644
index 00000000..ba955638
--- /dev/null
+++ b/test/transform/resource/after-delombok/LoggerConfig.java
@@ -0,0 +1,4 @@
+class LoggerWithConfig {
+ @java.lang.SuppressWarnings("all")
+ private final org.slf4j.Logger myLogger = org.slf4j.LoggerFactory.getLogger(LoggerWithConfig.class);
+} \ No newline at end of file
diff --git a/test/transform/resource/after-delombok/ToStringConfiguration.java b/test/transform/resource/after-delombok/ToStringConfiguration.java
new file mode 100644
index 00000000..035ecdb2
--- /dev/null
+++ b/test/transform/resource/after-delombok/ToStringConfiguration.java
@@ -0,0 +1,32 @@
+class ToStringConfiguration {
+ int x;
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ToStringConfiguration(" + this.x + ")";
+ }
+ @java.lang.SuppressWarnings("all")
+ public int getX() {
+ return this.x;
+ }
+}
+class ToStringConfiguration2 {
+ int x;
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ToStringConfiguration2(x=" + this.x + ")";
+ }
+}
+class ToStringConfiguration3 {
+ int x;
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ToStringConfiguration3(" + this.getX() + ")";
+ }
+ @java.lang.SuppressWarnings("all")
+ public int getX() {
+ return this.x;
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/after-ecj/AccessorsConfiguration.java b/test/transform/resource/after-ecj/AccessorsConfiguration.java
new file mode 100644
index 00000000..6678e020
--- /dev/null
+++ b/test/transform/resource/after-ecj/AccessorsConfiguration.java
@@ -0,0 +1,31 @@
+class AccessorsConfiguration {
+ private @lombok.Getter @lombok.Setter @lombok.experimental.Accessors(fluent = true) String m_FieldName = "";
+ AccessorsConfiguration() {
+ super();
+ }
+ public @java.lang.SuppressWarnings("all") String fieldName() {
+ return this.m_FieldName;
+ }
+ public @java.lang.SuppressWarnings("all") void fieldName(final String m_FieldName) {
+ this.m_FieldName = m_FieldName;
+ }
+}
+@lombok.experimental.Accessors(prefix = {}) class AccessorsConfiguration2 {
+ private @lombok.Setter String m_FieldName = "";
+ AccessorsConfiguration2() {
+ super();
+ }
+ public @java.lang.SuppressWarnings("all") void setM_FieldName(final String m_FieldName) {
+ this.m_FieldName = m_FieldName;
+ }
+}
+@lombok.experimental.Accessors(chain = true) class AccessorsConfiguration3 {
+ private @lombok.Setter String fFieldName = "";
+ AccessorsConfiguration3() {
+ super();
+ }
+ public @java.lang.SuppressWarnings("all") AccessorsConfiguration3 setFieldName(final String fFieldName) {
+ this.fFieldName = fFieldName;
+ return this;
+ }
+}
diff --git a/test/transform/resource/after-ecj/LoggerConfig.java b/test/transform/resource/after-ecj/LoggerConfig.java
new file mode 100644
index 00000000..907a7167
--- /dev/null
+++ b/test/transform/resource/after-ecj/LoggerConfig.java
@@ -0,0 +1,6 @@
+@lombok.extern.slf4j.Slf4j class LoggerWithConfig {
+ private final org.slf4j.Logger myLogger = org.slf4j.LoggerFactory.getLogger(LoggerWithConfig.class);
+ LoggerWithConfig() {
+ super();
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/after-ecj/ToStringConfiguration.java b/test/transform/resource/after-ecj/ToStringConfiguration.java
new file mode 100644
index 00000000..8bb99146
--- /dev/null
+++ b/test/transform/resource/after-ecj/ToStringConfiguration.java
@@ -0,0 +1,35 @@
+import lombok.ToString;
+import lombok.Getter;
+@ToString @Getter class ToStringConfiguration {
+ int x;
+ ToStringConfiguration() {
+ super();
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (("ToStringConfiguration(" + this.x) + ")");
+ }
+ public @java.lang.SuppressWarnings("all") int getX() {
+ return this.x;
+ }
+}
+@ToString(includeFieldNames = true) class ToStringConfiguration2 {
+ int x;
+ ToStringConfiguration2() {
+ super();
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (("ToStringConfiguration2(x=" + this.x) + ")");
+ }
+}
+@ToString(doNotUseGetters = false) @Getter class ToStringConfiguration3 {
+ int x;
+ ToStringConfiguration3() {
+ super();
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (("ToStringConfiguration3(" + this.getX()) + ")");
+ }
+ public @java.lang.SuppressWarnings("all") int getX() {
+ return this.x;
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/before/AccessorsConfiguration.java b/test/transform/resource/before/AccessorsConfiguration.java
new file mode 100644
index 00000000..187fd393
--- /dev/null
+++ b/test/transform/resource/before/AccessorsConfiguration.java
@@ -0,0 +1,20 @@
+//CONF: lombok.Accessors.prefix += m_
+//CONF: lombok.Accessors.prefix += f
+//CONF: lombok.Accessors.chain = false
+
+class AccessorsConfiguration {
+ @lombok.Getter @lombok.Setter @lombok.experimental.Accessors(fluent=true)
+ private String m_FieldName = "";
+}
+
+@lombok.experimental.Accessors(prefix = {})
+class AccessorsConfiguration2 {
+ @lombok.Setter
+ private String m_FieldName = "";
+}
+
+@lombok.experimental.Accessors(chain = true)
+class AccessorsConfiguration3 {
+ @lombok.Setter
+ private String fFieldName = "";
+}
diff --git a/test/transform/resource/before/BuilderInvalidUse.java b/test/transform/resource/before/BuilderInvalidUse.java
index 07f37d3d..d7052e1e 100644
--- a/test/transform/resource/before/BuilderInvalidUse.java
+++ b/test/transform/resource/before/BuilderInvalidUse.java
@@ -1,3 +1,4 @@
+//skip compare content
@lombok.experimental.Builder
class BuilderInvalidUse {
private int something;
diff --git a/test/transform/resource/before/DelegateOnStatic.java b/test/transform/resource/before/DelegateOnStatic.java
index ef56ef54..84d99636 100644
--- a/test/transform/resource/before/DelegateOnStatic.java
+++ b/test/transform/resource/before/DelegateOnStatic.java
@@ -1,3 +1,4 @@
+//skip compare content
import lombok.Delegate;
import lombok.Getter;
diff --git a/test/transform/resource/before/FlagUsages.java b/test/transform/resource/before/FlagUsages.java
new file mode 100644
index 00000000..6631224f
--- /dev/null
+++ b/test/transform/resource/before/FlagUsages.java
@@ -0,0 +1,11 @@
+//skip compare content
+//CONF: lombok.Getter.flagUsage = WARNING
+//CONF: lombok.experimental.flagUsage = ERROR
+public class FlagUsages {
+ @lombok.Getter String x;
+
+ @lombok.experimental.Wither String z;
+
+ public FlagUsages(String x, String y) {
+ }
+}
diff --git a/test/transform/resource/before/LoggerConfig.java b/test/transform/resource/before/LoggerConfig.java
new file mode 100644
index 00000000..14195e03
--- /dev/null
+++ b/test/transform/resource/before/LoggerConfig.java
@@ -0,0 +1,5 @@
+//CONF: lombok.log.fieldName = myLogger
+//CONF: lombok.log.fieldIsStatic = false
+@lombok.extern.slf4j.Slf4j
+class LoggerWithConfig {
+}
diff --git a/test/transform/resource/before/ToStringConfiguration.java b/test/transform/resource/before/ToStringConfiguration.java
new file mode 100644
index 00000000..7630cda5
--- /dev/null
+++ b/test/transform/resource/before/ToStringConfiguration.java
@@ -0,0 +1,13 @@
+//CONF: lombok.ToString.includeFieldNames = false
+//CONF: lombok.ToString.doNotUseGetters = true
+import lombok.ToString;
+import lombok.Getter;
+@ToString @Getter class ToStringConfiguration {
+ int x;
+}
+@ToString(includeFieldNames=true) class ToStringConfiguration2 {
+ int x;
+}
+@ToString(doNotUseGetters=false) @Getter class ToStringConfiguration3 {
+ int x;
+}
diff --git a/test/transform/resource/messages-delombok/BuilderInvalidUse.java.messages b/test/transform/resource/messages-delombok/BuilderInvalidUse.java.messages
index a04b4f9b..506a3426 100644
--- a/test/transform/resource/messages-delombok/BuilderInvalidUse.java.messages
+++ b/test/transform/resource/messages-delombok/BuilderInvalidUse.java.messages
@@ -1,2 +1,2 @@
-1 @Getter, @Setter, @Wither, @Data, @ToString, @EqualsAndHashCode, @AllArgsConstructor are not allowed on builder classes.
-12 @Value is not allowed on builder classes. \ No newline at end of file
+2 @Getter, @Setter, @Wither, @Data, @ToString, @EqualsAndHashCode, @AllArgsConstructor are not allowed on builder classes.
+13 @Value is not allowed on builder classes. \ No newline at end of file
diff --git a/test/transform/resource/messages-delombok/DelegateOnStatic.java.messages b/test/transform/resource/messages-delombok/DelegateOnStatic.java.messages
index b807b155..51dcf501 100644
--- a/test/transform/resource/messages-delombok/DelegateOnStatic.java.messages
+++ b/test/transform/resource/messages-delombok/DelegateOnStatic.java.messages
@@ -1,2 +1,2 @@
-5 @Delegate is legal only on instance fields or no-argument instance methods.
-9 @Delegate is legal only on instance fields or no-argument instance methods. \ No newline at end of file
+6 @Delegate is legal only on instance fields or no-argument instance methods.
+10 @Delegate is legal only on instance fields or no-argument instance methods. \ No newline at end of file
diff --git a/test/transform/resource/messages-delombok/FlagUsages.java.messages b/test/transform/resource/messages-delombok/FlagUsages.java.messages
new file mode 100644
index 00000000..13a148b1
--- /dev/null
+++ b/test/transform/resource/messages-delombok/FlagUsages.java.messages
@@ -0,0 +1,2 @@
+5 Use of @Getter is flagged according to lombok configuration.
+7 Use of any lombok.experimental feature is flagged according to lombok configuration.
diff --git a/test/transform/resource/messages-ecj/BuilderInvalidUse.java.messages b/test/transform/resource/messages-ecj/BuilderInvalidUse.java.messages
index 84942101..c5571b92 100644
--- a/test/transform/resource/messages-ecj/BuilderInvalidUse.java.messages
+++ b/test/transform/resource/messages-ecj/BuilderInvalidUse.java.messages
@@ -1,2 +1,2 @@
-1 @Getter, @Setter, @FieldDefaults, @Wither, @Data, @ToString, @EqualsAndHashCode, @AllArgsConstructor are not allowed on builder classes.
-12 @Value is not allowed on builder classes. \ No newline at end of file
+2 @Getter, @Setter, @FieldDefaults, @Wither, @Data, @ToString, @EqualsAndHashCode, @AllArgsConstructor are not allowed on builder classes.
+13 @Value is not allowed on builder classes. \ No newline at end of file
diff --git a/test/transform/resource/messages-ecj/DelegateOnStatic.java.messages b/test/transform/resource/messages-ecj/DelegateOnStatic.java.messages
index b807b155..51dcf501 100644
--- a/test/transform/resource/messages-ecj/DelegateOnStatic.java.messages
+++ b/test/transform/resource/messages-ecj/DelegateOnStatic.java.messages
@@ -1,2 +1,2 @@
-5 @Delegate is legal only on instance fields or no-argument instance methods.
-9 @Delegate is legal only on instance fields or no-argument instance methods. \ No newline at end of file
+6 @Delegate is legal only on instance fields or no-argument instance methods.
+10 @Delegate is legal only on instance fields or no-argument instance methods. \ No newline at end of file
diff --git a/test/transform/resource/messages-ecj/FlagUsages.java.messages b/test/transform/resource/messages-ecj/FlagUsages.java.messages
new file mode 100644
index 00000000..13a148b1
--- /dev/null
+++ b/test/transform/resource/messages-ecj/FlagUsages.java.messages
@@ -0,0 +1,2 @@
+5 Use of @Getter is flagged according to lombok configuration.
+7 Use of any lombok.experimental feature is flagged according to lombok configuration.