diff options
223 files changed, 3597 insertions, 2240 deletions
@@ -1,6 +1,7 @@ Lombok contributors in alphabetical order: Bulgakov Alexander <buls@yandex.ru> +Christian Nüssgens <christian@nuessgens.com> Christian Sterzl <christian.sterzl@gmail.com> DaveLaw <project.lombok@apconsult.de> Dave Brosius <dbrosius@mebigfatguy.com> @@ -13,6 +14,9 @@ Liu DongMiao <liudongmiao@gmail.com> Luan Nico <luannico27@gmail.com> Maarten Mulders <mthmulders@users.noreply.github.com> Mart Hagenaars <marthagenaars@gmail.com> +Mateusz Matela <mateusz.matela@gmail.com> +Michiel Verheul <cheelio@gmail.com> +Pascal Bihler <pascal@qfs.de> Peter Grant <petercgrant@users.noreply.github.com> Philipp Eichhorn <peichhor@web.de> Rabea Gransberger <rgra@users.noreply.github.com> @@ -21,9 +25,10 @@ Robbert Jan Grootjans <grootjans@gmail.com> Roel Spilker <r.spilker@gmail.com> Sander Koning <askoning@gmail.com> Szymon Pacanowski <spacanowski@gmail.com> -Takuya Murakami <tmurakam@tmurakam.org> Taiki Sugawara <buzz.taiki@gmail.com> +Takuya Murakami <tmurakam@tmurakam.org> Thomas Darimont <thomas.darimont@gmail.com> +Victor Williams Stafusa da Silva <victorwssilva@gmail.com> Yun Zhi Lin <yun@yunspace.com> By adding your name to this list, you grant full and irrevocable copyright and patent indemnity to Project Lombok and all use of Project Lombok, and you certify that you have the right to do so for all commits you add to Project Lombok. @@ -28,18 +28,10 @@ the common tasks and can be called on to run the main aspects of all the sub-scr <property name="build.compiler" value="javac1.6" /> <property name="ivy.retrieve.pattern" value="lib/[conf]/[organisation]-[artifact].[ext]" /> <available file="lib/ivyplusplus.jar" property="ivyplusplus.available" /> - <property name="rt-openjdk6" location="lib/openJDk6Environment/rt-openjdk6.jar" /> - <property name="rt-openjdk8" location="lib/openJDk8Environment/rt-openjdk8.jar" /> - <property name="openjdk6.md5" value="de953d5062b7183fbf3fa9f5d623e2e7" /> - <property name="openjdk8.md5" value="8099e5d7aa182374d299d03f5003a27f" /> - <checksum file="${rt-openjdk6}" property="${openjdk6.md5}" verifyProperty="rt-openjdk6.checksumOk" /> - <checksum file="${rt-openjdk8}" property="${openjdk8.md5}" verifyProperty="rt-openjdk8.checksumOk" /> - <condition property="rt-openjdk6.available"> - <equals arg1="${rt-openjdk6.checksumOk}" arg2="true" /> - </condition> - <condition property="rt-openjdk8.available"> - <equals arg1="${rt-openjdk8.checksumOk}" arg2="true" /> - </condition> + <property name="rt-openjdk6" location="lib/openJDK6Environment/openjdk6_rt.jar" /> + <property name="rt-openjdk8" location="lib/openJDK8Environment/openjdk8_rt.jar" /> + <available file="${rt-openjdk6}" property="rt-openjdk6.available" /> + <available file="${rt-openjdk8}" property="rt-openjdk8.available" /> <path id="build.path"> <fileset dir="lib/build"> @@ -169,7 +161,22 @@ the common tasks and can be called on to run the main aspects of all the sub-scr </ivy:cachedunjar> </target> - <target name="compile" depends="version, ensureBuildDeps, -unpackLibs" description="Compiles the code."> + <target name="-ensureJdk9"> + <condition property="java.version.insufficient"> + <or> + <equals arg1="${ant.java.version}" arg2="1.2" /> + <equals arg1="${ant.java.version}" arg2="1.3" /> + <equals arg1="${ant.java.version}" arg2="1.4" /> + <equals arg1="${ant.java.version}" arg2="1.5" /> + <equals arg1="${ant.java.version}" arg2="1.6" /> + <equals arg1="${ant.java.version}" arg2="1.7" /> + <equals arg1="${ant.java.version}" arg2="1.8" /> + </or> + </condition> + <fail if="java.version.insufficient">To compile lombok, you need JDK9 or higher; lombok requires this version because it's rather difficult to produce lombok builds that are compatible on JDK9 without at least building with JDK9. Sorry about that.</fail> + </target> + + <target name="compile" depends="version, ensureBuildDeps, -unpackLibs, -ensureJdk9" description="Compiles the code."> <!-- ant includes the destination dir on the classpath (and there are good reasons to do this), but that also means the bleeding edge lombok from the previous build is run, which means if there are bugs in it, you can't compile anymore until you 'ant clean'. That's very much not desired, so we kill the processor, which stops lombok from running. @@ -198,7 +205,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr </ivy:compile> <ivy:compile destdir="build/lombok-utils" source="1.6" target="1.6"> - <compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}lib/openJDK6Environment/rt-openjdk6.jar" /> + <compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}${rt-openjdk6}" /> <compilerarg value="-Xlint:-options" /> <src path="src/utils" /> <include name="lombok/javac/**" /> @@ -266,7 +273,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr </ivy:compile> <ivy:compile destdir="build/lombok" source="1.6" target="1.6"> - <compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}lib/openJDK6Environment/rt-openjdk6.jar" /> + <compilerarg value="-Xbootclasspath/p:build/stubs${path.separator}${rt-openjdk6}" /> <compilerarg value="-Xlint:-options" /> <src path="src/core" /> <src path="src/delombok" /> @@ -299,6 +306,9 @@ the common tasks and can be called on to run the main aspects of all the sub-scr <echo file="build/lombok/META-INF/services/javax.annotation.processing.Processor">lombok.launch.AnnotationProcessorHider$AnnotationProcessor lombok.launch.AnnotationProcessorHider$ClaimingProcessor</echo> <echo file="build/lombok/META-INF/services/org.mapstruct.ap.spi.AstModifyingAnnotationProcessor">lombok.launch.AnnotationProcessorHider$AstModificationNotifier</echo> + <mkdir dir="build/lombok/META-INF/gradle" /> + <echo file="build/lombok/META-INF/gradle/incremental.annotation.processors">lombok.launch.AnnotationProcessorHider$AnnotationProcessor,isolating +lombok.launch.AnnotationProcessorHider$ClaimingProcessor,isolating</echo> </target> <target name="-latestChanges" depends="version"> @@ -328,6 +338,7 @@ lombok.launch.AnnotationProcessorHider$ClaimingProcessor</echo> <include name="lombok/launch/**" /> <include name="lombok/delombok/ant/Tasks*" /> <include name="lombok/javac/apt/Processor.class" /> + <include name="lombok/META-INF/**" /> </fileset> <mappedresources> <fileset dir="build/lombok"> @@ -589,11 +600,11 @@ ${sourceWarning}</echo> <target name="setupJavaOpenJDK6TestEnvironment" depends="ensureTestDeps, contrib" description="Sets up the test so that 'ant test' will test against OpenJDK6."> <mkdir dir="lib/openJDK6Environment" /> <get src="https://projectlombok.org/ivyrepo/langtools/javac-1.6.0.18.jar" dest="lib/openJDK6Environment/javac6.jar" verbose="true" usetimestamp="true" /> - <get src="https://projectlombok.org/ivyrepo/langtools/rt-openjdk6.jar" dest="lib/openJDK6Environment/rt-openjdk6.jar" verbose="true" usetimestamp="true" /> + <get src="https://projectlombok.org/ivyrepo/langtools/rt-openjdk6.jar" dest="${rt-openjdk6}" verbose="true" usetimestamp="true" /> <propertyfile file="testenvironment.properties"> <entry key="test.location.javac" value="lib/openJDK6Environment/javac6.jar" /> <entry key="test.location.ecj" value="lib/ecj7/org.eclipse.custom-ecj.jar" /> - <entry key="test.location.bootclasspath" value="lib/openJDK6Environment/rt-openjdk6.jar" /> + <entry key="test.location.bootclasspath" value="${rt-openjdk6}" /> <entry key="test.location.name" value="OpenJDK6" /> <entry key="test.javaversion" value="6" /> </propertyfile> @@ -758,7 +769,7 @@ You can also create your own by writing a 'testenvironment.properties' file. The </replaceregexp> </target> - <target name="utils-maven" depends="version, dist-utils, test, utils-javadoc" description="Build a maven artifact bundle for lombok-utils."> + <target name="utils-maven" depends="version, dist-utils, utils-javadoc" description="Build a maven artifact bundle for lombok-utils."> <jar destfile="dist/lombok-utils-${lombok.version}-javadoc.jar"> <fileset dir="build/utils-api" /> </jar> @@ -790,7 +801,7 @@ You can also create your own by writing a 'testenvironment.properties' file. The </ant> </target> - <target name="maven" depends="version, dist, test, javadoc" description="Build a maven artifact bundle."> + <target name="maven" depends="version, dist, javadoc" description="Build a maven artifact bundle."> <jar destfile="dist/lombok-${lombok.version}-javadoc.jar"> <fileset dir="doc/api" /> </jar> @@ -852,7 +863,7 @@ You can also create your own by writing a 'testenvironment.properties' file. The knownHosts="ssh.knownHosts" /> </target> - <target name="publish" description="Publishes the latest build to googlecode." depends="config-ssh, version, dist, dist-utils, test"> + <target name="publish" description="Publishes the latest build to googlecode." depends="config-ssh, version, dist, dist-utils"> <ivy:scpUpload from="dist/lombok-utils-${lombok.version}.jar" to="/data/lombok/staging" diff --git a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.26.xml b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.26.xml new file mode 100644 index 00000000..6525604f --- /dev/null +++ b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.26.xml @@ -0,0 +1,14 @@ +<ivy-module version="2.0"> + <info organisation="org.projectlombok" module="lombok.patcher" revision="0.26" publication="20180528200000"> + <license name="MIT License" url="https://www.opensource.org/licenses/mit-license.php" /> + <ivyauthor name="rzwitserloot" url="https://github.com/rzwitserloot" /> + <ivyauthor name="rspilker" url="https://github.com/rspilker" /> + <description homepage="https://projectlombok.org/" /> + </info> + <configurations> + <conf name="default" /> + </configurations> + <publications> + <artifact conf="default" url="https://projectlombok.org/downloads/lombok.patcher-0.26.jar" /> + </publications> +</ivy-module> diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index a27c909e..c1ddc6fd 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -17,7 +17,7 @@ <conf name="supporters" /> </configurations> <dependencies> - <dependency org="org.projectlombok" name="lombok.patcher" rev="0.24" conf="buildBase->default; runtime->default" /> + <dependency org="org.projectlombok" name="lombok.patcher" rev="0.26" conf="buildBase->default; runtime->default" /> <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="buildBase->runtime; runtime" /> <dependency org="junit" name="junit" rev="4.8.2" conf="test->default; contrib->sources" /> @@ -26,7 +26,8 @@ <dependency org="commons-logging" name="commons-logging" rev="1.1.1" conf="test->default; contrib->sources" /> <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1" conf="test->default; contrib->sources" /> <dependency org="org.slf4j" name="slf4j-ext" rev="1.6.1" conf="test->default; contrib->sources" /> - <dependency org="org.jboss.logging" name="jboss-logging" rev="3.3.0.Final" conf="test->default; contrib->sources" /> + <dependency org="org.jboss.logging" name="jboss-logging" rev="3.3.0.Final" conf="test->default; contrib->sources" /> + <dependency org="com.google.flogger" name="flogger" rev="0.2" conf="test->default; contrib->sources" /> <dependency org="com.google.guava" name="guava" rev="18.0" conf="test->default; contrib->sources" /> <dependency org="com.google.code.findbugs" name="findbugs" rev="3.0.0" conf="test->master" /> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 9e84afb8..1648cdba 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,11 +1,29 @@ Lombok Changelog ---------------- -### v1.16.21 "Edgy Guinea Pig" -* v1.16.20 is the latest stable release of Project Lombok. -* PLATFORM: Fix for using lombok together with JDK9's new `module-info.java` feature. [Issue #985](https://github.com/rzwitserloot/lombok/issues/985) -* PLATFORM: Some initial work on supporting JDK10. -* BUGFIX: Potential fix for Netbeans < 9. [Issue #1555](https://github.com/rzwitserloot/lombok/issues/1555) +### v1.18.1 "Edgy Guinea Pig" +* v1.18.0 is the latest stable release of Project Lombok. + +### v1.18.0 (June 5th, 2018) +* BREAKING CHANGE: The in 1.16.22 introduced configuration key `lombok.noArgsConstructor.extraPrivate` is now `false` by default. [Issue #1708](https://github.com/rzwitserloot/lombok/issues/1708) +* BUGFIX: Do not generate a private no-args constructor if that breaks the code. [Issue #1703](https://github.com/rzwitserloot/lombok/issues/1703), [Issue #1704](https://github.com/rzwitserloot/lombok/issues/1704), [Issue #1712](https://github.com/rzwitserloot/lombok/issues/1712) +* BUGFIX: Using boolean parameters in lombok annotations would fail. [Issue #1709](https://github.com/rzwitserloot/lombok/issues/1709) +* BUGFIX: Delombok would give an error message. [Issue #1705](https://github.com/rzwitserloot/lombok/issues/1705) +* BUGFIX: Eclipse java10 var support didn't work if lombok was installed in your eclipse. [Issue #1676](https://github.com/rzwitserloot/lombok/issues/1676) +* FEATURE: Google's [Flogger (a.k.a. FluentLogger)](https://google.github.io/flogger/) is now available via `@Flogger`. [Issue #1697](https://github.com/rzwitserloot/lombok/issues/1697) +* FEATURE: `@FieldNameConstants` has been extended to support prefixes and suffixes. By default, the generated constants are prefixed with `FIELD_`. [Docs on @FieldNameConstants](https://projectlombok.org/features/experimental/FieldNameConstants). + +### v1.16.22 "Envious Ferret" (May 29th, 2018) +* FEATURE: Private no-args constructor for `@Data` and `@Value` to enable deserialization frameworks (like Jackson) to operate out-of-the-box. Use `lombok.noArgsConstructor.extraPrivate = false` to disable this behavior. +* FEATURE: Methods can now be marked for inclusion in `toString`, `equals`, and `hashCode` generation. There is a new mechanism to mark which fields (and now, methods) are to be included or excluded for the generation of these methods: mark the relevant member with for example `@ToString.Include` or `@EqualsAndHashCode.Exclude`. [ToString documentation](https://projectlombok.org/features/ToString) [EqualsAndHashCode documentation](https://projectlombok.org/features/EqualsAndHashCode) +* FEATURE: `@Getter` and `@Setter` also allow `onMethod` and `onParam` when put on a type. [Issue #1653](https://github.com/rzwitserloot/lombok/issues/1653) +* FEATURE: `@FieldNameConstants` is a new feature that generates string constants for your field names. [Docs on @FieldNameConstants](https://projectlombok.org/features/experimental/FieldNameConstants). +* PLATFORM: Lombok can be compiled on JDK10, and should run on JDK10. [Issue #1693](https://github.com/rzwitserloot/lombok/issues/1693) +* PLATFORM: lombok now counts as an _incremental annotation processor_ for gradle. Should speed up your gradle builds considerably! [Issue #1580](https://github.com/rzwitserloot/lombok/issues/1580) +* PLATFORM: Fix for using lombok together with JDK9+'s new `module-info.java` feature. [Issue #985](https://github.com/rzwitserloot/lombok/issues/985) +* BUGFIX: Solved some issues in eclipse that resulted in error 'A save participant caused problems'. [Issue #879](https://github.com/rzwitserloot/lombok/issues/879) +* BUGFIX: Netbeans on jdk9. [Issue #1617](https://github.com/rzwitserloot/lombok/issues/1617) +* BUGFIX: Netbeans < 9. [Issue #1555](https://github.com/rzwitserloot/lombok/issues/1555) * PROMOTION: `var` has been promoted from experimental to the main package with no changes. The 'old' experimental one is still around but is deprecated, and is an alias for the new main package one. [var documentation](https://projectlombok.org/features/var.html). * OLD-CRUFT: `lombok.experimental.Builder` and `lombok.experimental.Value` are deprecated remnants of when these features were still in experimental. They are now removed entirely. If your project is dependent on an older version of lombok which still has those; fret not, lombok still processes these annotations. It just no longer includes them in the jar. diff --git a/docker/ant/Dockerfile b/docker/ant/Dockerfile index 32457709..b4789a2e 100644 --- a/docker/ant/Dockerfile +++ b/docker/ant/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 as downloader -ARG jdk=9 +ARG jdk=10 ADD provision/jdk/java-${jdk}.sh provision/jdk/java-${jdk}.sh RUN provision/jdk/java-${jdk}.sh @@ -19,7 +19,7 @@ WORKDIR workspace ADD shared/ ./ -ARG jdk=9 +ARG jdk=10 ADD ant/files/jdk-${jdk} ./ ARG lombokjar=lombok.jar diff --git a/docker/ant/files/jdk-10/build.xml b/docker/ant/files/jdk-10/build.xml new file mode 100644 index 00000000..3f181ed9 --- /dev/null +++ b/docker/ant/files/jdk-10/build.xml @@ -0,0 +1,35 @@ +<project name="example" default="dist" basedir="."> + <property name="src" location="src/main/java"/> + <property name="build" location="build"/> + <property name="dist" location="dist"/> + <property name="build.sysclasspath" value="ignore"/> + + <target name="init"> + <tstamp/> + <mkdir dir="${build}"/> + </target> + + <target name="compile" depends="init" description="compile the source"> + <javac classpath="lombok.jar" srcdir="${src}" destdir="${build}" fork="true"> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED"/> + <compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"/> + </javac> + </target> + + <target name="dist" depends="compile" description="generate the distribution"> + <mkdir dir="${dist}/lib"/> + <jar jarfile="${dist}/lib/example-${DSTAMP}.jar" basedir="${build}"/> + </target> + + <target name="clean" description="clean up"> + <delete dir="${build}"/> + <delete dir="${dist}"/> + </target> +</project>
\ No newline at end of file diff --git a/docker/ant/readme.md b/docker/ant/readme.md index d6462523..6618cd03 100644 --- a/docker/ant/readme.md +++ b/docker/ant/readme.md @@ -13,17 +13,17 @@ The ant version to be used. Supported values: (To be executed from the `<lombokhome>/docker` directory) ``` -docker build -t lombok-ant-jdk9 -f gradle/Dockerfile . +docker build -t lombok-ant-jdk10 -f ant/Dockerfile . -docker build -t lombok-ant-jdk9 --build-arg lombokjar=lombok-1.16.18.jar -f gradle/Dockerfile . +docker build -t lombok-ant-jdk10 --build-arg lombokjar=lombok-1.16.20.jar -f ant/Dockerfile . ``` ## Example run commands: ``` -docker run -it lombok-ant-jdk9 +docker run -it lombok-ant-jdk10 -docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-ant-jdk9 +docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-ant-jdk10 ``` ## Example container commands: diff --git a/docker/bazel/Dockerfile b/docker/bazel/Dockerfile new file mode 100644 index 00000000..bbfc4e89 --- /dev/null +++ b/docker/bazel/Dockerfile @@ -0,0 +1,32 @@ +FROM ubuntu:16.04 as downloader + +ARG jdk=10 +ADD provision/jdk/java-${jdk}.sh provision/jdk/java-${jdk}.sh +RUN provision/jdk/java-${jdk}.sh + +ARG bazel=0.13.0 +ADD provision/bazel/bazel-${bazel}.sh provision/bazel/bazel-${bazel}.sh +RUN provision/bazel/bazel-${bazel}.sh + +FROM ubuntu:16.04 + +COPY --from=downloader /opt/bazel/ /opt/bazel/ +COPY --from=downloader /opt/jdk/ /opt/jdk/ + +RUN update-alternatives --install /usr/bin/java java /opt/jdk/bin/java 1000 && update-alternatives --install /usr/bin/javac javac /opt/jdk/bin/javac 1000 && update-alternatives --install /usr/bin/javadoc javadoc /opt/jdk/bin/javadoc 1000 && update-alternatives --install /usr/bin/javap javap /opt/jdk/bin/javap 1000 +RUN apt-get update && apt-get install -y g++ + +WORKDIR workspace + +ADD shared/ ./ +ADD bazel/files/ ./ +ARG lombokjar=lombok.jar +ADD https://projectlombok.org/downloads/${lombokjar} lombok.jar + +ARG jdk=10 +ENV JDK_VERSION=${jdk} +ENV JAVA_HOME=/opt/jdk +ENV BAZEL_HOME=/opt/bazel +ENV PATH="${JAVA_HOME}/bin:${BAZEL_HOME}/bin:${PATH}" + +ENTRYPOINT bash diff --git a/docker/bazel/files/BUILD b/docker/bazel/files/BUILD new file mode 100644 index 00000000..4a9c7655 --- /dev/null +++ b/docker/bazel/files/BUILD @@ -0,0 +1,18 @@ +java_binary( + name = "ProjectRunner", + main_class = "HelloWorld", + srcs = glob(["src/main/java/*.java"]), + deps = [":lombok"], +) + +java_plugin( + name = "lombok_plugin", + processor_class = "lombok.launch.AnnotationProcessorHider$AnnotationProcessor", + deps = ["@lombok_jar//:jar"], +) + +java_library( + name = "lombok", + exports = ["@lombok_jar//:jar"], + exported_plugins = [":lombok_plugin"], +)
\ No newline at end of file diff --git a/docker/bazel/files/BUILD.lombok b/docker/bazel/files/BUILD.lombok new file mode 100644 index 00000000..06836d17 --- /dev/null +++ b/docker/bazel/files/BUILD.lombok @@ -0,0 +1,5 @@ +java_import( + name = "jar", + jars = ["lombok.jar"], + visibility = ["//visibility:public"] +) diff --git a/docker/bazel/files/WORKSPACE b/docker/bazel/files/WORKSPACE new file mode 100644 index 00000000..4b073ec8 --- /dev/null +++ b/docker/bazel/files/WORKSPACE @@ -0,0 +1,5 @@ +new_local_repository( + name = "lombok_jar", + path = "/workspace", + build_file = "BUILD.lombok", +)
\ No newline at end of file diff --git a/docker/bazel/readme.md b/docker/bazel/readme.md new file mode 100644 index 00000000..2bed86f1 --- /dev/null +++ b/docker/bazel/readme.md @@ -0,0 +1,33 @@ +## Configuration + +[_(general configuration and options)_](../readme.md) + +### `ARG bazel=0.13.0` + +The bazel version to be used. Supported values: + +- `0.13.0` (default) + +## Example build commands: + +(To be executed from the `<lombokhome>/docker` directory) + +``` +docker build -t lombok-bazel-jdk10 -f bazel/Dockerfile . + +docker build -t lombok-bazel-jdk10 --build-arg lombokjar=lombok-1.16.20.jar -f bazel/Dockerfile . +``` + +## Example run commands: + +``` +docker run -it lombok-bazel-jdk10 + +docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-bazel-jdk10 +``` + +## Example container commands: + +``` +bazel build //:ProjectRunner +``` diff --git a/docker/gradle/Dockerfile b/docker/gradle/Dockerfile index 938d417e..204fe00f 100644 --- a/docker/gradle/Dockerfile +++ b/docker/gradle/Dockerfile @@ -1,10 +1,10 @@ FROM ubuntu:16.04 as downloader
-ARG jdk=9
+ARG jdk=10
ADD provision/jdk/java-${jdk}.sh provision/jdk/java-${jdk}.sh
RUN provision/jdk/java-${jdk}.sh
-ARG gradle=4.2.1
+ARG gradle=4.7
ADD provision/gradle/gradle-${gradle}.sh provision/gradle/gradle-${gradle}.sh
RUN provision/gradle/gradle-${gradle}.sh
@@ -22,7 +22,7 @@ ADD gradle/files/ ./ ARG lombokjar=lombok.jar
ADD https://projectlombok.org/downloads/${lombokjar} lombok.jar
-ARG jdk=9
+ARG jdk=10
ENV JDK_VERSION=${jdk}
ENV JAVA_HOME=/opt/jdk
ENV GRADLE_HOME=/opt/gradle/gradle
diff --git a/docker/gradle/readme.md b/docker/gradle/readme.md index efe4f237..486b430b 100644 --- a/docker/gradle/readme.md +++ b/docker/gradle/readme.md @@ -2,28 +2,29 @@ [_(general configuration and options)_](../readme.md) -### `ARG gradle=4.2.1` +### `ARG gradle=4.7` The gradle version to be used. Supported values: -- `4.2.1` (default) +- `4.7` (default) +- `4.2.1` ## Example build commands: (To be executed from the `<lombokhome>/docker` directory) ``` -docker build -t lombok-gradle-jdk9 -f gradle/Dockerfile . +docker build -t lombok-gradle-jdk10 -f gradle/Dockerfile . -docker build -t lombok-gradle-jdk9 --build-arg lombokjar=lombok-1.16.18.jar -f gradle/Dockerfile . +docker build -t lombok-gradle-jdk10 --build-arg lombokjar=lombok-1.16.20.jar -f gradle/Dockerfile . ``` ## Example run commands: ``` -docker run -it lombok-gradle-jdk9 +docker run -it lombok-gradle-jdk10 -docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-gradle-jdk9 +docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-gradle-jdk10 ``` ## Example container commands: diff --git a/docker/maven/Dockerfile b/docker/maven/Dockerfile index 83f124f1..a73faaf6 100644 --- a/docker/maven/Dockerfile +++ b/docker/maven/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:16.04 as downloader
-ARG jdk=9
+ARG jdk=10
ADD provision/jdk/java-${jdk}.sh provision/jdk/java-${jdk}.sh
RUN provision/jdk/java-${jdk}.sh
@@ -19,7 +19,7 @@ WORKDIR workspace ADD shared/ ./
-ARG jdk=9
+ARG jdk=10
ADD maven/files/jdk-${jdk} ./
ARG lombokjar=lombok.jar
diff --git a/docker/maven/files/jdk-10/pom.xml b/docker/maven/files/jdk-10/pom.xml new file mode 100644 index 00000000..9940955d --- /dev/null +++ b/docker/maven/files/jdk-10/pom.xml @@ -0,0 +1,53 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.example</groupId> + <artifactId>lombok-jdk-${env.JDK_VERSION}</artifactId> + <version>1.0-SNAPSHOT</version> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java.version>1.10</java.version> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.7.0</version> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + <showDeprecation>true</showDeprecation> + <showWarnings>true</showWarnings> + <fork>true</fork> + <compilerargs> + <arg>-Werror</arg> + <arg>-Xlint:all</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg> + <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg> + </compilerargs> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.2.3</version> + <scope>system</scope> + <systemPath>/workspace/lombok.jar</systemPath> + </dependency> + </dependencies> + +</project>
\ No newline at end of file diff --git a/docker/maven/readme.md b/docker/maven/readme.md index 20cf126f..15887fa5 100644 --- a/docker/maven/readme.md +++ b/docker/maven/readme.md @@ -13,17 +13,17 @@ The maven version to be used. Supported values: (To be executed from the `<lombokhome>/docker` directory) ``` -docker build -t lombok-maven-jdk9 -f maven/Dockerfile . +docker build -t lombok-maven-jdk10 -f maven/Dockerfile . -docker build -t lombok-maven-jdk9 --build-arg lombokjar=lombok-1.16.18.jar -f maven/Dockerfile . +docker build -t lombok-maven-jdk10 --build-arg lombokjar=lombok-1.16.20.jar -f maven/Dockerfile . ``` ## Example run commands: ``` -docker run -it lombok-maven-jdk9 +docker run -it lombok-maven-jdk10 -docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-maven-jdk9 +docker run --rm -it -v /<lombokhome>/dist/lombok.jar:/workspace/lombok.jar lombok-maven-jdk10 ``` ## Example container commands: diff --git a/docker/provision/bazel/bazel-0.13.0.sh b/docker/provision/bazel/bazel-0.13.0.sh new file mode 100644 index 00000000..24b50d9a --- /dev/null +++ b/docker/provision/bazel/bazel-0.13.0.sh @@ -0,0 +1,4 @@ +apt-get update && apt-get install -y wget pkg-config zip g++ zlib1g-dev unzip python +wget https://github.com/bazelbuild/bazel/releases/download/0.13.0/bazel-0.13.0-installer-linux-x86_64.sh -O bazel-installer.sh +chmod +x bazel-installer.sh +./bazel-installer.sh --prefix=/opt/bazel
\ No newline at end of file diff --git a/docker/provision/gradle/gradle-4.7.sh b/docker/provision/gradle/gradle-4.7.sh new file mode 100644 index 00000000..a2e3ebec --- /dev/null +++ b/docker/provision/gradle/gradle-4.7.sh @@ -0,0 +1,4 @@ +apt-get update && apt-get install -y wget unzip +wget https://services.gradle.org/distributions/gradle-4.7-bin.zip -O gradle.zip +mkdir /opt/gradle && unzip -d /opt/gradle gradle.zip +mv /opt/gradle/gradle-4.7 /opt/gradle/gradle diff --git a/docker/provision/jdk/java-10.sh b/docker/provision/jdk/java-10.sh index 9b5f3176..10790952 100755 --- a/docker/provision/jdk/java-10.sh +++ b/docker/provision/jdk/java-10.sh @@ -1,4 +1,4 @@ apt-get update && apt-get install -y wget -wget -c --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/10+46/76eac37278c24557a3c4199677f19b62/jdk-10_linux-x64_bin.tar.gz -O jdk.tar.gz +wget -c --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/10.0.1+10/fb4372174a714e6b8c52526dc134031e/jdk-10.0.1_linux-x64_bin.tar.gz -O jdk.tar.gz tar -xzf jdk.tar.gz -C /opt/ -mv /opt/jdk-10 /opt/jdk +mv /opt/jdk-10.0.1 /opt/jdk diff --git a/docker/provision/jdk/java-9.sh b/docker/provision/jdk/java-9.sh index fd488dc8..483c1a28 100755 --- a/docker/provision/jdk/java-9.sh +++ b/docker/provision/jdk/java-9.sh @@ -1,4 +1,4 @@ apt-get update && apt-get install -y wget -wget --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/9.0.4+11/c2514751926b4512b076cc82f959763f/jdk-9.0.4_linux-x64_bin.tar.gz -O jdk.tar.gz +wget https://download.java.net/java/GA/jdk9/9.0.4/binaries/openjdk-9.0.4_linux-x64_bin.tar.gz -O jdk.tar.gz tar -xzf jdk.tar.gz -C /opt/ mv /opt/jdk-9.0.4 /opt/jdk diff --git a/docker/readme.md b/docker/readme.md index f6b6e550..9939839d 100644 --- a/docker/readme.md +++ b/docker/readme.md @@ -10,11 +10,12 @@ Each docker image contains a `/workspace` where all relevant files are located. When building the image, a lombok.jar will be downloaded to `/workspace`. By default, this is the latest released version. You
can download a specific version by adding `--build-arg lombokjar=lombok-<major.minor.build>.jar`
-### `ARG jdk=9`
+### `ARG jdk=10`
The jdk version to be used. Supported values:
-- `9` (default)
+- `10` (default)
+- `9` (OpenJDK)
- `8`
The version is also accessible in `JDK_VERSION`.
diff --git a/sendSupporters b/sendSupporters new file mode 100755 index 00000000..ecc18c55 --- /dev/null +++ b/sendSupporters @@ -0,0 +1,11 @@ +#!/bin/bash +BASE=`dirname $0` +scp "$BASE/website/lombokSupporters/supporters.json" "escudo:/data/lombok/web/files/supporters.json" +if [ "$*" != "" ]; then + for var in "$@"; do + scp "$BASE/website/lombokSupporters/logos/$var" "escudo:/data/lombok/web/files/logos/$var" + done +fi + +echo Dont forget to list images as arguments + diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index ade86e27..f5134bbd 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -126,6 +126,13 @@ public class ConfigurationKeys { public static final ConfigurationKey<FlagUsageType> NO_ARGS_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.noArgsConstructor.flagUsage", "Emit a warning or error if @NoArgsConstructor is used.") {}; /** + * lombok configuration: {@code lombok.noArgsConstructor.extraPrivate} = {@code true} | {@code false}. + * + * If {@code true} (default), @Data and @Value will also generate a private no-args constructor, if there isn't already one, setting all fields to their default values. + */ + public static final ConfigurationKey<Boolean> NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE = new ConfigurationKey<Boolean>("lombok.noArgsConstructor.extraPrivate", "Generate a private no-ars constructor for @Data and @Value (default: true).") {}; + + /** * lombok configuration: {@code lombok.requiredArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}. * * If set, <em>any</em> usage of {@code @RequiredArgsConstructor} results in a warning / error. @@ -383,6 +390,13 @@ public class ConfigurationKeys { public static final ConfigurationKey<FlagUsageType> LOG_JBOSSLOG_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.jbosslog.flagUsage", "Emit a warning or error if @JBossLog is used.") {}; /** + * lombok configuration: {@code lombok.log.flogger.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, <em>any</em> usage of {@code @Flogger} results in a warning / error. + */ + public static final ConfigurationKey<FlagUsageType> LOG_FLOGGER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.log.flogger.flagUsage", "Emit a warning or error if @Flogger is used.") {}; + + /** * lombok configuration: {@code lombok.log.fieldName} = <String: aJavaIdentifier> (Default: {@code log}). * * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name. @@ -499,6 +513,28 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<FlagUsageType> UTILITY_CLASS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.utilityClass.flagUsage", "Emit a warning or error if @UtilityClass is used.") {}; + // ----- FieldNameConstants ----- + /** + * lombok configuration: {@code lombok.fieldNameConstants.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, <em>any</em> usage of {@code @FieldNameConstants} results in a warning / error. + */ + public static final ConfigurationKey<FlagUsageType> FIELD_NAME_CONSTANTS_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.fieldNameConstants.flagUsage", "Emit a warning or error if @FieldNameConstants is used.") {}; + + /** + * lombok configuration: {@code lombok.fieldNameConstants.prefix} = <String: aJavaIdentifierPrefix> (Default: {@code PREFIX_}). + * + * The names of the constants generated by {@code @FieldNameConstants} will be prefixed with this value. + */ + public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_PREFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.prefix", "names of constants generated by @FieldNameConstants will be prefixed with this value. (default: 'PREFIX_').") {}; + + /** + * lombok configuration: {@code lombok.fieldNameConstants.suffix} = <String: aJavaIdentifierPrefix> (Default: nothing). + * + * The names of the constants generated by {@code @FieldNameConstants} will be suffixed with this value. + */ + public static final ConfigurationKey<String> FIELD_NAME_CONSTANTS_SUFFIX = new ConfigurationKey<String>("lombok.fieldNameConstants.suffix", "names of constants generated by @FieldNameConstants will be suffixed with this value. (default: nothing).") {}; + // ----- Wither ----- /** diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java index 2f88ac50..b2fc672d 100644 --- a/src/core/lombok/EqualsAndHashCode.java +++ b/src/core/lombok/EqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +37,8 @@ public @interface EqualsAndHashCode { /** * Any fields listed here will not be taken into account in the generated {@code equals} and {@code hashCode} implementations. * Mutually exclusive with {@link #of()}. + * <p> + * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Exclude} annotation instead. * * @return A list of fields to exclude. */ @@ -47,6 +49,8 @@ public @interface EqualsAndHashCode { * Normally, all non-static, non-transient fields are used for identity. * <p> * Mutually exclusive with {@link #exclude()}. + * <p> + * Will soon be marked {@code @Deprecated}; use the {@code @EqualsAndHashCode.Include} annotation together with {@code @EqualsAndHashCode(onlyExplicitlyIncluded = true)}. * * @return A list of fields to use (<em>default</em>: all of them). */ @@ -89,4 +93,27 @@ public @interface EqualsAndHashCode { @Retention(RetentionPolicy.SOURCE) @Target({}) @interface AnyAnnotation {} + + /** + * Only include fields and methods explicitly marked with {@code @EqualsAndHashCode.Include}. + * Normally, all (non-static, non-transient) fields are included by default. + */ + boolean onlyExplicitlyIncluded() default false; + + /** + * If present, do not include this field in the generated {@code equals} and {@code hashCode} methods. + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.SOURCE) + public @interface Exclude {} + + /** + * Configure the behaviour of how this member is treated in the {@code equals} and {@code hashCode} implementation; if on a method, include the method's return value as part of calculating hashCode/equality. + */ + @Target({ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.SOURCE) + public @interface Include { + /** Defaults to the method name of the annotated member. If on a method and the name equals the name of a default-included field, this member takes its place. */ + String replaces() default ""; + } } diff --git a/src/core/lombok/ToString.java b/src/core/lombok/ToString.java index 0c43c40b..ae3f071f 100644 --- a/src/core/lombok/ToString.java +++ b/src/core/lombok/ToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,6 +45,8 @@ public @interface ToString { /** * Any fields listed here will not be printed in the generated {@code toString} implementation. * Mutually exclusive with {@link #of()}. + * <p> + * Will soon be marked {@code @Deprecated}; use the {@code @ToString.Exclude} annotation instead. * * @return A list of fields to exclude. */ @@ -55,6 +57,8 @@ public @interface ToString { * Normally, all non-static fields are printed. * <p> * Mutually exclusive with {@link #exclude()}. + * <p> + * Will soon be marked {@code @Deprecated}; use the {@code @ToString.Include} annotation together with {@code @ToString(onlyExplicitlyIncluded = true)}. * * @return A list of fields to use (<em>default</em>: all of them). */ @@ -75,4 +79,33 @@ public @interface ToString { * @return If {@code true}, always use direct field access instead of calling the getter method. */ boolean doNotUseGetters() default false; + + /** + * Only include fields and methods explicitly marked with {@code @ToString.Include}. + * Normally, all (non-static) fields are included by default. + */ + boolean onlyExplicitlyIncluded() default false; + + /** + * If present, do not include this field in the generated {@code toString}. + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.SOURCE) + public @interface Exclude {} + + /** + * Configure the behaviour of how this member is rendered in the {@code toString}; if on a method, include the method's return value in the output. + */ + @Target({ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.SOURCE) + public @interface Include { +// /** If true and the return value is {@code null}, omit this member entirely from the {@code toString} output. */ +// boolean skipNull() default false; // -- We'll add it later, it requires a complete rework on the toString code we generate. + + /** Higher ranks are printed first. Members of the same rank are printed in the order they appear in the source file. */ + int rank() default 0; + + /** Defaults to the field / method name of the annotated member. If the name equals the name of a default-included field, this member takes its place. */ + String name() default ""; + } } diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index 5b4ef393..04448ecb 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -26,6 +26,7 @@ import static lombok.core.Augments.ClassLoader_lombokAlreadyAddedTo; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; @@ -48,6 +49,7 @@ import lombok.patcher.ClassRootFinder; @SupportedAnnotationTypes("*") public class AnnotationProcessor extends AbstractProcessor { + private static String trace(Throwable t) { StringWriter w = new StringWriter(); t.printStackTrace(new PrintWriter(w, true)); @@ -63,6 +65,42 @@ public class AnnotationProcessor extends AbstractProcessor { private final List<ProcessorDescriptor> registered = Arrays.asList(new JavacDescriptor(), new EcjDescriptor()); private final List<ProcessorDescriptor> active = new ArrayList<ProcessorDescriptor>(); private final List<String> delayedWarnings = new ArrayList<String>(); + + /** + * This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment} + * It simply returns the processing environment, but in case of gradle incremental compilation, + * the delegate ProcessingEnvironment of the gradle wrapper is returned. + */ + public static ProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv, List<String> delayedWarnings) { + ProcessingEnvironment javacProcEnv = tryRecursivelyObtainJavacProcessingEnvironment(procEnv); + + if (javacProcEnv == null) { + delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment."); + } + + return javacProcEnv; + } + + private static ProcessingEnvironment tryRecursivelyObtainJavacProcessingEnvironment(ProcessingEnvironment procEnv) { + if (procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) { + return procEnv; + } + + for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { + try { + Field field = procEnvClass.getDeclaredField("delegate"); + field.setAccessible(true); + Object delegate = field.get(procEnv); + + return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate); + } catch (final Exception e) { + // no valid delegate, try superclass + } + } + + return null; + } + static class JavacDescriptor extends ProcessorDescriptor { private Processor processor; @@ -72,10 +110,12 @@ public class AnnotationProcessor extends AbstractProcessor { } @Override boolean want(ProcessingEnvironment procEnv, List<String> delayedWarnings) { - if (!procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) return false; - + ProcessingEnvironment javacProcEnv = getJavacProcessingEnvironment(procEnv, delayedWarnings); + + if (javacProcEnv == null) return false; + try { - ClassLoader classLoader = findAndPatchClassLoader(procEnv); + ClassLoader classLoader = findAndPatchClassLoader(javacProcEnv); processor = (Processor) Class.forName("lombok.javac.apt.LombokProcessor", false, classLoader).newInstance(); } catch (Exception e) { delayedWarnings.add("You found a bug in lombok; lombok.javac.apt.LombokProcessor is not available. Lombok will not run during this compilation: " + trace(e)); diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java index d04797cb..a24330fa 100644 --- a/src/core/lombok/core/AnnotationValues.java +++ b/src/core/lombok/core/AnnotationValues.java @@ -27,6 +27,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -42,7 +43,7 @@ public class AnnotationValues<A extends Annotation> { private final Class<A> type; private final Map<String, AnnotationValue> values; private final LombokNode<?, ?, ?> ast; - + /** * Represents a single method on the annotation class. For example, the value() method on the Getter annotation. */ @@ -50,8 +51,7 @@ public class AnnotationValues<A extends Annotation> { /** A list of the raw expressions. List is size 1 unless an array is provided. */ public final List<String> raws; - /** Guesses for each raw expression. If the raw expression is a literal expression, the guess will - * likely be right. If not, it'll be wrong. */ + /** Guesses for each raw expression. It's 'primitive' (String or primitive), an AV.ClassLiteral, an AV.FieldSelect, or an array of one of those. */ public final List<Object> valueGuesses; /** A list of the actual expressions. List is size 1 unless an array is provided. */ @@ -160,6 +160,62 @@ public class AnnotationValues<A extends Annotation> { private A cachedInstance = null; + public List<String> getAsStringList(String methodName) { + AnnotationValue v = values.get(methodName); + + if (v == null) { + String[] s = getDefaultIf(methodName, String[].class, new String[0]); + return Collections.unmodifiableList(Arrays.asList(s)); + } + + List<String> out = new ArrayList<String>(v.valueGuesses.size()); + int idx = 0; + for (Object guess : v.valueGuesses) { + Object result = guess == null ? null : guessToType(guess, String.class, v, idx); + if (result == null) { + if (v.valueGuesses.size() == 1) { + String[] s = getDefaultIf(methodName, String[].class, new String[0]); + return Collections.unmodifiableList(Arrays.asList(s)); + } + throw new AnnotationValueDecodeFail(v, + "I can't make sense of this annotation value. Try using a fully qualified literal.", idx); + } + out.add((String) result); + } + + return Collections.unmodifiableList(out); + } + + public String getAsString(String methodName) { + AnnotationValue v = values.get(methodName); + if (v == null || v.valueGuesses.size() != 1) { + return getDefaultIf(methodName, String.class, ""); + } + + Object guess = guessToType(v.valueGuesses.get(0), String.class, v, 0); + if (guess instanceof String) return (String) guess; + return getDefaultIf(methodName, String.class, ""); + } + + public boolean getAsBoolean(String methodName) { + AnnotationValue v = values.get(methodName); + if (v == null || v.valueGuesses.size() != 1) { + return getDefaultIf(methodName, boolean.class, false); + } + + Object guess = guessToType(v.valueGuesses.get(0), boolean.class, v, 0); + if (guess instanceof Boolean) return ((Boolean) guess).booleanValue(); + return getDefaultIf(methodName, boolean.class, false); + } + + public <T> T getDefaultIf(String methodName, Class<T> type, T defaultValue) { + try { + return type.cast(type.getMethod(methodName).getDefaultValue()); + } catch (Exception e) { + return defaultValue; + } + } + /** * Creates an actual annotation instance. You can use this to query any annotation methods, except for * those annotation methods with class literals, as those can most likely not be turned into Class objects. @@ -190,7 +246,7 @@ public class AnnotationValues<A extends Annotation> { if (!isArray && v.valueGuesses.size() > 1) { throw new AnnotationValueDecodeFail(v, - "Expected a single value, but " + method.getName() + " has an array of values", -1); + "Expected a single value, but " + method.getName() + " has an array of values", -1); } if (v.valueGuesses.size() == 0 && !isArray) { @@ -217,7 +273,7 @@ public class AnnotationValues<A extends Annotation> { return defaultValue; } throw new AnnotationValueDecodeFail(v, - "I can't make sense of this annotation value. Try using a fully qualified literal.", idx); + "I can't make sense of this annotation value. Try using a fully qualified literal.", idx); } Array.set(array, idx++, result); } @@ -230,48 +286,48 @@ public class AnnotationValues<A extends Annotation> { } private Object guessToType(Object guess, Class<?> expected, AnnotationValue v, int pos) { - if (expected == int.class) { + if (expected == int.class || expected == Integer.class) { if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) { - return ((Number)guess).intValue(); + return ((Number) guess).intValue(); } } - if (expected == long.class) { + if (expected == long.class || expected == Long.class) { if (guess instanceof Long || guess instanceof Integer || guess instanceof Short || guess instanceof Byte) { - return ((Number)guess).longValue(); + return ((Number) guess).longValue(); } } - if (expected == short.class) { + if (expected == short.class || expected == Short.class) { if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) { - int intVal = ((Number)guess).intValue(); - int shortVal = ((Number)guess).shortValue(); + int intVal = ((Number) guess).intValue(); + int shortVal = ((Number) guess).shortValue(); if (shortVal == intVal) return shortVal; } } - if (expected == byte.class) { + if (expected == byte.class || expected == Byte.class) { if (guess instanceof Integer || guess instanceof Short || guess instanceof Byte) { - int intVal = ((Number)guess).intValue(); - int byteVal = ((Number)guess).byteValue(); + int intVal = ((Number) guess).intValue(); + int byteVal = ((Number) guess).byteValue(); if (byteVal == intVal) return byteVal; } } - if (expected == double.class) { - if (guess instanceof Number) return ((Number)guess).doubleValue(); + if (expected == double.class || expected == Double.class) { + if (guess instanceof Number) return ((Number) guess).doubleValue(); } - if (expected == float.class) { - if (guess instanceof Number) return ((Number)guess).floatValue(); + if (expected == float.class || expected == Float.class) { + if (guess instanceof Number) return ((Number) guess).floatValue(); } - if (expected == boolean.class) { - if (guess instanceof Boolean) return ((Boolean)guess).booleanValue(); + if (expected == boolean.class || expected == Boolean.class) { + if (guess instanceof Boolean) return ((Boolean) guess).booleanValue(); } - if (expected == char.class) { - if (guess instanceof Character) return ((Character)guess).charValue(); + if (expected == char.class || expected == Character.class) { + if (guess instanceof Character) return ((Character) guess).charValue(); } if (expected == String.class) { @@ -279,27 +335,36 @@ public class AnnotationValues<A extends Annotation> { } if (Enum.class.isAssignableFrom(expected) ) { - if (guess instanceof String) { + if (guess instanceof FieldSelect) { + String fieldSel = ((FieldSelect) guess).getFinalPart(); for (Object enumConstant : expected.getEnumConstants()) { - String target = ((Enum<?>)enumConstant).name(); - if (target.equals(guess)) return enumConstant; + String target = ((Enum<?>) enumConstant).name(); + if (target.equals(fieldSel)) return enumConstant; } throw new AnnotationValueDecodeFail(v, - "Can't translate " + guess + " to an enum of type " + expected, pos); + "Can't translate " + fieldSel + " to an enum of type " + expected, pos); } } - if (Class.class == expected) { - if (guess instanceof String) try { - return Class.forName(toFQ((String)guess)); + if (expected == Class.class) { + if (guess instanceof ClassLiteral) try { + String classLit = ((ClassLiteral) guess).getClassName(); + return Class.forName(toFQ(classLit)); } catch (ClassNotFoundException e) { throw new AnnotationValueDecodeFail(v, - "Can't translate " + guess + " to a class object.", pos); + "Can't translate " + guess + " to a class object.", pos); } } + if (guess instanceof AnnotationValues) { + return ((AnnotationValues<?>) guess).getInstance(); + } + + if (guess instanceof FieldSelect) throw new AnnotationValueDecodeFail(v, + "You must use constant literals in lombok annotations; they cannot be references to (static) fields.", pos); + throw new AnnotationValueDecodeFail(v, - "Can't translate a " + guess.getClass() + " to the expected " + expected, pos); + "Can't translate a " + guess.getClass() + " to the expected " + expected, pos); } /** diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index 07c62151..d6708956 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -21,6 +21,7 @@ */ package lombok.core; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -275,4 +276,15 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, public boolean isStructurallySignificant() { return isStructurallySignificant; } + + public abstract boolean hasAnnotation(Class<? extends Annotation> type); + public abstract <Z extends Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type); + + public abstract boolean isStatic(); + public abstract boolean isTransient(); + public abstract boolean isEnumMember(); + + public abstract int countMethodParameters(); + + public abstract int getStartPos(); } diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 98f1e575..70af48e0 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,15 +30,16 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.16.21"; + private static final String VERSION = "1.18.1"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; -// private static final String RELEASE_NAME = "Dancing Elephant"; +// private static final String RELEASE_NAME = "Envious Ferret"; // Named version history: // Angry Butterfly // Branching Cobra // Candid Duck // Dancing Elephant + // Envious Ferret private Version() { //Prevent instantiation diff --git a/src/core/lombok/core/configuration/NullCheckExceptionType.java b/src/core/lombok/core/configuration/NullCheckExceptionType.java index 18a332fd..c4bb71f2 100644 --- a/src/core/lombok/core/configuration/NullCheckExceptionType.java +++ b/src/core/lombok/core/configuration/NullCheckExceptionType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ package lombok.core.configuration; public enum NullCheckExceptionType { ILLEGAL_ARGUMENT_EXCEPTION { public String toExceptionMessage(String fieldName) { - return fieldName + " is null"; + return fieldName + " is marked @NonNull but is null"; } @Override public String getExceptionType() { @@ -35,7 +35,7 @@ public enum NullCheckExceptionType { }, NULL_POINTER_EXCEPTION { @Override public String toExceptionMessage(String fieldName) { - return fieldName; + return fieldName + " is marked @NonNull but is null"; } public String getExceptionType() { diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 6b516904..0d64c550 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -57,6 +57,10 @@ import lombok.experimental.Wither; public class HandlerUtil { private HandlerUtil() {} + public enum FieldAccess { + GETTER, PREFER_FIELD, ALWAYS_FIELD; + } + public static int primeForHashcode() { return 59; } @@ -441,4 +445,16 @@ public class HandlerUtil { } return String.format("%s%s", prefix, suffix); } + + public static String camelCaseToConstant(String fieldName) { + if (fieldName == null || fieldName.isEmpty()) return ""; + StringBuilder b = new StringBuilder(); + b.append(Character.toUpperCase(fieldName.charAt(0))); + for (int i = 1; i < fieldName.length(); i++) { + char c = fieldName.charAt(i); + if (Character.isUpperCase(c)) b.append('_'); + b.append(Character.toUpperCase(c)); + } + return b.toString(); + } } diff --git a/src/core/lombok/core/handlers/InclusionExclusionUtils.java b/src/core/lombok/core/handlers/InclusionExclusionUtils.java new file mode 100644 index 00000000..8d6c717f --- /dev/null +++ b/src/core/lombok/core/handlers/InclusionExclusionUtils.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2009-2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.handlers; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.core.AST; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.LombokNode; + +public class InclusionExclusionUtils { + private static List<Integer> createListOfNonExistentFields(List<String> list, LombokNode<?, ?, ?> type, boolean excludeStandard, boolean excludeTransient) { + boolean[] matched = new boolean[list.size()]; + + for (LombokNode<?, ?, ?> child : type.down()) { + if (list.isEmpty()) break; + if (child.getKind() != Kind.FIELD) continue; + if (excludeStandard) { + if (child.isStatic()) continue; + if (child.getName().startsWith("$")) continue; + } + if (excludeTransient && child.isTransient()) continue; + + int idx = list.indexOf(child.getName()); + if (idx > -1) matched[idx] = true; + } + + List<Integer> problematic = new ArrayList<Integer>(); + for (int i = 0 ; i < list.size() ; i++) if (!matched[i]) problematic.add(i); + + return problematic; + } + + public static void checkForBogusFieldNames(LombokNode<?, ?, ?> type, AnnotationValues<?> annotation, List<String> excludes, List<String> includes) { + if (excludes != null && !excludes.isEmpty()) { + for (int i : createListOfNonExistentFields(excludes, type, true, false)) { + if (annotation != null) annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i); + } + } + + if (includes != null && !includes.isEmpty()) { + for (int i : createListOfNonExistentFields(includes, type, false, false)) { + if (annotation != null) annotation.setWarning("of", "This field does not exist.", i); + } + } + } + + public static class Included<L, I extends Annotation> { + private final L node; + private final I inc; + private final boolean defaultInclude; + + public Included(L node, I inc, boolean defaultInclude) { + this.node = node; + this.inc = inc; + this.defaultInclude = defaultInclude; + } + + public L getNode() { + return node; + } + + public I getInc() { + return inc; + } + + public boolean isDefaultInclude() { + return defaultInclude; + } + } + + private static String innerAnnName(Class<? extends Annotation> type) { + String name = type.getSimpleName(); + Class<?> c = type.getEnclosingClass(); + while (c != null) { + name = c.getSimpleName() + "." + name; + c = c.getEnclosingClass(); + } + return name; + } + + public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N, I extends Annotation> List<Included<L, I>> handleIncludeExcludeMarking(Class<I> inclType, String replaceName, Class<? extends Annotation> exclType, LombokNode<A, L, N> typeNode, AnnotationValues<?> annotation, LombokNode<A, L, N> annotationNode) { + List<String> oldExcludes = (annotation != null && annotation.isExplicit("exclude")) ? annotation.getAsStringList("exclude") : null; + List<String> oldIncludes = (annotation != null && annotation.isExplicit("of")) ? annotation.getAsStringList("of") : null; + + boolean onlyExplicitlyIncluded = annotation != null ? annotation.getAsBoolean("onlyExplicitlyIncluded") : false; + boolean memberAnnotationMode = onlyExplicitlyIncluded; + List<Included<L, I>> members = new ArrayList<Included<L, I>>(); + List<String> namesToAutoExclude = new ArrayList<String>(); + + if (typeNode == null || typeNode.getKind() != Kind.TYPE) return null; + + checkForBogusFieldNames(typeNode, annotation, oldExcludes, oldIncludes); + String inclTypeName = innerAnnName(inclType); + String exclTypeName = innerAnnName(exclType); + + if (oldExcludes != null && oldIncludes != null) { + oldExcludes = null; + if (annotation != null) annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored."); + } + + for (L child : typeNode.down()) { + boolean markExclude = child.getKind() == Kind.FIELD && child.hasAnnotation(exclType); + AnnotationValues<I> markInclude = null; + if (child.getKind() == Kind.FIELD || child.getKind() == Kind.METHOD) markInclude = child.findAnnotation(inclType); + + if (markExclude || markInclude != null) memberAnnotationMode = true; + + if (markInclude != null && markExclude) { + child.addError("@" + exclTypeName + " and @" + inclTypeName + " are mutually exclusive; the @Include annotation will be ignored"); + markInclude = null; + } + + String name = child.getName(); + + if (markExclude) { + if (onlyExplicitlyIncluded) { + child.addWarning("The @Exclude annotation is not needed; 'onlyExplicitlyIncluded' is set, so this member would be excluded anyway"); + } else if (child.isStatic()) { + child.addWarning("The @Exclude annotation is not needed; static fields aren't included anyway"); + } else if (name.startsWith("$")) { + child.addWarning("The @Exclude annotation is not needed; fields that start with $ aren't included anyway"); + } + continue; + } + + if (oldExcludes != null && oldExcludes.contains(name)) continue; + + if (markInclude != null) { + I inc = markInclude.getInstance(); + if (child.getKind() == Kind.METHOD) { + if (child.countMethodParameters() > 0) { + child.addError("Methods included with @" + inclTypeName + " must have no arguments; it will not be included"); + continue; + } + String n = replaceName != null ? markInclude.getAsString(replaceName) : ""; + if (n.isEmpty()) n = name; + namesToAutoExclude.add(n); + } + members.add(new Included<L, I>(child, inc, false)); + continue; + } + + if (onlyExplicitlyIncluded) continue; + if (oldIncludes != null) { + if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included<L, I>(child, null, false)); + continue; + } + if (child.getKind() != Kind.FIELD) continue; + if (child.isStatic()) continue; + if (name.startsWith("$")) continue; + if (child.isEnumMember()) continue; + members.add(new Included<L, I>(child, null, true)); + } + + /* delete default-included fields with the same name as an explicit inclusion */ { + Iterator<Included<L, I>> it = members.iterator(); + while (it.hasNext()) { + Included<L, I> m = it.next(); + if (m.isDefaultInclude() && namesToAutoExclude.contains(m.getNode().getName())) it.remove(); + } + } + + if (annotation == null || !annotation.isExplicit("exclude")) oldExcludes = null; + if (annotation == null || !annotation.isExplicit("of")) oldIncludes = null; + + if (memberAnnotationMode && (oldExcludes != null || oldIncludes != null)) { + annotationNode.addError("The old-style 'exclude/of' parameter cannot be used together with the new-style @Include / @Exclude annotations."); + return null; + } + + return members; + } + + public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> List<Included<L, ToString.Include>> handleToStringMarking(LombokNode<A, L, N> typeNode, AnnotationValues<ToString> annotation, LombokNode<A, L, N> annotationNode) { + List<Included<L, ToString.Include>> members = handleIncludeExcludeMarking(ToString.Include.class, "name", ToString.Exclude.class, typeNode, annotation, annotationNode); + + Collections.sort(members, new Comparator<Included<L, ToString.Include>>() { + @Override public int compare(Included<L, ToString.Include> a, Included<L, ToString.Include> b) { + int ra = a.getInc() == null ? 0 : a.getInc().rank(); + int rb = b.getInc() == null ? 0 : b.getInc().rank(); + if (ra < rb) return +1; + if (ra > rb) return -1; + + int pa = a.getNode().getStartPos(); + int pb = b.getNode().getStartPos(); + + if (pa < pb) return -1; + if (pa > pb) return +1; + + return 0; + } + }); + return members; + } + + public static <A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> List<Included<L, EqualsAndHashCode.Include>> handleEqualsAndHashCodeMarking(LombokNode<A, L, N> typeNode, AnnotationValues<EqualsAndHashCode> annotation, LombokNode<A, L, N> annotationNode) { + return handleIncludeExcludeMarking(EqualsAndHashCode.Include.class, "replaces", EqualsAndHashCode.Exclude.class, typeNode, annotation, annotationNode); + } +} diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 49867e62..4db1d38d 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -23,7 +23,9 @@ package lombok.eclipse; import java.util.List; +import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.eclipse.handlers.EclipseHandlerUtil; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -36,6 +38,7 @@ import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; /** * Eclipse specific version of the LombokNode class. @@ -184,4 +187,72 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode, public boolean isCompleteParse() { return ast.isCompleteParse(); } + + @Override public boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type) { + return EclipseHandlerUtil.hasAnnotation(type, this); + } + + @Override public <Z extends java.lang.annotation.Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type) { + EclipseNode annotation = EclipseHandlerUtil.findAnnotation(type, this); + if (annotation == null) return null; + return EclipseHandlerUtil.createAnnotation(type, annotation); + } + + private Integer getModifiers() { + if (node instanceof TypeDeclaration) return ((TypeDeclaration) node).modifiers; + if (node instanceof FieldDeclaration) return ((FieldDeclaration) node).modifiers; + if (node instanceof LocalDeclaration) return ((LocalDeclaration) node).modifiers; + if (node instanceof AbstractMethodDeclaration) return ((AbstractMethodDeclaration) node).modifiers; + + return null; + } + + @Override public boolean isStatic() { + if (node instanceof TypeDeclaration) { + EclipseNode directUp = directUp(); + if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true; + if (!(directUp.get() instanceof TypeDeclaration)) return false; + TypeDeclaration p = (TypeDeclaration) directUp.get(); + int f = p.modifiers; + if ((ClassFileConstants.AccInterface & f) != 0) return true; + if ((ClassFileConstants.AccEnum & f) != 0) return true; + } + + if (node instanceof FieldDeclaration) { + EclipseNode directUp = directUp(); + if (directUp != null && directUp.get() instanceof TypeDeclaration) { + TypeDeclaration p = (TypeDeclaration) directUp.get(); + int f = p.modifiers; + if ((ClassFileConstants.AccInterface & f) != 0) return true; + } + } + + Integer i = getModifiers(); + if (i == null) return false; + int f = i.intValue(); + return (ClassFileConstants.AccStatic & f) != 0; + } + + @Override public boolean isTransient() { + if (getKind() != Kind.FIELD) return false; + Integer i = getModifiers(); + return i != null && (i.intValue() & ClassFileConstants.AccTransient) != 0; + } + + @Override public boolean isEnumMember() { + if (getKind() != Kind.FIELD) return false; + return ((FieldDeclaration) node).getKind() == 3; + } + + @Override public int countMethodParameters() { + if (getKind() != Kind.METHOD) return 0; + + Argument[] a = ((AbstractMethodDeclaration) node).arguments; + if (a == null) return 0; + return a.length; + } + + @Override public int getStartPos() { + return node.sourceStart; + } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 6617d21a..2dce285c 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -746,7 +746,7 @@ public class EclipseHandlerUtil { * Provides AnnotationValues with the data it needs to do its thing. */ public static <A extends java.lang.annotation.Annotation> AnnotationValues<A> - createAnnotation(Class<A> type, final EclipseNode annotationNode) { + createAnnotation(Class<A> type, final EclipseNode annotationNode) { final Annotation annotation = (Annotation) annotationNode.get(); Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>(); @@ -763,7 +763,7 @@ public class EclipseHandlerUtil { String mName = (n == null || n.length == 0) ? "value" : new String(pair.name); final Expression rhs = pair.value; if (rhs instanceof ArrayInitializer) { - expressions = ((ArrayInitializer)rhs).expressions; + expressions = ((ArrayInitializer) rhs).expressions; } else if (rhs != null) { expressions = new Expression[] { rhs }; } @@ -920,10 +920,6 @@ public class EclipseHandlerUtil { return null; } - public enum FieldAccess { - GETTER, PREFER_FIELD, ALWAYS_FIELD; - } - static boolean lookForGetter(EclipseNode field, FieldAccess fieldAccess) { if (fieldAccess == FieldAccess.GETTER) return true; if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false; @@ -940,11 +936,13 @@ public class EclipseHandlerUtil { } static TypeReference getFieldType(EclipseNode field, FieldAccess fieldAccess) { + if (field.get() instanceof MethodDeclaration) return ((MethodDeclaration) field.get()).returnType; + boolean lookForGetter = lookForGetter(field, fieldAccess); GetterMethod getter = lookForGetter ? findGetter(field) : null; if (getter == null) { - return ((FieldDeclaration)field.get()).type; + return ((FieldDeclaration) field.get()).type; } return getter.type; @@ -952,7 +950,7 @@ public class EclipseHandlerUtil { static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source) { int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd; - long p = (long)pS << 32 | pE; + long p = (long) pS << 32 | pE; boolean lookForGetter = lookForGetter(field, fieldAccess); @@ -1020,6 +1018,43 @@ public class EclipseHandlerUtil { return call; } + static Expression createMethodAccessor(EclipseNode method, ASTNode source) { + int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd; + long p = (long) pS << 32 | pE; + + MethodDeclaration methodDecl = (MethodDeclaration) method.get(); + MessageSend call = new MessageSend(); + setGeneratedBy(call, source); + call.sourceStart = pS; call.statementEnd = call.sourceEnd = pE; + if ((methodDecl.modifiers & ClassFileConstants.AccStatic) == 0) { + call.receiver = new ThisReference(pS, pE); + setGeneratedBy(call.receiver, source); + } else { + EclipseNode containerNode = method.up(); + if (containerNode != null && containerNode.get() instanceof TypeDeclaration) { + call.receiver = new SingleNameReference(((TypeDeclaration) containerNode.get()).name, p); + setGeneratedBy(call.receiver, source); + } + } + + call.selector = methodDecl.selector; + return call; + } + + static Expression createMethodAccessor(EclipseNode method, ASTNode source, char[] receiver) { + int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd; + long p = (long) pS << 32 | pE; + + MethodDeclaration methodDecl = (MethodDeclaration) method.get(); + MessageSend call = new MessageSend(); + setGeneratedBy(call, source); + call.sourceStart = pS; call.statementEnd = call.sourceEnd = pE; + call.receiver = new SingleNameReference(receiver, p); + setGeneratedBy(call.receiver, source); + call.selector = methodDecl.selector; + return call; + } + /** Serves as return value for the methods that check for the existence of fields and methods. */ public enum MemberExistsResult { NOT_EXISTS, EXISTS_BY_LOMBOK, EXISTS_BY_USER; @@ -1097,7 +1132,7 @@ public class EclipseHandlerUtil { public static boolean filterField(FieldDeclaration declaration, boolean skipStatic) { // Skip the fake fields that represent enum constants. if (declaration.initialization instanceof AllocationExpression && - ((AllocationExpression)declaration.initialization).enumConstant != null) return false; + ((AllocationExpression) declaration.initialization).enumConstant != null) return false; if (declaration.type == null) return false; @@ -1163,6 +1198,12 @@ public class EclipseHandlerUtil { return AnnotationValues.of(Accessors.class, field); } + + public static EclipseNode upToTypeNode(EclipseNode node) { + if (node == null) throw new NullPointerException("node"); + while (node != null && !(node.get() instanceof TypeDeclaration)) node = node.up(); + return node; + } /** * Checks if there is a field with the provided name. @@ -1171,10 +1212,7 @@ public class EclipseHandlerUtil { * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof. */ public static MemberExistsResult fieldExists(String fieldName, EclipseNode node) { - while (node != null && !(node.get() instanceof TypeDeclaration)) { - node = node.up(); - } - + node = upToTypeNode(node); if (node != null && node.get() instanceof TypeDeclaration) { TypeDeclaration typeDecl = (TypeDeclaration)node.get(); if (typeDecl.fields != null) for (FieldDeclaration def : typeDecl.fields) { @@ -1260,10 +1298,7 @@ public class EclipseHandlerUtil { * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof. */ public static MemberExistsResult constructorExists(EclipseNode node) { - while (node != null && !(node.get() instanceof TypeDeclaration)) { - node = node.up(); - } - + node = upToTypeNode(node); if (node != null && node.get() instanceof TypeDeclaration) { TypeDeclaration typeDecl = (TypeDeclaration)node.get(); if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { @@ -1819,4 +1854,12 @@ public class EclipseHandlerUtil { private static long[] copy(long[] array) { return array == null ? null : array.clone(); } + + public static boolean isDirectDescendantOfObject(EclipseNode typeNode) { + if (!(typeNode.get() instanceof TypeDeclaration)) throw new IllegalArgumentException("not a type node"); + TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get(); + if (typeDecl.superclass == null) return true; + String p = typeDecl.superclass.toString(); + return p.equals("Object") || p.equals("java.lang.Object"); + } } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index fe19decd..e1b1af26 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -74,8 +74,10 @@ import lombok.Builder; import lombok.Builder.ObtainVia; import lombok.ConfigurationKeys; import lombok.Singular; +import lombok.ToString; import lombok.core.AST.Kind; import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.Eclipse; @@ -449,9 +451,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { - List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>(); + List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { - fieldNodes.addAll(bfd.createdFields); + for (EclipseNode f : bfd.createdFields) { + fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true)); + } } MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD); if (md != null) injectMethod(builderType, md); diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index a2940b88..cab847e6 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -42,8 +42,10 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; @@ -204,6 +206,20 @@ public class HandleConstructor { return true; } + public enum SkipIfConstructorExists { + YES, NO, I_AM_BUILDER; + } + + public void generateExtraNoArgsConstructor(EclipseNode typeNode, EclipseNode sourceNode) { + if (!isDirectDescendantOfObject(typeNode)) return; + + Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE); + if (v == null || !v) return; + + List<EclipseNode> fields = findFinalFields(typeNode); + generate(typeNode, AccessLevel.PRIVATE, fields, true, null, SkipIfConstructorExists.NO, Collections.<Annotation>emptyList(), sourceNode, true); + } + public void generateRequiredArgsConstructor( EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, EclipseNode sourceNode) { @@ -218,14 +234,17 @@ public class HandleConstructor { generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode); } - public enum SkipIfConstructorExists { - YES, NO, I_AM_BUILDER; - } - public void generateConstructor( EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, EclipseNode sourceNode) { + generate(typeNode, level, fields, allToDefault, staticName, skipIfConstructorExists, onConstructor, sourceNode, false); + } + + public void generate( + EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, + List<Annotation> onConstructor, EclipseNode sourceNode, boolean noArgs) { + ASTNode source = sourceNode.get(); boolean staticConstrRequired = staticName != null && !staticName.equals(""); @@ -257,6 +276,8 @@ public class HandleConstructor { } } + if (noArgs && noArgsConstructorExists(typeNode)) return; + ConstructorDeclaration constr = createConstructor( staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault, sourceNode, onConstructor); @@ -267,7 +288,29 @@ public class HandleConstructor { } } - public static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() }; + private static boolean noArgsConstructorExists(EclipseNode node) { + node = EclipseHandlerUtil.upToTypeNode(node); + + if (node != null && node.get() instanceof TypeDeclaration) { + TypeDeclaration typeDecl = (TypeDeclaration)node.get(); + if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { + if (def instanceof ConstructorDeclaration) { + Argument[] arguments = ((ConstructorDeclaration) def).arguments; + if (arguments == null || arguments.length == 0) return true; + } + } + } + + for (EclipseNode child : node.down()) { + if (annotationTypeMatches(NoArgsConstructor.class, child)) return true; + if (annotationTypeMatches(RequiredArgsConstructor.class, child) && findRequiredFields(node).isEmpty()) return true; + if (annotationTypeMatches(AllArgsConstructor.class, child) && findAllFields(node).isEmpty()) return true; + } + + return false; + } + + private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() }; public static Annotation[] createConstructorProperties(ASTNode source, Collection<EclipseNode> fields) { if (fields.isEmpty()) return null; diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index 025ceefd..4011890d 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -72,12 +72,13 @@ public class HandleData extends EclipseAnnotationHandler<Data> { //for whatever reason, though you can find callers of that one by focusing on the class name itself //and hitting 'find callers'. - handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); - handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); + handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList()); + handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList()); handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode); handleToString.generateToStringForType(typeNode, annotationNode); handleConstructor.generateRequiredArgsConstructor( typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES, Collections.<Annotation>emptyList(), annotationNode); + handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode); } } diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 75339f7c..c99b9b5f 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,12 +38,13 @@ import lombok.ConfigurationKeys; import lombok.EqualsAndHashCode; import lombok.core.AST.Kind; import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.InclusionExclusionUtils; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.configuration.CallSuperType; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import org.eclipse.jdt.internal.compiler.ast.ASTNode; @@ -57,7 +58,6 @@ import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; @@ -99,62 +99,41 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH public static final Set<String> BUILT_IN_TYPES = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList( "byte", "short", "int", "long", "char", "boolean", "double", "float"))); - public void checkForBogusFieldNames(EclipseNode type, AnnotationValues<EqualsAndHashCode> annotation) { - if (annotation.isExplicit("exclude")) { - for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().exclude()), type, true, true)) { - annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i); - } - } - if (annotation.isExplicit("of")) { - for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().of()), type, false, false)) { - annotation.setWarning("of", "This field does not exist.", i); - } - } - } - - public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) { - if (hasAnnotation(EqualsAndHashCode.class, typeNode)) { - //The annotation will make it happen, so we can skip it. - return; - } - - Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); - FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; - - generateMethods(typeNode, errorNode, null, null, null, false, access, new ArrayList<Annotation>()); - } - @Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode"); EqualsAndHashCode ann = annotation.getInstance(); - List<String> excludes = Arrays.asList(ann.exclude()); - List<String> includes = Arrays.asList(ann.of()); - EclipseNode typeNode = annotationNode.up(); + List<Included<EclipseNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode); + if (members == null) return; List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode); - checkForBogusFieldNames(typeNode, annotation); Boolean callSuper = ann.callSuper(); if (!annotation.isExplicit("callSuper")) callSuper = null; - if (!annotation.isExplicit("exclude")) excludes = null; - if (!annotation.isExplicit("of")) includes = null; - - if (excludes != null && includes != null) { - excludes = null; - annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored."); - } Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess, onParam); + generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, fieldAccess, onParam); + } + + public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) { + if (hasAnnotation(EqualsAndHashCode.class, typeNode)) { + //The annotation will make it happen, so we can skip it. + return; + } + + List<Included<EclipseNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null); + + Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); + FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; + + generateMethods(typeNode, errorNode, members, null, false, access, new ArrayList<Annotation>()); } - public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes, - Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) { - assert excludes == null || includes == null; + public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members, + Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) { TypeDeclaration typeDecl = null; @@ -172,18 +151,13 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH if (callSuper == null) { try { - callSuper = ((Boolean)EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue(); + callSuper = ((Boolean) EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue(); } catch (Exception ignore) { throw new InternalError("Lombok bug - this cannot happen - can't find callSuper field in EqualsAndHashCode annotation."); } } - boolean isDirectDescendantOfObject = true; - - if (typeDecl.superclass != null) { - String p = typeDecl.superclass.toString(); - isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object"); - } + boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode); if (isDirectDescendantOfObject && callSuper) { errorNode.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); @@ -209,27 +183,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } } - List<EclipseNode> nodesForEquality = new ArrayList<EclipseNode>(); - if (includes != null) { - for (EclipseNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); - if (includes.contains(new String(fieldDecl.name))) nodesForEquality.add(child); - } - } else { - for (EclipseNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); - if (!filterField(fieldDecl)) continue; - - //Skip transient fields. - if ((fieldDecl.modifiers & ClassFileConstants.AccTransient) != 0) continue; - //Skip excluded fields. - if (excludes != null && excludes.contains(new String(fieldDecl.name))) continue; - nodesForEquality.add(child); - } - } - boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0; boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject; MemberExistsResult equalsExists = methodExists("equals", typeNode, 1); @@ -258,7 +211,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH //fallthrough } - MethodDeclaration equalsMethod = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam); + MethodDeclaration equalsMethod = createEquals(typeNode, members, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam); equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope); injectMethod(typeNode, equalsMethod); @@ -268,17 +221,16 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH injectMethod(typeNode, canEqualMethod); } - MethodDeclaration hashCodeMethod = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess); + MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, errorNode.get(), fieldAccess); hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope); injectMethod(typeNode, hashCodeMethod); } - public MethodDeclaration createHashCode(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { + public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; - MethodDeclaration method = new MethodDeclaration( - ((CompilationUnitDeclaration) type.top().get()).compilationResult); + MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); setGeneratedBy(method, source); method.modifiers = toEclipseModifier(AccessLevel.PUBLIC); @@ -295,10 +247,10 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH List<Statement> statements = new ArrayList<Statement>(); - final boolean isEmpty = fields.isEmpty(); + final boolean isEmpty = members.isEmpty(); /* final int PRIME = X; */ { - /* Without fields, PRIME isn't used, and that would trigger a 'local variable not used' warning. */ + /* Without members, PRIME isn't used, as that would trigger a 'local variable not used' warning. */ if (!isEmpty) { LocalDeclaration primeDecl = new LocalDeclaration(PRIME, pS, pE); setGeneratedBy(primeDecl, source); @@ -311,7 +263,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } } - /*int result = ... */{ + /* int result = ... */ { LocalDeclaration resultDecl = new LocalDeclaration(RESULT, pS, pE); setGeneratedBy(resultDecl, source); final Expression init; @@ -335,11 +287,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH statements.add(resultDecl); } - for (EclipseNode field : fields) { - TypeReference fType = getFieldType(field, fieldAccess); - char[] dollarFieldName = ("$" + field.getName()).toCharArray(); + for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) { + EclipseNode memberNode = member.getNode(); + boolean isMethod = memberNode.getKind() == Kind.METHOD; + + TypeReference fType = getFieldType(memberNode, fieldAccess); + char[] dollarFieldName = ((isMethod ? "$$" : "$") + memberNode.getName()).toCharArray(); char[] token = fType.getLastToken(); - Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source); + Expression fieldAccessor = isMethod ? createMethodAccessor(memberNode, source) : createFieldAccessor(memberNode, fieldAccess, source); if (fType.dimensions() == 0 && token != null) { if (Arrays.equals(TypeConstants.BOOLEAN, token)) { /* booleanField ? X : Y */ @@ -479,14 +434,16 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH list.add(type.getName()); if (addWildcards) genericsCount.add(arraySizeOf(((TypeDeclaration) type.get()).typeParameters)); - boolean staticContext = (((TypeDeclaration) type.get()).modifiers & Modifier.STATIC) != 0; + boolean staticContext = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccStatic) != 0; EclipseNode tNode = type.up(); + if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true; while (tNode != null && tNode.getKind() == Kind.TYPE) { list.add(tNode.getName()); if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(((TypeDeclaration) tNode.get()).typeParameters)); if (!staticContext) staticContext = (((TypeDeclaration) tNode.get()).modifiers & Modifier.STATIC) != 0; tNode = tNode.up(); + if (!staticContext && tNode.getKind() == Kind.TYPE && (((TypeDeclaration) tNode.get()).modifiers & ClassFileConstants.AccInterface) != 0) staticContext = true; } Collections.reverse(list); if (addWildcards) Collections.reverse(genericsCount); @@ -533,12 +490,11 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH return arr == null ? 0 : arr.length; } - public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) { + public MethodDeclaration createEquals(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) { int pS = source.sourceStart; int pE = source.sourceEnd; long p = (long)pS << 32 | pE; - MethodDeclaration method = new MethodDeclaration( - ((CompilationUnitDeclaration) type.top().get()).compilationResult); + MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); setGeneratedBy(method, source); method.modifiers = toEclipseModifier(AccessLevel.PUBLIC); method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); @@ -605,7 +561,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH char[] otherName = "other".toCharArray(); /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ { - if (!fields.isEmpty() || needsCanEqual) { + if (!members.isEmpty() || needsCanEqual) { LocalDeclaration other = new LocalDeclaration(otherName, pS, pE); other.modifiers |= ClassFileConstants.AccFinal; setGeneratedBy(other, source); @@ -674,11 +630,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH statements.add(ifSuperEquals); } - for (EclipseNode field : fields) { - TypeReference fType = getFieldType(field, fieldAccess); + for (Included<EclipseNode, EqualsAndHashCode.Include> member : members) { + EclipseNode memberNode = member.getNode(); + boolean isMethod = memberNode.getKind() == Kind.METHOD; + + TypeReference fType = getFieldType(memberNode, fieldAccess); char[] token = fType.getLastToken(); - Expression thisFieldAccessor = createFieldAccessor(field, fieldAccess, source); - Expression otherFieldAccessor = createFieldAccessor(field, fieldAccess, source, otherName); + Expression thisFieldAccessor = isMethod ? createMethodAccessor(memberNode, source) : createFieldAccessor(memberNode, fieldAccess, source); + Expression otherFieldAccessor = isMethod ? createMethodAccessor(memberNode, source, otherName) : createFieldAccessor(memberNode, fieldAccess, source, otherName); if (fType.dimensions() == 0 && token != null) { if (Arrays.equals(TypeConstants.FLOAT, token)) { @@ -699,8 +658,8 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH /* final java.lang.Object this$fieldName = this.fieldName; */ /* final java.lang.Object other$fieldName = other.fieldName; */ /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */ - char[] thisDollarFieldName = ("this$" + field.getName()).toCharArray(); - char[] otherDollarFieldName = ("other$" + field.getName()).toCharArray(); + char[] thisDollarFieldName = ("this" + (isMethod ? "$$" : "$") + memberNode.getName()).toCharArray(); + char[] otherDollarFieldName = ("other" + (isMethod ? "$$" : "$") + memberNode.getName()).toCharArray(); statements.add(createLocalDeclaration(source, thisDollarFieldName, generateQualifiedTypeRef(source, TypeConstants.JAVA_LANG_OBJECT), thisFieldAccessor)); statements.add(createLocalDeclaration(source, otherDollarFieldName, generateQualifiedTypeRef(source, TypeConstants.JAVA_LANG_OBJECT), otherFieldAccessor)); @@ -713,7 +672,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH setGeneratedBy(other1, source); SingleNameReference other2 = new SingleNameReference(otherDollarFieldName, p); setGeneratedBy(other2, source); - NullLiteral nullLiteral = new NullLiteral(pS, pE); setGeneratedBy(nullLiteral, source); @@ -776,7 +734,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH return method; } - public MethodDeclaration createCanEqual(EclipseNode type, ASTNode source, List<Annotation> onParam) { /* protected boolean canEqual(final java.lang.Object other) { * return other instanceof Outer.Inner.MyType; @@ -787,8 +744,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH char[] otherName = "other".toCharArray(); - MethodDeclaration method = new MethodDeclaration( - ((CompilationUnitDeclaration) type.top().get()).compilationResult); + MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); setGeneratedBy(method, source); method.modifiers = toEclipseModifier(AccessLevel.PROTECTED); method.returnType = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java new file mode 100644 index 00000000..c3a28f7f --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014-2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers; + +import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.Collection; + +import lombok.AccessLevel; +import lombok.ConfigurationKeys; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.handlers.HandlerUtil; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.experimental.FieldNameConstants; + +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.StringLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.mangosdk.spi.ProviderFor; + +@ProviderFor(EclipseAnnotationHandler.class) +public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldNameConstants> { + public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, String prefix, String suffix) { + TypeDeclaration typeDecl = null; + if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); + + int modifiers = typeDecl == null ? 0 : typeDecl.modifiers; + boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; + + if (typeDecl == null || notAClass) { + errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field."); + return; + } + + for (EclipseNode field : typeNode.down()) { + if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix); + } + } + + private void generateFieldNameConstantsForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, String prefix, String suffix) { + if (hasAnnotation(FieldNameConstants.class, fieldNode)) return; + createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, pos, false); + } + + private boolean fieldQualifiesForFieldNameConstantsGeneration(EclipseNode field) { + if (field.getKind() != Kind.FIELD) return false; + FieldDeclaration fieldDecl = (FieldDeclaration) field.get(); + return filterField(fieldDecl); + } + + public void handle(AnnotationValues<FieldNameConstants> annotation, Annotation ast, EclipseNode annotationNode) { + handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants"); + + EclipseNode node = annotationNode.up(); + FieldNameConstants annotatationInstance = annotation.getInstance(); + AccessLevel level = annotatationInstance.level(); + String prefix = annotatationInstance.prefix(); + String suffix = annotatationInstance.suffix(); + if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX); + if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX); + if (prefix == null) prefix = "FIELD_"; + if (suffix == null) suffix = ""; + if (node == null) return; + + switch (node.getKind()) { + case FIELD: + if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true); + break; + case TYPE: + if (level == AccessLevel.NONE) { + annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE."); + return; + } + generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix); + break; + } + } + + private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + for (EclipseNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, source, whineIfExists); + } + + private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + if (fieldNode.getKind() != Kind.FIELD) { + errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field"); + return; + } + + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + String fieldName = new String(field.name); + String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix; + if (constantName.equals(fieldName)) { + fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field."); + return; + } + + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long) pS << 32 | pE; + FieldDeclaration fieldConstant = new FieldDeclaration(constantName.toCharArray(), pS,pE); + fieldConstant.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + fieldConstant.modifiers = toEclipseModifier(level) | Modifier.STATIC | Modifier.FINAL; + fieldConstant.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p,p,p}); + fieldConstant.initialization = new StringLiteral(field.name, pS, pE, 0); + injectField(fieldNode.up(), fieldConstant); + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index f417aca5..d0c2cc23 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -41,7 +41,6 @@ import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.agent.PatchDelegate; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; @@ -80,7 +79,7 @@ import org.mangosdk.spi.ProviderFor; public class HandleGetter extends EclipseAnnotationHandler<Getter> { private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0]; - public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter) { + public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter, List<Annotation> onMethod) { if (checkForTypeLevelGetter) { if (hasAnnotation(Getter.class, typeNode)) { //The annotation will make it happen, so we can skip it. @@ -100,7 +99,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } for (EclipseNode field : typeNode.down()) { - if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, false); + if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, false, onMethod); } return true; } @@ -123,13 +122,13 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { * If not, the getter is still generated if it isn't already there, though there will not * be a warning if its already there. The default access level is used. */ - public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean lazy) { + public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, boolean lazy, List<Annotation> onMethod) { if (hasAnnotation(Getter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - createGetterForField(level, fieldNode, fieldNode, pos, false, lazy, Collections.<Annotation>emptyList()); + createGetterForField(level, fieldNode, fieldNode, pos, false, lazy, onMethod); } public void handle(AnnotationValues<Getter> annotation, Annotation ast, EclipseNode annotationNode) { @@ -155,11 +154,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, lazy, onMethod); break; case TYPE: - if (!onMethod.isEmpty()) { - annotationNode.addError("'onMethod' is not supported for @Getter on a type."); - } if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type."); - generateGetterForType(node, annotationNode, level, false); + generateGetterForType(node, annotationNode, level, false, onMethod); break; } } diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index c49030d8..8c7f7971 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -109,7 +109,7 @@ public class HandleLog { private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String logFieldName, boolean useStatic, String loggerTopic) { int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; + long p = (long) pS << 32 | pE; // private static final <loggerType> log = <factoryMethod>(<parameter>); FieldDeclaration fieldDecl = new FieldDeclaration(logFieldName.toCharArray(), 0, -1); @@ -126,13 +126,15 @@ public class HandleLog { factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray(); Expression parameter; - if (loggerTopic == null || loggerTopic.trim().length() == 0) { + if (!framework.passTypeName) { + parameter = null; + } else if (loggerTopic == null || loggerTopic.trim().length() == 0) { parameter = framework.createFactoryParameter(loggingType, source); } else { parameter = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0); } - factoryMethodCall.arguments = new Expression[] { parameter }; + factoryMethodCall.arguments = parameter != null ? new Expression[] { parameter } : null; factoryMethodCall.nameSourcePosition = p; factoryMethodCall.sourceStart = pS; factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE; @@ -240,6 +242,17 @@ public class HandleLog { } } + /** + * Handles the {@link lombok.extern.flogger.Flogger} annotation for Eclipse. + */ + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleFloggerLog extends EclipseAnnotationHandler<lombok.extern.flogger.Flogger> { + @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, Annotation source, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); + processAnnotation(LoggingFramework.FLOGGER, annotation, source, annotationNode, ""); + } + } + enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS("org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory", "getLog", "@CommonsLog"), @@ -278,18 +291,31 @@ public class HandleLog { // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); JBOSSLOG("org.jboss.logging.Logger", "org.jboss.logging.Logger", "getLogger", "@JBossLog"), + + // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + FLOGGER("com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger", "forEnclosingClass", "@Flogger", false), ; private final String loggerTypeName; private final String loggerFactoryTypeName; private final String loggerFactoryMethodName; private final String annotationAsString; - + private final boolean passTypeName; + + LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString, boolean passTypeName) { + this.loggerTypeName = loggerTypeName; + this.loggerFactoryTypeName = loggerFactoryTypeName; + this.loggerFactoryMethodName = loggerFactoryMethodName; + this.annotationAsString = annotationAsString; + this.passTypeName = passTypeName; + } + LoggingFramework(String loggerTypeName, String loggerFactoryTypeName, String loggerFactoryMethodName, String annotationAsString) { this.loggerTypeName = loggerTypeName; this.loggerFactoryTypeName = loggerFactoryTypeName; this.loggerFactoryMethodName = loggerFactoryMethodName; this.annotationAsString = annotationAsString; + this.passTypeName = true; } final String getAnnotationAsString() { @@ -308,7 +334,7 @@ public class HandleLog { return loggerFactoryMethodName; } - Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source){ + Expression createFactoryParameter(ClassLiteralAccess loggingType, Annotation source) { TypeReference copy = copyType(loggingType.type, source); ClassLiteralAccess result = new ClassLiteralAccess(source.sourceEnd, copy); setGeneratedBy(result, source); diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 92489c09..d4df0deb 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -24,11 +24,12 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.toAllSetterNames; +import static lombok.eclipse.handlers.EclipseHandlerUtil.toSetterName; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import lombok.AccessLevel; @@ -38,7 +39,6 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -64,7 +64,7 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleSetter extends EclipseAnnotationHandler<Setter> { - public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter) { + public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter, List<Annotation> onMethod, List<Annotation> onParam) { if (checkForTypeLevelSetter) { if (hasAnnotation(Setter.class, typeNode)) { //The annotation will make it happen, so we can skip it. @@ -91,7 +91,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { //Skip final fields. if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) continue; - generateSetterForField(field, pos, level); + generateSetterForField(field, pos, level, onMethod, onParam); } return true; } @@ -108,15 +108,12 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { * If not, the setter is still generated if it isn't already there, though there will not * be a warning if its already there. The default access level is used. */ - public void generateSetterForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level) { + public void generateSetterForField(EclipseNode fieldNode, EclipseNode sourceNode, AccessLevel level, List<Annotation> onMethod, List<Annotation> onParam) { if (hasAnnotation(Setter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - - List<Annotation> empty = Collections.emptyList(); - - createSetterForField(level, fieldNode, sourceNode, false, empty, empty); + createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam); } @Override public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) { @@ -134,13 +131,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod, onParam); break; case TYPE: - if (!onMethod.isEmpty()) { - annotationNode.addError("'onMethod' is not supported for @Setter on a type."); - } - if (!onParam.isEmpty()) { - annotationNode.addError("'onParam' is not supported for @Setter on a type."); - } - generateSetterForType(node, annotationNode, level, false); + generateSetterForType(node, annotationNode, level, false, onMethod, onParam); break; } } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 12fc4761..6b0275e4 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -74,13 +74,14 @@ import lombok.Builder; import lombok.Builder.ObtainVia; import lombok.ConfigurationKeys; import lombok.Singular; +import lombok.ToString; import lombok.core.AST.Kind; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; @@ -307,9 +308,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Create the toString() method for the abstract builder. if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { - java.util.List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>(); + List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { - fieldNodes.addAll(bfd.createdFields); + for (EclipseNode f : bfd.createdFields) { + fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true)); + } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD); diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java index d8f4c569..02a19f8d 100644 --- a/src/core/lombok/eclipse/handlers/HandleToString.java +++ b/src/core/lombok/eclipse/handlers/HandleToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,6 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -37,17 +36,17 @@ import lombok.ConfigurationKeys; import lombok.ToString; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.handlers.InclusionExclusionUtils; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NameReference; @@ -70,17 +69,25 @@ import org.mangosdk.spi.ProviderFor; */ @ProviderFor(EclipseAnnotationHandler.class) public class HandleToString extends EclipseAnnotationHandler<ToString> { - public void checkForBogusFieldNames(EclipseNode type, AnnotationValues<ToString> annotation) { - if (annotation.isExplicit("exclude")) { - for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().exclude()), type, true, false)) { - annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i); - } - } - if (annotation.isExplicit("of")) { - for (int i : createListOfNonExistentFields(Arrays.asList(annotation.getInstance().of()), type, false, false)) { - annotation.setWarning("of", "This field does not exist.", i); - } - } + public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString"); + + ToString ann = annotation.getInstance(); + List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), annotation, annotationNode); + if (members == null) return; + + Boolean callSuper = ann.callSuper(); + + if (!annotation.isExplicit("callSuper")) callSuper = null; + + Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); + boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; + FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; + + Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES); + boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration; + + generateToString(annotationNode.up(), annotationNode, members, includeFieldNames, callSuper, true, fieldAccess); } public void generateToStringForType(EclipseNode typeNode, EclipseNode errorNode) { @@ -98,41 +105,13 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; - generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, access); + List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(typeNode, null, null); + generateToString(typeNode, errorNode, members, includeFieldNames, null, false, access); } - public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) { - handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString"); - - ToString ann = annotation.getInstance(); - List<String> excludes = Arrays.asList(ann.exclude()); - List<String> includes = Arrays.asList(ann.of()); - EclipseNode typeNode = annotationNode.up(); - Boolean callSuper = ann.callSuper(); + public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, ToString.Include>> members, + boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { - if (!annotation.isExplicit("callSuper")) callSuper = null; - if (!annotation.isExplicit("exclude")) excludes = null; - if (!annotation.isExplicit("of")) includes = null; - - if (excludes != null && includes != null) { - excludes = null; - annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored."); - } - - checkForBogusFieldNames(typeNode, annotation); - - Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); - boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; - FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - - Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES); - boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration; - - generateToString(typeNode, annotationNode, excludes, includes, includeFieldNames, callSuper, true, fieldAccess); - } - - public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes, - boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { TypeDeclaration typeDecl = null; if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); @@ -140,39 +119,20 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0; - if (typeDecl == null || notAClass) { - errorNode.addError("@ToString is only supported on a class or enum."); - } - if (callSuper == null) { try { callSuper = ((Boolean)ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue(); } catch (Exception ignore) {} } - List<EclipseNode> nodesForToString = new ArrayList<EclipseNode>(); - if (includes != null) { - for (EclipseNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); - if (includes.contains(new String(fieldDecl.name))) nodesForToString.add(child); - } - } else { - for (EclipseNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); - if (!filterField(fieldDecl)) continue; - - //Skip excluded fields. - if (excludes != null && excludes.contains(new String(fieldDecl.name))) continue; - - nodesForToString.add(child); - } + if (typeDecl == null || notAClass) { + errorNode.addError("@ToString is only supported on a class or enum."); + return; } switch (methodExists("toString", typeNode, 0)) { case NOT_EXISTS: - MethodDeclaration toString = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, errorNode.get(), fieldAccess); + MethodDeclaration toString = createToString(typeNode, members, includeFieldNames, callSuper, errorNode.get(), fieldAccess); injectMethod(typeNode, toString); break; case EXISTS_BY_LOMBOK: @@ -185,8 +145,9 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { } } - public static MethodDeclaration createToString(EclipseNode type, Collection<EclipseNode> fields, - boolean includeFieldNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { + public static MethodDeclaration createToString(EclipseNode type, Collection<Included<EclipseNode, ToString.Include>> members, + boolean includeNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { + String typeName = getTypeName(type); char[] suffix = ")".toCharArray(); String infixS = ", "; @@ -199,10 +160,13 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { if (callSuper) { prefix = (typeName + "(super=").toCharArray(); - } else if (fields.isEmpty()) { + } else if (members.isEmpty()) { prefix = (typeName + "()").toCharArray(); - } else if (includeFieldNames) { - prefix = (typeName + "(" + new String(((FieldDeclaration)fields.iterator().next().get()).name) + "=").toCharArray(); + } else if (includeNames) { + Included<EclipseNode, ToString.Include> firstMember = members.iterator().next(); + String name = firstMember.getInc() == null ? "" : firstMember.getInc().name(); + if (name.isEmpty()) name = firstMember.getNode().getName(); + prefix = (typeName + "(" + name + "=").toCharArray(); } else { prefix = (typeName + "(").toCharArray(); } @@ -223,29 +187,35 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { first = false; } - for (EclipseNode field : fields) { - TypeReference fieldType = getFieldType(field, fieldAccess); - Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source); + for (Included<EclipseNode, ToString.Include> member : members) { + EclipseNode memberNode = member.getNode(); + + TypeReference fieldType = getFieldType(memberNode, fieldAccess); + Expression memberAccessor; + if (memberNode.getKind() == Kind.METHOD) { + memberAccessor = createMethodAccessor(memberNode, source); + } else { + memberAccessor = createFieldAccessor(memberNode, fieldAccess, source); + } // The distinction between primitive and object will be useful if we ever add a 'hideNulls' option. boolean fieldBaseTypeIsPrimitive = BUILT_IN_TYPES.contains(new String(fieldType.getLastToken())); + @SuppressWarnings("unused") boolean fieldIsPrimitive = fieldType.dimensions() == 0 && fieldBaseTypeIsPrimitive; boolean fieldIsPrimitiveArray = fieldType.dimensions() == 1 && fieldBaseTypeIsPrimitive; boolean fieldIsObjectArray = fieldType.dimensions() > 0 && !fieldIsPrimitiveArray; - @SuppressWarnings("unused") - boolean fieldIsObject = !fieldIsPrimitive && !fieldIsPrimitiveArray && !fieldIsObjectArray; Expression ex; if (fieldIsPrimitiveArray || fieldIsObjectArray) { MessageSend arrayToString = new MessageSend(); arrayToString.sourceStart = pS; arrayToString.sourceEnd = pE; arrayToString.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Arrays".toCharArray()); - arrayToString.arguments = new Expression[] { fieldAccessor }; + arrayToString.arguments = new Expression[] { memberAccessor }; setGeneratedBy(arrayToString.arguments[0], source); arrayToString.selector = (fieldIsObjectArray ? "deepToString" : "toString").toCharArray(); ex = arrayToString; } else { - ex = fieldAccessor; + ex = memberAccessor; } setGeneratedBy(ex, source); @@ -258,8 +228,10 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { } StringLiteral fieldNameLiteral; - if (includeFieldNames) { - char[] namePlusEqualsSign = (infixS + field.getName() + "=").toCharArray(); + if (includeNames) { + String n = member.getInc() == null ? "" : member.getInc().name(); + if (n.isEmpty()) n = memberNode.getName(); + char[] namePlusEqualsSign = (infixS + n + "=").toCharArray(); fieldNameLiteral = new StringLiteral(namePlusEqualsSign, pS, pE, 0); } else { fieldNameLiteral = new StringLiteral(infix, pS, pE, 0); diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index a61ca6c3..2e0338a8 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -86,10 +86,11 @@ public class HandleValue extends EclipseAnnotationHandler<Value> { //for whatever reason, though you can find callers of that one by focusing on the class name itself //and hitting 'find callers'. - handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); + handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, Collections.<Annotation>emptyList()); handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode); handleToString.generateToStringForType(typeNode, annotationNode); handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), SkipIfConstructorExists.YES, Collections.<Annotation>emptyList(), annotationNode); + handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode); } } diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java index 200ebde7..c035fc26 100644 --- a/src/core/lombok/eclipse/handlers/HandleWither.java +++ b/src/core/lombok/eclipse/handlers/HandleWither.java @@ -36,7 +36,6 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess; import lombok.experimental.Wither; import org.eclipse.jdt.internal.compiler.ast.ASTNode; diff --git a/src/core/lombok/experimental/FieldNameConstants.java b/src/core/lombok/experimental/FieldNameConstants.java new file mode 100644 index 00000000..31c2970c --- /dev/null +++ b/src/core/lombok/experimental/FieldNameConstants.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014-2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.experimental; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import lombok.AccessLevel; + +/** + * Generates String constants containing the field name for each field. + */ +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.SOURCE) +public @interface FieldNameConstants { + lombok.AccessLevel level() default AccessLevel.PUBLIC; + String prefix() default " CONFIG DEFAULT "; + String suffix() default " CONFIG DEFAULT "; +} diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java index 04d5ef93..fa3d6f09 100644 --- a/src/core/lombok/extern/apachecommons/CommonsLog.java +++ b/src/core/lombok/extern/apachecommons/CommonsLog.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/flogger/Flogger.java b/src/core/lombok/extern/flogger/Flogger.java new file mode 100644 index 00000000..ecbfd28c --- /dev/null +++ b/src/core/lombok/extern/flogger/Flogger.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.extern.flogger; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Causes lombok to generate a logger field. + * <p> + * Complete documentation is found at <a href="https://projectlombok.org/features/Log">the project lombok features page for lombok log annotations</a>. + * <p> + * Example: + * <pre> + * @Flogger + * public class LogExample { + * } + * </pre> + * + * will generate: + * + * <pre> + * public class LogExample { + * private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + * } + * </pre> + * + * This annotation is valid for classes and enumerations.<br> + * @see <a href="https://google.github.io/flogger/">com.google.common.flogger</a> + * @see lombok.extern.apachecommons.CommonsLog @CommonsLog + * @see lombok.extern.java.Log @Log + * @see lombok.extern.log4j.Log4j @Log4j + * @see lombok.extern.log4j.Log4j2 @Log4j2 + * @see lombok.extern.slf4j.Slf4j @Slf4j + * @see lombok.extern.slf4j.XSlf4j @XSlf4j + * @see lombok.extern.jbosslog.JBossLog @JBossLog + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface Flogger { +} diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java index 553b7c4a..9a1ee412 100644 --- a/src/core/lombok/extern/java/Log.java +++ b/src/core/lombok/extern/java/Log.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/jbosslog/JBossLog.java b/src/core/lombok/extern/jbosslog/JBossLog.java index ea520aea..684585e0 100644 --- a/src/core/lombok/extern/jbosslog/JBossLog.java +++ b/src/core/lombok/extern/jbosslog/JBossLog.java @@ -53,8 +53,9 @@ import java.lang.annotation.Target; * @see lombok.extern.java.Log @Log * @see lombok.extern.log4j.Log4j @Log4j * @see lombok.extern.log4j.Log4j2 @Log4j2 + * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j - * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger * */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java index ee719407..249ef71a 100644 --- a/src/core/lombok/extern/log4j/Log4j.java +++ b/src/core/lombok/extern/log4j/Log4j.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java index 4a5b166c..a6aa90c0 100644 --- a/src/core/lombok/extern/log4j/Log4j2.java +++ b/src/core/lombok/extern/log4j/Log4j2.java @@ -56,6 +56,7 @@ import java.lang.annotation.Target; * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java index 24586d43..347d81d2 100644 --- a/src/core/lombok/extern/slf4j/Slf4j.java +++ b/src/core/lombok/extern/slf4j/Slf4j.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.XSlf4j @XSlf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java index 85a0fdd8..4d53a1eb 100644 --- a/src/core/lombok/extern/slf4j/XSlf4j.java +++ b/src/core/lombok/extern/slf4j/XSlf4j.java @@ -55,6 +55,7 @@ import java.lang.annotation.Target; * @see lombok.extern.log4j.Log4j2 @Log4j2 * @see lombok.extern.slf4j.Slf4j @Slf4j * @see lombok.extern.jbosslog.JBossLog @JBossLog + * @see lombok.extern.flogger.Flogger @Flogger */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 45679fd3..4ca2c050 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -35,6 +35,7 @@ import javax.annotation.processing.Messager; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; +import com.sun.tools.javac.util.JCDiagnostic; import lombok.core.AST; import com.sun.tools.javac.code.Source; @@ -395,7 +396,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { oldSource = log.useSource(newSource); if (pos == null) pos = astObject.pos(); } - if (pos != null && attemptToRemoveErrorsInRange) { + if (pos != null && node != null && attemptToRemoveErrorsInRange) { removeFromDeferredDiagnostics(pos.getStartPosition(), node.getEndPosition(pos)); } try { @@ -470,22 +471,21 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { increment(errorCount); error1(pos, message); } - + final void warning(DiagnosticPosition pos, String message) { increment(warningCount); - log.warning(pos, "proc.messager", message); + warning1(pos, message); } - + final void mandatoryWarning(DiagnosticPosition pos, String message) { increment(warningCount); - log.mandatoryWarning(pos, "proc.messager", message); + mandatoryWarning1(pos, message); } - - final void note(DiagnosticPosition pos, String message) { - log.note(pos, "proc.messager", message); - } - + abstract void error1(DiagnosticPosition pos, String message); + abstract void warning1(DiagnosticPosition pos, String message); + abstract void mandatoryWarning1(DiagnosticPosition pos, String message); + abstract void note(DiagnosticPosition pos, String message); private void increment(Field field) { if (field == null) return; @@ -520,18 +520,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { warningCount = f; } catch (Throwable t) {} - - Method logMethod = null; - Object multiple = null; - try { - Class<?> df = Class.forName("com.sun.tools.javac.util.JCDiagnostic$DiagnosticFlag"); - for (Object constant : df.getEnumConstants()) { - if (constant.toString().equals("MULTIPLE")) multiple = constant; - } - logMethod = log.getClass().getMethod("error", new Class<?>[] {df, DiagnosticPosition.class, String.class, Object[].class}); - } catch (Throwable t) {} - - return new Jdk9Plus(log, messager, errorCount, warningCount, logMethod, multiple); + return new Jdk9Plus(log, messager, errorCount, warningCount); } } @@ -549,22 +538,99 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { log.multipleErrors = prev; } } + + @Override void warning1(DiagnosticPosition pos, String message) { + log.warning(pos, "proc.messager", message); + } + + @Override void mandatoryWarning1(DiagnosticPosition pos, String message) { + log.mandatoryWarning(pos, "proc.messager", message); + } + + @Override void note(DiagnosticPosition pos, String message) { + log.note(pos, "proc.messager", message); + } } static class Jdk9Plus extends ErrorLog { - private final Object multiple; - private final Method logMethod; + private static final String PROC_MESSAGER = "proc.messager"; + private Object multiple; + private Method errorMethod, warningMethod, mandatoryWarningMethod, noteMethod; + private Method errorKey, warningKey, noteKey; + private JCDiagnostic.Factory diags; - private Jdk9Plus(Log log, Messager messager, Field errorCount, Field warningCount, Method logMethod, Object multiple) { + private Jdk9Plus(Log log, Messager messager, Field errorCount, Field warningCount) { super(log, messager, errorCount, warningCount); - this.logMethod = logMethod; - this.multiple = multiple; + + try { + final String jcd = "com.sun.tools.javac.util.JCDiagnostic"; + Class<?> df = Class.forName(jcd + "$DiagnosticFlag"); + for (Object constant : df.getEnumConstants()) { + if (constant.toString().equals("MULTIPLE")) this.multiple = constant; + } + + Class<?> errorCls = Class.forName(jcd + "$Error"); + Class<?> warningCls = Class.forName(jcd + "$Warning"); + Class<?> noteCls = Class.forName(jcd + "$Note"); + + Class<?> lc = log.getClass(); + this.errorMethod = lc.getMethod("error", df, DiagnosticPosition.class, errorCls); + this.warningMethod = lc.getMethod("warning", DiagnosticPosition.class, warningCls); + this.mandatoryWarningMethod = lc.getMethod("mandatoryWarning", DiagnosticPosition.class, warningCls); + this.noteMethod = lc.getMethod("note", DiagnosticPosition.class, noteCls); + + Field diagsField = lc.getSuperclass().getDeclaredField("diags"); + diagsField.setAccessible(true); + this.diags = (JCDiagnostic.Factory)diagsField.get(log); + + Class<?> dc = this.diags.getClass(); + this.errorKey = dc.getMethod("errorKey", String.class, Object[].class); + this.warningKey = dc.getDeclaredMethod("warningKey", String.class, Object[].class); + this.warningKey.setAccessible(true); + this.noteKey = dc.getDeclaredMethod("noteKey", String.class, Object[].class); + this.noteKey.setAccessible(true); + } catch (Throwable t) { + //t.printStackTrace(); + } } @Override void error1(DiagnosticPosition pos, String message) { try { - logMethod.invoke(log, multiple, pos, "proc.messager", new Object[] { message }); - } catch (Throwable t) {} + Object error = this.errorKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); + errorMethod.invoke(log, multiple, pos, error); + } catch (Throwable t) { + //t.printStackTrace(); + } + } + + @Override + void warning1(DiagnosticPosition pos, String message) { + try { + Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); + warningMethod.invoke(log, pos, warning); + } catch (Throwable t) { + //t.printStackTrace(); + } + } + + @Override + void mandatoryWarning1(DiagnosticPosition pos, String message) { + try { + Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); + mandatoryWarningMethod.invoke(log, pos, warning); + } catch (Throwable t) { + //t.printStackTrace(); + } + } + + @Override + void note(DiagnosticPosition pos, String message) { + try { + Object note = this.noteKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); + noteMethod.invoke(log, pos, note); + } catch (Throwable t) { + //t.printStackTrace(); + } } } } diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index fa24c2f9..2bce6e3a 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -21,13 +21,17 @@ */ package lombok.javac; +import java.lang.annotation.Annotation; import java.util.List; import javax.lang.model.element.Element; import javax.tools.Diagnostic; +import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.javac.handlers.JavacHandlerUtil; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.model.JavacTypes; import com.sun.tools.javac.tree.JCTree; @@ -36,6 +40,7 @@ import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Name; @@ -256,4 +261,70 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre public void addWarning(String message, DiagnosticPosition pos) { ast.printMessage(Diagnostic.Kind.WARNING, message, null, pos, false); } + + @Override public boolean hasAnnotation(Class<? extends Annotation> type) { + return JavacHandlerUtil.hasAnnotationAndDeleteIfNeccessary(type, this); + } + + @Override public <Z extends Annotation> AnnotationValues<Z> findAnnotation(Class<Z> type) { + JavacNode annotation = JavacHandlerUtil.findAnnotation(type, this, true); + if (annotation == null) return null; + return JavacHandlerUtil.createAnnotation(type, annotation); + } + + private JCModifiers getModifiers() { + if (node instanceof JCClassDecl) return ((JCClassDecl) node).getModifiers(); + if (node instanceof JCMethodDecl) return ((JCMethodDecl) node).getModifiers(); + if (node instanceof JCVariableDecl) return ((JCVariableDecl) node).getModifiers(); + return null; + } + + @Override public boolean isStatic() { + if (node instanceof JCClassDecl) { + JavacNode directUp = directUp(); + if (directUp == null || directUp.getKind() == Kind.COMPILATION_UNIT) return true; + if (!(directUp.get() instanceof JCClassDecl)) return false; + JCClassDecl p = (JCClassDecl) directUp.get(); + long f = p.mods.flags; + if ((Flags.INTERFACE & f) != 0) return true; + if ((Flags.ENUM & f) != 0) return true; + } + + if (node instanceof JCVariableDecl) { + JavacNode directUp = directUp(); + if (directUp != null && directUp.get() instanceof JCClassDecl) { + JCClassDecl p = (JCClassDecl) directUp.get(); + long f = p.mods.flags; + if ((Flags.INTERFACE & f) != 0) return true; + } + } + + JCModifiers mods = getModifiers(); + if (mods == null) return false; + return (mods.flags & Flags.STATIC) != 0; + } + + @Override public boolean isEnumMember() { + if (getKind() != Kind.FIELD) return false; + JCModifiers mods = getModifiers(); + return mods != null && (Flags.ENUM & mods.flags) != 0; + } + + @Override public boolean isTransient() { + if (getKind() != Kind.FIELD) return false; + JCModifiers mods = getModifiers(); + return mods != null && (Flags.TRANSIENT & mods.flags) != 0; + } + + @Override public int countMethodParameters() { + if (getKind() != Kind.METHOD) return 0; + + com.sun.tools.javac.util.List<JCVariableDecl> params = ((JCMethodDecl) node).params; + if (params == null) return 0; + return params.size(); + } + + @Override public int getStartPos() { + return node.getPreferredPosition(); + } } diff --git a/src/core/lombok/javac/apt/EmptyLombokFileObject.java b/src/core/lombok/javac/apt/EmptyLombokFileObject.java index 5a3a7def..84bb00e4 100644 --- a/src/core/lombok/javac/apt/EmptyLombokFileObject.java +++ b/src/core/lombok/javac/apt/EmptyLombokFileObject.java @@ -57,7 +57,7 @@ class EmptyLombokFileObject implements LombokFileObject { } @Override public URI toUri() { - return URI.create(name); + return URI.create("file:///" + (name.startsWith("/") ? name.substring(1) : name)); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 9c0a2dfa..04b494bf 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -69,7 +69,10 @@ import com.sun.tools.javac.util.Context; */ @SupportedAnnotationTypes("*") public class LombokProcessor extends AbstractProcessor { - private JavacProcessingEnvironment processingEnv; + + private ProcessingEnvironment processingEnv; + private JavacProcessingEnvironment javacProcessingEnv; + private JavacFiler javacFiler; private JavacTransformer transformer; private Trees trees; private boolean lombokDisabled = false; @@ -81,11 +84,13 @@ public class LombokProcessor extends AbstractProcessor { lombokDisabled = true; return; } - - this.processingEnv = (JavacProcessingEnvironment) procEnv; - + + this.processingEnv = procEnv; + this.javacProcessingEnv = getJavacProcessingEnvironment(procEnv); + this.javacFiler = getJavacFiler(procEnv.getFiler()); + placePostCompileAndDontMakeForceRoundDummiesHook(); - trees = Trees.instance(procEnv); + trees = Trees.instance(javacProcessingEnv); transformer = new JavacTransformer(procEnv.getMessager(), trees); SortedSet<Long> p = transformer.getPriorities(); if (p.isEmpty()) { @@ -124,7 +129,7 @@ public class LombokProcessor extends AbstractProcessor { @SuppressWarnings("unused") private String listAnnotationProcessorsBeforeOurs() { try { - Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.processingEnv); + Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.javacProcessingEnv); ArrayList<?> states = (ArrayList<?>) discoveredProcessors_procStateList.get(discoveredProcessors); if (states == null || states.isEmpty()) return null; if (states.size() == 1) return processorState_processor.get(states.get(0)).getClass().getName(); @@ -147,7 +152,7 @@ public class LombokProcessor extends AbstractProcessor { stopJavacProcessingEnvironmentFromClosingOurClassloader(); forceMultipleRoundsInNetBeansEditor(); - Context context = processingEnv.getContext(); + Context context = javacProcessingEnv.getContext(); disablePartialReparseInNetBeansEditor(context); try { Method keyMethod = Context.class.getDeclaredMethod("key", Class.class); @@ -161,14 +166,14 @@ public class LombokProcessor extends AbstractProcessor { if (!(originalFiler instanceof InterceptingJavaFileManager)) { final Messager messager = processingEnv.getMessager(); DiagnosticsReceiver receiver = new MessagerDiagnosticsReceiver(messager); - - JavaFileManager newFiler = new InterceptingJavaFileManager(originalFiler, receiver); - ht.put(key, newFiler); + + JavaFileManager newFilerManager = new InterceptingJavaFileManager(originalFiler, receiver); + ht.put(key, newFilerManager); Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager"); filerFileManagerField.setAccessible(true); - filerFileManagerField.set(processingEnv.getFiler(), newFiler); - - replaceFileManagerJdk9(context, newFiler); + filerFileManagerField.set(javacFiler, newFilerManager); + + replaceFileManagerJdk9(context, newFilerManager); } } catch (Exception e) { throw Lombok.sneakyThrow(e); @@ -203,7 +208,7 @@ public class LombokProcessor extends AbstractProcessor { try { Field f = JavacProcessingEnvironment.class.getDeclaredField("isBackgroundCompilation"); f.setAccessible(true); - f.set(processingEnv, true); + f.set(javacProcessingEnv, true); } catch (NoSuchFieldException e) { // only NetBeans has it } catch (Throwable t) { @@ -277,10 +282,10 @@ public class LombokProcessor extends AbstractProcessor { try { Field f = JavacProcessingEnvironment.class.getDeclaredField("processorClassLoader"); f.setAccessible(true); - ClassLoader unwrapped = (ClassLoader) f.get(processingEnv); + ClassLoader unwrapped = (ClassLoader) f.get(javacProcessingEnv); if (unwrapped == null) return; ClassLoader wrapped = wrapClassLoader(unwrapped); - f.set(processingEnv, wrapped); + f.set(javacProcessingEnv, wrapped); } catch (NoSuchFieldException e) { // Some versions of javac have this (and call close on it), some don't. I guess this one doesn't have it. } catch (Throwable t) { @@ -321,7 +326,7 @@ public class LombokProcessor extends AbstractProcessor { if (prioOfCu == null || prioOfCu != prio) continue; cusForThisRound.add(entry.getKey()); } - transformer.transform(prio, processingEnv.getContext(), cusForThisRound); + transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound); } // Step 3: Push up all CUs to the next level. Set level to null if there is no next level. @@ -349,7 +354,7 @@ public class LombokProcessor extends AbstractProcessor { newLevels.retainAll(priorityLevelsRequiringResolutionReset); if (!newLevels.isEmpty()) { // Force a new round to reset resolution. The next round will cause this method (process) to be called again. - forceNewRound(randomModuleName, (JavacFiler) processingEnv.getFiler()); + forceNewRound(randomModuleName, javacFiler); return false; } // None of the new levels need resolution, so just keep going. @@ -399,4 +404,57 @@ public class LombokProcessor extends AbstractProcessor { @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); } + + /** + * This class casts the given processing environment to a JavacProcessingEnvironment. In case of + * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned. + */ + public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) { + if (procEnv instanceof JavacProcessingEnvironment) { + return (JavacProcessingEnvironment) procEnv; + } + + // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment + for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { + try { + return getJavacProcessingEnvironment(tryGetDelegateField(procEnvClass, procEnv)); + } catch (final Exception e) { + // delegate field was not found, try on superclass + } + } + + processingEnv.getMessager().printMessage(Kind.WARNING, + "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work."); + return null; + } + + /** + * This class returns the given filer as a JavacFiler. In case the case that the filer is no + * JavacFiler (e.g. the Gradle IncrementalFiler), its "delegate" field is used to get the JavacFiler + * (directly or through a delegate field again) + */ + public JavacFiler getJavacFiler(Object filer) { + if (filer instanceof JavacFiler) { + return (JavacFiler) filer; + } + + // try to find a "delegate" field in the object, and use this to check for a JavacFiler + for (Class<?> filerClass = filer.getClass(); filerClass != null; filerClass = filerClass.getSuperclass()) { + try { + return getJavacFiler(tryGetDelegateField(filerClass, filer)); + } catch (final Exception e) { + // delegate field was not found, try on superclass + } + } + + processingEnv.getMessager().printMessage(Kind.WARNING, + "Can't get a JavacFiler from " + filer.getClass().getName() + ". Lombok won't work."); + return null; + } + + private Object tryGetDelegateField(Class<?> delegateClass, Object instance) throws Exception { + Field field = delegateClass.getDeclaredField("delegate"); + field.setAccessible(true); + return field.get(instance); + } } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index fec999ba..d56d6ac2 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -54,10 +54,12 @@ import lombok.Builder; import lombok.Builder.ObtainVia; import lombok.ConfigurationKeys; import lombok.Singular; +import lombok.ToString; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.experimental.NonFinal; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; @@ -398,10 +400,13 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { - java.util.List<JavacNode> fieldNodes = new ArrayList<JavacNode>(); + java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { - fieldNodes.addAll(bfd.createdFields); + for (JavacNode f : bfd.createdFields) { + fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true)); + } } + JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast); if (md != null) injectMethod(builderType, md); } diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index dca25ee7..32eb43b2 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,22 +22,8 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.*; -import static lombok.javac.handlers.JavacHandlerUtil.*; import static lombok.javac.Javac.*; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.ConfigurationKeys; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import lombok.core.AnnotationValues; -import lombok.core.AST.Kind; -import lombok.delombok.LombokOptionsFactory; -import lombok.javac.Javac; -import lombok.javac.JavacAnnotationHandler; -import lombok.javac.JavacNode; -import lombok.javac.JavacTreeMaker; +import static lombok.javac.handlers.JavacHandlerUtil.*; import org.mangosdk.spi.ProviderFor; @@ -61,6 +47,21 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.ConfigurationKeys; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.delombok.LombokOptionsFactory; +import lombok.javac.Javac; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; + public class HandleConstructor { @ProviderFor(JavacAnnotationHandler.class) public static class HandleNoArgsConstructor extends JavacAnnotationHandler<NoArgsConstructor> { @@ -191,19 +192,33 @@ public class HandleConstructor { return true; } - public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { - generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, source); - } - public enum SkipIfConstructorExists { YES, NO, I_AM_BUILDER; } + public void generateExtraNoArgsConstructor(JavacNode typeNode, JavacNode source) { + if (!isDirectDescendantOfObject(typeNode)) return; + + Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE); + if (v == null || !v) return; + + List<JavacNode> fields = findFinalFields(typeNode); + generate(typeNode, AccessLevel.PRIVATE, List.<JCAnnotation>nil(), fields, true, null, SkipIfConstructorExists.NO, source, true); + } + + public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { + generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, source); + } + public void generateAllArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), false, staticName, skipIfConstructorExists, source); } public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { + generate(typeNode, level, onConstructor, fields, allToDefault, staticName, skipIfConstructorExists, source, false); + } + + private void generate(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source, boolean noArgs) { boolean staticConstrRequired = staticName != null && !staticName.equals(""); if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; @@ -232,6 +247,8 @@ public class HandleConstructor { } } + if (noArgs && noArgsConstructorExists(typeNode)) return; + JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, source); ListBuffer<Type> argTypes = new ListBuffer<Type>(); for (JavacNode fieldNode : fields) { @@ -252,6 +269,27 @@ public class HandleConstructor { } } + private static boolean noArgsConstructorExists(JavacNode node) { + node = upToTypeNode(node); + + if (node != null && node.get() instanceof JCClassDecl) { + for (JCTree def : ((JCClassDecl) node.get()).defs) { + if (def instanceof JCMethodDecl) { + JCMethodDecl md = (JCMethodDecl) def; + if (md.name.contentEquals("<init>") && md.params.size() == 0) return true; + } + } + } + + for (JavacNode child : node.down()) { + if (annotationTypeMatches(NoArgsConstructor.class, child)) return true; + if (annotationTypeMatches(RequiredArgsConstructor.class, child) && findRequiredFields(node).isEmpty()) return true; + if (annotationTypeMatches(AllArgsConstructor.class, child) && findAllFields(node).isEmpty()) return true; + } + + return false; + } + public static void addConstructorProperties(JCModifiers mods, JavacNode node, List<JavacNode> fields) { if (fields.isEmpty()) return; JavacTreeMaker maker = node.getTreeMaker(); diff --git a/src/core/lombok/javac/handlers/HandleData.java b/src/core/lombok/javac/handlers/HandleData.java index 15f1fd83..15c9c9e7 100644 --- a/src/core/lombok/javac/handlers/HandleData.java +++ b/src/core/lombok/javac/handlers/HandleData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Data} annotation for javac. @@ -60,9 +61,11 @@ public class HandleData extends JavacAnnotationHandler<Data> { String staticConstructorName = annotation.getInstance().staticConstructor(); + // TODO move this to the end OR move it to the top in eclipse. handleConstructor.generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode); - handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); - handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); + handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode); + handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil()); + handleSetter.generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode); handleToString.generateToStringForType(typeNode, annotationNode); } diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index d8bfd154..aa0fe633 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,7 @@ */ package lombok.javac.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; @@ -29,19 +29,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import lombok.ConfigurationKeys; -import lombok.EqualsAndHashCode; -import lombok.core.AST.Kind; -import lombok.core.configuration.CallSuperType; -import lombok.core.AnnotationValues; -import lombok.core.handlers.HandlerUtil; -import lombok.javac.Javac; -import lombok.javac.JavacAnnotationHandler; -import lombok.javac.JavacNode; -import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; -import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; - import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.BoundKind; @@ -66,6 +53,20 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import lombok.ConfigurationKeys; +import lombok.EqualsAndHashCode; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.configuration.CallSuperType; +import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.HandlerUtil.FieldAccess; +import lombok.core.handlers.InclusionExclusionUtils; +import lombok.core.handlers.InclusionExclusionUtils.Included; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; + /** * Handles the {@code lombok.EqualsAndHashCode} annotation for javac. */ @@ -74,45 +75,23 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas private static final String RESULT_NAME = "result"; private static final String PRIME_NAME = "PRIME"; - public void checkForBogusFieldNames(JavacNode type, AnnotationValues<EqualsAndHashCode> annotation) { - if (annotation.isExplicit("exclude")) { - for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().exclude()), type, true, true)) { - annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i); - } - } - if (annotation.isExplicit("of")) { - for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().of()), type, false, false)) { - annotation.setWarning("of", "This field does not exist.", i); - } - } - } - @Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode"); deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class); EqualsAndHashCode ann = annotation.getInstance(); - List<String> excludes = List.from(ann.exclude()); - List<String> includes = List.from(ann.of()); + java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode); JavacNode typeNode = annotationNode.up(); List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode); - checkForBogusFieldNames(typeNode, annotation); Boolean callSuper = ann.callSuper(); if (!annotation.isExplicit("callSuper")) callSuper = null; - if (!annotation.isExplicit("exclude")) excludes = null; - if (!annotation.isExplicit("of")) includes = null; - - if (excludes != null && includes != null) { - excludes = null; - annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored."); - } Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess, onParam); + generateMethods(typeNode, annotationNode, members, callSuper, true, fieldAccess, onParam); } public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode source) { @@ -124,10 +103,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; - generateMethods(typeNode, source, null, null, null, false, access, List.<JCAnnotation>nil()); + java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null); + + generateMethods(typeNode, source, members, null, false, access, List.<JCAnnotation>nil()); } - public void generateMethods(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, + public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) { boolean notAClass = true; @@ -141,7 +122,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas return; } - boolean isDirectDescendantOfObject = true; boolean implicitCallSuper = callSuper == null; if (callSuper == null) { try { @@ -151,11 +131,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } } - JCTree extending = Javac.getExtendsClause((JCClassDecl)typeNode.get()); - if (extending != null) { - String p = extending.toString(); - isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object"); - } + boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode); if (isDirectDescendantOfObject && callSuper) { source.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); @@ -181,29 +157,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } } - ListBuffer<JavacNode> nodesForEquality = new ListBuffer<JavacNode>(); - if (includes != null) { - for (JavacNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); - if (includes.contains(fieldDecl.name.toString())) nodesForEquality.append(child); - } - } else { - for (JavacNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); - //Skip static fields. - if ((fieldDecl.mods.flags & Flags.STATIC) != 0) continue; - //Skip transient fields. - if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0) continue; - //Skip excluded fields. - if (excludes != null && excludes.contains(fieldDecl.name.toString())) continue; - //Skip fields that start with $ - if (fieldDecl.name.toString().startsWith("$")) continue; - nodesForEquality.append(child); - } - } - boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 0; boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject; MemberExistsResult equalsExists = methodExists("equals", typeNode, 1); @@ -232,7 +185,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas //fallthrough } - JCMethodDecl equalsMethod = createEquals(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, needsCanEqual, source.get(), onParam); + JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source.get(), onParam); injectMethod(typeNode, equalsMethod); @@ -241,11 +194,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas injectMethod(typeNode, canEqualMethod); } - JCMethodDecl hashCodeMethod = createHashCode(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, source.get()); + JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, fieldAccess, source.get()); injectMethod(typeNode, hashCodeMethod); } - public JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, JCTree source) { + public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, JCTree source) { JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); @@ -258,7 +211,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext()); /* final int PRIME = X; */ { - if (!fields.isEmpty()) { + if (!members.isEmpty()) { statements.append(maker.VarDef(maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode()))); } } @@ -268,8 +221,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas if (callSuper) { /* ... super.hashCode(); */ init = maker.Apply(List.<JCExpression>nil(), - maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")), - List.<JCExpression>nil()); + maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")), + List.<JCExpression>nil()); } else { /* ... 1; */ init = maker.Literal(1); @@ -277,10 +230,12 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas statements.append(maker.VarDef(maker.Modifiers(0), resultName, maker.TypeIdent(CTC_INT), init)); } - Name dollar = typeNode.toName("$"); - for (JavacNode fieldNode : fields) { - JCExpression fType = getFieldType(fieldNode, fieldAccess); - JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); + for (Included<JavacNode, EqualsAndHashCode.Include> member : members) { + JavacNode memberNode = member.getNode(); + JCExpression fType = getFieldType(memberNode, fieldAccess); + boolean isMethod = memberNode.getKind() == Kind.METHOD; + + JCExpression fieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess); if (fType instanceof JCPrimitiveTypeTree) { switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) { case BOOLEAN: @@ -289,7 +244,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse()))))); break; case LONG: { - Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); + Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName()); statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor)); statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName)))); } @@ -303,7 +258,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas break; case DOUBLE: { /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */ - Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); + Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName()); JCExpression init = maker.Apply( List.<JCExpression>nil(), genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"), @@ -333,7 +288,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* final java.lang.Object $fieldName = this.fieldName; */ /* ($fieldName == null ? NULL_PRIME : $fieldName.hashCode()) */ - Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); + Name dollarFieldName = memberNode.toName((isMethod ? "$$" : "$") + memberNode.getName()); statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor)); JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")), @@ -411,7 +366,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas return maker.TypeApply(expr, wildcards.toList()); } - public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) { + public JCMethodDecl createEquals(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) { JavacTreeMaker maker = typeNode.getTreeMaker(); Name oName = typeNode.toName("o"); @@ -440,7 +395,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ { - if (!fields.isEmpty() || needsCanEqual) { + if (!members.isEmpty() || needsCanEqual) { final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true); statements.append( @@ -469,12 +424,13 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas statements.append(maker.If(superNotEqual, returnBool(maker, false), null)); } - Name thisDollar = typeNode.toName("this$"); - Name otherDollar = typeNode.toName("other$"); - for (JavacNode fieldNode : fields) { - JCExpression fType = getFieldType(fieldNode, fieldAccess); - JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); - JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName)); + for (Included<JavacNode, EqualsAndHashCode.Include> member : members) { + JavacNode memberNode = member.getNode(); + boolean isMethod = memberNode.getKind() == Kind.METHOD; + + JCExpression fType = getFieldType(memberNode, fieldAccess); + JCExpression thisFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess); + JCExpression otherFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode, maker.Ident(otherName)) : createFieldAccessor(maker, memberNode, fieldAccess, maker.Ident(otherName)); if (fType instanceof JCPrimitiveTypeTree) { switch (((JCPrimitiveTypeTree)fType).getPrimitiveTypeKind()) { case FLOAT: @@ -505,9 +461,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* final java.lang.Object this$fieldName = this.fieldName; */ /* final java.lang.Object other$fieldName = other.fieldName; */ /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */ - Name fieldName = ((JCVariableDecl) fieldNode.get()).name; - Name thisDollarFieldName = thisDollar.append(fieldName); - Name otherDollarFieldName = otherDollar.append(fieldName); + Name thisDollarFieldName = memberNode.toName("this" + (isMethod ? "$$" : "$") + memberNode.getName()); + Name otherDollarFieldName = memberNode.toName("other" + (isMethod ? "$$" : "$") + memberNode.getName()); statements.append(maker.VarDef(maker.Modifiers(finalFlag), thisDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), thisFieldAccessor)); statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), otherFieldAccessor)); @@ -546,7 +501,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null)); JCBlock body = maker.Block(0, List.<JCStatement>of( - maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false))))); + maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false))))); return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); } diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java new file mode 100644 index 00000000..8ff136fc --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014-2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; +import static lombok.javac.handlers.JavacHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.Collection; + +import lombok.AccessLevel; +import lombok.ConfigurationKeys; +import lombok.core.AST.Kind; +import lombok.core.handlers.HandlerUtil; +import lombok.core.AnnotationValues; +import lombok.experimental.FieldNameConstants; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +@ProviderFor(JavacAnnotationHandler.class) +public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameConstants> { + public void generateFieldNameConstantsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, String prefix, String suffix) { + JCClassDecl typeDecl = null; + if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get(); + + long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags; + boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0; + + if (typeDecl == null || notAClass) { + errorNode.addError("@FieldNameConstants is only supported on a class, an enum, or a field."); + return; + } + + for (JavacNode field : typeNode.down()) { + if (fieldQualifiesForFieldNameConstantsGeneration(field)) generateFieldNameConstantsForField(field, errorNode.get(), level, prefix, suffix); + } + } + + private void generateFieldNameConstantsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, String prefix, String suffix) { + if (hasAnnotation(FieldNameConstants.class, fieldNode)) return; + createFieldNameConstantsForField(level, prefix, suffix, fieldNode, fieldNode, false); + } + + private boolean fieldQualifiesForFieldNameConstantsGeneration(JavacNode field) { + if (field.getKind() != Kind.FIELD) return false; + JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); + if (fieldDecl.name.toString().startsWith("$")) return false; + if ((fieldDecl.mods.flags & Flags.STATIC) != 0) return false; + return true; + } + + public void handle(AnnotationValues<FieldNameConstants> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants"); + + Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields(); + deleteAnnotationIfNeccessary(annotationNode, FieldNameConstants.class); + deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); + JavacNode node = annotationNode.up(); + FieldNameConstants annotatationInstance = annotation.getInstance(); + AccessLevel level = annotatationInstance.level(); + String prefix = annotatationInstance.prefix(); + String suffix = annotatationInstance.suffix(); + if (prefix.equals(" CONFIG DEFAULT ")) prefix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_PREFIX); + if (suffix.equals(" CONFIG DEFAULT ")) suffix = annotationNode.getAst().readConfiguration(ConfigurationKeys.FIELD_NAME_CONSTANTS_SUFFIX); + if (prefix == null) prefix = "FIELD_"; + if (suffix == null) suffix = ""; + if (node == null) return; + switch (node.getKind()) { + case FIELD: + if (level != AccessLevel.NONE) createFieldNameConstantsForFields(level, prefix, suffix, fields, annotationNode, annotationNode, true); + break; + case TYPE: + if (level == AccessLevel.NONE) { + annotationNode.addWarning("type-level '@FieldNameConstants' does not work with AccessLevel.NONE."); + return; + } + generateFieldNameConstantsForType(node, annotationNode, level, prefix, suffix); + break; + } + } + + private void createFieldNameConstantsForFields(AccessLevel level, String prefix, String suffix, Collection<JavacNode> fieldNodes, JavacNode annotationNode, JavacNode errorNode, boolean whineIfExists) { + for (JavacNode fieldNode : fieldNodes) createFieldNameConstantsForField(level, prefix, suffix, fieldNode, errorNode, whineIfExists); + } + + private void createFieldNameConstantsForField(AccessLevel level, String prefix, String suffix, JavacNode fieldNode, JavacNode source, boolean whineIfExists) { + if (fieldNode.getKind() != Kind.FIELD) { + source.addError("@FieldNameConstants is only supported on a class, an enum, or a field"); + return; + } + + JCVariableDecl field = (JCVariableDecl) fieldNode.get(); + String fieldName = field.name.toString(); + String constantName = prefix + HandlerUtil.camelCaseToConstant(fieldName) + suffix; + if (constantName.equals(fieldName)) { + fieldNode.addWarning("Not generating constant for this field: The name of the constant would be equal to the name of this field."); + return; + } + + JavacTreeMaker treeMaker = fieldNode.getTreeMaker(); + JCModifiers modifiers = treeMaker.Modifiers(toJavacModifier(level) | Modifier.STATIC | Modifier.FINAL); + JCExpression returnType = chainDots(fieldNode, "java", "lang", "String"); + JCExpression init = treeMaker.Literal(fieldNode.getName()); + JCVariableDecl fieldConstant = treeMaker.VarDef(modifiers, fieldNode.toName(constantName), returnType, init); + injectField(fieldNode.up(), fieldConstant); + } +}
\ No newline at end of file diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 0540465d..4fc6155c 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -41,7 +41,6 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.JavacTreeMaker.TypeTag; -import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; @@ -72,7 +71,7 @@ import com.sun.tools.javac.util.Name; */ @ProviderFor(JavacAnnotationHandler.class) public class HandleGetter extends JavacAnnotationHandler<Getter> { - public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter) { + public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter, List<JCAnnotation> onMethod) { if (checkForTypeLevelGetter) { if (hasAnnotation(Getter.class, typeNode)) { //The annotation will make it happen, so we can skip it. @@ -91,7 +90,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { } for (JavacNode field : typeNode.down()) { - if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, false); + if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, false, onMethod); } } @@ -120,12 +119,12 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { * @param fieldNode The node representing the field you want a getter for. * @param pos The node responsible for generating the getter (the {@code @Data} or {@code @Getter} annotation). */ - public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean lazy) { + public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean lazy, List<JCAnnotation> onMethod) { if (hasAnnotation(Getter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - createGetterForField(level, fieldNode, fieldNode, false, lazy, List.<JCAnnotation>nil()); + createGetterForField(level, fieldNode, fieldNode, false, lazy, onMethod); } @Override public void handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -154,11 +153,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { createGetterForFields(level, fields, annotationNode, true, lazy, onMethod); break; case TYPE: - if (!onMethod.isEmpty()) { - annotationNode.addError("'onMethod' is not supported for @Getter on a type."); - } if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type."); - generateGetterForType(node, annotationNode, level, false); + generateGetterForType(node, annotationNode, level, false, onMethod); break; } } diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index d0d709e3..6d742e76 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -91,16 +91,18 @@ public class HandleLog { // private static final <loggerType> log = <factoryMethod>(<parameter>); JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName()); JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName()); - + JCExpression loggerName; - if (loggerTopic == null || loggerTopic.trim().length() == 0) { + if (!framework.passTypeName) { + loggerName = null; + } else if (loggerTopic == null || loggerTopic.trim().length() == 0) { loggerName = framework.createFactoryParameter(typeNode, loggingType); } else { loggerName = maker.Literal(loggerTopic); } - - JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, List.<JCExpression>of(loggerName)); - + + JCMethodInvocation factoryMethodCall = maker.Apply(List.<JCExpression>nil(), factoryMethod, loggerName != null ? List.<JCExpression>of(loggerName) : List.<JCExpression>nil()); + JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); @@ -186,6 +188,17 @@ public class HandleLog { } } + /** + * Handles the {@link lombok.extern.flogger.Flogger} annotation for javac. + */ + @ProviderFor(JavacAnnotationHandler.class) + public static class HandleFloggerLog extends JavacAnnotationHandler<lombok.extern.flogger.Flogger> { + @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); + processAnnotation(LoggingFramework.FLOGGER, annotation, annotationNode, ""); + } + } + enum LoggingFramework { // private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TargetType.class); COMMONS(lombok.extern.apachecommons.CommonsLog.class, "org.apache.commons.logging.Log", "org.apache.commons.logging.LogFactory.getLog"), @@ -212,17 +225,29 @@ public class HandleLog { XSLF4J(lombok.extern.slf4j.XSlf4j.class, "org.slf4j.ext.XLogger", "org.slf4j.ext.XLoggerFactory.getXLogger"), // private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(TargetType.class); - JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger") + JBOSSLOG(lombok.extern.jbosslog.JBossLog.class, "org.jboss.logging.Logger", "org.jboss.logging.Logger.getLogger"), + + // private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + FLOGGER(lombok.extern.flogger.Flogger.class, "com.google.common.flogger.FluentLogger", "com.google.common.flogger.FluentLogger.forEnclosingClass", false), ; private final Class<? extends Annotation> annotationClass; private final String loggerTypeName; private final String loggerFactoryName; + private final boolean passTypeName; + + LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName, boolean passTypeName) { + this.annotationClass = annotationClass; + this.loggerTypeName = loggerTypeName; + this.loggerFactoryName = loggerFactoryName; + this.passTypeName = passTypeName; + } LoggingFramework(Class<? extends Annotation> annotationClass, String loggerTypeName, String loggerFactoryName) { this.annotationClass = annotationClass; this.loggerTypeName = loggerTypeName; this.loggerFactoryName = loggerFactoryName; + this.passTypeName = true; } final Class<? extends Annotation> getAnnotationClass() { diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index be3337db..0ddaa7d7 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -36,7 +36,6 @@ import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; @@ -62,7 +61,7 @@ import com.sun.tools.javac.util.Name; */ @ProviderFor(JavacAnnotationHandler.class) public class HandleSetter extends JavacAnnotationHandler<Setter> { - public void generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter) { + public void generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (checkForTypeLevelSetter) { if (hasAnnotation(Setter.class, typeNode)) { //The annotation will make it happen, so we can skip it. @@ -90,7 +89,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { //Skip final fields. if ((fieldDecl.mods.flags & Flags.FINAL) != 0) continue; - generateSetterForField(field, errorNode, level); + generateSetterForField(field, errorNode, level, onMethod, onParam); } } @@ -109,13 +108,13 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { * @param fieldNode The node representing the field you want a setter for. * @param pos The node responsible for generating the setter (the {@code @Data} or {@code @Setter} annotation). */ - public void generateSetterForField(JavacNode fieldNode, JavacNode sourceNode, AccessLevel level) { + public void generateSetterForField(JavacNode fieldNode, JavacNode sourceNode, AccessLevel level, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (hasAnnotation(Setter.class, fieldNode)) { //The annotation will make it happen, so we can skip it. return; } - createSetterForField(level, fieldNode, sourceNode, false, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); + createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam); } @Override public void handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) { @@ -137,9 +136,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { createSetterForFields(level, fields, annotationNode, true, onMethod, onParam); break; case TYPE: - if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Setter on a type."); - if (!onParam.isEmpty()) annotationNode.addError("'onParam' is not supported for @Setter on a type."); - generateSetterForType(node, annotationNode, level, false); + generateSetterForType(node, annotationNode, level, false, onMethod, onParam); break; } } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 1707fb0e..38fec2f6 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -56,17 +56,18 @@ import lombok.Builder; import lombok.Builder.ObtainVia; import lombok.ConfigurationKeys; import lombok.Singular; +import lombok.ToString; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.experimental.NonFinal; import lombok.experimental.SuperBuilder; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; @@ -255,8 +256,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } // Create the toString() method for the abstract builder. - java.util.List<JavacNode> fieldNodes = new ArrayList<JavacNode>(); - for (BuilderFieldData bfd : builderFields) fieldNodes.addAll(bfd.createdFields); + java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); + for (BuilderFieldData bfd : builderFields) { + for (JavacNode f : bfd.createdFields) { + fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true)); + } + } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. JCMethodDecl toStringMethod = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClassExpression != null, FieldAccess.ALWAYS_FIELD, ast); diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index 897d5f2c..28d18357 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,8 @@ import lombok.ConfigurationKeys; import lombok.ToString; import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.core.handlers.InclusionExclusionUtils; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -52,57 +54,33 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.ListBuffer; /** * Handles the {@code ToString} annotation for javac. */ @ProviderFor(JavacAnnotationHandler.class) public class HandleToString extends JavacAnnotationHandler<ToString> { - public void checkForBogusFieldNames(JavacNode type, AnnotationValues<ToString> annotation) { - if (annotation.isExplicit("exclude")) { - for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().exclude()), type, true, false)) { - annotation.setWarning("exclude", "This field does not exist, or would have been excluded anyway.", i); - } - } - if (annotation.isExplicit("of")) { - for (int i : createListOfNonExistentFields(List.from(annotation.getInstance().of()), type, false, false)) { - annotation.setWarning("of", "This field does not exist.", i); - } - } - } - @Override public void handle(AnnotationValues<ToString> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString"); deleteAnnotationIfNeccessary(annotationNode, ToString.class); ToString ann = annotation.getInstance(); - List<String> excludes = List.from(ann.exclude()); - List<String> includes = List.from(ann.of()); - JavacNode typeNode = annotationNode.up(); - - checkForBogusFieldNames(typeNode, annotation); + java.util.List<Included<JavacNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), annotation, annotationNode); + if (members == null) return; Boolean callSuper = ann.callSuper(); if (!annotation.isExplicit("callSuper")) callSuper = null; - if (!annotation.isExplicit("exclude")) excludes = null; - if (!annotation.isExplicit("of")) includes = null; - - if (excludes != null && includes != null) { - excludes = null; - annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored."); - } Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES); - boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration; + boolean includeNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration; - generateToString(typeNode, annotationNode, excludes, includes, includeFieldNames, callSuper, true, fieldAccess); + generateToString(annotationNode.up(), annotationNode, members, includeNames, callSuper, true, fieldAccess); } public void generateToStringForType(JavacNode typeNode, JavacNode errorNode) { @@ -111,7 +89,6 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { return; } - boolean includeFieldNames = true; try { Boolean configuration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES); @@ -121,20 +98,22 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS); FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; - generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, access); + java.util.List<Included<JavacNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(typeNode, null, null); + generateToString(typeNode, errorNode, members, includeFieldNames, null, false, access); } - public void generateToString(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, - boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { + public void generateToString(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, ToString.Include>> members, + boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) { + boolean notAClass = true; if (typeNode.get() instanceof JCClassDecl) { - long flags = ((JCClassDecl)typeNode.get()).mods.flags; + long flags = ((JCClassDecl) typeNode.get()).mods.flags; notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0; } if (callSuper == null) { try { - callSuper = ((Boolean)ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue(); + callSuper = ((Boolean) ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue(); } catch (Exception ignore) {} } @@ -143,30 +122,9 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { return; } - ListBuffer<JavacNode> nodesForToString = new ListBuffer<JavacNode>(); - if (includes != null) { - for (JavacNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); - if (includes.contains(fieldDecl.name.toString())) nodesForToString.append(child); - } - } else { - for (JavacNode child : typeNode.down()) { - if (child.getKind() != Kind.FIELD) continue; - JCVariableDecl fieldDecl = (JCVariableDecl) child.get(); - //Skip static fields. - if ((fieldDecl.mods.flags & Flags.STATIC) != 0) continue; - //Skip excluded fields. - if (excludes != null && excludes.contains(fieldDecl.name.toString())) continue; - //Skip fields that start with $. - if (fieldDecl.name.toString().startsWith("$")) continue; - nodesForToString.append(child); - } - } - switch (methodExists("toString", typeNode, 0)) { case NOT_EXISTS: - JCMethodDecl method = createToString(typeNode, nodesForToString.toList(), includeFieldNames, callSuper, fieldAccess, source.get()); + JCMethodDecl method = createToString(typeNode, members, includeFieldNames, callSuper, fieldAccess, source.get()); injectMethod(typeNode, method); break; case EXISTS_BY_LOMBOK: @@ -180,7 +138,9 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { } } - static JCMethodDecl createToString(JavacNode typeNode, Collection<JavacNode> fields, boolean includeFieldNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) { + static JCMethodDecl createToString(JavacNode typeNode, Collection<Included<JavacNode, ToString.Include>> members, + boolean includeNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) { + JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); @@ -195,10 +155,13 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { String prefix; if (callSuper) { prefix = typeName + "(super="; - } else if (fields.isEmpty()) { + } else if (members.isEmpty()) { prefix = typeName + "()"; - } else if (includeFieldNames) { - prefix = typeName + "(" + ((JCVariableDecl)fields.iterator().next().get()).name.toString() + "="; + } else if (includeNames) { + Included<JavacNode, ToString.Include> firstMember = members.iterator().next(); + String name = firstMember.getInc() == null ? "" : firstMember.getInc().name(); + if (name.isEmpty()) name = firstMember.getNode().getName(); + prefix = typeName + "(" + name + "="; } else { prefix = typeName + "("; } @@ -207,30 +170,35 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { if (callSuper) { JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), - maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("toString")), - List.<JCExpression>nil()); + maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("toString")), + List.<JCExpression>nil()); current = maker.Binary(CTC_PLUS, current, callToSuper); first = false; } - for (JavacNode fieldNode : fields) { + for (Included<JavacNode, ToString.Include> member : members) { JCExpression expr; - JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess); + JCExpression memberAccessor; + JavacNode memberNode = member.getNode(); + if (memberNode.getKind() == Kind.METHOD) { + memberAccessor = createMethodAccessor(maker, memberNode); + } else { + memberAccessor = createFieldAccessor(maker, memberNode, fieldAccess); + } - JCExpression fieldType = getFieldType(fieldNode, fieldAccess); + JCExpression memberType = getFieldType(memberNode, fieldAccess); // The distinction between primitive and object will be useful if we ever add a 'hideNulls' option. - boolean fieldIsPrimitive = fieldType instanceof JCPrimitiveTypeTree; - boolean fieldIsPrimitiveArray = fieldType instanceof JCArrayTypeTree && ((JCArrayTypeTree) fieldType).elemtype instanceof JCPrimitiveTypeTree; - boolean fieldIsObjectArray = !fieldIsPrimitiveArray && fieldType instanceof JCArrayTypeTree; @SuppressWarnings("unused") - boolean fieldIsObject = !fieldIsPrimitive && !fieldIsPrimitiveArray && !fieldIsObjectArray; + boolean fieldIsPrimitive = memberType instanceof JCPrimitiveTypeTree; + boolean fieldIsPrimitiveArray = memberType instanceof JCArrayTypeTree && ((JCArrayTypeTree) memberType).elemtype instanceof JCPrimitiveTypeTree; + boolean fieldIsObjectArray = !fieldIsPrimitiveArray && memberType instanceof JCArrayTypeTree; if (fieldIsPrimitiveArray || fieldIsObjectArray) { JCExpression tsMethod = chainDots(typeNode, "java", "util", "Arrays", fieldIsObjectArray ? "deepToString" : "toString"); - expr = maker.Apply(List.<JCExpression>nil(), tsMethod, List.<JCExpression>of(fieldAccessor)); - } else expr = fieldAccessor; + expr = maker.Apply(List.<JCExpression>nil(), tsMethod, List.<JCExpression>of(memberAccessor)); + } else expr = memberAccessor; if (first) { current = maker.Binary(CTC_PLUS, current, expr); @@ -238,8 +206,10 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { continue; } - if (includeFieldNames) { - current = maker.Binary(CTC_PLUS, current, maker.Literal(infix + fieldNode.getName() + "=")); + if (includeNames) { + String n = member.getInc() == null ? "" : member.getInc().name(); + if (n.isEmpty()) n = memberNode.getName(); + current = maker.Binary(CTC_PLUS, current, maker.Literal(infix + n + "=")); } else { current = maker.Binary(CTC_PLUS, current, maker.Literal(infix)); } @@ -254,7 +224,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { JCBlock body = maker.Block(0, List.of(returnStatement)); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("toString"), returnType, - List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext()); + List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext()); } public static String getTypeName(JavacNode typeNode) { diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java index d1af4168..abc5a5ca 100644 --- a/src/core/lombok/javac/handlers/HandleValue.java +++ b/src/core/lombok/javac/handlers/HandleValue.java @@ -40,6 +40,7 @@ import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Value} annotation for javac. @@ -76,7 +77,8 @@ public class HandleValue extends JavacAnnotationHandler<Value> { } handleFieldDefaults.generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true); handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode); - handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); + handleConstructor.generateExtraNoArgsConstructor(typeNode, annotationNode); + handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true, List.<JCAnnotation>nil()); handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode); handleToString.generateToStringForType(typeNode, annotationNode); } diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java index 987a3d34..87f3c16a 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWither.java @@ -36,7 +36,6 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc; -import lombok.javac.handlers.JavacHandlerUtil.FieldAccess; import org.mangosdk.spi.ProviderFor; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 65d09a9a..f335cf94 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -216,7 +216,11 @@ public class JavacHandlerUtil { } } - static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) { + public static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node) { + return findAnnotation(type, node, false); + } + + public static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) { if (node == null) return null; if (type == null) return null; switch (node.getKind()) { @@ -321,8 +325,19 @@ public class JavacHandlerUtil { * @param node A Lombok AST node representing an annotation in source code. */ public static <A extends Annotation> AnnotationValues<A> createAnnotation(Class<A> type, final JavacNode node) { + return createAnnotation(type, (JCAnnotation) node.get(), node); + } + + /** + * Creates an instance of {@code AnnotationValues} for the provided AST Node + * and Annotation expression. + * + * @param type An annotation class type, such as {@code lombok.Getter.class}. + * @param anno the annotation expression + * @param node A Lombok AST node representing an annotation in source code. + */ + public static <A extends Annotation> AnnotationValues<A> createAnnotation(Class<A> type, JCAnnotation anno, final JavacNode node) { Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>(); - JCAnnotation anno = (JCAnnotation) node.get(); List<JCExpression> arguments = anno.getArguments(); for (JCExpression arg : arguments) { @@ -343,17 +358,39 @@ public class JavacHandlerUtil { } if (rhs instanceof JCNewArray) { - List<JCExpression> elems = ((JCNewArray)rhs).elems; + List<JCExpression> elems = ((JCNewArray) rhs).elems; for (JCExpression inner : elems) { raws.add(inner.toString()); expressions.add(inner); - guesses.add(calculateGuess(inner)); + if (inner instanceof JCAnnotation) { + try { + @SuppressWarnings("unchecked") + Class<A> innerClass = (Class<A>) Class.forName(inner.type.toString()); + + guesses.add(createAnnotation(innerClass, (JCAnnotation) inner, node)); + } catch (ClassNotFoundException ex) { + guesses.add(calculateGuess(inner)); + } + } else { + guesses.add(calculateGuess(inner)); + } positions.add(inner.pos()); } } else { raws.add(rhs.toString()); expressions.add(rhs); - guesses.add(calculateGuess(rhs)); + if (rhs instanceof JCAnnotation) { + try { + @SuppressWarnings("unchecked") + Class<A> innerClass = (Class<A>) Class.forName(rhs.type.toString()); + + guesses.add(createAnnotation(innerClass, (JCAnnotation) rhs, node)); + } catch (ClassNotFoundException ex) { + guesses.add(calculateGuess(rhs)); + } + } else { + guesses.add(calculateGuess(rhs)); + } positions.add(rhs.pos()); } @@ -841,10 +878,6 @@ public class JavacHandlerUtil { return null; } - public enum FieldAccess { - GETTER, PREFER_FIELD, ALWAYS_FIELD; - } - static boolean lookForGetter(JavacNode field, FieldAccess fieldAccess) { if (fieldAccess == FieldAccess.GETTER) return true; if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false; @@ -866,12 +899,14 @@ public class JavacHandlerUtil { * @see #createFieldAccessor(TreeMaker, JavacNode, FieldAccess) */ static JCExpression getFieldType(JavacNode field, FieldAccess fieldAccess) { + if (field.getKind() == Kind.METHOD) return ((JCMethodDecl) field.get()).restype; + boolean lookForGetter = lookForGetter(field, fieldAccess); GetterMethod getter = lookForGetter ? findGetter(field) : null; if (getter == null) { - return ((JCVariableDecl)field.get()).vartype; + return ((JCVariableDecl) field.get()).vartype; } return getter.type; @@ -908,7 +943,29 @@ public class JavacHandlerUtil { if (receiver == null) receiver = maker.Ident(field.toName("this")); JCMethodInvocation call = maker.Apply(List.<JCExpression>nil(), - maker.Select(receiver, getter.name), List.<JCExpression>nil()); + maker.Select(receiver, getter.name), List.<JCExpression>nil()); + return call; + } + + static JCExpression createMethodAccessor(JavacTreeMaker maker, JavacNode method) { + return createMethodAccessor(maker, method, null); + } + + static JCExpression createMethodAccessor(JavacTreeMaker maker, JavacNode method, JCExpression receiver) { + JCMethodDecl methodDecl = (JCMethodDecl) method.get(); + + if (receiver == null && (methodDecl.mods.flags & Flags.STATIC) == 0) { + receiver = maker.Ident(method.toName("this")); + } else if (receiver == null) { + JavacNode containerNode = method.up(); + if (containerNode != null && containerNode.get() instanceof JCClassDecl) { + JCClassDecl container = (JCClassDecl) method.up().get(); + receiver = maker.Ident(container.name); + } + } + + JCMethodInvocation call = maker.Apply(List.<JCExpression>nil(), + receiver == null ? maker.Ident(methodDecl.name) : maker.Select(receiver, methodDecl.name), List.<JCExpression>nil()); return call; } @@ -1756,4 +1813,12 @@ public class JavacHandlerUtil { docComments.put(from.get(), filtered[1]); } } + + public static boolean isDirectDescendantOfObject(JavacNode typeNode) { + if (!(typeNode.get() instanceof JCClassDecl)) throw new IllegalArgumentException("not a type node"); + JCTree extending = Javac.getExtendsClause((JCClassDecl)typeNode.get()); + if (extending == null) return true; + String p = extending.toString(); + return p.equals("Object") || p.equals("java.lang.Object"); + } } diff --git a/src/core9/module-info.java b/src/core9/module-info.java index 87f819e2..f4d5815f 100644 --- a/src/core9/module-info.java +++ b/src/core9/module-info.java @@ -31,6 +31,7 @@ module lombok { exports lombok.extern.jbosslog; exports lombok.extern.log4j; exports lombok.extern.slf4j; + exports lombok.extern.flogger; provides javax.annotation.processing.Processor with lombok.launch.AnnotationProcessorHider.AnnotationProcessor; provides org.mapstruct.ap.spi.AstModifyingAnnotationProcessor with lombok.launch.AnnotationProcessorHider.AstModificationNotifier; diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 0d887cb9..f5372fbb 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -86,6 +86,7 @@ public class Delombok { private PrintStream feedback = System.err; private boolean verbose; private boolean noCopy; + private boolean onlyChanged; private boolean force = false; private String classpath, sourcepath, bootclasspath; private LinkedHashMap<File, File> fileToBase = new LinkedHashMap<File, File>(); @@ -145,6 +146,9 @@ public class Delombok { @Shorthand("n") private boolean nocopy; + @Description("Output only changed files (implies -n)") + private boolean onlyChanged; + private boolean help; } @@ -238,7 +242,8 @@ public class Delombok { } if (args.verbose) delombok.setVerbose(true); - if (args.nocopy) delombok.setNoCopy(true); + if (args.nocopy || args.onlyChanged) delombok.setNoCopy(true); + if (args.onlyChanged) delombok.setOnlyChanged(true); if (args.print) { delombok.setOutputToStandardOut(); } else { @@ -364,6 +369,10 @@ public class Delombok { this.noCopy = noCopy; } + public void setOnlyChanged(boolean onlyChanged) { + this.onlyChanged = onlyChanged; + } + public void setOutput(File dir) { if (dir.isFile() || (!dir.isDirectory() && dir.getName().endsWith(".java"))) throw new IllegalArgumentException( "DELOMBOK: delombok will only write to a directory. " + @@ -585,6 +594,10 @@ public class Delombok { FormatPreferences fps = new FormatPreferences(formatPrefs); for (JCCompilationUnit unit : roots) { DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit), fps); + if (onlyChanged && !result.isChanged() && !options.isChanged(unit)) { + if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), "unchanged (skipped)"); + continue; + } if (verbose) feedback.printf("File: %s [%s%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged", force && !options.isChanged(unit) ? " (forced)" : ""); Writer rawWriter; if (presetWriter != null) rawWriter = createUnicodeEscapeWriter(presetWriter); diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java index aa753fc8..2ba4c6ed 100644 --- a/src/delombok/lombok/delombok/DelombokApp.java +++ b/src/delombok/lombok/delombok/DelombokApp.java @@ -79,7 +79,7 @@ public class DelombokApp extends LombokApp { } } - System.err.printf("Can't find tools.jar. Rerun delombok as: java -cp lombok.jar%1$s%2$s lombok.core.Main delombok %3$s\n", + System.err.printf("Can't find tools.jar. Rerun delombok as: java -cp lombok.jar%1$s%2$s lombok.launch.Main delombok %3$s\n", File.pathSeparator, examplePath, sb.toString()); return null; } diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 33d7a496..a6d745b6 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -106,7 +106,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchHideGeneratedNodes(sm); patchPostCompileHookEclipse(sm); patchFixSourceTypeConverter(sm); - patchDisableLombokForCodeFormatterAndCleanup(sm); + patchDisableLombokForCodeCleanup(sm); patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); @@ -224,13 +224,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { .build()); } - private static void patchDisableLombokForCodeFormatterAndCleanup(ScriptManager sm) { - sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit")) - .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean")) - .symbol("lombok.disable") - .build()); - + private static void patchDisableLombokForCodeCleanup(ScriptManager sm) { sm.addScript(ScriptBuilder.exitEarly() .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.DoStatement")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.EnhancedForStatement")) @@ -349,18 +343,19 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { } private static void patchFormatters(ScriptManager sm) { + // before Eclipse Mars sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.java.JavaFormattingStrategy", "format", "void")) - .callToWrap(new Hook("org.eclipse.jdt.internal.corext.util.CodeFormatterUtil", "reformat", "org.eclipse.text.edits.TextEdit", - "int", "java.lang.String", "int", "int", "int", "java.lang.String", "java.util.Map")) - .symbol("lombok.disable").build()); + .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit")) + .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean")) + .symbol("lombok.disable") + .build()); + // Eclipse Mars and beyond sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() - .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.CodeFormatFix", "createCleanUp", "org.eclipse.jdt.ui.cleanup.ICleanUpFix", - "org.eclipse.jdt.core.ICompilationUnit", "org.eclipse.jface.text.IRegion[]", "boolean", "boolean", "boolean", "boolean")) - .callToWrap(new Hook("org.eclipse.jdt.internal.corext.util.CodeFormatterUtil", "reformat", "org.eclipse.text.edits.TextEdit", - "int", "java.lang.String", "int", "java.lang.String", "java.util.Map")) - .symbol("lombok.disable").build()); + .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "parseSourceCode")) + .callToWrap(new Hook("org.eclipse.jdt.core.dom.ASTParser", "createAST", "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.core.runtime.IProgressMonitor")) + .symbol("lombok.disable") + .build()); } private static void patchRefactorScripts(ScriptManager sm) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 3da37869..c2a362bd 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -21,9 +21,11 @@ */ package lombok.eclipse.agent; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; @@ -32,8 +34,11 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.ImportBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -84,11 +89,28 @@ public class PatchVal { return true; } - public static boolean couldBe(String key, TypeReference ref) { + public static boolean couldBe(ImportBinding[] imports, String key, TypeReference ref) { String[] keyParts = key.split("\\."); if (ref instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)ref).token; - return matches(keyParts[keyParts.length - 1], token); + if (!matches(keyParts[keyParts.length - 1], token)) return false; + if (imports == null) return true; + top: + for (ImportBinding ib : imports) { + ImportReference ir = ib.reference; + if (ir == null) continue; + if (ir.isStatic()) continue; + boolean star = ((ir.bits & ASTNode.OnDemand) != 0); + int len = keyParts.length - (star ? 1 : 0); + char[][] t = ir.tokens; + if (len != t.length) continue; + for (int i = 0; i < len; i++) { + if (keyParts[i].length() != t[i].length) continue top; + for (int j = 0; j < t[i].length; j++) if (keyParts[i].charAt(j) != t[i][j]) continue top; + } + return true; + } + return false; } if (ref instanceof QualifiedTypeReference) { @@ -104,10 +126,53 @@ public class PatchVal { return false; } - + + public static boolean couldBe(ImportReference[] imports, String key, TypeReference ref) { + String[] keyParts = key.split("\\."); + if (ref instanceof SingleTypeReference) { + char[] token = ((SingleTypeReference)ref).token; + if (!matches(keyParts[keyParts.length - 1], token)) return false; + if (imports == null) return true; + top: + for (ImportReference ir : imports) { + if (ir.isStatic()) continue; + boolean star = ((ir.bits & ASTNode.OnDemand) != 0); + int len = keyParts.length - (star ? 1 : 0); + char[][] t = ir.tokens; + if (len != t.length) continue; + for (int i = 0; i < len; i++) { + if (keyParts[i].length() != t[i].length) continue top; + for (int j = 0; j < t[i].length; j++) if (keyParts[i].charAt(j) != t[i][j]) continue top; + } + return true; + } + return false; + } + + if (ref instanceof QualifiedTypeReference) { + char[][] tokens = ((QualifiedTypeReference)ref).tokens; + if (keyParts.length != tokens.length) return false; + for(int i = 0; i < tokens.length; ++i) { + String part = keyParts[i]; + char[] token = tokens[i]; + if (!matches(part, token)) return false; + } + return true; + } + + return false; + } + private static boolean is(TypeReference ref, BlockScope scope, String key) { - if (!couldBe(key, ref)) return false; - + Scope s = scope.parent; + while (s != null && !(s instanceof CompilationUnitScope)) { + Scope ns = s.parent; + s = ns == s ? null : ns; + } + ImportBinding[] imports = null; + if (s instanceof CompilationUnitScope) imports = ((CompilationUnitScope) s).imports; + if (!couldBe(imports, key, ref)) return false; + TypeBinding resolvedType = ref.resolvedType; if (resolvedType == null) resolvedType = ref.resolveType(scope, false); if (resolvedType == null) return false; @@ -224,7 +289,7 @@ public class PatchVal { boolean val = isVal(forEach.elementVariable, scope); boolean var = isVar(forEach.elementVariable, scope); - if (!(val || var)) return false; + if (!(val || var)) return false; TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 46237dcf..d59b6a2e 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -45,6 +45,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; @@ -66,8 +67,8 @@ public class PatchValEclipse { ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; ASTNode init = foreachDecl.collection; if (init == null) return; - boolean val = couldBeVal(foreachDecl.elementVariable.type); - boolean var = couldBeVar(foreachDecl.elementVariable.type); + boolean val = couldBeVal(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, foreachDecl.elementVariable.type); + boolean var = couldBeVar(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, foreachDecl.elementVariable.type); if (foreachDecl.elementVariable == null || !(val || var)) return; try { @@ -91,8 +92,8 @@ public class PatchValEclipse { if (!(variableDecl instanceof LocalDeclaration)) return; ASTNode init = variableDecl.initialization; if (init == null) return; - boolean val = couldBeVal(variableDecl.type); - boolean var = couldBeVar(variableDecl.type); + boolean val = couldBeVal(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, variableDecl.type); + boolean var = couldBeVar(parser == null ? null : parser.compilationUnit == null ? null : parser.compilationUnit.imports, variableDecl.type); if (!(val || var)) return; try { @@ -102,8 +103,8 @@ public class PatchValEclipse { } } - private static boolean couldBeVar(TypeReference type) { - return PatchVal.couldBe("lombok.experimental.var", type) || PatchVal.couldBe("lombok.var", type); + private static boolean couldBeVar(ImportReference[] imports, TypeReference type) { + return PatchVal.couldBe(imports, "lombok.experimental.var", type) || PatchVal.couldBe(imports, "lombok.var", type); } public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { @@ -124,7 +125,7 @@ public class PatchValEclipse { Annotation valAnnotation = null; for (Annotation ann : in.annotations) { - if (couldBeVal(ann.type)) { + if (couldBeVal(null, ann.type)) { found = true; valAnnotation = ann; break; @@ -176,8 +177,8 @@ public class PatchValEclipse { } } - private static boolean couldBeVal(TypeReference type) { - return PatchVal.couldBe("lombok.val", type); + private static boolean couldBeVal(ImportReference[] imports, TypeReference type) { + return PatchVal.couldBe(imports, "lombok.val", type); } public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index b1d73352..317b06a4 100644 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -148,7 +148,11 @@ final class PatchFixesHider { } public static String addLombokNotesToEclipseAboutDialog(String origReturnValue, String key) { - return (String) Util.invokeMethod(LombokDeps.ADD_LOMBOK_NOTES, origReturnValue, key); + try { + return (String) Util.invokeMethod(LombokDeps.ADD_LOMBOK_NOTES, origReturnValue, key); + } catch (Throwable t) { + return origReturnValue; + } } public static byte[] runPostCompiler(byte[] bytes, String fileName) { diff --git a/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java index b807f02b..917091c0 100644 --- a/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocationProvider.java @@ -43,18 +43,19 @@ public class EclipseProductLocationProvider implements IdeLocationProvider { this.descriptor = descriptor; } - @Override public final IdeLocation create(String path) throws CorruptedIdeLocationException { - return create0(path); - } - /** * Create a new EclipseLocation by pointing at either the directory contains the Eclipse executable, or the executable itself, * or an eclipse.ini file. * - * @throws NotAnIdeLocationException + * @throws CorruptedIdeLocationException * If this isn't an Eclipse executable or a directory with an * Eclipse executable. + * @throws NullPointerException if {@code path} is {@code null}. */ + @Override public final IdeLocation create(String path) throws CorruptedIdeLocationException { + return create0(path); + } + private IdeLocation create0(String path) throws CorruptedIdeLocationException { if (path == null) throw new NullPointerException("path"); String iniName = descriptor.getIniFileName(); diff --git a/src/utils/lombok/core/ClassLiteral.java b/src/utils/lombok/core/ClassLiteral.java new file mode 100644 index 00000000..077ead31 --- /dev/null +++ b/src/utils/lombok/core/ClassLiteral.java @@ -0,0 +1,13 @@ +package lombok.core; + +public class ClassLiteral { + private final String className; + + public ClassLiteral(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } +} diff --git a/src/utils/lombok/core/FieldSelect.java b/src/utils/lombok/core/FieldSelect.java new file mode 100644 index 00000000..ab784401 --- /dev/null +++ b/src/utils/lombok/core/FieldSelect.java @@ -0,0 +1,13 @@ +package lombok.core; + +public class FieldSelect { + private final String finalPart; + + public FieldSelect(String finalPart) { + this.finalPart = finalPart; + } + + public String getFinalPart() { + return finalPart; + } +} diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index 18b22256..5ef33086 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -27,6 +27,8 @@ import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; +import lombok.core.ClassLiteral; +import lombok.core.FieldSelect; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -40,6 +42,7 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -161,7 +164,7 @@ public class Eclipse { */ public static Object calculateValue(Expression e) { if (e instanceof Literal) { - ((Literal)e).computeConstant(); + ((Literal) e).computeConstant(); switch (e.constant.typeID()) { case TypeIds.T_int: return e.constant.intValue(); case TypeIds.T_byte: return e.constant.byteValue(); @@ -175,13 +178,24 @@ public class Eclipse { default: return null; } } else if (e instanceof ClassLiteralAccess) { - return Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName()); + return new ClassLiteral(Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName())); } else if (e instanceof SingleNameReference) { - return new String(((SingleNameReference)e).token); + return new FieldSelect(new String(((SingleNameReference)e).token)); } else if (e instanceof QualifiedNameReference) { String qName = Eclipse.toQualifiedName(((QualifiedNameReference)e).tokens); int idx = qName.lastIndexOf('.'); - return idx == -1 ? qName : qName.substring(idx+1); + return new FieldSelect(idx == -1 ? qName : qName.substring(idx+1)); + } else if (e instanceof UnaryExpression) { + if ("-".equals(((UnaryExpression) e).operatorToString())) { + Object inner = calculateValue(((UnaryExpression) e).expression); + if (inner instanceof Integer) return - ((Integer) inner).intValue(); + if (inner instanceof Byte) return - ((Byte) inner).byteValue(); + if (inner instanceof Short) return - ((Short) inner).shortValue(); + if (inner instanceof Long) return - ((Long) inner).longValue(); + if (inner instanceof Float) return - ((Float) inner).floatValue(); + if (inner instanceof Double) return - ((Double) inner).doubleValue(); + return null; + } } return null; diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 9ff4d22f..92961726 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -36,6 +36,8 @@ import javax.lang.model.type.NoType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeVisitor; +import lombok.core.ClassLiteral; +import lombok.core.FieldSelect; import lombok.javac.JavacTreeMaker.TreeTag; import lombok.javac.JavacTreeMaker.TypeTag; @@ -143,16 +145,17 @@ public class Javac { return ((Number) lit.value).intValue() == 0 ? false : true; } return lit.value; - } else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) { + } + + if (expr instanceof JCIdent || expr instanceof JCFieldAccess) { String x = expr.toString(); - if (x.endsWith(".class")) x = x.substring(0, x.length() - 6); - else { - int idx = x.lastIndexOf('.'); - if (idx > -1) x = x.substring(idx + 1); - } - return x; - } else - return null; + if (x.endsWith(".class")) return new ClassLiteral(x.substring(0, x.length() - 6)); + int idx = x.lastIndexOf('.'); + if (idx > -1) x = x.substring(idx + 1); + return new FieldSelect(x); + } + + return null; } public static final TypeTag CTC_BOOLEAN = typeTag("BOOLEAN"); diff --git a/src/website/lombok/website/FetchCurrentVersion.java b/src/website/lombok/website/FetchCurrentVersion.java index 6c1ca639..0d789256 100644 --- a/src/website/lombok/website/FetchCurrentVersion.java +++ b/src/website/lombok/website/FetchCurrentVersion.java @@ -23,7 +23,7 @@ public class FetchCurrentVersion { BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); for (String line = br.readLine(); line != null; line = br.readLine()) { Matcher m = VERSION_PATTERN.matcher(line); - if (m.matches() && m.group(1).equals("currentVersionFull") == fetchFull) return m.group(2); + if (m.matches() && m.group(1).equals("currentVersionFull") == fetchFull) return m.group(2).replace(""", "\""); } throw new IOException("Expected a span with id 'currentVersion'"); } finally { diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index 1a454585..3d672bc4 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -243,7 +243,7 @@ public abstract class AbstractRunTests { int size = Math.min(expectedLines.length, actualLines.length); if (size == 0 && expectedLines.length + actualLines.length > 0) { - Assert.fail("Missing / empty expected file."); + Assert.fail("Missing / empty expected file: " + name); } for (int i = 0; i < size; i++) { diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index 6ed1e950..4e6a6a55 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -146,6 +146,7 @@ public class RunTestsViaEcj extends AbstractRunTests { classpath.add("lib/test/org.jboss.logging-jboss-logging.jar"); classpath.add("lib/test/com.google.guava-guava.jar"); classpath.add("lib/test/com.google.code.findbugs-findbugs.jar"); + classpath.add("lib/test/com.google.flogger-flogger.jar"); return new FileSystem(classpath.toArray(new String[0]), new String[] {file.getAbsolutePath()}, "UTF-8"); } } diff --git a/test/transform/resource/after-delombok/ConstructorsWithAccessors.java b/test/transform/resource/after-delombok/ConstructorsWithAccessors.java index dd4ce12f..2e09b2df 100644 --- a/test/transform/resource/after-delombok/ConstructorsWithAccessors.java +++ b/test/transform/resource/after-delombok/ConstructorsWithAccessors.java @@ -26,16 +26,16 @@ class ConstructorsWithAccessorsNonNull { @java.lang.SuppressWarnings("all") public ConstructorsWithAccessorsNonNull(@lombok.NonNull final Integer plower, @lombok.NonNull final Integer upper, @lombok.NonNull final Integer huh, @lombok.NonNull final Integer _huh2) { if (plower == null) { - throw new java.lang.NullPointerException("plower"); + throw new java.lang.NullPointerException("plower is marked @NonNull but is null"); } if (upper == null) { - throw new java.lang.NullPointerException("upper"); + throw new java.lang.NullPointerException("upper is marked @NonNull but is null"); } if (huh == null) { - throw new java.lang.NullPointerException("huh"); + throw new java.lang.NullPointerException("huh is marked @NonNull but is null"); } if (_huh2 == null) { - throw new java.lang.NullPointerException("_huh2"); + throw new java.lang.NullPointerException("_huh2 is marked @NonNull but is null"); } this.plower = plower; this.pUpper = upper; diff --git a/test/transform/resource/after-delombok/DataConfiguration.java b/test/transform/resource/after-delombok/DataConfiguration.java index b71e1c81..6771a6a7 100644 --- a/test/transform/resource/after-delombok/DataConfiguration.java +++ b/test/transform/resource/after-delombok/DataConfiguration.java @@ -5,6 +5,10 @@ class DataConfiguration { this.x = x; } @java.lang.SuppressWarnings("all") + private DataConfiguration() { + this.x = 0; + } + @java.lang.SuppressWarnings("all") public int getX() { return this.x; } diff --git a/test/transform/resource/after-delombok/DataOnLocalClass.java b/test/transform/resource/after-delombok/DataOnLocalClass.java index 84817897..d611490b 100644 --- a/test/transform/resource/after-delombok/DataOnLocalClass.java +++ b/test/transform/resource/after-delombok/DataOnLocalClass.java @@ -64,7 +64,7 @@ class DataOnLocalClass2 { @java.lang.SuppressWarnings("all") public InnerLocal(@lombok.NonNull final String name) { if (name == null) { - throw new java.lang.NullPointerException("name"); + throw new java.lang.NullPointerException("name is marked @NonNull but is null"); } this.name = name; } @@ -76,7 +76,7 @@ class DataOnLocalClass2 { @java.lang.SuppressWarnings("all") public void setName(@lombok.NonNull final String name) { if (name == null) { - throw new java.lang.NullPointerException("name"); + throw new java.lang.NullPointerException("name is marked @NonNull but is null"); } this.name = name; } diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeNewStyle.java b/test/transform/resource/after-delombok/EqualsAndHashCodeNewStyle.java new file mode 100644 index 00000000..59c7b806 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeNewStyle.java @@ -0,0 +1,46 @@ +public class EqualsAndHashCodeNewStyle { + int b; + double c; + int f; + int d; + int f() { + return 0; + } + int g; + long i() { + return 0; + } + int j; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCodeNewStyle)) return false; + final EqualsAndHashCodeNewStyle other = (EqualsAndHashCodeNewStyle) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.b != other.b) return false; + if (java.lang.Double.compare(this.c, other.c) != 0) return false; + if (this.d != other.d) return false; + if (this.f() != other.f()) return false; + if (this.i() != other.i()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCodeNewStyle; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.b; + final long $c = java.lang.Double.doubleToLongBits(this.c); + result = result * PRIME + (int) ($c >>> 32 ^ $c); + result = result * PRIME + this.d; + result = result * PRIME + this.f(); + final long $$i = this.i(); + result = result * PRIME + (int) ($$i >>> 32 ^ $$i); + return result; + } +} diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInners.java b/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInners.java index 501d45a1..9eb3cdb3 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInners.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInners.java @@ -1,3 +1,4 @@ +//version 7: public class EqualsAndHashCodeWithGenericsOnInners<A> { class Inner<B> { int x; diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java b/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java new file mode 100644 index 00000000..ed25b317 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java @@ -0,0 +1,27 @@ +public interface EqualsAndHashCodeWithGenericsOnInnersInInterfaces<A> { + class Inner<B> { + int x; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner)) return false; + final EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner<?> other = (EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner<?>) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.x != other.x) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.x; + return result; + } + } +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsBasic.java b/test/transform/resource/after-delombok/FieldNameConstantsBasic.java new file mode 100644 index 00000000..4e547aa5 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsBasic.java @@ -0,0 +1,8 @@ +public class FieldNameConstantsBasic { + protected static final java.lang.String FIELD_I_AM_A_DVD_PLAYER = "iAmADvdPlayer"; + public static final java.lang.String FIELD_BUT_PRINT_ME_PLEASE = "butPrintMePlease"; + String iAmADvdPlayer; + int $skipMe; + static double skipMeToo; + String butPrintMePlease; +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java b/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java new file mode 100644 index 00000000..c71b9264 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsConfigKeys.java @@ -0,0 +1,4 @@ +public class FieldNameConstantsConfigKeys { + public static final java.lang.String I_AM_A_DVD_PLAYER_SFX = "iAmADvdPlayer"; + String iAmADvdPlayer; +} diff --git a/test/transform/resource/after-delombok/FieldNameConstantsWeird.java b/test/transform/resource/after-delombok/FieldNameConstantsWeird.java new file mode 100644 index 00000000..6940f628 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldNameConstantsWeird.java @@ -0,0 +1,6 @@ +public class FieldNameConstantsWeird { + public static final java.lang.String FIELD_AZ = "A"; + String iAmADvdPlayer; + String X; + String A; +} diff --git a/test/transform/resource/after-delombok/GetterOnMethodErrors.java b/test/transform/resource/after-delombok/GetterOnMethodErrors.java deleted file mode 100644 index a69966ec..00000000 --- a/test/transform/resource/after-delombok/GetterOnMethodErrors.java +++ /dev/null @@ -1,9 +0,0 @@ -class PlaceFillerToMakeSurePositionIsRelevant { -} -class GetterOnMethodErrors { - private int test; - @java.lang.SuppressWarnings("all") - public int getTest() { - return this.test; - } -} diff --git a/test/transform/resource/after-delombok/GetterOnMethodOnType.java b/test/transform/resource/after-delombok/GetterOnMethodOnType.java new file mode 100644 index 00000000..625909c1 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterOnMethodOnType.java @@ -0,0 +1,14 @@ +class GetterOnMethodOnType { + private int test; + private String name; + @Deprecated + @java.lang.SuppressWarnings("all") + public int getTest() { + return this.test; + } + @Deprecated + @java.lang.SuppressWarnings("all") + public String getName() { + return this.name; + } +} diff --git a/test/transform/resource/after-delombok/InnerClass.java b/test/transform/resource/after-delombok/InnerClass.java index 6d42bb79..2e49b9ad 100644 --- a/test/transform/resource/after-delombok/InnerClass.java +++ b/test/transform/resource/after-delombok/InnerClass.java @@ -1,3 +1,4 @@ +//version 8: class A { class B { String s; @@ -48,4 +49,4 @@ class C { return "C.D(a=" + this.getA() + ")"; } } -}
\ No newline at end of file +} diff --git a/test/transform/resource/after-delombok/LoggerFlogger.java b/test/transform/resource/after-delombok/LoggerFlogger.java new file mode 100644 index 00000000..41d49fe4 --- /dev/null +++ b/test/transform/resource/after-delombok/LoggerFlogger.java @@ -0,0 +1,14 @@ +class LoggerFlogger { + @java.lang.SuppressWarnings("all") + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); +} +class LoggerFloggerWithImport { + @java.lang.SuppressWarnings("all") + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); +} +class LoggerFloggerOuter { + static class Inner { + @java.lang.SuppressWarnings("all") + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + } +} diff --git a/test/transform/resource/after-delombok/NoPrivateNoArgsConstructor.java b/test/transform/resource/after-delombok/NoPrivateNoArgsConstructor.java new file mode 100644 index 00000000..b354a85d --- /dev/null +++ b/test/transform/resource/after-delombok/NoPrivateNoArgsConstructor.java @@ -0,0 +1,73 @@ +public class NoPrivateNoArgsConstructor { + public static class NoPrivateNoArgsConstructorData { + private final int i; + @java.lang.SuppressWarnings("all") + public NoPrivateNoArgsConstructorData(final int i) { + this.i = i; + } + @java.lang.SuppressWarnings("all") + public int getI() { + return this.i; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData)) return false; + final NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData other = (NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.getI() != other.getI()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getI(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData(i=" + this.getI() + ")"; + } + } + public static final class NoPrivateNoArgsConstructorValue { + private final int i; + @java.lang.SuppressWarnings("all") + public NoPrivateNoArgsConstructorValue(final int i) { + this.i = i; + } + @java.lang.SuppressWarnings("all") + public int getI() { + return this.i; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue)) return false; + final NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue other = (NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue) o; + if (this.getI() != other.getI()) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getI(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue(i=" + this.getI() + ")"; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/NonNullOnParameter.java b/test/transform/resource/after-delombok/NonNullOnParameter.java index a27d19c9..fa06e41b 100644 --- a/test/transform/resource/after-delombok/NonNullOnParameter.java +++ b/test/transform/resource/after-delombok/NonNullOnParameter.java @@ -2,22 +2,22 @@ class NonNullOnParameter extends Thread { NonNullOnParameter(@lombok.NonNull String arg) { this(arg, ""); if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } } NonNullOnParameter(@lombok.NonNull String arg, @lombok.NonNull String arg2) { super(arg); if (arg2 == null) { - throw new java.lang.NullPointerException("arg2"); + throw new java.lang.NullPointerException("arg2 is marked @NonNull but is null"); } if (arg == null) throw new NullPointerException(); } public void test2(@lombok.NonNull String arg, @lombok.NonNull String arg2, @lombok.NonNull String arg3) { if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } if (arg3 == null) { - throw new java.lang.NullPointerException("arg3"); + throw new java.lang.NullPointerException("arg3 is marked @NonNull but is null"); } if (arg2 == null) { throw new NullPointerException("arg2"); @@ -26,21 +26,21 @@ class NonNullOnParameter extends Thread { } public void test3(@lombok.NonNull String arg) { if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } if (arg != null) throw new IllegalStateException(); } public void test(@lombok.NonNull String stringArg, @lombok.NonNull String arg2, @lombok.NonNull int primitiveArg) { if (stringArg == null) { - throw new java.lang.NullPointerException("stringArg"); + throw new java.lang.NullPointerException("stringArg is marked @NonNull but is null"); } if (arg2 == null) { - throw new java.lang.NullPointerException("arg2"); + throw new java.lang.NullPointerException("arg2 is marked @NonNull but is null"); } } public void test(@lombok.NonNull String arg) { if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println("Hey"); if (arg == null) throw new NullPointerException(); diff --git a/test/transform/resource/after-delombok/NonNullOnParameterAbstract.java b/test/transform/resource/after-delombok/NonNullOnParameterAbstract.java index 62fd878a..a2dcb49c 100644 --- a/test/transform/resource/after-delombok/NonNullOnParameterAbstract.java +++ b/test/transform/resource/after-delombok/NonNullOnParameterAbstract.java @@ -1,7 +1,7 @@ abstract class NonNullOnParameterAbstract { public void test(@lombok.NonNull String arg) { if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println("Hey"); } diff --git a/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java b/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java index e220296f..cf10253b 100644 --- a/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java +++ b/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java @@ -3,7 +3,7 @@ interface NonNullOnParameterOfDefaultMethod { void test(@lombok.NonNull String arg); default void test2(@lombok.NonNull String arg) { if (arg == null) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println(arg); } diff --git a/test/transform/resource/after-delombok/NonNullPlain.java b/test/transform/resource/after-delombok/NonNullPlain.java index f6b8037e..d3de3dcf 100644 --- a/test/transform/resource/after-delombok/NonNullPlain.java +++ b/test/transform/resource/after-delombok/NonNullPlain.java @@ -13,7 +13,7 @@ class NonNullPlain { @java.lang.SuppressWarnings("all") public NonNullPlain(@lombok.NonNull final int i, @lombok.NonNull final String s) { if (s == null) { - throw new java.lang.NullPointerException("s"); + throw new java.lang.NullPointerException("s is marked @NonNull but is null"); } this.i = i; this.s = s; @@ -39,7 +39,7 @@ class NonNullPlain { @java.lang.SuppressWarnings("all") public void setS(@lombok.NonNull final String s) { if (s == null) { - throw new java.lang.NullPointerException("s"); + throw new java.lang.NullPointerException("s is marked @NonNull but is null"); } this.s = s; } diff --git a/test/transform/resource/after-delombok/NonNullWithAlternateException.java b/test/transform/resource/after-delombok/NonNullWithAlternateException.java index 76c6406a..982da7d8 100644 --- a/test/transform/resource/after-delombok/NonNullWithAlternateException.java +++ b/test/transform/resource/after-delombok/NonNullWithAlternateException.java @@ -3,14 +3,14 @@ public class NonNullWithAlternateException { private String test; public void testMethod(@lombok.NonNull String arg) { if (arg == null) { - throw new java.lang.IllegalArgumentException("arg is null"); + throw new java.lang.IllegalArgumentException("arg is marked @NonNull but is null"); } System.out.println(arg); } @java.lang.SuppressWarnings("all") public void setTest(@lombok.NonNull final String test) { if (test == null) { - throw new java.lang.IllegalArgumentException("test is null"); + throw new java.lang.IllegalArgumentException("test is marked @NonNull but is null"); } this.test = test; } diff --git a/test/transform/resource/after-delombok/NonNullWithSneakyThrows.java b/test/transform/resource/after-delombok/NonNullWithSneakyThrows.java index 97de0d8a..5000f16d 100644 --- a/test/transform/resource/after-delombok/NonNullWithSneakyThrows.java +++ b/test/transform/resource/after-delombok/NonNullWithSneakyThrows.java @@ -2,7 +2,7 @@ class NonNullWithSneakyThrows { void test(@lombok.NonNull String in) { try { if (in == null) { - throw new java.lang.NullPointerException("in"); + throw new java.lang.NullPointerException("in is marked @NonNull but is null"); } System.out.println(in); } catch (final java.lang.Throwable $ex) { diff --git a/test/transform/resource/after-delombok/PrivateNoArgsConstructor.java b/test/transform/resource/after-delombok/PrivateNoArgsConstructor.java new file mode 100644 index 00000000..18e6f211 --- /dev/null +++ b/test/transform/resource/after-delombok/PrivateNoArgsConstructor.java @@ -0,0 +1,236 @@ +public class PrivateNoArgsConstructor { + private static class Base { + } + public static class PrivateNoArgsConstructorNotOnExtends extends Base { + private final int a; + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorNotOnExtends(final int a) { + this.a = a; + } + @java.lang.SuppressWarnings("all") + public int getA() { + return this.a; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (!super.equals(o)) return false; + if (this.getA() != other.getA()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + result = result * PRIME + this.getA(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends(a=" + this.getA() + ")"; + } + } + public static class PrivateNoArgsConstructorOnExtendsObject extends Object { + private final int b; + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorOnExtendsObject(final int b) { + this.b = b; + } + @java.lang.SuppressWarnings("all") + private PrivateNoArgsConstructorOnExtendsObject() { + this.b = 0; + } + @java.lang.SuppressWarnings("all") + public int getB() { + return this.b; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.getB() != other.getB()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getB(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject(b=" + this.getB() + ")"; + } + } + public static class PrivateNoArgsConstructorExplicitBefore { + private final int c; + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorExplicitBefore() { + this.c = 0; + } + @java.lang.SuppressWarnings("all") + public int getC() { + return this.c; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.getC() != other.getC()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getC(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore(c=" + this.getC() + ")"; + } + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorExplicitBefore(final int c) { + this.c = c; + } + } + public static class PrivateNoArgsConstructorExplicitAfter { + private final int d; + @java.lang.SuppressWarnings("all") + public int getD() { + return this.d; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.getD() != other.getD()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getD(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter(d=" + this.getD() + ")"; + } + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorExplicitAfter() { + this.d = 0; + } + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorExplicitAfter(final int d) { + this.d = d; + } + } + public static class PrivateNoArgsConstructorExplicitNone { + private final int e; + @java.lang.SuppressWarnings("all") + public int getE() { + return this.e; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.getE() != other.getE()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.getE(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone(e=" + this.getE() + ")"; + } + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorExplicitNone(final int e) { + this.e = e; + } + } + public static class PrivateNoArgsConstructorNoFields { + @java.lang.SuppressWarnings("all") + public PrivateNoArgsConstructorNoFields() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields)) return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields) o; + if (!other.canEqual((java.lang.Object) this)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + int result = 1; + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields()"; + } + } +} diff --git a/test/transform/resource/after-delombok/SetterOnClass.java b/test/transform/resource/after-delombok/SetterOnClass.java index f2347bcb..f880e20b 100644 --- a/test/transform/resource/after-delombok/SetterOnClass.java +++ b/test/transform/resource/after-delombok/SetterOnClass.java @@ -54,7 +54,7 @@ class SetterOnClass6 { @java.lang.SuppressWarnings("all") public void setNonNull(@lombok.NonNull final String nonNull) { if (nonNull == null) { - throw new java.lang.NullPointerException("nonNull"); + throw new java.lang.NullPointerException("nonNull is marked @NonNull but is null"); } this.nonNull = nonNull; } diff --git a/test/transform/resource/after-delombok/ToStringNewStyle.java b/test/transform/resource/after-delombok/ToStringNewStyle.java new file mode 100644 index 00000000..0a54bd24 --- /dev/null +++ b/test/transform/resource/after-delombok/ToStringNewStyle.java @@ -0,0 +1,18 @@ +public class ToStringNewStyle { + int b; + double c; + int f; + int d; + int f() { + return 0; + } + int g; + int h; + int i; + int j; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ToStringNewStyle(a=" + this.b + ", c=" + this.c + ", e=" + this.d + ", f=" + this.f() + ", g=" + this.g + ", i=" + this.i + ", h=" + this.h + ")"; + } +} diff --git a/test/transform/resource/after-delombok/WitherOnClass.java b/test/transform/resource/after-delombok/WitherOnClass.java index 45d0c4b5..93309c89 100644 --- a/test/transform/resource/after-delombok/WitherOnClass.java +++ b/test/transform/resource/after-delombok/WitherOnClass.java @@ -36,7 +36,7 @@ class WitherOnClass3 { @java.lang.SuppressWarnings("all") public WitherOnClass3 withNonNull(@lombok.NonNull final String nonNull) { if (nonNull == null) { - throw new java.lang.NullPointerException("nonNull"); + throw new java.lang.NullPointerException("nonNull is marked @NonNull but is null"); } return this.nonNull == nonNull ? this : new WitherOnClass3(this.couldBeNull, nonNull); } diff --git a/test/transform/resource/after-ecj/ConstructorsWithAccessors.java b/test/transform/resource/after-ecj/ConstructorsWithAccessors.java index 301e6132..6050ab9f 100644 --- a/test/transform/resource/after-ecj/ConstructorsWithAccessors.java +++ b/test/transform/resource/after-ecj/ConstructorsWithAccessors.java @@ -20,19 +20,19 @@ super(); if ((plower == null)) { - throw new java.lang.NullPointerException("plower"); + throw new java.lang.NullPointerException("plower is marked @NonNull but is null"); } if ((upper == null)) { - throw new java.lang.NullPointerException("upper"); + throw new java.lang.NullPointerException("upper is marked @NonNull but is null"); } if ((huh == null)) { - throw new java.lang.NullPointerException("huh"); + throw new java.lang.NullPointerException("huh is marked @NonNull but is null"); } if ((_huh2 == null)) { - throw new java.lang.NullPointerException("_huh2"); + throw new java.lang.NullPointerException("_huh2 is marked @NonNull but is null"); } this.plower = plower; this.pUpper = upper; diff --git a/test/transform/resource/after-ecj/DataConfiguration.java b/test/transform/resource/after-ecj/DataConfiguration.java index 1e7adfbf..25f7620e 100644 --- a/test/transform/resource/after-ecj/DataConfiguration.java +++ b/test/transform/resource/after-ecj/DataConfiguration.java @@ -31,4 +31,8 @@ super(); this.x = x; } + private @java.lang.SuppressWarnings("all") DataConfiguration() { + super(); + this.x = 0; + } } diff --git a/test/transform/resource/after-ecj/DataOnLocalClass.java b/test/transform/resource/after-ecj/DataOnLocalClass.java index 341df49b..ff2a3d20 100644 --- a/test/transform/resource/after-ecj/DataOnLocalClass.java +++ b/test/transform/resource/after-ecj/DataOnLocalClass.java @@ -64,7 +64,7 @@ class DataOnLocalClass2 { public @java.lang.SuppressWarnings("all") void setName(final @lombok.NonNull String name) { if ((name == null)) { - throw new java.lang.NullPointerException("name"); + throw new java.lang.NullPointerException("name is marked @NonNull but is null"); } this.name = name; } @@ -99,7 +99,7 @@ class DataOnLocalClass2 { super(); if ((name == null)) { - throw new java.lang.NullPointerException("name"); + throw new java.lang.NullPointerException("name is marked @NonNull but is null"); } this.name = name; } diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeNewStyle.java b/test/transform/resource/after-ecj/EqualsAndHashCodeNewStyle.java new file mode 100644 index 00000000..7fbe6d24 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeNewStyle.java @@ -0,0 +1,53 @@ +import lombok.EqualsAndHashCode; +public @EqualsAndHashCode class EqualsAndHashCodeNewStyle { + @EqualsAndHashCode.Include int b; + double c; + int f; + @EqualsAndHashCode.Include int d; + int g; + @EqualsAndHashCode.Exclude int j; + public EqualsAndHashCodeNewStyle() { + super(); + } + @EqualsAndHashCode.Include int f() { + return 0; + } + @EqualsAndHashCode.Include(replaces = "g") long i() { + return 0; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeNewStyle))) + return false; + final EqualsAndHashCodeNewStyle other = (EqualsAndHashCodeNewStyle) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.b != other.b)) + return false; + if ((java.lang.Double.compare(this.c, other.c) != 0)) + return false; + if ((this.d != other.d)) + return false; + if ((this.f() != other.f())) + return false; + if ((this.i() != other.i())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCodeNewStyle); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.b); + final long $c = java.lang.Double.doubleToLongBits(this.c); + result = ((result * PRIME) + (int) ($c ^ ($c >>> 32))); + result = ((result * PRIME) + this.d); + result = ((result * PRIME) + this.f()); + final long $$i = this.i(); + result = ((result * PRIME) + (int) ($$i ^ ($$i >>> 32))); + return result; + } +} diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java b/test/transform/resource/after-ecj/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java new file mode 100644 index 00000000..8c849502 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java @@ -0,0 +1,30 @@ +public interface EqualsAndHashCodeWithGenericsOnInnersInInterfaces<A> { + @lombok.EqualsAndHashCode class Inner<B> { + int x; + Inner() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner))) + return false; + final EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner<?> other = (EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner<?>) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.x != other.x)) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCodeWithGenericsOnInnersInInterfaces.Inner); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.x); + return result; + } + } +} + diff --git a/test/transform/resource/after-ecj/FieldNameConstantsBasic.java b/test/transform/resource/after-ecj/FieldNameConstantsBasic.java new file mode 100644 index 00000000..f77203ba --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsBasic.java @@ -0,0 +1,15 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; +public @FieldNameConstants class FieldNameConstantsBasic { + public static final java.lang.String FIELD_BUT_PRINT_ME_PLEASE = "butPrintMePlease"; + protected static final java.lang.String FIELD_I_AM_A_DVD_PLAYER = "iAmADvdPlayer"; + @FieldNameConstants(level = AccessLevel.PROTECTED) String iAmADvdPlayer; + int $skipMe; + static double skipMeToo; + String butPrintMePlease; + <clinit>() { + } + public FieldNameConstantsBasic() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java b/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java new file mode 100644 index 00000000..44629ee5 --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsConfigKeys.java @@ -0,0 +1,9 @@ +public @lombok.experimental.FieldNameConstants class FieldNameConstantsConfigKeys { + public static final java.lang.String I_AM_A_DVD_PLAYER_SFX = "iAmADvdPlayer"; + String iAmADvdPlayer; + <clinit>() { + } + public FieldNameConstantsConfigKeys() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/FieldNameConstantsWeird.java b/test/transform/resource/after-ecj/FieldNameConstantsWeird.java new file mode 100644 index 00000000..9958f664 --- /dev/null +++ b/test/transform/resource/after-ecj/FieldNameConstantsWeird.java @@ -0,0 +1,13 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; +public @FieldNameConstants class FieldNameConstantsWeird { + public static final java.lang.String FIELD_AZ = "A"; + @FieldNameConstants(level = AccessLevel.NONE) String iAmADvdPlayer; + @FieldNameConstants(prefix = "") String X; + @FieldNameConstants(suffix = "Z") String A; + <clinit>() { + } + public FieldNameConstantsWeird() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/GetterOnMethodErrors.java b/test/transform/resource/after-ecj/GetterOnMethodErrors.java deleted file mode 100644 index 16c625b5..00000000 --- a/test/transform/resource/after-ecj/GetterOnMethodErrors.java +++ /dev/null @@ -1,14 +0,0 @@ -class PlaceFillerToMakeSurePositionIsRelevant { - PlaceFillerToMakeSurePositionIsRelevant() { - super(); - } -} -@lombok.Getter() class GetterOnMethodErrors { - private int test; - GetterOnMethodErrors() { - super(); - } - public @java.lang.SuppressWarnings("all") int getTest() { - return this.test; - } -}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/GetterOnMethodOnType.java b/test/transform/resource/after-ecj/GetterOnMethodOnType.java new file mode 100644 index 00000000..2b39abf2 --- /dev/null +++ b/test/transform/resource/after-ecj/GetterOnMethodOnType.java @@ -0,0 +1,13 @@ +@lombok.Getter() class GetterOnMethodOnType { + private int test; + private String name; + GetterOnMethodOnType() { + super(); + } + public @Deprecated @java.lang.SuppressWarnings("all") int getTest() { + return this.test; + } + public @Deprecated @java.lang.SuppressWarnings("all") String getName() { + return this.name; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/LoggerFlogger.java b/test/transform/resource/after-ecj/LoggerFlogger.java new file mode 100644 index 00000000..d0526eee --- /dev/null +++ b/test/transform/resource/after-ecj/LoggerFlogger.java @@ -0,0 +1,30 @@ +import lombok.extern.flogger.Flogger; +@lombok.extern.flogger.Flogger class LoggerFlogger { + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + <clinit>() { + } + LoggerFlogger() { + super(); + } +} +@Flogger class LoggerFloggerWithImport { + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + <clinit>() { + } + LoggerFloggerWithImport() { + super(); + } +} +class LoggerFloggerOuter { + static @lombok.extern.flogger.Flogger class Inner { + private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); + <clinit>() { + } + Inner() { + super(); + } + } + LoggerFloggerOuter() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/NoPrivateNoArgsConstructor.java b/test/transform/resource/after-ecj/NoPrivateNoArgsConstructor.java new file mode 100644 index 00000000..a2bfe3bd --- /dev/null +++ b/test/transform/resource/after-ecj/NoPrivateNoArgsConstructor.java @@ -0,0 +1,68 @@ +public class NoPrivateNoArgsConstructor { + public static @lombok.Data class NoPrivateNoArgsConstructorData { + private final int i; + public @java.lang.SuppressWarnings("all") int getI() { + return this.i; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData))) + return false; + final NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData other = (NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getI() != other.getI())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getI()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorData(i=" + this.getI()) + ")"); + } + public @java.lang.SuppressWarnings("all") NoPrivateNoArgsConstructorData(final int i) { + super(); + this.i = i; + } + } + public static final @lombok.Value class NoPrivateNoArgsConstructorValue { + private final int i; + public @java.lang.SuppressWarnings("all") int getI() { + return this.i; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue))) + return false; + final NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue other = (NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue) o; + if ((this.getI() != other.getI())) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getI()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("NoPrivateNoArgsConstructor.NoPrivateNoArgsConstructorValue(i=" + this.getI()) + ")"); + } + public @java.lang.SuppressWarnings("all") NoPrivateNoArgsConstructorValue(final int i) { + super(); + this.i = i; + } + } + public NoPrivateNoArgsConstructor() { + super(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/NonNullOnParameter.java b/test/transform/resource/after-ecj/NonNullOnParameter.java index bbceb153..fde47e1d 100644 --- a/test/transform/resource/after-ecj/NonNullOnParameter.java +++ b/test/transform/resource/after-ecj/NonNullOnParameter.java @@ -3,14 +3,14 @@ class NonNullOnParameter extends Thread { this(arg, ""); if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } } NonNullOnParameter(@lombok.NonNull String arg, @lombok.NonNull String arg2) { super(arg); if ((arg2 == null)) { - throw new java.lang.NullPointerException("arg2"); + throw new java.lang.NullPointerException("arg2 is marked @NonNull but is null"); } if ((arg == null)) throw new NullPointerException(); @@ -18,11 +18,11 @@ class NonNullOnParameter extends Thread { public void test2(@lombok.NonNull String arg, @lombok.NonNull String arg2, @lombok.NonNull String arg3) { if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } if ((arg3 == null)) { - throw new java.lang.NullPointerException("arg3"); + throw new java.lang.NullPointerException("arg3 is marked @NonNull but is null"); } if ((arg2 == null)) { @@ -34,7 +34,7 @@ class NonNullOnParameter extends Thread { public void test3(@lombok.NonNull String arg) { if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } if ((arg != null)) throw new IllegalStateException(); @@ -42,17 +42,17 @@ class NonNullOnParameter extends Thread { public void test(@lombok.NonNull String stringArg, @lombok.NonNull String arg2, @lombok.NonNull int primitiveArg) { if ((stringArg == null)) { - throw new java.lang.NullPointerException("stringArg"); + throw new java.lang.NullPointerException("stringArg is marked @NonNull but is null"); } if ((arg2 == null)) { - throw new java.lang.NullPointerException("arg2"); + throw new java.lang.NullPointerException("arg2 is marked @NonNull but is null"); } } public void test(@lombok.NonNull String arg) { if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println("Hey"); if ((arg == null)) diff --git a/test/transform/resource/after-ecj/NonNullOnParameterAbstract.java b/test/transform/resource/after-ecj/NonNullOnParameterAbstract.java index a7dae247..d3e1fdd6 100644 --- a/test/transform/resource/after-ecj/NonNullOnParameterAbstract.java +++ b/test/transform/resource/after-ecj/NonNullOnParameterAbstract.java @@ -5,7 +5,7 @@ abstract class NonNullOnParameterAbstract { public void test(@lombok.NonNull String arg) { if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println("Hey"); } diff --git a/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java b/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java index 85e99702..7293bcf5 100644 --- a/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java +++ b/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java @@ -3,7 +3,7 @@ interface NonNullOnParameterOfDefaultMethod { default void test2(@lombok.NonNull String arg) { if ((arg == null)) { - throw new java.lang.NullPointerException("arg"); + throw new java.lang.NullPointerException("arg is marked @NonNull but is null"); } System.out.println(arg); } diff --git a/test/transform/resource/after-ecj/NonNullPlain.java b/test/transform/resource/after-ecj/NonNullPlain.java index 9edb576b..c703f38a 100644 --- a/test/transform/resource/after-ecj/NonNullPlain.java +++ b/test/transform/resource/after-ecj/NonNullPlain.java @@ -9,7 +9,7 @@ import java.lang.annotation.*; super(); if ((s == null)) { - throw new java.lang.NullPointerException("s"); + throw new java.lang.NullPointerException("s is marked @NonNull but is null"); } this.i = i; this.s = s; @@ -29,7 +29,7 @@ import java.lang.annotation.*; public @java.lang.SuppressWarnings("all") void setS(final @lombok.NonNull String s) { if ((s == null)) { - throw new java.lang.NullPointerException("s"); + throw new java.lang.NullPointerException("s is marked @NonNull but is null"); } this.s = s; } diff --git a/test/transform/resource/after-ecj/NonNullWithAlternateException.java b/test/transform/resource/after-ecj/NonNullWithAlternateException.java index 8a547ecf..39e9c0a8 100644 --- a/test/transform/resource/after-ecj/NonNullWithAlternateException.java +++ b/test/transform/resource/after-ecj/NonNullWithAlternateException.java @@ -6,14 +6,14 @@ public class NonNullWithAlternateException { public void testMethod(@lombok.NonNull String arg) { if ((arg == null)) { - throw new java.lang.IllegalArgumentException("arg is null"); + throw new java.lang.IllegalArgumentException("arg is marked @NonNull but is null"); } System.out.println(arg); } public @java.lang.SuppressWarnings("all") void setTest(final @lombok.NonNull String test) { if ((test == null)) { - throw new java.lang.IllegalArgumentException("test is null"); + throw new java.lang.IllegalArgumentException("test is marked @NonNull but is null"); } this.test = test; } diff --git a/test/transform/resource/after-ecj/NonNullWithSneakyThrows.java b/test/transform/resource/after-ecj/NonNullWithSneakyThrows.java index 1a57be29..22799b5e 100644 --- a/test/transform/resource/after-ecj/NonNullWithSneakyThrows.java +++ b/test/transform/resource/after-ecj/NonNullWithSneakyThrows.java @@ -7,7 +7,7 @@ class NonNullWithSneakyThrows { { if ((in == null)) { - throw new java.lang.NullPointerException("in"); + throw new java.lang.NullPointerException("in is marked @NonNull but is null"); } System.out.println(in); } diff --git a/test/transform/resource/after-ecj/PrivateNoArgsConstructor.java b/test/transform/resource/after-ecj/PrivateNoArgsConstructor.java new file mode 100644 index 00000000..f746ec9a --- /dev/null +++ b/test/transform/resource/after-ecj/PrivateNoArgsConstructor.java @@ -0,0 +1,219 @@ +public class PrivateNoArgsConstructor { + private static class Base { + private Base() { + super(); + } + } + public static @lombok.Data class PrivateNoArgsConstructorNotOnExtends extends Base { + private final int a; + public @java.lang.SuppressWarnings("all") int getA() { + return this.a; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((! super.equals(o))) + return false; + if ((this.getA() != other.getA())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + result = ((result * PRIME) + this.getA()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PrivateNoArgsConstructor.PrivateNoArgsConstructorNotOnExtends(a=" + this.getA()) + ")"); + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorNotOnExtends(final int a) { + super(); + this.a = a; + } + } + public static @lombok.Data class PrivateNoArgsConstructorOnExtendsObject extends Object { + private final int b; + public @java.lang.SuppressWarnings("all") int getB() { + return this.b; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getB() != other.getB())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getB()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PrivateNoArgsConstructor.PrivateNoArgsConstructorOnExtendsObject(b=" + this.getB()) + ")"); + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorOnExtendsObject(final int b) { + super(); + this.b = b; + } + private @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorOnExtendsObject() { + super(); + this.b = 0; + } + } + public static @lombok.NoArgsConstructor(force = true) @lombok.Data @lombok.RequiredArgsConstructor class PrivateNoArgsConstructorExplicitBefore { + private final int c; + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorExplicitBefore() { + super(); + this.c = 0; + } + public @java.lang.SuppressWarnings("all") int getC() { + return this.c; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getC() != other.getC())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getC()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitBefore(c=" + this.getC()) + ")"); + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorExplicitBefore(final int c) { + super(); + this.c = c; + } + } + public static @lombok.Data @lombok.NoArgsConstructor(force = true) @lombok.RequiredArgsConstructor class PrivateNoArgsConstructorExplicitAfter { + private final int d; + public @java.lang.SuppressWarnings("all") int getD() { + return this.d; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getD() != other.getD())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getD()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitAfter(d=" + this.getD()) + ")"); + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorExplicitAfter() { + super(); + this.d = 0; + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorExplicitAfter(final int d) { + super(); + this.d = d; + } + } + public static @lombok.Data @lombok.NoArgsConstructor(access = lombok.AccessLevel.NONE) @lombok.RequiredArgsConstructor class PrivateNoArgsConstructorExplicitNone { + private final int e; + public @java.lang.SuppressWarnings("all") int getE() { + return this.e; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getE() != other.getE())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getE()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PrivateNoArgsConstructor.PrivateNoArgsConstructorExplicitNone(e=" + this.getE()) + ")"); + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorExplicitNone(final int e) { + super(); + this.e = e; + } + } + public static @lombok.Data class PrivateNoArgsConstructorNoFields { + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields))) + return false; + final PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields other = (PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + int result = 1; + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "PrivateNoArgsConstructor.PrivateNoArgsConstructorNoFields()"; + } + public @java.lang.SuppressWarnings("all") PrivateNoArgsConstructorNoFields() { + super(); + } + } + public PrivateNoArgsConstructor() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/SetterOnClass.java b/test/transform/resource/after-ecj/SetterOnClass.java index aa3459bb..c7aec900 100644 --- a/test/transform/resource/after-ecj/SetterOnClass.java +++ b/test/transform/resource/after-ecj/SetterOnClass.java @@ -64,7 +64,7 @@ public @java.lang.SuppressWarnings("all") void setNonNull(final @lombok.NonNull String nonNull) { if ((nonNull == null)) { - throw new java.lang.NullPointerException("nonNull"); + throw new java.lang.NullPointerException("nonNull is marked @NonNull but is null"); } this.nonNull = nonNull; } diff --git a/test/transform/resource/after-ecj/ToStringNewStyle.java b/test/transform/resource/after-ecj/ToStringNewStyle.java new file mode 100644 index 00000000..cdc6f5bc --- /dev/null +++ b/test/transform/resource/after-ecj/ToStringNewStyle.java @@ -0,0 +1,20 @@ +import lombok.ToString; +public @ToString class ToStringNewStyle { + @ToString.Include(name = "a") int b; + double c; + int f; + @ToString.Include(name = "e") int d; + int g; + @ToString.Include(rank = (- 1)) int h; + int i; + @ToString.Exclude int j; + public ToStringNewStyle() { + super(); + } + @ToString.Include int f() { + return 0; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((((((((((("ToStringNewStyle(a=" + this.b) + ", c=") + this.c) + ", e=") + this.d) + ", f=") + this.f()) + ", g=") + this.g) + ", i=") + this.i) + ", h=") + this.h) + ")"); + } +} diff --git a/test/transform/resource/after-ecj/WitherOnClass.java b/test/transform/resource/after-ecj/WitherOnClass.java index 82132e87..086ba591 100644 --- a/test/transform/resource/after-ecj/WitherOnClass.java +++ b/test/transform/resource/after-ecj/WitherOnClass.java @@ -34,7 +34,7 @@ public @java.lang.SuppressWarnings("all") WitherOnClass3 withNonNull(final @lombok.NonNull String nonNull) { if ((nonNull == null)) { - throw new java.lang.NullPointerException("nonNull"); + throw new java.lang.NullPointerException("nonNull is marked @NonNull but is null"); } return ((this.nonNull == nonNull) ? this : new WitherOnClass3(this.couldBeNull, nonNull)); } diff --git a/test/transform/resource/before/BuilderWithRecursiveGenerics.java b/test/transform/resource/before/BuilderWithRecursiveGenerics.java index 041da414..0ab86220 100644 --- a/test/transform/resource/before/BuilderWithRecursiveGenerics.java +++ b/test/transform/resource/before/BuilderWithRecursiveGenerics.java @@ -5,7 +5,7 @@ import lombok.Value; public class BuilderWithRecursiveGenerics { interface Inter<T, U extends Inter<T, U>> {} - + @Builder @Value public static class Test<Foo, Bar extends Set<Foo>, Quz extends Inter<Bar, Quz>> { Foo foo; Bar bar; diff --git a/test/transform/resource/before/DataConfiguration.java b/test/transform/resource/before/DataConfiguration.java index 8b9657f9..9e0bd420 100644 --- a/test/transform/resource/before/DataConfiguration.java +++ b/test/transform/resource/before/DataConfiguration.java @@ -1,6 +1,7 @@ //CONF: lombok.anyConstructor.suppressConstructorProperties = true //CONF: lombok.toString.doNotUseGetters = true //CONF: lombok.equalsAndHashCode.doNotUseGetters = true +//CONF: lombok.noArgsConstructor.extraPrivate = true @lombok.Data class DataConfiguration { final int x; diff --git a/test/transform/resource/before/EqualsAndHashCodeNewStyle.java b/test/transform/resource/before/EqualsAndHashCodeNewStyle.java new file mode 100644 index 00000000..0665d120 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeNewStyle.java @@ -0,0 +1,16 @@ +import lombok.EqualsAndHashCode; +@EqualsAndHashCode +public class EqualsAndHashCodeNewStyle { + @EqualsAndHashCode.Include int b; + double c; + int f; + @EqualsAndHashCode.Include int d; + @EqualsAndHashCode.Include int f() { + return 0; + } + int g; + @EqualsAndHashCode.Include(replaces = "g") long i() { + return 0; + } + @EqualsAndHashCode.Exclude int j; +} diff --git a/test/transform/resource/before/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java b/test/transform/resource/before/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java new file mode 100644 index 00000000..585ebbde --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeWithGenericsOnInnersInInterfaces.java @@ -0,0 +1,6 @@ +public interface EqualsAndHashCodeWithGenericsOnInnersInInterfaces<A> { + @lombok.EqualsAndHashCode class Inner<B> { + int x; + } +} + diff --git a/test/transform/resource/before/FieldNameConstantsBasic.java b/test/transform/resource/before/FieldNameConstantsBasic.java new file mode 100644 index 00000000..1bc15d84 --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsBasic.java @@ -0,0 +1,11 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; + +@FieldNameConstants +public class FieldNameConstantsBasic { + @FieldNameConstants(level = AccessLevel.PROTECTED) + String iAmADvdPlayer; + int $skipMe; + static double skipMeToo; + String butPrintMePlease; +} diff --git a/test/transform/resource/before/FieldNameConstantsConfigKeys.java b/test/transform/resource/before/FieldNameConstantsConfigKeys.java new file mode 100644 index 00000000..ab8e3091 --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsConfigKeys.java @@ -0,0 +1,7 @@ +//CONF: lombok.fieldNameConstants.prefix = +//CONF: lombok.fieldNameConstants.suffix = _SFX + +@lombok.experimental.FieldNameConstants +public class FieldNameConstantsConfigKeys { + String iAmADvdPlayer; +} diff --git a/test/transform/resource/before/FieldNameConstantsWeird.java b/test/transform/resource/before/FieldNameConstantsWeird.java new file mode 100644 index 00000000..74ec299a --- /dev/null +++ b/test/transform/resource/before/FieldNameConstantsWeird.java @@ -0,0 +1,12 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; + +@FieldNameConstants +public class FieldNameConstantsWeird { + @FieldNameConstants(level = AccessLevel.NONE) + String iAmADvdPlayer; + @FieldNameConstants(prefix = "") + String X; + @FieldNameConstants(suffix = "Z") + String A; +} diff --git a/test/transform/resource/before/GetterOnMethodErrors.java b/test/transform/resource/before/GetterOnMethodErrors.java deleted file mode 100644 index ec4704f0..00000000 --- a/test/transform/resource/before/GetterOnMethodErrors.java +++ /dev/null @@ -1,6 +0,0 @@ -class PlaceFillerToMakeSurePositionIsRelevant { -} -@lombok.Getter(onMethod=@__(@Deprecated)) -class GetterOnMethodErrors { - private int test; -} diff --git a/test/transform/resource/before/GetterOnMethodOnType.java b/test/transform/resource/before/GetterOnMethodOnType.java new file mode 100644 index 00000000..296ebcc4 --- /dev/null +++ b/test/transform/resource/before/GetterOnMethodOnType.java @@ -0,0 +1,5 @@ +@lombok.Getter(onMethod=@__(@Deprecated)) +class GetterOnMethodOnType { + private int test; + private String name; +} diff --git a/test/transform/resource/before/LoggerFlogger.java b/test/transform/resource/before/LoggerFlogger.java new file mode 100644 index 00000000..b143aae9 --- /dev/null +++ b/test/transform/resource/before/LoggerFlogger.java @@ -0,0 +1,16 @@ +import lombok.extern.flogger.Flogger; + +@lombok.extern.flogger.Flogger +class LoggerFlogger { +} + +@Flogger +class LoggerFloggerWithImport { +} + +class LoggerFloggerOuter { + @lombok.extern.flogger.Flogger + static class Inner { + + } +} diff --git a/test/transform/resource/before/NoPrivateNoArgsConstructor.java b/test/transform/resource/before/NoPrivateNoArgsConstructor.java new file mode 100644 index 00000000..b7c2a616 --- /dev/null +++ b/test/transform/resource/before/NoPrivateNoArgsConstructor.java @@ -0,0 +1,12 @@ +//CONF: lombok.noArgsConstructor.extraPrivate = false +public class NoPrivateNoArgsConstructor { + @lombok.Data + public static class NoPrivateNoArgsConstructorData { + private final int i; + } + + @lombok.Value + public static class NoPrivateNoArgsConstructorValue { + int i; + } +} diff --git a/test/transform/resource/before/PrivateNoArgsConstructor.java b/test/transform/resource/before/PrivateNoArgsConstructor.java new file mode 100644 index 00000000..38f5aed0 --- /dev/null +++ b/test/transform/resource/before/PrivateNoArgsConstructor.java @@ -0,0 +1,41 @@ +// CONF: lombok.noArgsConstructor.extraPrivate = true +// CONF: lombok.equalsAndHashCode.callSuper = call +public class PrivateNoArgsConstructor { + private static class Base { + } + + @lombok.Data + public static class PrivateNoArgsConstructorNotOnExtends extends Base { + private final int a; + } + + @lombok.Data + public static class PrivateNoArgsConstructorOnExtendsObject extends Object { + private final int b; + } + + @lombok.NoArgsConstructor(force=true) + @lombok.Data + @lombok.RequiredArgsConstructor + public static class PrivateNoArgsConstructorExplicitBefore { + private final int c; + } + + @lombok.Data + @lombok.NoArgsConstructor(force=true) + @lombok.RequiredArgsConstructor + public static class PrivateNoArgsConstructorExplicitAfter { + private final int d; + } + + @lombok.Data + @lombok.NoArgsConstructor(access=lombok.AccessLevel.NONE) + @lombok.RequiredArgsConstructor + public static class PrivateNoArgsConstructorExplicitNone { + private final int e; + } + + @lombok.Data + public static class PrivateNoArgsConstructorNoFields { + } +} diff --git a/test/transform/resource/before/ToStringNewStyle.java b/test/transform/resource/before/ToStringNewStyle.java new file mode 100644 index 00000000..7e436e51 --- /dev/null +++ b/test/transform/resource/before/ToStringNewStyle.java @@ -0,0 +1,15 @@ +import lombok.ToString; +@ToString +public class ToStringNewStyle { + @ToString.Include(name = "a") int b; + double c; + int f; + @ToString.Include(name = "e") int d; + @ToString.Include int f() { + return 0; + } + int g; + @ToString.Include(rank = -1) int h; + int i; + @ToString.Exclude int j; +} diff --git a/test/transform/resource/before/ToStringWithConstantRefInOf.java b/test/transform/resource/before/ToStringWithConstantRefInOf.java new file mode 100644 index 00000000..6246dcaf --- /dev/null +++ b/test/transform/resource/before/ToStringWithConstantRefInOf.java @@ -0,0 +1,10 @@ +//skip compare contents +import lombok.ToString; + +@ToString(of = ToStringWithConstantRefInOf.FIELD_NAME) +public class ToStringWithConstantRefInOf { + static final String FIELD_NAME = "id"; + private String id; + private int whatever; +} + diff --git a/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages b/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages new file mode 100644 index 00000000..02a38d58 --- /dev/null +++ b/test/transform/resource/messages-delombok/FieldNameConstantsWeird.java.messages @@ -0,0 +1 @@ +9 Not generating constant for this field: The name of the constant would be equal to the name of this field. diff --git a/test/transform/resource/messages-delombok/GetterOnMethodErrors.java.messages b/test/transform/resource/messages-delombok/GetterOnMethodErrors.java.messages deleted file mode 100644 index 26c30298..00000000 --- a/test/transform/resource/messages-delombok/GetterOnMethodErrors.java.messages +++ /dev/null @@ -1 +0,0 @@ -3 'onMethod' is not supported for @Getter on a type.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/ToStringWithConstantRefInOf.java.messages b/test/transform/resource/messages-delombok/ToStringWithConstantRefInOf.java.messages new file mode 100644 index 00000000..d88e2754 --- /dev/null +++ b/test/transform/resource/messages-delombok/ToStringWithConstantRefInOf.java.messages @@ -0,0 +1 @@ +4 You must use constant literals in lombok annotations; they cannot be references to (static) fields. diff --git a/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages b/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages new file mode 100644 index 00000000..02a38d58 --- /dev/null +++ b/test/transform/resource/messages-ecj/FieldNameConstantsWeird.java.messages @@ -0,0 +1 @@ +9 Not generating constant for this field: The name of the constant would be equal to the name of this field. diff --git a/test/transform/resource/messages-ecj/GetterOnMethodErrors.java.messages b/test/transform/resource/messages-ecj/GetterOnMethodErrors.java.messages deleted file mode 100644 index 26c30298..00000000 --- a/test/transform/resource/messages-ecj/GetterOnMethodErrors.java.messages +++ /dev/null @@ -1 +0,0 @@ -3 'onMethod' is not supported for @Getter on a type.
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/ToStringWithConstantRefInOf.java.messages b/test/transform/resource/messages-ecj/ToStringWithConstantRefInOf.java.messages new file mode 100644 index 00000000..d88e2754 --- /dev/null +++ b/test/transform/resource/messages-ecj/ToStringWithConstantRefInOf.java.messages @@ -0,0 +1 @@ +4 You must use constant literals in lombok annotations; they cannot be references to (static) fields. diff --git a/usage_examples/BuilderExample_post.jpage b/usage_examples/BuilderExample_post.jpage deleted file mode 100644 index 0b64703c..00000000 --- a/usage_examples/BuilderExample_post.jpage +++ /dev/null @@ -1,87 +0,0 @@ -import java.util.Set; - -public class BuilderExample { - private long created; - private String name; - private int age; - private Set<String> occupations; - - BuilderExample(String name, int age, Set<String> occupations) { - this.name = name; - this.age = age; - this.occupations = occupations; - } - - private static long $default$created() { - return System.currentTimeMillis(); - } - - public static BuilderExampleBuilder builder() { - return new BuilderExampleBuilder(); - } - - public static class BuilderExampleBuilder { - private long created; - private boolean created$set; - private String name; - private int age; - private java.util.ArrayList<String> occupations; - - BuilderExampleBuilder() { - } - - public BuilderExampleBuilder created(long created) { - this.created = created; - this.created$set = true; - return this; - } - - public BuilderExampleBuilder name(String name) { - this.name = name; - return this; - } - - public BuilderExampleBuilder age(int age) { - this.age = age; - return this; - } - - public BuilderExampleBuilder occupation(String occupation) { - if (this.occupations == null) { - this.occupations = new java.util.ArrayList<String>(); - } - - this.occupations.add(occupation); - return this; - } - - public BuilderExampleBuilder occupations(Collection<? extends String> occupations) { - if (this.occupations == null) { - this.occupations = new java.util.ArrayList<String>(); - } - - this.occupations.addAll(occupations); - return this; - } - - public BuilderExampleBuilder clearOccupations() { - if (this.occupations != null) { - this.occupations.clear(); - } - - return this; - } - - public BuilderExample build() { - // complicated switch statement to produce a compact properly sized immutable set omitted. - // go to https://projectlombok.org/features/Singular-snippet.html to see it. - Set<String> occupations = ...; - return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations); - } - - @java.lang.Override - public String toString() { - return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")"; - } - } -}
\ No newline at end of file diff --git a/usage_examples/BuilderExample_pre.jpage b/usage_examples/BuilderExample_pre.jpage deleted file mode 100644 index 3b1b0df2..00000000 --- a/usage_examples/BuilderExample_pre.jpage +++ /dev/null @@ -1,11 +0,0 @@ -import lombok.Builder; -import lombok.Singular; -import java.util.Set; - -@Builder -public class BuilderExample { - @Builder.Default private long created = System.currentTimeMillis(); - private String name; - private int age; - @Singular private Set<String> occupations; -} diff --git a/usage_examples/CleanupExample_post.jpage b/usage_examples/CleanupExample_post.jpage deleted file mode 100644 index 7e87c153..00000000 --- a/usage_examples/CleanupExample_post.jpage +++ /dev/null @@ -1,26 +0,0 @@ -import java.io.*; - -public class CleanupExample { - public static void main(String[] args) throws IOException { - InputStream in = new FileInputStream(args[0]); - try { - OutputStream out = new FileOutputStream(args[1]); - try { - byte[] b = new byte[10000]; - while (true) { - int r = in.read(b); - if (r == -1) break; - out.write(b, 0, r); - } - } finally { - if (out != null) { - out.close(); - } - } - } finally { - if (in != null) { - in.close(); - } - } - } -} diff --git a/usage_examples/CleanupExample_pre.jpage b/usage_examples/CleanupExample_pre.jpage deleted file mode 100644 index 9f639171..00000000 --- a/usage_examples/CleanupExample_pre.jpage +++ /dev/null @@ -1,15 +0,0 @@ -import lombok.Cleanup; -import java.io.*; - -public class CleanupExample { - public static void main(String[] args) throws IOException { - @Cleanup InputStream in = new FileInputStream(args[0]); - @Cleanup OutputStream out = new FileOutputStream(args[1]); - byte[] b = new byte[10000]; - while (true) { - int r = in.read(b); - if (r == -1) break; - out.write(b, 0, r); - } - } -} diff --git a/usage_examples/ConstructorExample_post.jpage b/usage_examples/ConstructorExample_post.jpage deleted file mode 100644 index 8a2d5069..00000000 --- a/usage_examples/ConstructorExample_post.jpage +++ /dev/null @@ -1,28 +0,0 @@ -public class ConstructorExample<T> { - private int x, y; - @NonNull private T description; - - private ConstructorExample(T description) { - if (description == null) throw new NullPointerException("description"); - this.description = description; - } - - public static <T> ConstructorExample<T> of(T description) { - return new ConstructorExample<T>(description); - } - - @java.beans.ConstructorProperties({"x", "y", "description"}) - protected ConstructorExample(int x, int y, T description) { - if (description == null) throw new NullPointerException("description"); - this.x = x; - this.y = y; - this.description = description; - } - - public static class NoArgsExample { - @NonNull private String field; - - public NoArgsExample() { - } - } -} diff --git a/usage_examples/ConstructorExample_pre.jpage b/usage_examples/ConstructorExample_pre.jpage deleted file mode 100644 index ac0d3c28..00000000 --- a/usage_examples/ConstructorExample_pre.jpage +++ /dev/null @@ -1,16 +0,0 @@ -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.AllArgsConstructor; -import lombok.NonNull; - -@RequiredArgsConstructor(staticName = "of") -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class ConstructorExample<T> { - private int x, y; - @NonNull private T description; - - @NoArgsConstructor - public static class NoArgsExample { - @NonNull private String field; - } -} diff --git a/usage_examples/DataExample_post.jpage b/usage_examples/DataExample_post.jpage deleted file mode 100644 index bef0a0f1..00000000 --- a/usage_examples/DataExample_post.jpage +++ /dev/null @@ -1,119 +0,0 @@ -import java.util.Arrays; - -public class DataExample { - private final String name; - private int age; - private double score; - private String[] tags; - - public DataExample(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - void setAge(int age) { - this.age = age; - } - - public int getAge() { - return this.age; - } - - public void setScore(double score) { - this.score = score; - } - - public double getScore() { - return this.score; - } - - public String[] getTags() { - return this.tags; - } - - public void setTags(String[] tags) { - this.tags = tags; - } - - @Override public String toString() { - return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")"; - } - - protected boolean canEqual(Object other) { - return other instanceof DataExample; - } - - @Override public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof DataExample)) return false; - DataExample other = (DataExample) o; - if (!other.canEqual((Object)this)) return false; - if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; - if (this.getAge() != other.getAge()) return false; - if (Double.compare(this.getScore(), other.getScore()) != 0) return false; - if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false; - return true; - } - - @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - final long temp1 = Double.doubleToLongBits(this.getScore()); - result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); - result = (result*PRIME) + this.getAge(); - result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32)); - result = (result*PRIME) + Arrays.deepHashCode(this.getTags()); - return result; - } - - public static class Exercise<T> { - private final String name; - private final T value; - - private Exercise(String name, T value) { - this.name = name; - this.value = value; - } - - public static <T> Exercise<T> of(String name, T value) { - return new Exercise<T>(name, value); - } - - public String getName() { - return this.name; - } - - public T getValue() { - return this.value; - } - - @Override public String toString() { - return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")"; - } - - protected boolean canEqual(Object other) { - return other instanceof Exercise; - } - - @Override public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof Exercise)) return false; - Exercise<?> other = (Exercise<?>) o; - if (!other.canEqual((Object)this)) return false; - if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false; - if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false; - return true; - } - - @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); - result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode()); - return result; - } - } -} diff --git a/usage_examples/DataExample_pre.jpage b/usage_examples/DataExample_pre.jpage deleted file mode 100644 index 404d3458..00000000 --- a/usage_examples/DataExample_pre.jpage +++ /dev/null @@ -1,18 +0,0 @@ -import lombok.AccessLevel; -import lombok.Setter; -import lombok.Data; -import lombok.ToString; - -@Data public class DataExample { - private final String name; - @Setter(AccessLevel.PACKAGE) private int age; - private double score; - private String[] tags; - - @ToString(includeFieldNames=true) - @Data(staticConstructor="of") - public static class Exercise<T> { - private final String name; - private final T value; - } -} diff --git a/usage_examples/EqualsAndHashCodeExample_post.jpage b/usage_examples/EqualsAndHashCodeExample_post.jpage deleted file mode 100644 index 91e78250..00000000 --- a/usage_examples/EqualsAndHashCodeExample_post.jpage +++ /dev/null @@ -1,72 +0,0 @@ -import java.util.Arrays; - -public class EqualsAndHashCodeExample { - private transient int transientVar = 10; - private String name; - private double score; - private Shape shape = new Square(5, 10); - private String[] tags; - private int id; - - public String getName() { - return this.name; - } - - @Override public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof EqualsAndHashCodeExample)) return false; - EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o; - if (!other.canEqual((Object)this)) return false; - if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; - if (Double.compare(this.score, other.score) != 0) return false; - if (!Arrays.deepEquals(this.tags, other.tags)) return false; - return true; - } - - @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - final long temp1 = Double.doubleToLongBits(this.score); - result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode()); - result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32)); - result = (result*PRIME) + Arrays.deepHashCode(this.tags); - return result; - } - - protected boolean canEqual(Object other) { - return other instanceof EqualsAndHashCodeExample; - } - - public static class Square extends Shape { - private final int width, height; - - public Square(int width, int height) { - this.width = width; - this.height = height; - } - - @Override public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof Square)) return false; - Square other = (Square) o; - if (!other.canEqual((Object)this)) return false; - if (!super.equals(o)) return false; - if (this.width != other.width) return false; - if (this.height != other.height) return false; - return true; - } - - @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - result = (result*PRIME) + super.hashCode(); - result = (result*PRIME) + this.width; - result = (result*PRIME) + this.height; - return result; - } - - protected boolean canEqual(Object other) { - return other instanceof Square; - } - } -} diff --git a/usage_examples/EqualsAndHashCodeExample_pre.jpage b/usage_examples/EqualsAndHashCodeExample_pre.jpage deleted file mode 100644 index 64faf59f..00000000 --- a/usage_examples/EqualsAndHashCodeExample_pre.jpage +++ /dev/null @@ -1,25 +0,0 @@ -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode(exclude={"id", "shape"}) -public class EqualsAndHashCodeExample { - private transient int transientVar = 10; - private String name; - private double score; - private Shape shape = new Square(5, 10); - private String[] tags; - private int id; - - public String getName() { - return this.name; - } - - @EqualsAndHashCode(callSuper=true) - public static class Square extends Shape { - private final int width, height; - - public Square(int width, int height) { - this.width = width; - this.height = height; - } - } -} diff --git a/usage_examples/GetterLazyExample_post.jpage b/usage_examples/GetterLazyExample_post.jpage deleted file mode 100644 index 5f34c43e..00000000 --- a/usage_examples/GetterLazyExample_post.jpage +++ /dev/null @@ -1,26 +0,0 @@ -public class GetterLazyExample { - private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>(); - - public double[] getCached() { - java.lang.Object value = this.cached.get(); - if (value == null) { - synchronized(this.cached) { - value = this.cached.get(); - if (value == null) { - final double[] actualValue = expensive(); - value = actualValue == null ? this.cached : actualValue; - this.cached.set(value); - } - } - } - return (double[])(value == this.cached ? null : value); - } - - private double[] expensive() { - double[] result = new double[1000000]; - for (int i = 0; i < result.length; i++) { - result[i] = Math.asin(i); - } - return result; - } -} diff --git a/usage_examples/GetterLazyExample_pre.jpage b/usage_examples/GetterLazyExample_pre.jpage deleted file mode 100644 index ca6c9d58..00000000 --- a/usage_examples/GetterLazyExample_pre.jpage +++ /dev/null @@ -1,13 +0,0 @@ -import lombok.Getter; - -public class GetterLazyExample { - @Getter(lazy=true) private final double[] cached = expensive(); - - private double[] expensive() { - double[] result = new double[1000000]; - for (int i = 0; i < result.length; i++) { - result[i] = Math.asin(i); - } - return result; - } -} diff --git a/usage_examples/GetterSetterExample_post.jpage b/usage_examples/GetterSetterExample_post.jpage deleted file mode 100644 index 241a3a4e..00000000 --- a/usage_examples/GetterSetterExample_post.jpage +++ /dev/null @@ -1,42 +0,0 @@ -public class GetterSetterExample { - /** - * Age of the person. Water is wet. - */ - private int age = 10; - - /** - * Name of the person. - */ - private String name; - - @Override public String toString() { - return String.format("%s (age: %d)", name, age); - } - - /** - * Age of the person. Water is wet. - * - * @return The current value of this person's age. Circles are round. - */ - public int getAge() { - return age; - } - - /** - * Age of the person. Water is wet. - * - * @param age New value for this person's age. Sky is blue. - */ - public void setAge(int age) { - this.age = age; - } - - /** - * Changes the name of this person. - * - * @param name The new value. - */ - protected void setName(String name) { - this.name = name; - } -} diff --git a/usage_examples/GetterSetterExample_pre.jpage b/usage_examples/GetterSetterExample_pre.jpage deleted file mode 100644 index 4183aa5d..00000000 --- a/usage_examples/GetterSetterExample_pre.jpage +++ /dev/null @@ -1,26 +0,0 @@ -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; - -public class GetterSetterExample { - /** - * Age of the person. Water is wet. - * - * @param age New value for this person's age. Sky is blue. - * @return The current value of this person's age. Circles are round. - */ - @Getter @Setter private int age = 10; - - /** - * Name of the person. - * -- SETTER -- - * Changes the name of this person. - * - * @param name The new value. - */ - @Setter(AccessLevel.PROTECTED) private String name; - - @Override public String toString() { - return String.format("%s (age: %d)", name, age); - } -} diff --git a/usage_examples/LogExample_post.jpage b/usage_examples/LogExample_post.jpage deleted file mode 100644 index eab3b046..00000000 --- a/usage_examples/LogExample_post.jpage +++ /dev/null @@ -1,23 +0,0 @@ -public class LogExample { - private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); - - public static void main(String... args) { - log.error("Something's wrong here"); - } -} - -public class LogExampleOther { - private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class); - - public static void main(String... args) { - log.error("Something else is wrong here"); - } -} - -public class LogExampleCategory { - private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog"); - - public static void main(String... args) { - log.error("Calling the 'CounterLog' with a message"); - } -} diff --git a/usage_examples/LogExample_pre.jpage b/usage_examples/LogExample_pre.jpage deleted file mode 100644 index ba27dd27..00000000 --- a/usage_examples/LogExample_pre.jpage +++ /dev/null @@ -1,26 +0,0 @@ -import lombok.extern.java.Log; -import lombok.extern.slf4j.Slf4j; - -@Log -public class LogExample { - - public static void main(String... args) { - log.error("Something's wrong here"); - } -} - -@Slf4j -public class LogExampleOther { - - public static void main(String... args) { - log.error("Something else is wrong here"); - } -} - -@CommonsLog(topic="CounterLog") -public class LogExampleCategory { - - public static void main(String... args) { - log.error("Calling the 'CounterLog' with a message"); - } -} diff --git a/usage_examples/NonNullExample_post.jpage b/usage_examples/NonNullExample_post.jpage deleted file mode 100644 index 24175e06..00000000 --- a/usage_examples/NonNullExample_post.jpage +++ /dev/null @@ -1,13 +0,0 @@ -import lombok.NonNull; - -public class NonNullExample extends Something { - private String name; - - public NonNullExample(@NonNull Person person) { - super("Hello"); - if (person == null) { - throw new NullPointerException("person"); - } - this.name = person.getName(); - } -} diff --git a/usage_examples/NonNullExample_pre.jpage b/usage_examples/NonNullExample_pre.jpage deleted file mode 100644 index 47556ce7..00000000 --- a/usage_examples/NonNullExample_pre.jpage +++ /dev/null @@ -1,10 +0,0 @@ -import lombok.NonNull; - -public class NonNullExample extends Something { - private String name; - - public NonNullExample(@NonNull Person person) { - super("Hello"); - this.name = person.getName(); - } -} diff --git a/usage_examples/Singular-snippetExample_post.jpage b/usage_examples/Singular-snippetExample_post.jpage deleted file mode 100644 index 4e2b0460..00000000 --- a/usage_examples/Singular-snippetExample_post.jpage +++ /dev/null @@ -1,160 +0,0 @@ -import java.util.Collection; -import java.util.Set; -import java.util.SortedMap; -import com.google.common.collect.ImmutableList; - -public class SingularExample<T extends Number> { - private Set<String> occupations; - private ImmutableList<String> axes; - private SortedMap<Integer, T> elves; - private Collection<?> minutiae; - - SingularExample(Set<String> occupations, ImmutableList<String> axes, SortedMap<Integer, T> elves, Collection<?> minutiae) { - this.occupations = occupations; - this.axes = axes; - this.elves = elves; - this.minutiae = minutiae; - } - - public static class SingularExampleBuilder<T extends Number> { - private java.util.ArrayList<String> occupations; - private com.google.common.collect.ImmutableList.Builder<String> axes; - private java.util.ArrayList<Integer> elves$key; - private java.util.ArrayList<T> elves$value; - private java.util.ArrayList<java.lang.Object> minutiae; - - SingularExampleBuilder() { - } - - public SingularExampleBuilder<T> occupation(String occupation) { - if (this.occupations == null) { - this.occupations = new java.util.ArrayList<String>(); - } - - this.occupations.add(occupation); - return this; - } - - @java.lang.SuppressWarnings("all") - public SingularExampleBuilder<T> occupations(java.util.Collection<? extends String> occupations) { - if (this.occupations == null) { - this.occupations = new java.util.ArrayList<String>(); - } - - this.occupations.addAll(occupations); - return this; - } - - public SingularExampleBuilder<T> axis(String axis) { - if (this.axes == null) { - this.axes = com.google.common.collect.ImmutableList.builder(); - } - - this.axes.add(axis); - return this; - } - - public SingularExampleBuilder<T> axes(java.lang.Iterable<? extends String> axes) { - if (this.axes == null) { - this.axes = com.google.common.collect.ImmutableList.builder(); - } - - this.axes.addAll(axes); - return this; - } - - public SingularExampleBuilder<T> elf(Integer elfKey, T elfValue) { - if (this.elves$key == null) { - this.elves$key = new java.util.ArrayList<Integer>(); - this.elves$value = new java.util.ArrayList<T>(); - } - - this.elves$key.add(elfKey); - this.elves$value.add(elfValue); - return this; - } - - public SingularExampleBuilder<T> elves(java.util.Map<? extends Integer, ? extends T> elves) { - if (this.elves$key == null) { - this.elves$key = new java.util.ArrayList<Integer>(); - this.elves$value = new java.util.ArrayList<T>(); - } - - for (java.util.Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) { - this.elves$key.add($lombokEntry.getKey()); - this.elves$value.add($lombokEntry.getValue()); - } - return this; - } - - public SingularExampleBuilder<T> minutia(java.lang.Object minutia) { - if (this.minutiae == null) { - this.minutiae = new java.util.ArrayList<java.lang.Object>(); - } - - this.minutiae.add(minutia); - return this; - } - - public SingularExampleBuilder<T> minutiae(java.util.Collection<?> minutiae) { - if (this.minutiae == null) { - this.minutiae = new java.util.ArrayList<java.lang.Object>(); - } - - this.minutiae.addAll(minutiae); - return this; - } - - public SingularExample<T> build() { - java.util.Set<String> occupations; - switch (this.occupations == null ? 0 : this.occupations.size()) { - case 0: - occupations = java.util.Collections.emptySet(); - break; - - case 1: - occupations = java.util.Collections.singleton(this.occupations.get(0)); - break; - - default: - occupations = new java.util.LinkedHashSet<String>(this.occupations.size() < 1073741824 ? 1 + this.occupations.size() + (this.occupations.size() - 3) / 3 : java.lang.Integer.MAX_VALUE); - occupations.addAll(this.occupations); - occupations = java.util.Collections.unmodifiableSet(occupations); - - } - - com.google.common.collect.ImmutableList<String> axes = this.axes == null ? com.google.common.collect.ImmutableList.<String>of() : this.axes.build(); - - java.util.SortedMap<Integer, T> elves = new java.util.TreeMap<Integer, T>(); - if (this.elves$key != null) for (int $i = 0; $i < (this.elves$key == null ? 0 : this.elves$key.size()); $i++) elves.put(this.elves$key.get($i), this.elves$value.get($i)); - elves = java.util.Collections.unmodifiableSortedMap(elves); - - java.util.Collection<java.lang.Object> minutiae; - switch (this.minutiae == null ? 0 : this.minutiae.size()) { - case 0: - minutiae = java.util.Collections.emptyList(); - break; - - case 1: - minutiae = java.util.Collections.singletonList(this.minutiae.get(0)); - break; - - default: - minutiae = java.util.Collections.unmodifiableList(new java.util.ArrayList<java.lang.Object>(this.minutiae)); - - } - - return new SingularExample<T>(occupations, axes, elves, minutiae); - } - - @java.lang.Override - public java.lang.String toString() { - return "SingularExample.SingularExampleBuilder(occupations=" + this.occupations + ", axes=" + this.axes + ", elves$key=" + this.elves$key + ", elves$value=" + this.elves$value + ", minutiae=" + this.minutiae + ")"; - } - } - - @java.lang.SuppressWarnings("all") - public static <T extends Number> SingularExampleBuilder<T> builder() { - return new SingularExampleBuilder<T>(); - } -} diff --git a/usage_examples/Singular-snippetExample_pre.jpage b/usage_examples/Singular-snippetExample_pre.jpage deleted file mode 100644 index 65f6bbc8..00000000 --- a/usage_examples/Singular-snippetExample_pre.jpage +++ /dev/null @@ -1,14 +0,0 @@ -import lombok.Builder; -import lombok.Singular; -import java.util.Collection; -import java.util.Set; -import java.util.SortedMap; -import com.google.common.collect.ImmutableList; - -@Builder -public class SingularExample<T extends Number> { - private @Singular Set<String> occupations; - private @Singular("axis") ImmutableList<String> axes; - private @Singular SortedMap<Integer, T> elves; - private @Singular Collection<?> minutiae; -} diff --git a/usage_examples/SneakyThrowsExample_post.jpage b/usage_examples/SneakyThrowsExample_post.jpage deleted file mode 100644 index 916d94f0..00000000 --- a/usage_examples/SneakyThrowsExample_post.jpage +++ /dev/null @@ -1,19 +0,0 @@ -import lombok.Lombok; - -public class SneakyThrowsExample implements Runnable { - public String utf8ToString(byte[] bytes) { - try { - return new String(bytes, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw Lombok.sneakyThrow(e); - } - } - - public void run() { - try { - throw new Throwable(); - } catch (Throwable t) { - throw Lombok.sneakyThrow(t); - } - } -} diff --git a/usage_examples/SneakyThrowsExample_pre.jpage b/usage_examples/SneakyThrowsExample_pre.jpage deleted file mode 100644 index be6d72d5..00000000 --- a/usage_examples/SneakyThrowsExample_pre.jpage +++ /dev/null @@ -1,13 +0,0 @@ -import lombok.SneakyThrows; - -public class SneakyThrowsExample implements Runnable { - @SneakyThrows(UnsupportedEncodingException.class) - public String utf8ToString(byte[] bytes) { - return new String(bytes, "UTF-8"); - } - - @SneakyThrows - public void run() { - throw new Throwable(); - } -} diff --git a/usage_examples/SynchronizedExample_post.jpage b/usage_examples/SynchronizedExample_post.jpage deleted file mode 100644 index 219ab88a..00000000 --- a/usage_examples/SynchronizedExample_post.jpage +++ /dev/null @@ -1,23 +0,0 @@ -public class SynchronizedExample { - private static final Object $LOCK = new Object[0]; - private final Object $lock = new Object[0]; - private final Object readLock = new Object(); - - public static void hello() { - synchronized($LOCK) { - System.out.println("world"); - } - } - - public int answerToLife() { - synchronized($lock) { - return 42; - } - } - - public void foo() { - synchronized(readLock) { - System.out.println("bar"); - } - } -} diff --git a/usage_examples/SynchronizedExample_pre.jpage b/usage_examples/SynchronizedExample_pre.jpage deleted file mode 100644 index ace39f85..00000000 --- a/usage_examples/SynchronizedExample_pre.jpage +++ /dev/null @@ -1,20 +0,0 @@ -import lombok.Synchronized; - -public class SynchronizedExample { - private final Object readLock = new Object(); - - @Synchronized - public static void hello() { - System.out.println("world"); - } - - @Synchronized - public int answerToLife() { - return 42; - } - - @Synchronized("readLock") - public void foo() { - System.out.println("bar"); - } -} diff --git a/usage_examples/ToStringExample_post.jpage b/usage_examples/ToStringExample_post.jpage deleted file mode 100644 index 67e78f20..00000000 --- a/usage_examples/ToStringExample_post.jpage +++ /dev/null @@ -1,30 +0,0 @@ -import java.util.Arrays; - -public class ToStringExample { - private static final int STATIC_VAR = 10; - private String name; - private Shape shape = new Square(5, 10); - private String[] tags; - private int id; - - public String getName() { - return this.getName(); - } - - public static class Square extends Shape { - private final int width, height; - - public Square(int width, int height) { - this.width = width; - this.height = height; - } - - @Override public String toString() { - return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")"; - } - } - - @Override public String toString() { - return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")"; - } -} diff --git a/usage_examples/ToStringExample_pre.jpage b/usage_examples/ToStringExample_pre.jpage deleted file mode 100644 index 39b25892..00000000 --- a/usage_examples/ToStringExample_pre.jpage +++ /dev/null @@ -1,24 +0,0 @@ -import lombok.ToString; - -@ToString(exclude="id") -public class ToStringExample { - private static final int STATIC_VAR = 10; - private String name; - private Shape shape = new Square(5, 10); - private String[] tags; - private int id; - - public String getName() { - return this.name; - } - - @ToString(callSuper=true, includeFieldNames=true) - public static class Square extends Shape { - private final int width, height; - - public Square(int width, int height) { - this.width = width; - this.height = height; - } - } -} diff --git a/usage_examples/ValueExample_post.jpage b/usage_examples/ValueExample_post.jpage deleted file mode 100644 index 8a5d4836..00000000 --- a/usage_examples/ValueExample_post.jpage +++ /dev/null @@ -1,120 +0,0 @@ -import java.util.Arrays; - -public final class ValueExample { - private final String name; - private int age; - private final double score; - protected final String[] tags; - - @java.beans.ConstructorProperties({"name", "age", "score", "tags"}) - public ValueExample(String name, int age, double score, String[] tags) { - this.name = name; - this.age = age; - this.score = score; - this.tags = tags; - } - - public String getName() { - return this.name; - } - - public int getAge() { - return this.age; - } - - public double getScore() { - return this.score; - } - - public String[] getTags() { - return this.tags; - } - - @java.lang.Override - public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof ValueExample)) return false; - final ValueExample other = (ValueExample)o; - final Object this$name = this.getName(); - final Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; - if (this.getAge() != other.getAge()) return false; - if (Double.compare(this.getScore(), other.getScore()) != 0) return false; - if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); - result = result * PRIME + this.getAge(); - final long $score = Double.doubleToLongBits(this.getScore()); - result = result * PRIME + (int)($score >>> 32 ^ $score); - result = result * PRIME + Arrays.deepHashCode(this.getTags()); - return result; - } - - @java.lang.Override - public String toString() { - return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")"; - } - - ValueExample withAge(int age) { - return this.age == age ? this : new ValueExample(name, age, score, tags); - } - - public static final class Exercise<T> { - private final String name; - private final T value; - - private Exercise(String name, T value) { - this.name = name; - this.value = value; - } - - public static <T> Exercise<T> of(String name, T value) { - return new Exercise<T>(name, value); - } - - public String getName() { - return this.name; - } - - public T getValue() { - return this.value; - } - - @java.lang.Override - public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof ValueExample.Exercise)) return false; - final Exercise<?> other = (Exercise<?>)o; - final Object this$name = this.getName(); - final Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; - final Object this$value = this.getValue(); - final Object other$value = other.getValue(); - if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); - final Object $value = this.getValue(); - result = result * PRIME + ($value == null ? 43 : $value.hashCode()); - return result; - } - - @java.lang.Override - public String toString() { - return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")"; - } - } -}
\ No newline at end of file diff --git a/usage_examples/ValueExample_pre.jpage b/usage_examples/ValueExample_pre.jpage deleted file mode 100644 index d9550c25..00000000 --- a/usage_examples/ValueExample_pre.jpage +++ /dev/null @@ -1,19 +0,0 @@ -import lombok.AccessLevel; -import lombok.experimental.NonFinal; -import lombok.experimental.Value; -import lombok.experimental.Wither; -import lombok.ToString; - -@Value public class ValueExample { - String name; - @Wither(AccessLevel.PACKAGE) @NonFinal int age; - double score; - protected String[] tags; - - @ToString(includeFieldNames=true) - @Value(staticConstructor="of") - public static class Exercise<T> { - String name; - T value; - } -} diff --git a/usage_examples/experimental/AccessorsExample_post.jpage b/usage_examples/experimental/AccessorsExample_post.jpage deleted file mode 100644 index ae5a39db..00000000 --- a/usage_examples/experimental/AccessorsExample_post.jpage +++ /dev/null @@ -1,20 +0,0 @@ -public class AccessorsExample { - private int age = 10; - - public int age() { - return this.age; - } - - public AccessorsExample age(final int age) { - this.age = age; - return this; - } -} - -class PrefixExample { - private String fName = "Hello, World!"; - - public String getName() { - return this.fName; - } -} diff --git a/usage_examples/experimental/AccessorsExample_pre.jpage b/usage_examples/experimental/AccessorsExample_pre.jpage deleted file mode 100644 index f1591aba..00000000 --- a/usage_examples/experimental/AccessorsExample_pre.jpage +++ /dev/null @@ -1,14 +0,0 @@ -import lombok.experimental.Accessors; -import lombok.Getter; -import lombok.Setter; - -@Accessors(fluent = true) -public class AccessorsExample { - @Getter @Setter - private int age = 10; -} - -class PrefixExample { - @Accessors(prefix = "f") @Getter - private String fName = "Hello, World!"; -} diff --git a/usage_examples/experimental/DelegateExample_post.jpage b/usage_examples/experimental/DelegateExample_post.jpage deleted file mode 100644 index 1c5239f1..00000000 --- a/usage_examples/experimental/DelegateExample_post.jpage +++ /dev/null @@ -1,97 +0,0 @@ -import java.util.ArrayList; -import java.util.Collection; - -public class DelegationExample { - private interface SimpleCollection { - boolean add(String item); - boolean remove(Object item); - } - - private final Collection<String> collection = new ArrayList<String>(); - - @java.lang.SuppressWarnings("all") - public boolean add(final java.lang.String item) { - return this.collection.add(item); - } - - @java.lang.SuppressWarnings("all") - public boolean remove(final java.lang.Object item) { - return this.collection.remove(item); - } -} - -class ExcludesDelegateExample { - long counter = 0L; - - private interface Add { - boolean add(String x); - boolean addAll(Collection<? extends String> x); - } - - private final Collection<String> collection = new ArrayList<String>(); - - public boolean add(String item) { - counter++; - return collection.add(item); - } - - public boolean addAll(Collection<? extends String> col) { - counter += col.size(); - return collection.addAll(col); - } - - @java.lang.SuppressWarnings("all") - public int size() { - return this.collection.size(); - } - - @java.lang.SuppressWarnings("all") - public boolean isEmpty() { - return this.collection.isEmpty(); - } - - @java.lang.SuppressWarnings("all") - public boolean contains(final java.lang.Object arg0) { - return this.collection.contains(arg0); - } - - @java.lang.SuppressWarnings("all") - public java.util.Iterator<java.lang.String> iterator() { - return this.collection.iterator(); - } - - @java.lang.SuppressWarnings("all") - public java.lang.Object[] toArray() { - return this.collection.toArray(); - } - - @java.lang.SuppressWarnings("all") - public <T extends .java.lang.Object>T[] toArray(final T[] arg0) { - return this.collection.<T>toArray(arg0); - } - - @java.lang.SuppressWarnings("all") - public boolean remove(final java.lang.Object arg0) { - return this.collection.remove(arg0); - } - - @java.lang.SuppressWarnings("all") - public boolean containsAll(final java.util.Collection<?> arg0) { - return this.collection.containsAll(arg0); - } - - @java.lang.SuppressWarnings("all") - public boolean removeAll(final java.util.Collection<?> arg0) { - return this.collection.removeAll(arg0); - } - - @java.lang.SuppressWarnings("all") - public boolean retainAll(final java.util.Collection<?> arg0) { - return this.collection.retainAll(arg0); - } - - @java.lang.SuppressWarnings("all") - public void clear() { - this.collection.clear(); - } -} diff --git a/usage_examples/experimental/DelegateExample_pre.jpage b/usage_examples/experimental/DelegateExample_pre.jpage deleted file mode 100644 index 885ab3a8..00000000 --- a/usage_examples/experimental/DelegateExample_pre.jpage +++ /dev/null @@ -1,37 +0,0 @@ -import java.util.ArrayList; -import java.util.Collection; - -import lombok.experimental.Delegate; - -public class DelegationExample { - private interface SimpleCollection { - boolean add(String item); - boolean remove(Object item); - } - - @Delegate(types=SimpleCollection.class) - private final Collection<String> collection = new ArrayList<String>(); -} - - -class ExcludesDelegateExample { - long counter = 0L; - - private interface Add { - boolean add(String x); - boolean addAll(Collection<? extends String> x); - } - - @Delegate(excludes=Add.class) - private final Collection<String> collection = new ArrayList<String>(); - - public boolean add(String item) { - counter++; - return collection.add(item); - } - - public boolean addAll(Collection<? extends String> col) { - counter += col.size(); - return collection.addAll(col); - } -} diff --git a/usage_examples/experimental/ExtensionMethodExample_post.jpage b/usage_examples/experimental/ExtensionMethodExample_post.jpage deleted file mode 100644 index de46d776..00000000 --- a/usage_examples/experimental/ExtensionMethodExample_post.jpage +++ /dev/null @@ -1,21 +0,0 @@ -public class ExtensionMethodExample { - public String test() { - int[] intArray = {5, 3, 8, 2}; - java.util.Arrays.sort(intArray); - - String iAmNull = null; - return Extensions.or(iAmNull, Extensions.toTitleCase("hELlO, WORlD!")); - } -} - -class Extensions { - public static <T> T or(T obj, T ifNull) { - return obj != null ? obj : ifNull; - } - - public static String toTitleCase(String in) { - if (in.isEmpty()) return in; - return "" + Character.toTitleCase(in.charAt(0)) + - in.substring(1).toLowerCase(); - } -} diff --git a/usage_examples/experimental/ExtensionMethodExample_pre.jpage b/usage_examples/experimental/ExtensionMethodExample_pre.jpage deleted file mode 100644 index b3b9f1fa..00000000 --- a/usage_examples/experimental/ExtensionMethodExample_pre.jpage +++ /dev/null @@ -1,24 +0,0 @@ -import lombok.experimental.ExtensionMethod; - -@ExtensionMethod({java.util.Arrays.class, Extensions.class}) -public class ExtensionMethodExample { - public String test() { - int[] intArray = {5, 3, 8, 2}; - intArray.sort(); - - String iAmNull = null; - return iAmNull.or("hELlO, WORlD!".toTitleCase()); - } -} - -class Extensions { - public static <T> T or(T obj, T ifNull) { - return obj != null ? obj : ifNull; - } - - public static String toTitleCase(String in) { - if (in.isEmpty()) return in; - return "" + Character.toTitleCase(in.charAt(0)) + - in.substring(1).toLowerCase(); - } -} diff --git a/usage_examples/experimental/FieldDefaultsExample_post.jpage b/usage_examples/experimental/FieldDefaultsExample_post.jpage deleted file mode 100644 index 95c17a4b..00000000 --- a/usage_examples/experimental/FieldDefaultsExample_post.jpage +++ /dev/null @@ -1,12 +0,0 @@ -public class FieldDefaultsExample { - public final int a; - private final int b; - private int c; - final int d; - - FieldDefaultsExample() { - a = 0; - b = 0; - d = 0; - } -} diff --git a/usage_examples/experimental/FieldDefaultsExample_pre.jpage b/usage_examples/experimental/FieldDefaultsExample_pre.jpage deleted file mode 100644 index c8335832..00000000 --- a/usage_examples/experimental/FieldDefaultsExample_pre.jpage +++ /dev/null @@ -1,18 +0,0 @@ -import lombok.AccessLevel; -import lombok.experimental.FieldDefaults; -import lombok.experimental.NonFinal; -import lombok.experimental.PackagePrivate; - -@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) -public class FieldDefaultsExample { - public final int a; - int b; - @NonFinal int c; - @PackagePrivate int d; - - FieldDefaultsExample() { - a = 0; - b = 0; - d = 0; - } -} diff --git a/usage_examples/experimental/HelperExample_post.jpage b/usage_examples/experimental/HelperExample_post.jpage deleted file mode 100644 index 04a97b9f..00000000 --- a/usage_examples/experimental/HelperExample_post.jpage +++ /dev/null @@ -1,14 +0,0 @@ -public class HelperExample { - int someMethod(int arg1) { - int localVar = 5; - - class Helpers { - int helperMethod(int arg) { - return arg + localVar; - } - } - Helpers $Helpers = new Helpers(); - - return $Helpers.helperMethod(10); - } -} diff --git a/usage_examples/experimental/HelperExample_pre.jpage b/usage_examples/experimental/HelperExample_pre.jpage deleted file mode 100644 index cd86ef3c..00000000 --- a/usage_examples/experimental/HelperExample_pre.jpage +++ /dev/null @@ -1,15 +0,0 @@ -import lombok.experimental.Helper; - -public class HelperExample { - int someMethod(int arg1) { - int localVar = 5; - - @Helper class Helpers { - int helperMethod(int arg) { - return arg + localVar; - } - } - - return helperMethod(10); - } -} diff --git a/usage_examples/experimental/UtilityClassExample_post.jpage b/usage_examples/experimental/UtilityClassExample_post.jpage deleted file mode 100644 index 70810230..00000000 --- a/usage_examples/experimental/UtilityClassExample_post.jpage +++ /dev/null @@ -1,11 +0,0 @@ -public final class UtilityClassExample { - private static final int CONSTANT = 5; - - private UtilityClassExample() { - throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated"); - } - - public static void addSomething(int in) { - return in + CONSTANT; - } -} diff --git a/usage_examples/experimental/UtilityClassExample_pre.jpage b/usage_examples/experimental/UtilityClassExample_pre.jpage deleted file mode 100644 index 85731b81..00000000 --- a/usage_examples/experimental/UtilityClassExample_pre.jpage +++ /dev/null @@ -1,10 +0,0 @@ -import lombok.experimental.UtilityClass; - -@UtilityClass -public class UtilityClassExample { - private final int CONSTANT = 5; - - public void addSomething(int in) { - return in + CONSTANT; - } -} diff --git a/usage_examples/experimental/WitherExample_post.jpage b/usage_examples/experimental/WitherExample_post.jpage deleted file mode 100644 index 3447192a..00000000 --- a/usage_examples/experimental/WitherExample_post.jpage +++ /dev/null @@ -1,21 +0,0 @@ -import lombok.NonNull; - -public class WitherExample { - private final int age; - private @NonNull final String name; - - public WitherExample(String name, int age) { - if (name == null) throw new NullPointerException(); - this.name = name; - this.age = age; - } - - public WitherExample withAge(int age) { - return this.age == age ? this : new WitherExample(name, age); - } - - protected WitherExample withName(@NonNull String name) { - if (name == null) throw new java.lang.NullPointerException("name"); - return this.name == name ? this : new WitherExample(name, age); - } -}
\ No newline at end of file diff --git a/usage_examples/experimental/WitherExample_pre.jpage b/usage_examples/experimental/WitherExample_pre.jpage deleted file mode 100644 index 5db799fc..00000000 --- a/usage_examples/experimental/WitherExample_pre.jpage +++ /dev/null @@ -1,14 +0,0 @@ -import lombok.AccessLevel; -import lombok.NonNull; -import lombok.experimental.Wither; - -public class WitherExample { - @Wither private final int age; - @Wither(AccessLevel.PROTECTED) @NonNull private final String name; - - public WitherExample(String name, int age) { - if (name == null) throw new NullPointerException(); - this.name = name; - this.age = age; - } -} diff --git a/usage_examples/experimental/onXExample_post.jpage b/usage_examples/experimental/onXExample_post.jpage deleted file mode 100644 index 1be94f2a..00000000 --- a/usage_examples/experimental/onXExample_post.jpage +++ /dev/null @@ -1,22 +0,0 @@ -import javax.inject.Inject; -import javax.persistence.Id; -import javax.persistence.Column; -import javax.validation.constraints.Max; - -public class OnXExample { - private long unid; - - @Inject - public OnXExample(long unid) { - this.unid = unid; - } - - @Id @Column(name="unique-id") - public long getUnid() { - return unid; - } - - public void setUnid(@Max(10000) long unid) { - this.unid = unid; - } -} diff --git a/usage_examples/experimental/onXExample_pre.jpage b/usage_examples/experimental/onXExample_pre.jpage deleted file mode 100644 index e54371ae..00000000 --- a/usage_examples/experimental/onXExample_pre.jpage +++ /dev/null @@ -1,17 +0,0 @@ -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -import javax.inject.Inject; -import javax.persistence.Id; -import javax.persistence.Column; -import javax.validation.constraints.Max; - -@AllArgsConstructor(onConstructor=@__(@Inject)) -public class OnXExample { -// @Getter(onMethod=@__({@Id, @Column(name="unique-id")})) //JDK7 -// @Setter(onParam=@__(@Max(10000))) //JDK7 - @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 - @Setter(onParam_=@Max(10000)) //JDK8 - private long unid; -} diff --git a/usage_examples/valExample_post.jpage b/usage_examples/valExample_post.jpage deleted file mode 100644 index fa2e852e..00000000 --- a/usage_examples/valExample_post.jpage +++ /dev/null @@ -1,21 +0,0 @@ -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class ValExample { - public String example() { - final ArrayList<String> example = new ArrayList<String>(); - example.add("Hello, World!"); - final String foo = example.get(0); - return foo.toLowerCase(); - } - - public void example2() { - final HashMap<Integer, String> map = new HashMap<Integer, String>(); - map.put(0, "zero"); - map.put(5, "five"); - for (final Map.Entry<Integer, String> entry : map.entrySet()) { - System.out.printf("%d: %s\n", entry.getKey(), entry.getValue()); - } - } -} diff --git a/usage_examples/valExample_pre.jpage b/usage_examples/valExample_pre.jpage deleted file mode 100644 index a621640f..00000000 --- a/usage_examples/valExample_pre.jpage +++ /dev/null @@ -1,21 +0,0 @@ -import java.util.ArrayList; -import java.util.HashMap; -import lombok.val; - -public class ValExample { - public String example() { - val example = new ArrayList<String>(); - example.add("Hello, World!"); - val foo = example.get(0); - return foo.toLowerCase(); - } - - public void example2() { - val map = new HashMap<Integer, String>(); - map.put(0, "zero"); - map.put(5, "five"); - for (val entry : map.entrySet()) { - System.out.printf("%d: %s\n", entry.getKey(), entry.getValue()); - } - } -} diff --git a/website/extra/htaccess b/website/extra/htaccess index db3393af..2d5b6b2a 100644 --- a/website/extra/htaccess +++ b/website/extra/htaccess @@ -22,8 +22,6 @@ RewriteRule ^all-versions$ /all-versions.html [L,END] RewriteRule ^all-versions(\.html)?$ /all-versions [NC,R=301] RewriteRule ^disable-checked-exceptions$ /disable-checked-exceptions.html [L,END] RewriteRule ^disable-checked-exceptions(\.html)?$ /disable-checked-exceptions [NC,R=301] -RewriteRule ^contributing$ /contributing.html [L,END] -RewriteRule ^contributing(\.html)?$ /contributing [NC,R=301] RewriteRule ^supporters$ /supporters.html [L,END] RewriteRule ^supporters(.html)?$ /supporters [NC,R=301] RewriteRule ^order-license-info$ /order-license-info.html [L,END] @@ -31,6 +29,14 @@ RewriteRule ^order-?license-?info(.html)?$ /order-license-info [NC,R=301] RewriteRule ^order-license$ /order-license.html [L,END] RewriteRule ^order-?license(.html)?$ /order-license [NC,R=301] +RewriteRule ^contributing/index$ /contributing/index.html [L,END] +RewriteRule ^contributing(\.html)?$ /contributing/index [NC,R=301] +RewriteRule ^contributing/index(\.html)?$ /contributing/index [NC,R=301] +RewriteRule ^contributing/contributing$ /contributing/contributing.html [L,END] +RewriteRule ^contributing/contributing(\.html)?$ /contributing/contributing [NC,R=301] +RewriteRule ^contributing/lombok-execution-path$ /contributing/lombok-execution-path.html [L,END] +RewriteRule ^contributing/lombok-execution-path(\.html)?$ /contributing/lombok-execution-path [NC,R=301] + <#list setupPages as pg> RewriteRule ^setup/${pg?no_esc}$ /setup/${pg?no_esc}.html [L,END] RewriteRule ^setup/${pg?no_esc}(\.html)?$ /setup/${pg?no_esc} [NC,R=301] diff --git a/website/resources/js/supporters.js b/website/resources/js/supporters.js index 07319226..58db28cc 100644 --- a/website/resources/js/supporters.js +++ b/website/resources/js/supporters.js @@ -26,7 +26,7 @@ function toDate(s) { var x = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s); - if (x) return new Date(parseInt(x[1]), parseInt(x[2]), parseInt(x[3])); + if (x) return new Date(parseInt(x[1]), parseInt(x[2]) - 1, parseInt(x[3])); return null; } diff --git a/website/templates/_scaffold.html b/website/templates/_scaffold.html index 8bb22635..7acfb6b6 100644 --- a/website/templates/_scaffold.html +++ b/website/templates/_scaffold.html @@ -43,10 +43,12 @@ <title>${title}</title> - <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js" + integrity="sha384-bPV3mA2eo3edoq56VzcPBmG1N1QVUfjYMxVIJPPzyFJyFZ8GFfN7Npt06Zr23qts" crossorigin="anonymous"></script> <link href="/css/bootstrap.css" rel="stylesheet" /> - <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" /> + <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" + integrity="sha384-CmLV3WR+cw/TcN50vJSYAs2EAzhDD77tQvGcmoZ1KEzxtpl2K5xkrpFz9N2H9ClN" crossorigin="anonymous"> <link href="/css/custom.css" rel="stylesheet" /> @@ -55,8 +57,10 @@ <link href="${ld?url_path}" rel="stylesheet" /> </#if> </#list> - <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> - <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js"></script> + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js" + integrity="sha384-Pn+PczAsODRZ2PiGg0IheRROpP7lXO1NTIjiPo6cca8TliBvaeil42fobhzvZd74" crossorigin="anonymous"></script> + <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js" + integrity="sha384-VI5+XuguQ/l3kUhh4knz7Hxptx47wpQbVRDnp8v7Vvuhzwn1PEYb/uvtH6KLxv6d" crossorigin="anonymous"></script> <script src="/js/history.js"></script> <script src="/js/main.js"></script> @@ -98,7 +102,7 @@ ga('send', 'pageview'); <ul class="dropdown-menu" aria-labelledby="themes"> <li><a href="https://groups.google.com/group/project-lombok" rel="noopener">Discuss / Help</a></li> <li><a href="https://github.com/rzwitserloot/lombok/issues" rel="noopener">Issues</a></li> - <li><a href="/contributing">Contribute</a></li> + <li><a href="/contributing/index">Documentation for contributors</a></li> </ul> </li> <li> diff --git a/website/templates/contributing.html b/website/templates/contributing/contributing.html index 16d68f32..8da9b827 100644 --- a/website/templates/contributing.html +++ b/website/templates/contributing/contributing.html @@ -1,4 +1,4 @@ -<#import "/_scaffold.html" as main> +<#import "../_scaffold.html" as main> <@main.scaffold title="Contribute"> <div class="page-header top5"> diff --git a/website/templates/contributing/index.html b/website/templates/contributing/index.html new file mode 100644 index 00000000..4f6a1bca --- /dev/null +++ b/website/templates/contributing/index.html @@ -0,0 +1,17 @@ +<#import "../_scaffold.html" as main> + +<@main.scaffold title="Documentation for being a lombok developer"> + <div class="page-header top5"> + <div class="row text-center"> + <@main.h1 title="Documentation for lombok developers" /> + </div> + <div class="row"> + <@main.feature title="contributing" href="contributing"> + Want to contribute to Project Lombok? Start by reading this introduction. + </@main.feature> + <@main.feature title="execution path" href="lombok-execution-path"> + Discusses how lombok ends up being invoked, and how it gets around to transforming code being compiled / edited. + </@main.feature> + </div> + </div> +</@main.scaffold> diff --git a/website/templates/contributing/lombok-execution-path.html b/website/templates/contributing/lombok-execution-path.html new file mode 100644 index 00000000..1fa2f697 --- /dev/null +++ b/website/templates/contributing/lombok-execution-path.html @@ -0,0 +1,45 @@ +<#import "../_scaffold.html" as main> + +<@main.scaffold title="Lombok Execution Path"> + <div class="page-header top5"> + <div class="row text-center"> + <@main.h1 title="Lombok Execution Path" /> + </div><div class="row text-center"> + <@main.h1 title="Javac: Launching as annotation processor" /> + </div><div class="row"> + <p> + With <code>javac</code> (and netbeans, maven, gradle, and most other build systems), lombok runs as an annotation processor. + </p><p> + Lombok is on the classpath, and <code>javac</code> will load every <code>META-INF/services/javax.annotation.processing.Processor</code> file on the classpath it can find, reading each line and loading that class, then executing it as an annotation processor. <code>lombok.jar</code> has this file, it lists <code>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</code> as entry. + </p><p> + This class is not actually visible (it is public, but its outer class (<code>AnnotationProcessorHider</code>) is package private, making it invisible to java-the-language), however, it is considered visible for the purposes of java-the-VM and therefore it will run. This convoluted trick is used to ensure that anybody who develops with lombok on the classpath doesn't get lombok's classes or lombok's dependencies injected into their 'namespace' (for example, if you add lombok to your project, your IDE will <em>not</em> start suggesting lombok classes for auto-complete dialogs). + </p><p> + The <code>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</code> class is loaded by <code>javac</code>, instantiated, and <code>init()</code> is called on it. This class starts lombok's <code>ShadowClassLoader</code>; it finds the jar file it is in, then will start loading classes from this jar file. It looks not for files ending in <code>.class</code> like normal loaders, it looks for files ending in <code>.SCL.lombok</code> instead (this too is for the purpose of hiding lombok's classes from IDEs and such). Via this classloader, the <em>real</em> annotation processor is launched, which is class <code>lombok.core.AnnotationProcessor</code>. + </p><p> + The <code>lombok.core.AnnotationProcessor</code> is also a delegating processor. It can delegate to one of 2 sub-processors based on the environment lombok finds itself in: If it's javac, class <code>lombok.javac.apt.LombokProcessor</code> is used (and if the plexus compiler framework is used, which can be the case when compiling with javac, some extra code runs to patch lombok into its modular classloading architecture). If it's ecj (eclipse's compiler, which means we're either running inside eclipse itself, or being invoked as annotation processor for ecj, the standalone eclipse compiler), errors/warnings are injected into the compilation process to tell the user they should use different parameters to <a href="/setup/ecj">use lombok in eclipse/ecj</a>. + </p><p> + <code>lombok.javac.apt.LombokProcessor</code> is the 'real' annotation processor that does the work of transforming your code. + </p><p> + code transformation is fundamentally a cyclic concept: To generate some code you want to know about the code (which annotations are in it, for example), but when you generate new code, interpreting it means we start over. The same applies to lombok itself: Some of lombok's transformations add methods which then have an effect on other lombok transformations. Because of that, lombok divides up the handlers into 'levels'. All handlers at the highest level are executed, then a new annotation round is forced (which integrates generated stuff into the symbol tables and such), and then the handlers at the next level are executed. These levels are indicated via the <code>@HandlerPriority</code> annotation. You force javac to run another round by generating a file. We don't actually want to generate any files, so we generate a dummy file and patch the javac <em>filer</em> to not actually save lombok-generated dummy files anywhere. The various <code>HandleX</code> classes, which apply the actual lombok transformations, are stored in <code>HandlerLibrary</code> which uses SPI to discover the handle classes. + </p> + </div><div class="row text-center"> + <@main.h1 title="Eclipse/ECJ: Launching as agent" /> + </div><div class="row"> + <p> + With <code>ecj</code> and <code>eclipse</code>, lombok starts as an 'agent'. That's a bit like a debugger: It lets lombok inspect raw class bytecode <em>before</em> the JVM actually loads these classes, and lombok will modify this code in order to ensure that ecj/eclipse involves lombok in the compilation process. + </p><p> + The patching of classes is done by the code in the <code>src/eclipseAgent</code> sourcedir. Note that the patching code has to patch equinox, the eclipse module system, to ensure lombok and the java compilation module (The 'JDT' module, in eclipse parlance) can see each other. + </p><p> + A bunch of ad-hoc fixes to issues (such as the eclipse format-my-code feature needing a few tactical bytecode patches to ensure it doesn't mess up formatting source) are applied, but the main 'run lombok as part of the compilation process' hook injected into ecj/eclipse leads to the <code>lombok.eclipse.TransformEclipseAST</code> class, which can be considered the entrypoint. Unless you want to mess with how lombok is loaded into eclipse/ecj, start there. + </p><p> + Each <code>HandleX</code> class is discovered via SPI and lombok will invoke the handle classes as needed. Handle classes find lombok annotations and apply the desired transformations. The handlers are in the <code>lombok.eclipse.handlers</code> package from the <code>src/core</code> sourcedir. + </p> + </div><div class="row text-center"> + <@main.h1 title="VSCode and IntelliJ: Launching as a plugin" /> + </div><div class="row"> + <p> + Lombok support in these two IDEs is taken care of by plugins for these IDEs. + </p> + </div> + </div> +</@main.scaffold> diff --git a/website/templates/features/EqualsAndHashCode.html b/website/templates/features/EqualsAndHashCode.html index 3c11367f..5a7b8166 100644 --- a/website/templates/features/EqualsAndHashCode.html +++ b/website/templates/features/EqualsAndHashCode.html @@ -3,7 +3,7 @@ <@f.scaffold title="@EqualsAndHashCode" logline="Equality made easy: Generates <code>hashCode</code> and <code>equals</code> implementations from the fields of your object."> <@f.overview> <p> - Any class definition may be annotated with <code>@EqualsAndHashCode</code> to let lombok generate implementations of the <code>equals(Object other)</code> and <code>hashCode()</code> methods. By default, it'll use all non-static, non-transient fields, but you can exclude more fields by naming them in the optional <code>exclude</code> parameter to the annotation. Alternatively, you can specify exactly which fields you wish to be used by naming them in the <code>of</code> parameter. + Any class definition may be annotated with <code>@EqualsAndHashCode</code> to let lombok generate implementations of the <code>equals(Object other)</code> and <code>hashCode()</code> methods. By default, it'll use all non-static, non-transient fields, but you can modify which fields are used (and even specify that the output of various methods is to be used) by marking type members with <code>@EqualsAndHashCode.Include</code> or <code>@EqualsAndHashCode.Exclude</code>. Alternatively, you can specify exactly which fields or methods you wish to be used by marking them with <code>@EqualsAndHashCode.Include</code> and using <code>@EqualsAndHashCode(onlyExplicitlyIncluded = true)</code>. </p><p> If applying <code>@EqualsAndHashCode</code> to a class that extends another, this feature gets a bit trickier. Normally, auto-generating an <code>equals</code> and <code>hashCode</code> method for such classes is a bad idea, as the superclass also defines fields, which also need equals/hashCode code but this code will not be generated. By setting <code>callSuper</code> to <em>true</em>, you can include the <code>equals</code> and <code>hashCode</code> methods of your superclass in the generated methods. For <code>hashCode</code>, the result of <code>super.hashCode()</code> is included in the hash algorithm, and for<code>equals</code>, the generated method will return false if the super implementation thinks it is not equal to the passed in object. Be aware that not all <code>equals</code> implementations handle this situation properly. However, lombok-generated <code>equals</code> implementations <strong>do</strong> handle this situation properly, so you can safely call your superclass equals if it, too, has a lombok-generated <code>equals</code> method. If you have an explicit superclass you are forced to supply some value for <code>callSuper</code> to acknowledge that you've considered it; failure to do so results in a warning. </p><p> @@ -43,11 +43,13 @@ </p><p> If there is <em>any</em> method named either <code>hashCode</code> or <code>equals</code>, regardless of return type, no methods will be generated, and a warning is emitted instead. These 2 methods need to be in sync with each other, which lombok cannot guarantee unless it generates all the methods, hence you always get a warning if one <em>or</em> both of the methods already exist. You can mark any method with <code>@lombok.experimental.Tolerate</code> to hide them from lombok. </p><p> - Attempting to exclude fields that don't exist or would have been excluded anyway (because they are static or transient) results in warnings on the named fields. You therefore don't have to worry about typos. + Attempting to exclude fields that don't exist or would have been excluded anyway (because they are static or transient) results in warnings on the named fields. </p><p> - Having both <code>exclude</code> and <code>of</code> generates a warning; the <code>exclude</code> parameter will be ignored in that case. + If a method is marked for inclusion and it has the same name as a field, it replaces the field (the method is included, the field is excluded). </p><p> - By default, any variables that start with a $ symbol are excluded automatically. You can onlyinclude them by using the 'of' parameter. + Prior to lombok 1.16.22, inclusion/exclusion could be done with the <code>of</code> and <code>exclude</code> parameters of the <code>@EqualsAndHashCode</code> annotation. This old-style inclusion mechanism is still supported but will be deprecated in the future. + </p><p> + By default, any variables that start with a $ symbol are excluded automatically. You can only include them by marking them with <code>@EqualsAndHashCode.Include</code>. </p><p> If a getter exists for a field to be included, it is called instead of using a direct field reference. This behaviour can be suppressed:<br /> <code>@EqualsAndHashCode(doNotUseGetters = true)</code> diff --git a/website/templates/features/NonNull.html b/website/templates/features/NonNull.html index 28d083d0..3d99a3c7 100644 --- a/website/templates/features/NonNull.html +++ b/website/templates/features/NonNull.html @@ -11,7 +11,7 @@ </p><p> Lombok has always treated any annotation named <code>@NonNull</code> on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via for example <a href="/features/Data"><code>@Data</code></a>. Now, however, using lombok's own <code>@lombok.NonNull</code> on a parameter results in the insertion of just the null-check statement inside your own method or constructor. </p><p> - The null-check looks like <code>if (param == null) throw new NullPointerException("param");</code> and will be inserted at the very top of your method. For constructors, the null-check will be inserted immediately following any explicit <code>this()</code> or <code>super()</code> calls. + The null-check looks like <code>if (param == null) throw new NullPointerException("param is marked @NonNull but is null");</code> and will be inserted at the very top of your method. For constructors, the null-check will be inserted immediately following any explicit <code>this()</code> or <code>super()</code> calls. </p><p> If a null-check is already present at the top, no additional null-check will be generated. </p> @@ -23,7 +23,7 @@ <dt> <code>lombok.nonNull.exceptionType</code> = [<code>NullPointerException</code> | <code>IllegalArgumentException</code>] (default: <code>NullPointerException</code>). </dt><dd> - When lombok generates a null-check <code>if</code> statement, by default, a <code>java.lang.NullPointerException</code> will be thrown with the field name as the exception message. However, you can use <code>IllegalArgumentException</code> in this configuration key to have lombok throw that exception, with '<em>fieldName</em> is null' as exception message. + When lombok generates a null-check <code>if</code> statement, by default, a <code>java.lang.NullPointerException</code> will be thrown with '<em>field name</em> is marked @NonNull but is null' as the exception message. However, you can use <code>IllegalArgumentException</code> in this configuration key to have lombok throw that exception with this message instead. </dd><dt> <code>lombok.nonNull.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> diff --git a/website/templates/features/ToString.html b/website/templates/features/ToString.html index 6f230561..d31cf35d 100644 --- a/website/templates/features/ToString.html +++ b/website/templates/features/ToString.html @@ -7,9 +7,13 @@ </p><p> By setting the <code>includeFieldNames</code> parameter to <em>true</em> you can add some clarity (but also quite some length) to the output of the <code>toString()</code> method. </p><p> - By default, all non-static fields will be printed. If you want to skip some fields, you can name them in the <code>exclude</code> parameter; each named field will not be printed at all. Alternatively, you can specify exactly which fields you wish to be used by naming them in the <code>of</code> parameter. + By default, all non-static fields will be printed. If you want to skip some fields, you can annotate these fields with <code>@ToString.Exclude</code>. Alternatively, you can specify exactly which fields you wish to be used by using <code>@ToString(onlyExplicitlyIncluded = true)</code>, then marking each field you want to include with <code>@ToString.Include</code>. </p><p> By setting <code>callSuper</code> to <em>true</em>, you can include the output of the superclass implementation of <code>toString</code> to the output. Be aware that the default implementation of <code>toString()</code> in <code>java.lang.Object</code> is pretty much meaningless, so you probably don't want to do this unless you are extending another class. + </p><p> + You can also include the output of a method call in your <code>toString</code>. Only instance (non-static) methods that take no arguments can be included. To do so, mark the method with <code>@ToString.Include</code>. + </p><p> + You can change the name used to identify the member with <code>@ToString.Include(name = "some other name")</code>, and you can change the order in which the members are printed via <code>@ToString.Include(rank = -1)</code>. Members without a rank are considered to have rank 0, members of a higher rank are printed first, and members of the same rank are printed in the same order they appear in the source file. </p> </@f.overview> @@ -37,13 +41,15 @@ </p><p> Arrays are printed via <code>Arrays.deepToString</code>, which means that arrays that contain themselves will result in <code>StackOverflowError</code>s. However, this behaviour is no different from e.g. <code>ArrayList</code>. </p><p> - Attempting to exclude fields that don't exist or would have been excluded anyway (because they are static) results in warnings on the named fields. You therefore don't have to worry about typos. + If a method is marked for inclusion and it has the same name as a field, it replaces the toString output for that field (the method is included, the field is excluded, and the method's output is printed in the place the field would be printed). + </p><p> + Prior to lombok 1.16.22, inclusion/exclusion could be done with the <code>of</code> and <code>exclude</code> parameters of the <code>@ToString</code> annotation. This old-style inclusion mechanism is still supported but will be deprecated in the future. </p><p> - Having both <code>exclude</code> and <code>of</code> generates a warning; the <code>exclude</code> parameter will be ignored in that case. + Having both <code>@ToString.Exclude</code> and <code>@ToString.Include</code> on a member generates a warning; the member will be excluded in this case. </p><p> We don't promise to keep the output of the generated <code>toString()</code> methods the same between lombok versions. You should never design your API so that other code is forced to parse your <code>toString()</code> output anyway! </p><p> - By default, any variables that start with a $ symbol are excluded automatically. You can only include them by using the 'of' parameter. + By default, any variables that start with a $ symbol are excluded automatically. You can only include them by using the <code>@ToString.Include</code> annotation. </p><p> If a getter exists for a field to be included, it is called instead of using a direct field reference. This behaviour can be suppressed:<br /> <code>@ToString(doNotUseGetters = true)</code> diff --git a/website/templates/features/experimental/FieldNameConstants.html b/website/templates/features/experimental/FieldNameConstants.html new file mode 100644 index 00000000..c5e57195 --- /dev/null +++ b/website/templates/features/experimental/FieldNameConstants.html @@ -0,0 +1,54 @@ +<#import "../_features.html" as f> + +<@f.scaffold title="@FieldNameConstants" logline="Name... that... field! String constants for your field's names."> + <@f.history> + <p> + @FieldNameConstants was introduced as experimental feature in lombok v1.16.22. + </p> + </@f.history> + + <@f.experimental> + <ul> + <li> + New feature; unsure if this busts enough boilerplate. + </li> + </ul> + Current status: <em>neutral</em> - As a just-introduced feature we're still gathering feedback. + </@f.experimental> + + <@f.overview> + <p> + The <code>@FieldNameConstants</code> annotation generates string constants (fields marked <code>public static final</code>, of type <code>java.lang.String</code>) containing the field's name, as a string. This is useful for various marshalling and serialization frameworks. The constant field by default is named <code>FIELD_<em>NAME_OF_FIELD</em></code>, where <em>NAME_OF_FIELD</em> is the same name as the field it represents, except with all uppercase letters, with underscores in front of the uppercase letters in the original field. The prefix (and suffix) is configurable on the <code>@FieldNameConstants</code> annotation. + </p><p> + The <code>public</code> access modifier can be changed via the parameter <code>level = AccessLevel.PACKAGE</code> for example. You can force a field to be skipped by supplying <code>level = AccessLevel.NONE</code>. + </p><p> + Can be applied to classes (in which case every field gets a constant), or to an individual field. + </p> + </@f.overview> + + <@f.snippets name="experimental/FieldNameConstants" /> + + <@f.confKeys> + <dt> + <code>lombok.fieldNameConstants.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) + </dt><dd> + Lombok will flag any usage of <code>@FieldDefaults</code> as a warning or error if configured. + </dd><dt> + <code>lombok.fieldNameConstants.prefix</code> = <em>a string</em> (default: 'PREFIX_') + </dt><dd> + Lombok will generate the name for each fieldconstant by constant-casing the field name and then prefixing this string to the result. + </dd><dt> + <code>lombok.fieldNameConstants.suffix</code> = <em>a string</em> (default: '' - the blank string) + </dt><dd> + Lombok will generate the name for each fieldconstant by constant-casing the field name and then suffixing this string to the result. + </dd> + </@f.confKeys> + + <@f.smallPrint> + <p> + Like other lombok handlers that touch fields, any field whose name starts with a dollar (<code>$</code>) symbol is skipped entirely. Such a field will not be modified at all. Static fields are also skipped. + </p><p> + The annotation can itself be used to set prefix/suffix. If you do so, it overrides the <code>lombok.fieldNameConstants.prefix/suffix</code> config key. Example: <code>@FieldNameConstants(prefix = "")</code>: This would generate for field <code>helloWorld</code> a constant named <code>HELLO_WORLD</code> instead of the default <code>FIELD_HELLO_WORLD</code>. + </p> + </@f.smallPrint> +</@f.scaffold> diff --git a/website/templates/features/experimental/index.html b/website/templates/features/experimental/index.html index 988a7154..ba830ab5 100644 --- a/website/templates/features/experimental/index.html +++ b/website/templates/features/experimental/index.html @@ -63,6 +63,10 @@ With a little help from my friends... Helper methods for java. </@main.feature> + <@main.feature title="@FieldNameConstants" href="FieldNameConstants"> + Name... that... field! String constants for your field's names. + </@main.feature> + <@main.feature title="@SuperBuilder" href="SuperBuilder"> Bob now knows his ancestors: Builders with fields from superclasses, too. </@main.feature> diff --git a/website/templates/features/log.html b/website/templates/features/log.html index 2854e896..1de26836 100644 --- a/website/templates/features/log.html +++ b/website/templates/features/log.html @@ -6,6 +6,8 @@ The various <code>@Log</code> variants were added in lombok v0.10. <em>NEW in lombok 0.10: </em>You can annotate any class with a log annotation to let lombok generate a logger field.<br/> The logger is named <code>log</code> and the field's type depends on which logger you have selected. + </p><p> + <em>NEW in lombok v1.16.24: </em>Addition of google's FluentLogger (flogger). </p> </@f.history> @@ -20,13 +22,17 @@ </dt><dd> Creates <code><span class="keyword">private static final </span><a href="https://commons.apache.org/logging/apidocs/org/apache/commons/logging/Log.html">org.apache.commons.logging.Log</a> <span class="staticfield">log</span> = <a href="https://commons.apache.org/logging/apidocs/org/apache/commons/logging/LogFactory.html#getLog(java.lang.Class)">org.apache.commons.logging.LogFactory.getLog</a>(LogExample.<span class="keyword">class</span>);</code> </dd><dt> + <code>@Flogger</code> + </dt><dd> + Creates <code><span class="keyword">private static final </span><a href="https://google.github.io/flogger/">com.google.common.flogger.FluentLogger</a> <span class="staticfield">log</span> = com.google.common.flogger.FluentLogger.forEnclosingClass();</code> + </dd><dt> <code>@JBossLog</code> </dt><dd> - Creates <code><span class="keyword">private static final </span><a href="http://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html">org.jboss.logging.Logger</a> <span class="staticfield">log</span> = <a href="http://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html#getLogger(java.lang.Class)">org.jboss.logging.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>);</code> + Creates <code><span class="keyword">private static final </span><a href="https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html">org.jboss.logging.Logger</a> <span class="staticfield">log</span> = <a href="https://docs.jboss.org/jbosslogging/latest/org/jboss/logging/Logger.html#getLogger(java.lang.Class)">org.jboss.logging.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>);</code> </dd><dt> <code>@Log</code> </dt><dd> - Creates <code><span class="keyword">private static final </span><a href="http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html">java.util.logging.Logger</a> <span class="staticfield">log</span> = <a href="http://download.oracle.com/javase/6/docs/api/java/util/logging/Logger.html#getLogger(java.lang.String)">java.util.logging.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>.getName());</code> + Creates <code><span class="keyword">private static final </span><a href="https://docs.oracle.com/javase/6/docs/api/java/util/logging/Logger.html">java.util.logging.Logger</a> <span class="staticfield">log</span> = <a href="https://docs.oracle.com/javase/6/docs/api/java/util/logging/Logger.html#getLogger(java.lang.String)">java.util.logging.Logger.getLogger</a>(LogExample.<span class="keyword">class</span>.getName());</code> </dd><dt> <code>@Log4j</code> </dt><dd> @@ -38,11 +44,11 @@ </dd><dt> <code>@Slf4j</code> </dt><dd> - Creates <code><span class="keyword">private static final </span><a href="http://www.slf4j.org/api/org/slf4j/Logger.html">org.slf4j.Logger</a> <span class="staticfield">log</span> = <a href="http://www.slf4j.org/apidocs/org/slf4j/LoggerFactory.html#getLogger(java.lang.Class)">org.slf4j.LoggerFactory.getLogger</a>(LogExample.<span class="keyword">class</span>);</code> + Creates <code><span class="keyword">private static final </span><a href="https://www.slf4j.org/api/org/slf4j/Logger.html">org.slf4j.Logger</a> <span class="staticfield">log</span> = <a href="https://www.slf4j.org/api/org/slf4j/LoggerFactory.html#getLogger(java.lang.Class)">org.slf4j.LoggerFactory.getLogger</a>(LogExample.<span class="keyword">class</span>);</code> </dd><dt> <code>@XSlf4j</code> </dt><dd> - Creates <code><span class="keyword">private static final </span><a href="http://www.slf4j.org/api/org/slf4j/ext/XLogger.html">org.slf4j.ext.XLogger</a> <span class="staticfield">log</span> = <a href="http://www.slf4j.org/apidocs/org/slf4j/ext/XLoggerFactory.html#getXLogger(java.lang.Class)">org.slf4j.ext.XLoggerFactory.getXLogger</a>(LogExample.<span class="keyword">class</span>);</code> + Creates <code><span class="keyword">private static final </span><a href="https://www.slf4j.org/api/org/slf4j/ext/XLogger.html">org.slf4j.ext.XLogger</a> <span class="staticfield">log</span> = <a href="https://www.slf4j.org/api/org/slf4j/ext/XLoggerFactory.html#getXLogger(java.lang.Class)">org.slf4j.ext.XLoggerFactory.getXLogger</a>(LogExample.<span class="keyword">class</span>);</code> </dd> </dl> </p><p> @@ -70,14 +76,18 @@ </dt><dd> Lombok will flag any usage of <code>@lombok.extern.apachecommons.CommonsLog</code> as a warning or error if configured. </dd><dt> - <code>lombok.log.javaUtilLogging.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) + <code>lombok.log.flogger.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> - Lombok will flag any usage of <code>@lombok.extern.java.Log</code> as a warning or error if configured. + Lombok will flag any usage of <code>@lombok.extern.flogger.Flogger</code> as a warning or error if configured. </dd><dt> <code>lombok.log.jbosslog.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> Lombok will flag any usage of <code>@lombok.extern.jbosslog.JBossLog</code> as a warning or error if configured. </dd><dt> + <code>lombok.log.javaUtilLogging.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) + </dt><dd> + Lombok will flag any usage of <code>@lombok.extern.java.Log</code> as a warning or error if configured. + </dd><dt> <code>lombok.log.log4j.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set) </dt><dd> Lombok will flag any usage of <code>@lombok.extern.log4j.Log4j</code> as a warning or error if configured. diff --git a/website/usageExamples/BuilderExample_post.jpage b/website/usageExamples/BuilderExample_post.jpage index 54b064d7..24d326b3 100644 --- a/website/usageExamples/BuilderExample_post.jpage +++ b/website/usageExamples/BuilderExample_post.jpage @@ -1,6 +1,7 @@ import java.util.Set; public class BuilderExample { + private long created; private String name; private int age; private Set<String> occupations; @@ -11,11 +12,17 @@ public class BuilderExample { this.occupations = occupations; } + private static long $default$created() { + return System.currentTimeMillis(); + } + public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } public static class BuilderExampleBuilder { + private long created; + private boolean created$set; private String name; private int age; private java.util.ArrayList<String> occupations; @@ -23,6 +30,12 @@ public class BuilderExample { BuilderExampleBuilder() { } + public BuilderExampleBuilder created(long created) { + this.created = created; + this.created$set = true; + return this; + } + public BuilderExampleBuilder name(String name) { this.name = name; return this; @@ -61,14 +74,13 @@ public class BuilderExample { public BuilderExample build() { // complicated switch statement to produce a compact properly sized immutable set omitted. - // go to https://projectlombok.org/features/Singular-snippet.html to see it. Set<String> occupations = ...; - return new BuilderExample(name, age, occupations); + return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations); } @java.lang.Override public String toString() { - return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")"; + return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")"; } } }
\ No newline at end of file diff --git a/website/usageExamples/BuilderExample_pre.jpage b/website/usageExamples/BuilderExample_pre.jpage index 1557fff4..3b1b0df2 100644 --- a/website/usageExamples/BuilderExample_pre.jpage +++ b/website/usageExamples/BuilderExample_pre.jpage @@ -4,6 +4,7 @@ import java.util.Set; @Builder public class BuilderExample { + @Builder.Default private long created = System.currentTimeMillis(); private String name; private int age; @Singular private Set<String> occupations; diff --git a/website/usageExamples/EqualsAndHashCodeExample_pre.jpage b/website/usageExamples/EqualsAndHashCodeExample_pre.jpage index 64faf59f..cf235917 100644 --- a/website/usageExamples/EqualsAndHashCodeExample_pre.jpage +++ b/website/usageExamples/EqualsAndHashCodeExample_pre.jpage @@ -1,13 +1,13 @@ import lombok.EqualsAndHashCode; -@EqualsAndHashCode(exclude={"id", "shape"}) +@EqualsAndHashCode public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; - private Shape shape = new Square(5, 10); + @EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10); private String[] tags; - private int id; + @EqualsAndHashCode.Exclude private int id; public String getName() { return this.name; diff --git a/website/usageExamples/NonNullExample_post.jpage b/website/usageExamples/NonNullExample_post.jpage index 24175e06..bb67b3f6 100644 --- a/website/usageExamples/NonNullExample_post.jpage +++ b/website/usageExamples/NonNullExample_post.jpage @@ -6,7 +6,7 @@ public class NonNullExample extends Something { public NonNullExample(@NonNull Person person) { super("Hello"); if (person == null) { - throw new NullPointerException("person"); + throw new NullPointerException("person is marked @NonNull but is null"); } this.name = person.getName(); } diff --git a/website/usageExamples/ToStringExample_pre.jpage b/website/usageExamples/ToStringExample_pre.jpage index a15fb944..1b6b58e0 100644 --- a/website/usageExamples/ToStringExample_pre.jpage +++ b/website/usageExamples/ToStringExample_pre.jpage @@ -1,15 +1,15 @@ import lombok.ToString; -@ToString(exclude="id") +@ToString public class ToStringExample { private static final int STATIC_VAR = 10; private String name; private Shape shape = new Square(5, 10); private String[] tags; - private int id; + @ToString.Exclude private int id; public String getName() { - return this.getName(); + return this.name; } @ToString(callSuper=true, includeFieldNames=true) diff --git a/website/usageExamples/experimental/FieldNameConstantsExample_post.jpage b/website/usageExamples/experimental/FieldNameConstantsExample_post.jpage new file mode 100644 index 00000000..67d89891 --- /dev/null +++ b/website/usageExamples/experimental/FieldNameConstantsExample_post.jpage @@ -0,0 +1,7 @@ +public class FieldNameConstantsExample { + public static final String FIELD_I_AM_A_FIELD = "iAmAField"; + static final String FIELD_AND_SO_AM_I = "andSoAmI"; + + private final String iAmAField; + private final int andSoAmI; +} diff --git a/website/usageExamples/experimental/FieldNameConstantsExample_pre.jpage b/website/usageExamples/experimental/FieldNameConstantsExample_pre.jpage new file mode 100644 index 00000000..dc6376eb --- /dev/null +++ b/website/usageExamples/experimental/FieldNameConstantsExample_pre.jpage @@ -0,0 +1,9 @@ +import lombok.experimental.FieldNameConstants; +import lombok.AccessLevel; + +@FieldNameConstants +public class FieldNameConstantsExample { + private final String iAmAField; + @FieldNameConstants(level = AccessLevel.PACKAGE) + private final int andSoAmI; +} diff --git a/website/usageExamples/experimental/onXExample_pre.jpage b/website/usageExamples/experimental/onXExample_pre.jpage index f8fcb435..e54371ae 100644 --- a/website/usageExamples/experimental/onXExample_pre.jpage +++ b/website/usageExamples/experimental/onXExample_pre.jpage @@ -9,7 +9,9 @@ import javax.validation.constraints.Max; @AllArgsConstructor(onConstructor=@__(@Inject)) public class OnXExample { - @Getter(onMethod=@__({@Id, @Column(name="unique-id")})) - @Setter(onParam=@__(@Max(10000))) +// @Getter(onMethod=@__({@Id, @Column(name="unique-id")})) //JDK7 +// @Setter(onParam=@__(@Max(10000))) //JDK7 + @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 + @Setter(onParam_=@Max(10000)) //JDK8 private long unid; } diff --git a/usage_examples/experimental/varExample_post.jpage b/website/usageExamples/experimental/varExample_post.jpage index d0a7c124..d0a7c124 100644 --- a/usage_examples/experimental/varExample_post.jpage +++ b/website/usageExamples/experimental/varExample_post.jpage diff --git a/usage_examples/experimental/varExample_pre.jpage b/website/usageExamples/experimental/varExample_pre.jpage index e58c4c0d..e58c4c0d 100644 --- a/usage_examples/experimental/varExample_pre.jpage +++ b/website/usageExamples/experimental/varExample_pre.jpage |